2015-02-14 00:17:40 +01:00
|
|
|
window.onload = function () {
|
2017-12-29 04:57:37 +01:00
|
|
|
$('#subcategory').prop('disabled', true);
|
|
|
|
$('#category').change(function() {
|
|
|
|
fillSubcategory(this.value)
|
2015-02-14 00:17:40 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
customizeUploadButton()
|
|
|
|
}
|
|
|
|
|
|
|
|
function sortCategories(categories) {
|
|
|
|
var sortedCategories = []
|
|
|
|
for(var key in categories) {
|
2015-02-15 03:48:39 +01:00
|
|
|
sortedCategories.push(categories[key])
|
2015-02-14 00:17:40 +01:00
|
|
|
}
|
|
|
|
sortedCategories.sort()
|
|
|
|
return sortedCategories
|
|
|
|
}
|
|
|
|
|
2015-02-21 03:01:47 +01:00
|
|
|
function fillDetectedFilelist(file) {
|
|
|
|
var reader = new FileReader();
|
2018-04-02 02:43:23 +02:00
|
|
|
fileList = document.querySelectorAll(".detectedFiles")[0]
|
|
|
|
fileList.querySelector(".label").innerHTML = ""
|
|
|
|
fileList.querySelector(".content").innerHTML = ""
|
2015-02-21 03:01:47 +01:00
|
|
|
reader.onload = function() {
|
2015-02-21 04:29:47 +01:00
|
|
|
autodetectSuccess = false
|
2015-02-21 03:01:47 +01:00
|
|
|
b = new bencode()
|
2015-02-21 04:29:47 +01:00
|
|
|
try {
|
|
|
|
torrentObject = b.decode(reader.result)
|
|
|
|
} catch(err) {
|
|
|
|
|
2015-02-21 03:01:47 +01:00
|
|
|
}
|
|
|
|
|
2015-02-21 04:29:47 +01:00
|
|
|
if(torrentObject.info.name) {
|
|
|
|
document.querySelectorAll("input.name")[0].value = torrentObject.info.name
|
|
|
|
}
|
2015-02-21 03:01:47 +01:00
|
|
|
|
|
|
|
sizeGroup = document.querySelectorAll(".sizeGroup")[0]
|
2015-02-21 04:29:47 +01:00
|
|
|
if(torrentObject.info.pieces.length && torrentObject.info["piece length"]) {
|
2015-02-21 03:01:47 +01:00
|
|
|
sizeGroup.style.display = ""
|
2015-02-21 04:29:47 +01:00
|
|
|
size = (torrentObject.info.pieces.length / 20) * torrentObject.info["piece length"]
|
|
|
|
size = getNextUnit(size)
|
|
|
|
document.querySelectorAll(".detectedSize")[0].innerHTML = ((Math.round(size[0] * 100)) / 100) + " " + size[1]
|
|
|
|
autodetectSuccess = true
|
2015-02-21 03:01:47 +01:00
|
|
|
} else {
|
|
|
|
sizeGroup.style.display = "none"
|
|
|
|
}
|
|
|
|
|
|
|
|
trackerGroup = document.querySelectorAll(".trackerGroup")[0]
|
2015-02-21 04:29:47 +01:00
|
|
|
if(torrentObject.announce) {
|
2015-02-21 03:01:47 +01:00
|
|
|
trackerGroup.style.display = ""
|
|
|
|
document.querySelectorAll(".detectedTracker")[0].innerHTML = torrentObject.announce
|
2015-02-21 04:29:47 +01:00
|
|
|
autodetectSuccess = true
|
2015-02-21 03:01:47 +01:00
|
|
|
} else {
|
|
|
|
trackerGroup.style.display = "none"
|
|
|
|
}
|
2015-02-21 04:29:47 +01:00
|
|
|
|
|
|
|
filesGroup = document.querySelectorAll(".filesGroup")[0]
|
2018-04-02 02:43:23 +02:00
|
|
|
if(torrentObject["info"]["files"] != undefined && torrentObject["info"]["files"].length > 0) {
|
2018-04-02 02:52:05 +02:00
|
|
|
// render the file-tree if multiple files are present
|
2015-02-21 04:29:47 +01:00
|
|
|
autodetectSuccess = true
|
|
|
|
for(var fileIndex = 0; fileIndex < torrentObject.info.files.length; fileIndex++){
|
2018-04-02 02:43:23 +02:00
|
|
|
path = torrentObject["info"]["files"][fileIndex]["path"]
|
|
|
|
renderFile(getRoot(), path.reverse())
|
2015-02-21 04:29:47 +01:00
|
|
|
}
|
2018-04-02 02:52:05 +02:00
|
|
|
} else {
|
|
|
|
// assume the torrent is only one file named "name"
|
|
|
|
autodetectSuccess = true
|
|
|
|
renderFile(getRoot(), [torrentObject["info"]["name"]])
|
2015-02-21 04:29:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var detectInfosGroup = document.querySelectorAll(".detectedInfosGroup")[0]
|
|
|
|
if(autodetectSuccess) {
|
|
|
|
detectInfosGroup.style.display = "block"
|
|
|
|
} else {
|
|
|
|
detectInfosGroup.style.display = "none"
|
|
|
|
}
|
2015-02-21 03:01:47 +01:00
|
|
|
}
|
|
|
|
reader.readAsArrayBuffer(file)
|
|
|
|
}
|
|
|
|
|
2018-04-02 02:43:23 +02:00
|
|
|
function renderFile(root, path) {
|
|
|
|
if(path.length == 0){
|
|
|
|
return 0
|
|
|
|
} else {
|
|
|
|
nextElement = path.pop()
|
|
|
|
folderName = ""
|
|
|
|
for(var i = 0; i < nextElement.length; i++) {
|
|
|
|
code = nextElement.charCodeAt(i)
|
|
|
|
if((code >= 97 && code <= 122) || (code >= 65 && code <= 90)) {
|
|
|
|
folderName = folderName + nextElement[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
type = path.length > 0 ? "dir" : "file"
|
|
|
|
newRoot = getOrCreate(root, folderName, nextElement, type)
|
|
|
|
renderFile(newRoot, path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getOrCreate(root, foldername, displayname, type) {
|
|
|
|
var obj = root.querySelector("div." + type + "." + foldername)
|
|
|
|
|
|
|
|
if(obj == undefined || obj.length == 0){
|
|
|
|
element = document.createElement("div")
|
|
|
|
element.classList.add(type)
|
|
|
|
element.classList.add(foldername)
|
|
|
|
label = document.createElement("div")
|
|
|
|
label.classList.add("label")
|
|
|
|
label.innerHTML = displayname
|
|
|
|
element.appendChild(label)
|
|
|
|
|
|
|
|
if(type == "dir") {
|
|
|
|
label.classList.add("closed")
|
|
|
|
label.onclick = function() {
|
|
|
|
if(this.classList.contains("closed")) {
|
|
|
|
this.classList.remove("closed")
|
|
|
|
this.classList.add("opened")
|
|
|
|
} else if(this.classList.contains("opened")) {
|
|
|
|
this.classList.remove("opened")
|
|
|
|
this.classList.add("closed")
|
|
|
|
}
|
|
|
|
content = this.parentElement.querySelector(".content")
|
|
|
|
content.hidden = !content.hidden
|
|
|
|
}
|
|
|
|
content = document.createElement("div")
|
|
|
|
content.classList.add("content")
|
|
|
|
content.hidden = true
|
|
|
|
element.appendChild(content)
|
|
|
|
}
|
|
|
|
foobar = root
|
|
|
|
root = root.querySelector(".content")
|
|
|
|
root.appendChild(element)
|
|
|
|
return element
|
|
|
|
} else {
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getRoot() {
|
|
|
|
rootElement = document.querySelectorAll(".detectedFiles.fileRoot")[0]
|
|
|
|
return rootElement
|
|
|
|
}
|
|
|
|
|
2017-12-29 04:57:37 +01:00
|
|
|
function fillSubcategory(value) {
|
|
|
|
var subSelect = $('#subcategory')
|
2017-12-29 08:03:17 +01:00
|
|
|
var selText = $(':first-child', subSelect).text()
|
2017-12-29 04:57:37 +01:00
|
|
|
subSelect.empty();
|
2017-12-29 08:03:17 +01:00
|
|
|
subSelect.append($('<option value="-1" selected>'+selText+'</selected>'))
|
2017-12-29 04:57:37 +01:00
|
|
|
if (value >= 0) {
|
|
|
|
var subcategories = null
|
|
|
|
for(var i = 0; i < global_categories.length; i++) {
|
|
|
|
if (global_categories[i]["id"] == value) {
|
|
|
|
subcategories = global_categories[i]["subcategories"]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(subcategories) {
|
|
|
|
for(subcategoryIndex in subcategories) {
|
|
|
|
var subcategoryId = subcategories[subcategoryIndex]["id"]
|
|
|
|
var subcategoryLocalString = subcategories[subcategoryIndex]["label"]
|
|
|
|
var node = $('<option value="'+subcategoryId+'">'+subcategoryLocalString+'</string>')
|
|
|
|
subSelect.append(node)
|
|
|
|
}
|
2015-02-21 03:01:47 +01:00
|
|
|
}
|
2015-02-14 00:17:40 +01:00
|
|
|
}
|
2017-12-29 04:57:37 +01:00
|
|
|
subSelect.prop('disabled', value < 0)
|
2015-02-14 00:17:40 +01:00
|
|
|
}
|
|
|
|
|
2015-02-15 03:48:39 +01:00
|
|
|
// Hides the default browser-upload-form and replaces it by an button
|
2015-02-14 00:17:40 +01:00
|
|
|
function customizeUploadButton() {
|
2015-02-15 05:43:17 +01:00
|
|
|
$("input.file").before('<button id="button-file" type="button" class="btn btn-default"><span class="text">Upload...</span><span class="glyphicon glyphicon-open-file" aria-hidden="true"></span></button>');
|
|
|
|
$("input.file").hide();
|
2015-02-14 00:17:40 +01:00
|
|
|
$('body').on('click', '#button-file', function() {
|
2015-02-15 05:43:17 +01:00
|
|
|
$("input.file").trigger('click');
|
2015-02-14 00:17:40 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-02-15 03:48:39 +01:00
|
|
|
// This sets the Uploadbutton to the filename of the uploaded file
|
2015-02-14 00:17:40 +01:00
|
|
|
function setButtonToFilename(event) {
|
2015-02-15 03:48:39 +01:00
|
|
|
$("input[name='torrentFile']").each(function() {
|
2015-02-14 00:17:40 +01:00
|
|
|
var fileName = $(this).val().split('/').pop().split('\\').pop();
|
|
|
|
targetInput = event["target"]
|
|
|
|
button = targetInput.previousSibling.getElementsByClassName("text")[0]
|
2015-02-15 03:48:39 +01:00
|
|
|
button.innerHTML = chunk(fileName, 40)
|
2015-02-21 03:01:47 +01:00
|
|
|
fillDetectedFilelist(this.files[0])
|
2015-02-14 00:17:40 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-30 22:28:26 +01:00
|
|
|
function setError(element) {
|
|
|
|
element.classList.add("has-error")
|
2018-04-01 21:29:42 +02:00
|
|
|
element.classList.remove("has-success")
|
2017-12-30 22:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function setSuccess(element) {
|
|
|
|
element.classList.add("has-success")
|
|
|
|
element.classList.remove("has-error")
|
|
|
|
}
|
|
|
|
|
2015-02-15 05:43:17 +01:00
|
|
|
function validateForm() {
|
|
|
|
valid = true
|
2017-12-30 22:28:26 +01:00
|
|
|
|
|
|
|
/* TODO: Iterate over these to do dynamic requirement checking
|
|
|
|
form_groups = document.querySelectorAll(".torrent-form .form-group.required")
|
|
|
|
required_inputs = document.querySelectorAll(".torrent-form input.required")
|
|
|
|
required_dropdown = document.querySelectorAll(".torrent-form select.dropdown.required")
|
|
|
|
required_textarea = document.querySelectorAll(".torrent-form textarea.required")
|
|
|
|
*/
|
|
|
|
|
|
|
|
file = document.querySelector(".torrent-form .file input")
|
|
|
|
category = document.querySelector("#category")
|
|
|
|
subcategory = document.querySelector("#subcategory")
|
|
|
|
torrentname = document.querySelector(".torrent-form .name input")
|
|
|
|
description = document.querySelector(".torrent-form .description textarea")
|
|
|
|
|
|
|
|
file_label = document.querySelector(".torrent-form .file")
|
|
|
|
category_label = document.querySelector(".torrent-form .category")
|
|
|
|
name_label = document.querySelector(".torrent-form .name")
|
|
|
|
description_label = document.querySelector(".torrent-form .description")
|
|
|
|
|
2015-02-17 23:03:19 +01:00
|
|
|
if(file.value.length <= 0) {
|
|
|
|
valid = false
|
2017-12-30 22:28:26 +01:00
|
|
|
setError(file_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
} else {
|
2017-12-30 22:28:26 +01:00
|
|
|
setSuccess(file_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
}
|
|
|
|
|
2017-12-29 04:57:37 +01:00
|
|
|
if(category.value < 0) {
|
2015-02-17 23:03:19 +01:00
|
|
|
valid = false
|
2017-12-30 22:28:26 +01:00
|
|
|
setError(category_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
} else {
|
2017-12-30 22:28:26 +01:00
|
|
|
setSuccess(category_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
}
|
|
|
|
|
2017-12-29 04:57:37 +01:00
|
|
|
if(subcategory.value < 0) {
|
2015-02-17 23:03:19 +01:00
|
|
|
valid = false
|
2017-12-30 22:28:26 +01:00
|
|
|
setError(category_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
} else {
|
2017-12-30 22:28:26 +01:00
|
|
|
setSuccess(category_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(torrentname.value.length <= 0) {
|
|
|
|
valid = false
|
2017-12-30 22:28:26 +01:00
|
|
|
setError(name_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
} else {
|
2017-12-30 22:28:26 +01:00
|
|
|
setSuccess(name_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(description.value.length <= 0) {
|
|
|
|
valid = false
|
2017-12-30 22:28:26 +01:00
|
|
|
setError(description_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
} else {
|
2017-12-30 22:28:26 +01:00
|
|
|
setSuccess(description_label)
|
2015-02-17 23:03:19 +01:00
|
|
|
}
|
2015-02-15 05:43:17 +01:00
|
|
|
|
2015-02-17 23:03:19 +01:00
|
|
|
return valid;
|
2015-02-15 05:43:17 +01:00
|
|
|
}
|
|
|
|
|
2015-02-15 03:48:39 +01:00
|
|
|
function chunk(string, n) {
|
|
|
|
var ret = "";
|
|
|
|
for(var i=0, len=string.length; i < len; i += n) {
|
|
|
|
if(i==0) {
|
|
|
|
ret = string.substr(i, n)
|
|
|
|
} else {
|
|
|
|
ret += "<br/>" + string.substr(i, n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
};
|
2015-02-21 03:01:47 +01:00
|
|
|
|
|
|
|
|
|
|
|
// Bencode Library
|
|
|
|
// Copyright 2014 Steven Goodwin
|
|
|
|
// Released under the GPL, version 2
|
|
|
|
|
|
|
|
// For format details, please see:
|
|
|
|
// http://en.wikipedia.org/wiki/Bencode
|
|
|
|
|
|
|
|
bencode = function() {
|
|
|
|
this.STATE_NULL = 0;
|
|
|
|
this.STATE_INTEGER = 1; // i-?[0-9]e
|
|
|
|
this.STATE_STRING_LENGTH = 2; // [0-9]+:\a+
|
|
|
|
this.STATE_STRING_CONTENT = 3; // [0-9]+:\a+
|
|
|
|
this.STATE_LIST = 4; // l<contents>e
|
|
|
|
this.STATE_DICTIONARY = 5; // d<contents>e
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse accepts an array of characters to process, and the index of the
|
|
|
|
// first character to parse.
|
|
|
|
// It returns an object containing the parsed result (in result.o), and the index
|
|
|
|
// of the next character to parse in result.idx
|
|
|
|
bencode.prototype.parse = function(dataArray, fromIndex) {
|
|
|
|
var length = dataArray.byteLength;
|
|
|
|
var idx = fromIndex;
|
|
|
|
var state = this.STATE_NULL;
|
|
|
|
|
|
|
|
// State data
|
|
|
|
var current = "";
|
|
|
|
var currentObject = null;;
|
|
|
|
// String-specific state data
|
|
|
|
var stringLength;
|
|
|
|
|
|
|
|
while(idx < length) {
|
|
|
|
var c = String.fromCharCode(dataArray[idx]) ;
|
|
|
|
|
|
|
|
switch(state) {
|
|
|
|
case this.STATE_NULL:
|
|
|
|
switch(c) {
|
|
|
|
case 'i':
|
|
|
|
state = this.STATE_INTEGER;
|
|
|
|
current = "";
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
state = this.STATE_STRING_LENGTH;
|
|
|
|
current = c;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
currentObject = new Array();
|
|
|
|
state = this.STATE_LIST;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
currentObject = new Object();
|
|
|
|
state = this.STATE_DICTIONARY;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
++idx;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case this.STATE_INTEGER:
|
|
|
|
switch(c) {
|
|
|
|
case '-': // we assume that negative numbers start with -
|
|
|
|
current = "-";
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
return { o : current, idx : idx+1 };
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
current += c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++idx;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case this.STATE_STRING_LENGTH:
|
|
|
|
switch(c) {
|
|
|
|
case ':': // the separator between length and content
|
|
|
|
stringLength = parseInt(current, 10);
|
|
|
|
state = this.STATE_STRING_CONTENT;
|
|
|
|
current = ""; // We now parse the string content
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
current += c;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
++idx;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case this.STATE_STRING_CONTENT:
|
|
|
|
current += c;
|
|
|
|
if (--stringLength == 0) {
|
|
|
|
return { o : current, idx : idx+1 };
|
|
|
|
}
|
|
|
|
|
|
|
|
++idx;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case this.STATE_DICTIONARY:
|
|
|
|
|
|
|
|
if (c == 'e') {
|
|
|
|
return { o : currentObject, idx : idx+1 };
|
|
|
|
} else {
|
|
|
|
var objKey = this.parse(dataArray, idx);
|
|
|
|
var objValue = this.parse(dataArray, objKey.idx);
|
|
|
|
|
|
|
|
currentObject[objKey.o] = objValue.o;
|
|
|
|
idx = objValue.idx;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case this.STATE_LIST:
|
|
|
|
|
|
|
|
if (c == 'e') {
|
|
|
|
return { o : currentObject, idx : idx+1 };
|
|
|
|
} else {
|
|
|
|
var obj = this.parse(dataArray, idx);
|
|
|
|
|
|
|
|
currentObject.push(obj.o);
|
|
|
|
idx = obj.idx;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
bencode.prototype.decode = function(byteArray) {
|
|
|
|
var dataArray = new Uint8Array(byteArray);
|
|
|
|
var result = this.parse(dataArray, 0);
|
|
|
|
|
|
|
|
return result.o;
|
|
|
|
}
|