whisper.cat stuff
This commit is contained in:
BIN
weboasis/torrent/t2m/favicon.png
Normal file
BIN
weboasis/torrent/t2m/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 411 B |
56
weboasis/torrent/t2m/index.html
Normal file
56
weboasis/torrent/t2m/index.html
Normal 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>
|
103
weboasis/torrent/t2m/src/base32.js
Normal file
103
weboasis/torrent/t2m/src/base32.js
Normal 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;
|
||||
},
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
202
weboasis/torrent/t2m/src/bencode.js
Normal file
202
weboasis/torrent/t2m/src/bencode.js
Normal 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);
|
||||
},
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
235
weboasis/torrent/t2m/src/sha1.js
Normal file
235
weboasis/torrent/t2m/src/sha1.js
Normal 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;
|
||||
|
||||
})();
|
||||
|
||||
|
102
weboasis/torrent/t2m/src/sha1.test.js
Normal file
102
weboasis/torrent/t2m/src/sha1.test.js
Normal 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();
|
||||
|
||||
})();
|
||||
|
||||
|
752
weboasis/torrent/t2m/src/t2m.js
Normal file
752
weboasis/torrent/t2m/src/t2m.js
Normal 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;
|
||||
|
||||
})();
|
||||
|
||||
|
418
weboasis/torrent/t2m/src/t2m.loader.js
Normal file
418
weboasis/torrent/t2m/src/t2m.loader.js
Normal 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
|
617
weboasis/torrent/t2m/style.css
Normal file
617
weboasis/torrent/t2m/style.css
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user