whisper.cat stuff

This commit is contained in:
[Harper Innes]
2023-10-05 23:28:32 +11:00
parent 2a6e28637c
commit f127b4fea8
5224 changed files with 919361 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="description" content="Convert torrent files to magnet URIs using Javascript" />
<meta name="keywords" content="torrent,magnet,javascript,convert,online,sha1,bencode,base32" />
<title>WebOas.is - Torrent to Magnet Converter</title>
<link rel="shortcut icon" href="favicon.png" />
<link rel="stylesheet" href="style.css" />
<script src="src/t2m.loader.js"></script>
</head>
<body>
<div class="header_bar">
<div class="main main_no_overflow header">
<table class="header_table"><tbody>
<tr>
<td class="header_table_cell header_table_cell_full">
<div class="header_table_description">
<div class="header_table_description_name"><h3>Torrent to Magnet</h3></div>
</div>
</td>
</tr>
</tbody></table>
</div>
</div>
<div class="main body">
<p><div class="script_disabled script_visible">Javascript is required to use the inline converter.</div>
<div class="script_enabled">
<div class="converter">
<div class="converter_container">
<div class="converter_table">
<div class="converter_cell converter_cell_left">
<div class="converter_svg_container">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" class="converter_svg_graphic">
<polygon points="0.7,0 0.7,0.5 1,0.5 0.5,1 0,0.5 0.3,0.5 0.3,0" class="converter_svg_graphic_poly"></polygon>
</svg>
</div>
</div>
<div class="converter_cell converter_cell_right">
<div class="converter_info">
<div class="converter_info_line1">Drop <a class="link_external light_underline link_stop_propagation" href="https://en.wikipedia.org/wiki/Torrent_file" target="_blank"><span>.torrent</span></a> files here</div>
<div class="converter_info_line2">to convert them to <a class="link_external light_underline link_stop_propagation" href="https://en.wikipedia.org/wiki/Magnet_uri" target="_blank"><span>magnet URI</span></a>s</div>
<div class="converter_info_line3">Or click to open the file browser</div>
<input type="file" class="converter_files_input" multiple />
</div>
</div>
</div>
</div>
</div>
</div></p>
<div class="converted"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,103 @@
// Module for encoding/decoding base32
var Base32 = (function () {
"use strict";
// Vars used
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
pad_lengths = [ 0, 1, 3, 4, 6 ],
pad_char = "=";
// Encode/decode functions
return {
/**
Encode a string into base32
@param str
The string to convert.
This string should be encoded in some way such that each character is in the range [0,255]
@return
A base32 encoded string
*/
encode: function (str) {
var len = str.length,
str_new = "",
i = 0,
c1, c2, c3, c4, c5;
// Null pad
while ((str.length % 5) !== 0) str += "\x00";
// String modify
while (i < len) {
c1 = str.charCodeAt(i++);
c2 = str.charCodeAt(i++);
c3 = str.charCodeAt(i++);
c4 = str.charCodeAt(i++);
c5 = str.charCodeAt(i++);
str_new += alphabet[(c1 >> 3)];
str_new += alphabet[((c1 & 0x07) << 2) | (c2 >> 6)];
str_new += alphabet[((c2 & 0x3F) >> 1)];
str_new += alphabet[((c2 & 0x01) << 4) | (c3 >> 4)];
str_new += alphabet[((c3 & 0x0F) << 1) | (c4 >> 7)];
str_new += alphabet[((c4 & 0x7F) >> 2)];
str_new += alphabet[((c4 & 0x03) << 3) | (c5 >> 5)];
str_new += alphabet[(c5 & 0x1F)];
}
// Padding
if (i > len) {
i = pad_lengths[i - len]; // (i - len) equals the number of times \x00 was padded
str_new = str_new.substr(0, str_new.length - i);
while ((str_new.length % 8) !== 0) str_new += pad_char;
}
// Done
return str_new;
},
/**
Decode a string from base32
@param str
A valid base32 string
@return
The original string
*/
decode: function (str) {
var len = str.length,
str_new = "",
bits = 0,
char_buffer = 0,
i;
// Cut off padding
while (len > 0 && str[len - 1] == "=") --len;
// Iterate
for (i = 0; i < len; ++i) {
// Update with the 32bit value
char_buffer = (char_buffer << 5) | alphabet.indexOf(str[i]);
// Update bitcount
bits += 5;
if (bits >= 8) {
// Update string
str_new += String.fromCharCode((char_buffer >> (bits - 8)) & 0xFF);
bits -= 8;
}
}
// Done
return str_new;
},
};
})();

View File

@ -0,0 +1,202 @@
// Module for encoding/decoding Bencoded data
var Bencode = (function () {
"use strict";
// Encoding functions
var encode = function (value) {
// Type
var t = typeof(value);
// Number
if (t == "number") return encode_int(Math.floor(value));
// String
if (t == "string") return encode_string(value);
// Array
if (Array.isArray(value)) return encode_list(value);
// Dict
return encode_dict(value);
};
var encode_int = function (value) {
return "i" + value + "e";
};
var encode_string = function (value) {
return "" + value.length + ":" + value;
};
var encode_list = function (value) {
var str = [ "l" ],
i;
// List values
for (i = 0; i < value.length; ++i) {
str.push(encode(value[i]));
}
// End
str.push("e");
return str.join("");
};
var encode_dict = function (value) {
var str = [ "d" ],
keys = [],
i;
// Get and sort keys
for (i in value) keys.push(i);
keys.sort();
// Push values
for (i = 0; i < keys.length; ++i) {
str.push(encode_string(keys[i]));
str.push(encode(value[keys[i]]));
}
// End
str.push("e");
return str.join("");
};
// Decoding class
var Decoder = function () {
this.pos = 0;
};
Decoder.prototype = {
constructor: Decoder,
decode: function (str) {
// Errors
var k = str[this.pos];
if (!(k in decode_generic)) throw "Invalid format";
// Call
return decode_generic[k].call(this, str);
},
decode_int: function (str) {
// Skip the "i" prefix
++this.pos;
var end = str.indexOf("e", this.pos),
value;
// No end
if (end < 0) throw "Invalid format";
// Assume proper number format
value = parseInt(str.substr(this.pos, end - this.pos), 10);
// Done
this.pos = end + 1;
return value;
},
decode_string: function (str) {
var delim = str.indexOf(":", this.pos),
length, value;
// No end
if (delim < 0) throw "Invalid format";
// Assume proper number format
length = parseInt(str.substr(this.pos, delim - this.pos), 10);
value = str.substr(delim + 1, length);
// Done
this.pos = delim + length + 1;
return value;
},
decode_list: function (str) {
// Skip the "l" prefix
++this.pos;
// Read list
var list = [],
value;
// Loop until end or exception
while (str[this.pos] != "e") {
value = this.decode(str); // this throws errors if str[this.pos] is out of bounds
list.push(value);
}
// Done; skip "e" suffix
++this.pos;
return list;
},
decode_dict: function (str) {
// Skip the "d" prefix
++this.pos;
// Read dict
var dict = {},
key, value;
// Loop until end or exception
while (str[this.pos] != "e") {
key = this.decode_string(str);
value = this.decode(str); // this throws errors if str[this.pos] is out of bounds
dict[key] = value;
}
// Done; skip "e" suffix
++this.pos;
return dict;
},
};
// Generic decode functions
var decode_generic = {
"l": Decoder.prototype.decode_list,
"d": Decoder.prototype.decode_dict,
"i": Decoder.prototype.decode_int,
},
i;
for (i = 0; i < 10; ++i) decode_generic[i.toString()] = Decoder.prototype.decode_string;
// Encode/decode functions
return {
/**
encode: function (obj)
Encodes an object into a Bencode'd string
@param obj
The object to encode
This should only be one of the following:
string
number (floats are floor'd to integers)
array (containing things only from this list)
object (containing things only from this list)
Strings should be encoded in some way such that each character is in the range [0,255]
@return
A string representing the object
*/
encode: encode,
/**
decode: function (str)
Decodes a Bencode'd string back into its original type
@param str
The string to decode
@return
The original object represented by str
@throws
Any one of the following self-explanatory strings
"Invalid format"
"Invalid string"
"Invalid int"
*/
decode: function (str) {
// Create a decoder and call
return (new Decoder()).decode(str);
},
};
})();

View File

@ -0,0 +1,235 @@
// Class for SHA1 computation
var SHA1 = (function () {
"use strict";
// Private variables
var hash_size = 20,
message_block_length = 64,
message_block_terminator = 0x80,
message_length_bytes = 8,
initial_intermediate_hash = new Uint32Array(5),
K_constants = new Uint32Array(4);
initial_intermediate_hash[0] = 0x67452301;
initial_intermediate_hash[1] = 0xEFCDAB89;
initial_intermediate_hash[2] = 0x98BADCFE;
initial_intermediate_hash[3] = 0x10325476;
initial_intermediate_hash[4] = 0xC3D2E1F0;
K_constants[0] = 0x5A827999;
K_constants[1] = 0x6ED9EBA1;
K_constants[2] = 0x8F1BBCDC;
K_constants[3] = 0xCA62C1D6;
/**
SHA1 instance constructor; creates an empty SHA1 object.
@return
A new SHA1 instance
*/
var SHA1 = function () {
this.length = 0;
this.message_block_index = 0;
this.message_block = new Uint8Array(message_block_length);
this.intermediate_hash = new Uint32Array(initial_intermediate_hash);
};
// Private methods
var pad = function () {
var maxlen = this.message_block.length - message_length_bytes,
high = Math.floor(this.length / 0x0FFFFFFFF) & 0xFFFFFFFF,
low = this.length & 0xFFFFFFFF,
message_block = this.message_block,
message_block_index = this.message_block_index,
input_intermediate_hash = this.intermediate_hash,
output_intermediate_hash = new Uint32Array(this.intermediate_hash.length);
// Termination byte
message_block[message_block_index] = message_block_terminator;
// Process another block if there's no space for the length
if (message_block_index >= maxlen) {
// 0-ify
while (++message_block_index < message_block.length) message_block[message_block_index] = 0;
// Process block
process.call(this, message_block, input_intermediate_hash, output_intermediate_hash);
// Create copies that don't interfere with "this"
message_block = new Uint8Array(message_block.length); // no 0-ifying needed
input_intermediate_hash = output_intermediate_hash;
}
else {
// 0-ify
while (++message_block_index < maxlen) message_block[message_block_index] = 0;
}
// Store length
message_block[maxlen] = (high >>> 24) & 0xFF;
message_block[++maxlen] = (high >>> 16) & 0xFF;
message_block[++maxlen] = (high >>> 8) & 0xFF;
message_block[++maxlen] = (high) & 0xFF;
message_block[++maxlen] = (low >>> 24) & 0xFF;
message_block[++maxlen] = (low >>> 16) & 0xFF;
message_block[++maxlen] = (low >>> 8) & 0xFF;
message_block[++maxlen] = (low) & 0xFF;
process.call(this, message_block, input_intermediate_hash, output_intermediate_hash);
// Return hash
return output_intermediate_hash;
};
var process = function (message_block, intermediate_hash_input, intermediate_hash_output) {
var W = new Uint32Array(80),
i, i4, temp, A, B, C, D, E;
// Init W
for (i = 0; i < 16; ++i) {
i4 = i * 4;
W[i] =
(message_block[i4] << 24) |
(message_block[i4 + 1] << 16) |
(message_block[i4 + 2] << 8) |
(message_block[i4 + 3]);
}
for (/*i = 16*/; i < 80; ++i) {
W[i] = circular_shift(1, W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]);
}
A = intermediate_hash_input[0];
B = intermediate_hash_input[1];
C = intermediate_hash_input[2];
D = intermediate_hash_input[3];
E = intermediate_hash_input[4];
for (i = 0; i < 20; ++i) {
temp = circular_shift(5, A) + ((B & C) | ((~B) & D)) + E + W[i] + K_constants[0];
E = D;
D = C;
C = circular_shift(30, B);
B = A;
A = temp & 0xFFFFFFFF;
}
for (/*i = 20*/; i < 40; ++i) {
temp = circular_shift(5, A) + (B ^ C ^ D) + E + W[i] + K_constants[1];
E = D;
D = C;
C = circular_shift(30, B);
B = A;
A = temp & 0xFFFFFFFF;
}
for (/*i = 40*/; i < 60; ++i) {
temp = circular_shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[i] + K_constants[2];
E = D;
D = C;
C = circular_shift(30, B);
B = A;
A = temp & 0xFFFFFFFF;
}
for (/*i = 60*/; i < 80; ++i) {
temp = circular_shift(5, A) + (B ^ C ^ D) + E + W[i] + K_constants[3];
E = D;
D = C;
C = circular_shift(30, B);
B = A;
A = temp & 0xFFFFFFFF;
}
intermediate_hash_output[0] = intermediate_hash_input[0] + A;
intermediate_hash_output[1] = intermediate_hash_input[1] + B;
intermediate_hash_output[2] = intermediate_hash_input[2] + C;
intermediate_hash_output[3] = intermediate_hash_input[3] + D;
intermediate_hash_output[4] = intermediate_hash_input[4] + E;
};
var circular_shift = function (bits, word) {
return (word << bits) | (word >>> (32 - bits));
};
// Public methods
SHA1.prototype = {
constructor: SHA1,
/**
Reset the state of the hashing object to its initial state.
*/
reset: function () {
// Reset everything
var i;
this.length = 0;
this.message_block_index = 0;
for (i = 0; i < this.intermediate_hash.length; ++i) {
this.intermediate_hash[i] = initial_intermediate_hash[i];
}
for (i = 0; i < this.message_block.length; ++i) {
this.message_block[i] = 0;
}
},
/**
Feed data into the instance to update the hash.
@param value_array
The values to update with. This can either be:
- A string (encoded so that every character is in the range [0,255])
- A (typed) array
*/
update: function (value_array) {
var is_string = (typeof(value_array) == "string"),
i;
for (i = 0; i < value_array.length; ++i) {
// Update block
this.message_block[this.message_block_index] = is_string ? value_array.charCodeAt(i) : value_array[i];
// Update length
this.length += 8;
// Process block
if (++this.message_block_index >= this.message_block.length) {
process.call(this, this.message_block, this.intermediate_hash, this.intermediate_hash);
this.message_block_index = 0;
}
}
},
/**
Computes the SHA1 digest of the data input so far.
@return
A Uint8Array of the computed digest
*/
digest: function () {
// Setup
var digest = new Uint8Array(hash_size),
intermediate_hash_temp = pad.call(this),
i;
// Hash
for (i = 0; i < digest.length; ++i) {
digest[i] = intermediate_hash_temp[i >> 2] >> (8 * (3 - (i & 0x03)));
}
// Done
return digest;
},
};
// Return the class object
return SHA1;
})();

View File

@ -0,0 +1,102 @@
// Functions for testing sha1.js
(function () {
"use strict";
// Tests
var tests = [
{
value: "abc",
repeat: 1,
correct: "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D",
},
{
value: "abcdbcdecdefdefgefghfghighijhi" + "jkijkljklmklmnlmnomnopnopq",
repeat: 1,
correct: "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1",
},
{
value: "a",
repeat: 1000000,
correct: "34 AA 97 3C D4 C4 DA A4 F6 1E EB 2B DB AD 27 31 65 34 01 6F",
},
{
value: "01234567012345670123456701234567" + "01234567012345670123456701234567",
repeat: 10,
correct: "DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52",
},
{
value: "a",
repeat: 133047678,
correct: "94 A8 41 C9 02 1D 23 57 A8 0A 77 60 01 E2 7D 2F 27 93 91 05",
},
];
// Readable hex
var digest_to_spaced_hex = function (digest) {
// String build
var s = [],
c, i;
for (i = 0; i < digest.length; ++i) {
if (i > 0) s.push(" ");
c = digest[i].toString(16).toUpperCase();
if (c.length < 2) s.push("0");
s.push(c);
}
return s.join("");
};
// Test function
var execute_tests = function () {
// Vars for testing
var sha = new SHA1(),
failures = 0,
test, digest, i, j;
// Run tests
for (i = 0; i < tests.length; ++i) {
test = tests[i];
console.log("Test " + (i + 1) + ": " + JSON.stringify(test.value) + " repeated " + test.repeat + " time" + (test.repeat == 1 ? "" : "s"));
sha.reset();
for (j = 0; j < test.repeat; ++j) {
sha.update(test.value);
}
digest = digest_to_spaced_hex(sha.digest());
if (digest == test.correct) {
console.log("Digest matches: YES");
console.log(" " + digest);
}
else {
console.log("Digest matches: NO");
console.log(" " + digest + "(calculated)");
console.log(" " + test.correct + " (correct)");
++failures;
}
console.log("");
}
// Final status
if (failures === 0) {
console.log("All tests okay");
}
else {
console.log("" + failures + " test" + (failures == 1 ? "" : "s") + " failed");
}
};
execute_tests();
})();

View File

@ -0,0 +1,752 @@
var T2M = (function () {
"use strict";
// Module for encoding/decoding UTF8
var UTF8 = (function () {
return {
/**
Encode a string into UTF-8
@param str
The string to convert.
This string should be encoded in some way such that each character is in the range [0,255]
@return
A UTF-8 encoded string
*/
encode: function (str) {
return unescape(encodeURIComponent(str));
},
/**
Decode a string from UTF-8
@param str
A valid UTF-8 string
@return
The original string
*/
decode: function (str) {
return decodeURIComponent(escape(str));
},
};
})();
// Class for reading .torrent files
var Torrent = (function () {
var Torrent = function () {
this.events = {
"load": [],
"error": [],
"read_error": [],
"read_abort": [],
};
this.file_name = null;
this.data = null;
};
var on_reader_load = function (event) {
// Decode
var data_str = event.target.result;
if (data_str instanceof ArrayBuffer) {
// Convert to string
var data_str2 = "",
i;
data_str = new Uint8Array(data_str);
for (i = 0; i < data_str.length; ++i) {
data_str2 += String.fromCharCode(data_str[i]);
}
data_str = data_str2;
}
try {
this.data = Bencode.decode(data_str);
}
catch (e) {
// Throw an error
this.data = null;
this.file_name = null;
trigger.call(this, "error", {
type: "Bencode error",
exception: e,
});
return;
}
// Loaded
trigger.call(this, "load", {});
};
var on_reader_error = function () {
trigger.call(this, "read_error", {});
};
var on_reader_abort = function () {
trigger.call(this, "read_abort", {});
};
var trigger = function (event, data) {
// Trigger an event
var callbacks = this.events[event],
i;
for (i = 0; i < callbacks.length; ++i) {
callbacks[i].call(this, data, event);
}
};
var no_change = function (x) {
return x;
};
var magnet_component_order_default = [ "xt" , "xl" , "dn" , "tr" ];
var format_uri = function (array_values, encode_fcn) {
if (array_values.length <= 1) return encode_fcn(array_values[0]);
return array_values[0].replace(/\{([0-9]+)\}/, function (match) {
return encode_fcn(array_values[parseInt(match[1], 10) + 1] || "");
});
};
/**
Convert URI components object into a magnet URI.
This is used to format the same object multiple times without rehashing anything.
@param link_components
An object returned from convert_to_magnet with return_components=true
@param custom_name
Can take one of the following values:
null/undefined: name will remain the same as it originally was
string: the custom name to give the magnet URI
@param tracker_mode
Can take one of the following values:
null/undefined/false/number < 0: single tracker only (primary one)
true: multiple trackers (without numbered suffix)
number >= 0: multiple trackers (with numbered suffix starting at the specified number)
@param uri_encode
Can take one of the following values:
null/undefined/true: encode components using encodeURIComponent
false: no encoding; components are left as-is
function: custom encoding function
@param component_order
A list containing the order URI components should appear in.
Default is [ "xt" , "xl" , "dn" , "tr" ]
null/undefined will use the default
@return
A formatted URI
*/
Torrent.components_to_magnet = function (link_components, custom_name, tracker_mode, uri_encode, component_order) {
// Vars
var link, obj, list1, val, i, j;
uri_encode = (uri_encode === false) ? no_change : (typeof(uri_encode) == "function" ? uri_encode : encodeURIComponent);
component_order = (component_order === null) ? magnet_component_order_default : component_order;
// Setup
if (typeof(custom_name) == "string") {
link_components.dn.values = [ custom_name ];
}
link_components.tr.suffix = -1;
if (typeof(tracker_mode) == "number") {
tracker_mode = Math.floor(tracker_mode);
if (tracker_mode >= 0) link_components.tr.suffix = tracker_mode;
}
else if (tracker_mode === true) {
link_components.tr.suffix = -2;
}
// Form into a URL
link = "magnet:";
val = 0; // number of components added
for (i = 0; i < component_order.length; ++i) {
if (!(component_order[i] in link_components)) continue; // not valid
obj = link_components[component_order[i]];
list1 = obj.values;
for (j = 0; j < list1.length; ++j) {
// Separator
link += (val === 0 ? "?" : "&");
++val;
// Key
link += component_order[i];
// Number
if (obj.suffix >= 0 && list1.length > 1) {
link += ".";
link += obj.suffix;
++obj.suffix;
}
// Value
link += "=";
link += format_uri(list1[j], uri_encode);
// Done
if (obj.suffix == -1) break;
}
}
// Done
return link;
};
Torrent.prototype = {
constructor: Torrent,
read: function (file) {
this.data = null;
this.file_name = file.name;
var reader = new FileReader();
reader.addEventListener("load", on_reader_load.bind(this), false);
reader.addEventListener("error", on_reader_error.bind(this), false);
reader.addEventListener("abort", on_reader_abort.bind(this), false);
try {
reader.readAsBinaryString(file);
}
catch (e) {
reader.readAsArrayBuffer(file);
}
},
on: function (event, callback) {
if (event in this.events) {
this.events[event].push(callback);
return true;
}
return false;
},
off: function (event, callback) {
if (event in this.events) {
var callbacks = this.events[event],
i;
for (i = 0; i < callbacks.length; ++i) {
if (callbacks[i] == callback) {
callbacks.splice(i, 1);
return true;
}
}
}
return false;
},
/**
Convert the torrent data into a magnet link.
@param custom_name
Can take one of the following values:
null/undefined: no custom name will be generated, but if the name field is absent, it will be assumed from the original file's name
false: no custom name will be generated OR assumed from the original file name
string: the custom name to give the magnet URI
@param tracker_mode
Can take one of the following values:
null/undefined/false/number < 0: single tracker only (primary one)
true: multiple trackers (without numbered suffix)
number >= 0: multiple trackers (with numbered suffix starting at the specified number)
@param uri_encode
Can take one of the following values:
null/undefined/true: encode components using encodeURIComponent
false: no encoding; components are left as-is
function: custom encoding function
@param component_order
A list containing the order URI components should appear in.
Default is [ "xt" , "xl" , "dn" , "tr" ]
null/undefined will use the default
@param return_components
If true, this returns the link components which can then be used with components_to_magnet
@return
A formatted URI if return_components is falsy, else an object containing the parts of the link
Also can return null if insufficient data is found
*/
convert_to_magnet: function (custom_name, tracker_mode, uri_encode, component_order, return_components) {
// Insufficient data
if (this.data === null || !("info" in this.data)) return null;
// Bencode info
var info = this.data.info,
info_bencoded = Bencode.encode(info),
info_hasher = new SHA1(),
link_components = {},
info_hash, link, list1, list2, val, i, j;
// Hash
info_hasher.update(info_bencoded);
info_hash = info_hasher.digest();
info_hash = String.fromCharCode.apply(null, info_hash); // convert to binary string
info_hash = Base32.encode(info_hash); // convert to base32
// Setup link
for (i = 0; i < magnet_component_order_default.length; ++i) {
link_components[magnet_component_order_default[i]] = {
suffix: -1,
values: [],
};
}
// Create
link_components.xt.values.push([ "urn:btih:{0}", info_hash ]);
if ("length" in info) {
link_components.xl.values.push([ info.length ]);
}
if (typeof(custom_name) == "string") {
link_components.dn.values.push([ custom_name ]);
}
else if ("name" in info) {
link_components.dn.values.push([ UTF8.decode(info.name) ]);
}
else if (custom_name !== false && this.file_name) {
link_components.dn.values.push([ this.file_name ]);
}
list1 = link_components.tr.values;
if ("announce" in this.data) {
list1.push([ UTF8.decode(this.data.announce) ]);
}
if ("announce-list" in this.data && Array.isArray(list2 = this.data["announce-list"])) {
// Add more trackers
for (i = 0; i < list2.length; ++i) {
if (!Array.isArray(list2[i])) continue; // bad data
for (j = 0; j < list2[i].length; ++j) {
val = UTF8.decode(list2[i][j]);
if (list1.indexOf(val) < 0) list1.push([ val ]);
}
}
}
// Convert
if (return_components) return link_components;
link = Torrent.components_to_magnet(link_components, null, tracker_mode, uri_encode, component_order);
// Done
return link;
},
};
return Torrent;
})();
// Class for enumerating the results in the DOM
var Result = (function () {
var Result = function () {
this.torrent_magnet_components = null;
this.container = null;
this.magnet_link = null;
this.magnet_link_text = null;
this.magnet_textbox = null;
this.options_link = null;
this.options_container = null;
this.options = null;
};
var on_options_link_click = function () {
if (this.options_container.classList.contains("converted_item_options_container_visible")) {
this.options_container.classList.remove("converted_item_options_container_visible");
this.magnet_textbox.readOnly = true;
}
else {
this.options_container.classList.add("converted_item_options_container_visible");
this.magnet_textbox.readOnly = false;
}
};
var on_textbox_click = function () {
if (this.magnet_textbox.readOnly) {
this.magnet_textbox.select();
}
};
var on_textbox_keydown = function () {
if (this.magnet_textbox.readOnly) return;
setTimeout(on_textbox_update.bind(this), 10);
};
var on_textbox_change = function () {
on_textbox_update.call(this);
};
var on_textbox_update = function () {
// Get value
var uri = this.magnet_textbox.value,
protocol = "magnet:";
// Must have correct protocol
if (uri.substr(0, protocol.length).toLowerCase() != protocol) {
if (uri.length < protocol.length && uri.toLowerCase() == protocol.substr(0, uri.length)) {
// Almost correct
uri += protocol.substr(uri.length);
}
else {
// Wrong
uri = protocol + uri;
}
}
// Update
this.magnet_link.setAttribute("href", uri);
this.magnet_link_text.textContent = uri;
};
var on_option_change = function () {
update_links.call(this, true);
};
var update_links = function (update_displays) {
// Update magnet links
var magnet_uri = "magnet:asdf",
tracker_mode = false,
order = [ "xt" ];
if (this.options[0][0][1].checked) {
order.push("dn");
}
if (this.options[1][0][1].checked) {
order.push("xl");
}
if (this.options[2][0][1].checked) {
order.push("tr");
if (this.options[2][1][1].checked) {
tracker_mode = true;
if (this.options[2][2][1].checked) {
tracker_mode = 1;
}
}
}
magnet_uri = Torrent.components_to_magnet(this.torrent_magnet_components, null, tracker_mode, true, order);
// Update text/values
this.magnet_link.setAttribute("href", magnet_uri);
this.magnet_link_text.textContent = magnet_uri;
this.magnet_textbox.value = magnet_uri;
if (!update_displays) return;
// Update display
var i, j, opt_list;
for (i = 0; i < this.options.length; ++i) {
opt_list = this.options[i];
for (j = 0; j < opt_list.length; ++j) {
if (!opt_list[j][1].checked) {
// This is unchecked; modify boxes after
opt_list[j][0].classList.add("converted_item_option_part_visible");
// Hide
while (++j < opt_list.length) {
opt_list[j][0].classList.remove("converted_item_option_part_visible");
opt_list[j][1].checked = false;
}
break;
}
}
}
};
Result.prototype = {
constructor: Result,
generate: function (torrent_object, parent_node) {
var n1, n2, n3, n4, n5, i, j, ev_bind;
// Clear
this.options = [];
//{ Setup DOM nodes
this.container = document.createElement("div");
this.container.className = "converted_item";
// Title
n1 = document.createElement("div");
n1.className = "converted_item_title_container";
n2 = document.createElement("div");
n2.className = "converted_item_title";
n2.textContent = torrent_object.file_name || (torrent_object.data && torrent_object.data.info ? torrent_object.data.name : null) || ".torrent";
n1.appendChild(n2);
this.container.appendChild(n1);
// Contents
n1 = document.createElement("div");
n1.className = "converted_item_contents";
// Links
n2 = document.createElement("div");
n2.className = "converted_item_link_container";
this.magnet_link = document.createElement("a");
this.magnet_link.className = "converted_item_link";
this.magnet_link_text = document.createElement("span");
this.magnet_link.appendChild(this.magnet_link_text);
n2.appendChild(this.magnet_link);
this.magnet_textbox = document.createElement("input");
this.magnet_textbox.className = "converted_item_textbox";
this.magnet_textbox.setAttribute("type", "text");
this.magnet_textbox.readOnly = true;
n2.appendChild(this.magnet_textbox);
n1.appendChild(n2);
// Options container
this.options_container = document.createElement("div");
this.options_container.className = "converted_item_options_container";
// Header
n2 = document.createElement("div");
n2.className = "converted_item_header";
n3 = document.createElement("span");
n3.className = "converted_item_header_text";
n3.textContent = "Options:";
n2.appendChild(n3);
this.options_link = document.createElement("a");
this.options_link.className = "converted_item_options_toggle";
n3 = document.createElement("span");
this.options_link.appendChild(n3);
n2.appendChild(this.options_link);
this.options_container.appendChild(n2);
// Options
n2 = document.createElement("div");
n2.className = "converted_item_options";
// Name
this.options.push([]);
n3 = document.createElement("div");
n3.className = "converted_item_option";
n4 = document.createElement("label");
n4.className = "converted_item_option_part converted_item_option_part_visible";
n5 = document.createElement("input");
n5.className = "converted_item_option_checkbox checkbox";
n5.setAttribute("type", "checkbox");
n5.checked = true;
n4.appendChild(n5);
this.options[this.options.length - 1].push([ n4 , n5 ]);
n5 = document.createElement("span");
n5.className = "converted_item_option_text";
n5.textContent = "Include name";
n4.appendChild(n5);
n3.appendChild(n4);
n2.appendChild(n3);
// Data length
this.options.push([]);
n3 = document.createElement("div");
n3.className = "converted_item_option";
n4 = document.createElement("label");
n4.className = "converted_item_option_part converted_item_option_part_visible";
n5 = document.createElement("input");
n5.className = "converted_item_option_checkbox checkbox";
n5.setAttribute("type", "checkbox");
n5.checked = true;
n4.appendChild(n5);
this.options[this.options.length - 1].push([ n4 , n5 ]);
n5 = document.createElement("span");
n5.className = "converted_item_option_text";
n5.textContent = "Include data length";
n4.appendChild(n5);
n3.appendChild(n4);
n2.appendChild(n3);
// Tracker
this.options.push([]);
n3 = document.createElement("div");
n3.className = "converted_item_option";
n4 = document.createElement("label");
n4.className = "converted_item_option_part converted_item_option_part_visible";
n5 = document.createElement("input");
n5.className = "converted_item_option_checkbox checkbox";
n5.setAttribute("type", "checkbox");
n5.checked = true;
n4.appendChild(n5);
this.options[this.options.length - 1].push([ n4 , n5 ]);
n5 = document.createElement("span");
n5.className = "converted_item_option_text";
n5.textContent = "Include tracker";
n4.appendChild(n5);
n3.appendChild(n4);
n4 = document.createElement("label");
n4.className = "converted_item_option_part converted_item_option_part_visible";
n5 = document.createElement("input");
n5.className = "converted_item_option_checkbox checkbox";
n5.setAttribute("type", "checkbox");
n5.checked = false;
n4.appendChild(n5);
this.options[this.options.length - 1].push([ n4 , n5 ]);
n5 = document.createElement("span");
n5.className = "converted_item_option_text";
n5.textContent = "Allow multiple trackers";
n4.appendChild(n5);
n3.appendChild(n4);
n4 = document.createElement("label");
n4.className = "converted_item_option_part";
n5 = document.createElement("input");
n5.className = "converted_item_option_checkbox checkbox";
n5.setAttribute("type", "checkbox");
n5.checked = false;
n4.appendChild(n5);
this.options[this.options.length - 1].push([ n4 , n5 ]);
n5 = document.createElement("span");
n5.className = "converted_item_option_text";
n5.textContent = "Numbered keys";
n4.appendChild(n5);
n3.appendChild(n4);
n2.appendChild(n3);
// Add options
this.options_container.appendChild(n2);
n1.appendChild(this.options_container);
// Done
this.container.appendChild(n1);
//}
// Data
this.torrent_magnet_components = torrent_object.convert_to_magnet(null, false, true, null, true);
update_links.call(this, false);
// Events
this.options_link.addEventListener("click", on_options_link_click.bind(this), false);
this.magnet_textbox.addEventListener("click", on_textbox_click.bind(this), false);
this.magnet_textbox.addEventListener("keydown", on_textbox_keydown.bind(this), false);
this.magnet_textbox.addEventListener("change", on_textbox_change.bind(this), false);
ev_bind = on_option_change.bind(this);
for (i = 0; i < this.options.length; ++i) {
for (j = 0; j < this.options[i].length; ++j) {
this.options[i][j][1].addEventListener("change", ev_bind, false);
}
}
// Rice and add
if (rice_checkboxes) {
rice_checkboxes(this.container.querySelectorAll("input[type=checkbox].checkbox"));
}
if (parent_node) parent_node.appendChild(this.container);
},
update: function () {
},
};
return Result;
})();
// Other functions
var rice_checkboxes = null;
var on_torrent_load = function () {
var container = document.querySelector(".converted"),
result;
if (container === null) return;
container.classList.add("converted_visible");
result = new Result();
result.generate(this, container);
};
// Exposed functions
var functions = {
setup: function (rice_checkboxes_import) {
rice_checkboxes = rice_checkboxes_import;
},
queue_torrent_files: function (files) {
// Read files
var i, t;
for (i = 0; i < files.length; ++i) {
t = new Torrent();
t.on("load", on_torrent_load);
t.read(files[i]);
}
},
};
return functions;
})();

View File

@ -0,0 +1,418 @@
(function () {
"use strict";
// Function for performing actions as soon as possible
var on_ready = (function () {
// Vars
var callbacks = [],
check_interval = null,
check_interval_time = 250;
// Check if ready and run callbacks
var callback_check = function () {
if (
(document.readyState === "interactive" || document.readyState === "complete") &&
callbacks !== null
) {
// Run callbacks
var cbs = callbacks,
cb_count = cbs.length,
i;
// Clear
callbacks = null;
for (i = 0; i < cb_count; ++i) {
cbs[i].call(null);
}
// Clear events and checking interval
window.removeEventListener("load", callback_check, false);
window.removeEventListener("readystatechange", callback_check, false);
if (check_interval !== null) {
clearInterval(check_interval);
check_interval = null;
}
// Okay
return true;
}
// Not executed
return false;
};
// Listen
window.addEventListener("load", callback_check, false);
window.addEventListener("readystatechange", callback_check, false);
// Callback adding function
return function (cb) {
if (callbacks === null) {
// Ready to execute
cb.call(null);
}
else {
// Delay
callbacks.push(cb);
// Set a check interval
if (check_interval === null && callback_check() !== true) {
check_interval = setInterval(callback_check, check_interval_time);
}
}
};
})();
// Functions
var script_add = (function () {
var script_on_load = function (state) {
// Okay
script_remove_event_listeners.call(this, state, true);
};
var script_on_error = function (state) {
// Error
script_remove_event_listeners.call(this, state, false);
};
var script_on_readystatechange = function (state) {
if (this.readyState === "loaded" || this.readyState === "complete") {
// Okay
script_remove_event_listeners.call(this, state, true);
}
};
var script_remove_event_listeners = function (state, okay) {
// Remove event listeners
this.addEventListener("load", state.on_load, false);
this.addEventListener("error", state.on_error, false);
this.addEventListener("readystatechange", state.on_readystatechange, false);
state.on_load = null;
state.on_error = null;
state.on_readystatechange = null;
// Trigger
if (state.callback) state.callback.call(null, okay, this);
// Remove
var par = this.parentNode;
if (par) par.removeChild(this);
};
return function (url, callback) {
var head = document.head,
script, state;
if (!head) {
// Callback and done
callback.call(null, false, null);
return false;
}
// Load state
state = {
on_load: null,
on_error: null,
on_readystatechange: null,
callback: callback,
};
// New script tag
script = document.createElement("script");
script.async = true;
script.setAttribute("src", url);
// Events
script.addEventListener("load", (state.on_load = script_on_load.bind(script, state)), false);
script.addEventListener("error", (state.on_error = script_on_error.bind(script, state)), false);
script.addEventListener("readystatechange", (state.on_readystatechange = script_on_readystatechange.bind(script, state)), false);
// Add
head.appendChild(script);
// Done
return true;
};
})();
var on_generic_stop_propagation = function (event) {
event.stopPropagation();
};
var on_exclusive_mode_change = function (flag_node) {
exclusive_mode_update.call(this, flag_node, false);
};
var exclusive_mode_update = (function () {
var previous_fragment = "";
return function (flag_node, check_fragment) {
var hash_is_exclusive = (window.location.hash == "#converter.exclusive");
if (check_fragment) {
this.checked = hash_is_exclusive;
}
else {
if (this.checked ^ (!hash_is_exclusive)) {
previous_fragment = window.location.hash;
}
window.history.replaceState({}, "", window.location.pathname + (this.checked ? "#converter.exclusive" : previous_fragment));
}
if (this.checked) {
flag_node.classList.add("exclusive_enabled");
}
else {
flag_node.classList.remove("exclusive_enabled");
}
};
})();
var on_converter_click = function (converter_files_input, event) {
if (event.which != 2 && event.which != 3) {
converter_files_input.click();
}
};
var on_converter_files_change = function (converter) {
// Read
on_converter_test_files.call(converter, this.files);
// Nullify
this.value = null;
};
var on_file_dragover = function (converter, event) {
if (Array.prototype.indexOf.call(event.dataTransfer.types, "Files") < 0) return;
converter.classList.add("converter_files_active");
if (this === converter) converter.classList.add("converter_files_hover");
event.dataTransfer.dropEffect = "copy";
event.preventDefault();
event.stopPropagation();
return false;
};
var on_file_dragleave = function (converter, event) {
if (Array.prototype.indexOf.call(event.dataTransfer.types, "Files") < 0) return;
converter.classList.remove("converter_files_hover");
if (this !== converter) converter.classList.remove("converter_files_active");
event.preventDefault();
event.stopPropagation();
return false;
};
var on_file_drop = function (converter, event) {
// Reset style
converter.classList.remove("converter_files_active");
converter.classList.remove("converter_files_hover");
event.preventDefault();
event.stopPropagation();
// Not over the converter
if (this !== converter) return false;
// Read files
on_converter_test_files.call(converter, event.dataTransfer.files);
// Done
return false;
};
var on_converter_test_files = function (files) {
// Read
var re_ext = /(\.[^\.]*|)$/,
read_files = [],
ext, i;
for (i = 0; i < files.length; ++i) {
ext = re_ext.exec(files[i].name)[1].toLowerCase();
if (ext == ".torrent") {
read_files.push(files[i]);
}
}
// Nothing to do
if (read_files.length === 0) return;
// Load scripts if necessary
load_requirements(function (errors) {
if (errors === 0) {
// Load
var T2M_obj;
try {
T2M_obj = T2M;
}
catch(e) {
return; // not found
}
T2M_obj.queue_torrent_files(read_files);
}
});
};
var load_requirements = (function () {
// Script requirements
var requirements = [
"src/sha1.js",
"src/bencode.js",
"src/base32.js",
"src/t2m.js",
];
var on_all_scripts_loaded = function () {
var T2M_obj;
try {
T2M_obj = T2M;
}
catch(e) {
return; // not found
}
T2M_obj.setup(rice_checkboxes);
};
var on_script_load = function (state, callback, okay) {
if (okay) ++state.okay;
if (++state.count >= state.total) {
// All loaded/errored
if (state.total - state.okay === 0) on_all_scripts_loaded();
callback.call(null, state.total - state.okay);
}
};
// Return the loading function
return function (callback) {
// Already loaded?
if (requirements === null) {
// Yes
callback.call(null, 0);
return;
}
var head = document.head,
on_load, i;
if (!head) return false;
// Load
on_load = on_script_load.bind(null, { okay: 0, count: 0, total: requirements.length, }, callback);
for (i = 0; i < requirements.length; ++i) {
script_add(requirements[i], on_load);
}
// Done
requirements = null;
return true;
};
})();
var restyle_noscript = function () {
// Script
var nodes = document.querySelectorAll(".script_disabled"),
i;
for (i = 0; i < nodes.length; ++i) {
nodes[i].classList.remove("script_visible");
}
nodes = document.querySelectorAll(".script_enabled");
for (i = 0; i < nodes.length; ++i) {
nodes[i].classList.add("script_visible");
}
};
var rice_checkboxes = function (nodes) {
var svgns = "http://www.w3.org/2000/svg",
i, par, sib, node, n1, n2, n3;
nodes = nodes || document.querySelectorAll("input[type=checkbox].checkbox");
for (i = 0; i < nodes.length; ++i) {
node = nodes[i];
par = node.parentNode;
sib = node.nextSibling;
// Create new checkbox
n1 = document.createElement("label");
n1.className = node.className;
n2 = document.createElementNS(svgns, "svg");
n2.setAttribute("svgns", svgns);
n2.setAttribute("viewBox", "0 0 16 16");
n3 = document.createElementNS(svgns, "polygon");
n3.setAttribute("points", "13,0 16,2 8,16 5,16 0,11 2,8 6,11.5");
// Re-add
n2.appendChild(n3);
n1.appendChild(n2);
par.insertBefore(n1, node);
n1.insertBefore(node, n2);
}
};
// Execute
on_ready(function () {
// Noscript
var nodes, i;
// Rice
restyle_noscript();
rice_checkboxes();
// Stop propagation links
nodes = document.querySelectorAll(".link_stop_propagation");
for (i = 0; i < nodes.length; ++i) {
nodes[i].addEventListener("click", on_generic_stop_propagation, false);
}
// Setup converter
var converter = document.querySelector(".converter"),
converter_files = document.querySelector(".converter_files_input"),
exclusive_mode = document.querySelector("input.converter_exclusive_mode_check"),
non_exclusive_body = document.querySelector(".non_exclusive"),
body = document.body;
if (converter !== null) {
// File browser
if (converter_files !== null) {
converter.addEventListener("click", on_converter_click.bind(converter, converter_files), false);
converter_files.addEventListener("change", on_converter_files_change.bind(converter_files, converter), false);
}
// File drag/drop events
converter.addEventListener("dragover", on_file_dragover.bind(converter, converter), false);
converter.addEventListener("dragleave", on_file_dragleave.bind(converter, converter), false);
converter.addEventListener("drop", on_file_drop.bind(converter, converter), false);
body.addEventListener("dragover", on_file_dragover.bind(body, converter), false);
body.addEventListener("dragleave", on_file_dragleave.bind(body, converter), false);
body.addEventListener("drop", on_file_drop.bind(body, converter), false);
// Exclusive
if (exclusive_mode !== null) {
exclusive_mode_update.call(exclusive_mode, non_exclusive_body, true);
exclusive_mode.addEventListener("change", on_exclusive_mode_change.bind(exclusive_mode, non_exclusive_body), false);
}
}
});
})();

View File

@ -0,0 +1,617 @@
body {
padding: 0;
margin: 0;
border: none;
color: #111111;
background-color: #ffffff;
font-family: Arial;
font-size: 16px;
overflow-x: hidden;
overflow-y: scroll;
text-align: center;
}
table,tbody,tr,td {
margin: 0;
padding: 0;
border-spacing: 0;
}
p {
margin: 0;
padding: 0;
line-height: 1.5em;
}
ol,ul {
margin: 0 0 0 1em;
padding: 0;
}
ol>li,ul>li {
line-height: 1.5em;
}
ol>li+li,ul>li+li {
margin-top: 0.5em;
}
h1,h2,h3,h4,h5,h6 {
margin: 0;
padding: 0;
font-weight: bold;
line-height: 1.5em;
position: relative;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.8em;
}
h3 {
font-size: 1.6em;
}
h4 {
font-size: 1.4em;
}
h5 {
font-size: 1.2em;
}
h6 {
font-size: 1em;
}
input,
textarea {
font-size: inherit;
}
input:focus,
textarea:focus {
outline: none;
}
.hardlink_text {
vertical-align: middle;
}
.hardlink_text:not(:hover)>a.hardlink {
visibility: hidden;
opacity: 0;
-webkit-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
-moz-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
-o-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
}
a.hardlink {
display: block;
visibility: visible;
position: absolute;
right: 100%;
top: 0;
padding: 0 0.25em 0 0.5em;
color: #c8c8c8;
font-weight: bold;
-webkit-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
-moz-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
-o-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
}
a.hardlink:hover {
text-decoration: none;
color: #0280cf;
}
a.hardlink:after {
content: "#";
}
p+p,
h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,
p+h1,p+h2,p+h3,p+h4,p+h5,p+h6,
h4+h6 {
margin-top: 1em;
}
strong {
font-size: 1em;
}
code {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
code.nowrap {
display: inline-block;
white-space: nowrap;
}
.codeblock {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
display: block;
background: #f3f3f3;
border: 1px solid #e5e5e5;
overflow-x: auto;
overflow-y: hidden;
padding: 0;
line-height: 1.5em;
}
.codeblock_inner {
display: inline-block;
padding: 0.5em;
}
.codeblock.codeblock_pre>.codeblock_inner {
white-space: pre;
}
*::selection {
color: #ffffff;
background: #0280cf;
text-shadow: none;
}
*::-moz-selection {
color: #ffffff ;
background: #0280cf;
text-shadow: none;
}
.section_id {
}
.script_disabled {
}
.script_disabled:not(.script_visible) {
display: none;
}
.script_enabled {
}
.script_enabled:not(.script_visible) {
display: none;
}
input[type=checkbox],
input[type=radio] {
padding: 0;
margin: 0;
vertical-align: middle;
}
label.checkbox {
display: inline-block;
width: 0.75em;
height: 0.75em;
vertical-align: middle;
border: 0.09375em solid #111111;
border-radius: 0.25em;
padding: 0.125em;
position: relative;
cursor: pointer;
}
label.checkbox:before {
z-index: -1;
position: absolute;
display: block;
left: 0;
right: 0;
bottom: 0;
top: 0;
content: "";
border: none;
border-radius: 0.125em;
background: #ffffff;
}
label.checkbox:hover:before,
label:not([for]):hover label.checkbox:before {
border: 0.125em solid #0280cf;
}
label.checkbox>input[type=checkbox] {
position: absolute;
visibility: hidden;
display: none;
}
label.checkbox>svg {
display: none;
width: 100%;
height: 100%;
position: relative;
}
label.checkbox>svg>polygon {
fill: #111111;
}
label.checkbox.delete_checkbox>svg>polygon:not(:first-child) {
visibility: hidden;
}
label.checkbox.delete_checkbox:hover>svg>polygon:first-child,
label:not([for]):hover label.checkbox.delete_checkbox>svg>polygon:first-child {
visibility: hidden;
}
label.checkbox.delete_checkbox:hover>svg>polygon:not(:first-child),
label:not([for]):hover label.checkbox.delete_checkbox>svg>polygon:not(:first-child) {
visibility: visible;
}
label.checkbox>input[type=checkbox]:checked+svg {
display: block;
}
a {
color: #0280cf;
cursor: pointer;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a.light_underline {
color: #c8c8c8;
}
a.light_underline>span {
color: #0280cf;
}
a.light_nohover_color_hover {
color: #c8c8c8;
}
a.light_nohover_color_hover:hover {
color: #0280cf;
text-decoration: none;
}
.main {
text-align: left;
display: inline-block;
width: 60em;
vertical-align: middle;
}
.main.main_no_overflow {
overflow: hidden;
}
.main.body {
margin: 0.5em 0 4em 0;
}
.header_bar {
position: relative;
background: #f3f3f3;
background: -webkit-linear-gradient(180deg, #f9f9f9, #f3f3f3);
background: -moz-linear-gradient(180deg, #f9f9f9, #f3f3f3);
background: -o-linear-gradient(180deg, #f9f9f9, #f3f3f3);
background: linear-gradient(180deg, #f9f9f9, #f3f3f3);
border-bottom: 1px solid #e5e5e5;
}
.header_table {
margin: 0.5em 0;
text-align: left;
}
.header_table td {
vertical-align: middle;
}
.header_table_cell {
width: 0;
}
.header_table_cell.header_table_cell_full {
width: 100%;
}
.header_table_name {
font-size: 2em;
line-height: 1.2em;
white-space: nowrap;
}
.header_table_name_user {
}
.header_table_name_separator {
display: inline-block;
margin: 0 0.125em;
color: #c8c8c8;
}
.header_table_name_title {
}
.header_table_name_title>span {
font-weight: bold;
}
.header_table_separator {
vertical-align: middle;
display: inline-block;
font-size: 2em;
height: 1.2em;
margin: 0 0.5em;
border-left: 1px solid #c8c8c8;
}
.header_table_description {
line-height: 1.1em;
}
.header_table_description_name {
font-weight: bold;
color: #404040;
}
.header_table_description_body {
color: #606060;
}
.header_table_view_on_github {
display: block;
white-space: nowrap;
margin-left: 1em;
text-align: right;
}
.header_table_view_on_github_line1 {
font-size: 0.8em;
line-height: 1em;
}
.header_table_view_on_github_line2 {
line-height: 1em;
}
.light {
color: #808080;
}
.italic {
font-style: italic;
}
.converter_exclusive_mode {
white-space: nowrap;
margin-left: 1em;
padding: 0 2em 0 1em;
display: inline-block;
font-size: 0.5em;
font-weight: normal;
line-height: 1em;
cursor: pointer;
}
.converter_exclusive_mode_text {
vertical-align: middle;
opacity: 0;
-webkit-transition: opacity 0.25s ease-in-out 0s;
-moz-transition: opacity 0.25s ease-in-out 0s;
-o-transition: opacity 0.25s ease-in-out 0s;
transition: opacity 0.25s ease-in-out 0s;
}
.converter_exclusive_mode_text:after {
content: "exclusive mode";
}
.converter_exclusive_mode:hover>.converter_exclusive_mode_text {
opacity: 1;
-webkit-transition: opacity 0.25s ease-in-out 0.5s;
-moz-transition: opacity 0.25s ease-in-out 0.5s;
-o-transition: opacity 0.25s ease-in-out 0.5s;
transition: opacity 0.25s ease-in-out 0.5s;
}
.converter_exclusive_mode_check {
margin-right: 0.25em;
opacity: 0;
-webkit-transition: opacity 0.25s ease-in-out 0s;
-moz-transition: opacity 0.25s ease-in-out 0s;
-o-transition: opacity 0.25s ease-in-out 0s;
transition: opacity 0.25s ease-in-out 0s;
}
.converter_exclusive_mode:hover>.converter_exclusive_mode_check {
opacity: 1;
-webkit-transition: opacity 0.25s ease-in-out 0.5s;
-moz-transition: opacity 0.25s ease-in-out 0.5s;
-o-transition: opacity 0.25s ease-in-out 0.5s;
transition: opacity 0.25s ease-in-out 0.5s;
}
.converter {
display: block;
padding: 2em;
border: 0.25em dashed #c8c8c8;
cursor: pointer;
text-align: center;
-webkit-transition: border-color 0.25s ease-in-out 0s;
-moz-transition: border-color 0.25s ease-in-out 0s;
-o-transition: border-color 0.25s ease-in-out 0s;
transition: border-color 0.25s ease-in-out 0s;
background: #f3f3f3;
}
.converter.converter_files_active {
border-color: #0280cf;
}
.converter_container {
display: inline-block;
padding-right: 3em;
}
.converter_table {
text-align: left;
display: table;
vertical-align: middle;
}
.converter_cell {
display: table-cell;
vertical-align: middle;
}
.converter_cell_left {
width: 0;
}
.converter_cell_right {
width: 100%;
}
.converter_svg_container {
width: 8.5em;
height: 10em;
}
.converter_svg_graphic {
width: 10em;
height: 10em;
-webkit-transition: transform 0.25s ease-in-out 0s;
-moz-transition: transform 0.25s ease-in-out 0s;
-o-transition: transform 0.25s ease-in-out 0s;
transition: transform 0.25s ease-in-out 0s;
}
.converter_svg_graphic_poly {
fill: #c8c8c8;
stroke: none;
-webkit-transition: fill 0.25s ease-in-out 0s;
-moz-transition: fill 0.25s ease-in-out 0s;
-o-transition: fill 0.25s ease-in-out 0s;
transition: fill 0.25s ease-in-out 0s;
}
.converter_info {
display: inline-block;
text-align: right;
}
.converter_info_line1 {
font-weight: bold;
font-size: 4em;
line-height: 1em;
}
.converter_info_line2 {
font-size: 2em;
line-height: 1em;
}
.converter_info_line3 {
margin-top: 2em;
line-height: 1em;
color: #a0a0a0;
}
.converter_files_input {
display: none;
}
.converter:hover .converter_svg_graphic,
.converter.converter_files_hover .converter_svg_graphic {
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webkit-transform: scale(1.25);
-moz-transform: scale(1.25);
-ms-transform: scale(1.25);
-o-transform: scale(1.25);
transform: scale(1.25);
}
.converter.converter_files_active .converter_svg_graphic_poly {
fill: #0280cf;
}
.converted {
margin-top: 2em;
}
.converted:not(.converted_visible) {
display: none;
}
.converted_item {
}
.converted_item+.converted_item {
margin-top: 1em;
}
.converted_item_title_container {
border-bottom: 0.25em solid #c8c8c8;
margin-bottom: 1em;
}
.converted_item_title {
color: #0280cf;
font-size: 2em;
font-weight: bold;
line-height: 1.2em;
max-height: 2.4em;
overflow: hidden;
}
.converted_item_contents {
margin-left: 2em;
}
.converted_item_link_container {
width: 100%;
overflow-x: hidden;
margin-bottom: 1em;
}
a.converted_item_link {
font-size: 1.25em;
color: #0280cf;
white-space: nowrap;
}
a.converted_item_link:hover {
text-decoration: underline;
}
a.converted_item_link>span {
color: #111111;
}
.converted_item_textbox {
display: block;
width: 100%;
margin: 0.5em 0 0 0;
padding: 0.5em;
border: 1px solid #c8c8c8;
box-sizing: border-box;
-moz-box-sizing: border-box;
line-height: 1.2em;
color: #111111;
}
.converted_item_textbox[readonly] {
color: #808080;
}
.converted_item_header {
margin: 0;
}
.converted_item_header_text {
display: inline-block;
font-weight: bold;
}
.converted_item_options_container:not(.converted_item_options_container_visible)>.converted_item_header>.converted_item_header_text {
display: none;
}
a.converted_item_options_toggle {
color: #0280cf;
display: inline-block;
}
.converted_item_options_container.converted_item_options_container_visible>.converted_item_header>a.converted_item_options_toggle {
margin-left: 1em;
}
a.converted_item_options_toggle>span {
color: #c8c8c8;
}
a.converted_item_options_toggle:hover>span {
color: #111111;
}
a.converted_item_options_toggle>span:after {
content: "Show options";
}
.converted_item_options_container.converted_item_options_container_visible>.converted_item_header>a.converted_item_options_toggle>span:after {
content: "Hide";
}
.converted_item_options_container {
}
.converted_item_options {
margin-top: 0.5em;
}
.converted_item_options_container:not(.converted_item_options_container_visible)>.converted_item_options {
display: none;
}
.converted_item_option {
}
.converted_item_option+.converted_item_option {
margin-top: 0.5em;
}
.converted_item_option_part {
cursor: pointer;
display: inline-block;
}
.converted_item_option_part+.converted_item_option_part {
margin-left: 1em;
}
.converted_item_option_part:not(.converted_item_option_part_visible) {
display: none;
}
.converted_item_option_checkbox {
vertical-align: middle;
margin-right: 0.25em;
}
.converted_item_option_text {
vertical-align: middle;
}
.non_exclusive {
margin-top: 2em;
}
.non_exclusive.exclusive_enabled {
display: none;
}