window.onload = function () { $('#subcategory').prop('disabled', true); $('#category').change(function() { fillSubcategory(this.value) }); customizeUploadButton() } function sortCategories(categories) { var sortedCategories = [] for(var key in categories) { sortedCategories.push(categories[key]) } sortedCategories.sort() return sortedCategories } function fillDetectedFilelist(file) { var reader = new FileReader(); fileList = document.querySelectorAll(".detectedFiles")[0] fileList.querySelector(".label").innerHTML = "" fileList.querySelector(".content").innerHTML = "" reader.onload = function() { autodetectSuccess = false b = new bencode() try { torrentObject = b.decode(reader.result) } catch(err) { } if(torrentObject.info.name) { document.querySelectorAll("input.name")[0].value = torrentObject.info.name } sizeGroup = document.querySelectorAll(".sizeGroup")[0] if(torrentObject.info.pieces.length && torrentObject.info["piece length"]) { sizeGroup.style.display = "" 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 } else { sizeGroup.style.display = "none" } trackerGroup = document.querySelectorAll(".trackerGroup")[0] if(torrentObject.announce) { trackerGroup.style.display = "" document.querySelectorAll(".detectedTracker")[0].innerHTML = torrentObject.announce autodetectSuccess = true } else { trackerGroup.style.display = "none" } filesGroup = document.querySelectorAll(".filesGroup")[0] if(torrentObject["info"]["files"] != undefined && torrentObject["info"]["files"].length > 0) { // render the file-tree if multiple files are present autodetectSuccess = true for(var fileIndex = 0; fileIndex < torrentObject.info.files.length; fileIndex++){ path = torrentObject["info"]["files"][fileIndex]["path"] renderFile(getRoot(), path.reverse()) } } else { // assume the torrent is only one file named "name" autodetectSuccess = true renderFile(getRoot(), [torrentObject["info"]["name"]]) } var detectInfosGroup = document.querySelectorAll(".detectedInfosGroup")[0] if(autodetectSuccess) { detectInfosGroup.style.display = "block" } else { detectInfosGroup.style.display = "none" } } reader.readAsArrayBuffer(file) } 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) } root = root.querySelector(".content") root.appendChild(element) return element } else { return obj } } function getRoot() { rootElement = document.querySelectorAll(".detectedFiles.fileRoot")[0] return rootElement } function fillSubcategory(value) { var subSelect = $('#subcategory') var selText = $(':first-child', subSelect).text() subSelect.empty(); subSelect.append($('<option value="-1" selected>'+selText+'</selected>')) 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) } } } subSelect.prop('disabled', value < 0) } // Hides the default browser-upload-form and replaces it by an button function customizeUploadButton() { $("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(); $('body').on('click', '#button-file', function() { $("input.file").trigger('click'); }); } // This sets the Uploadbutton to the filename of the uploaded file function setButtonToFilename(event) { $("input[name='torrentFile']").each(function() { var fileName = $(this).val().split('/').pop().split('\\').pop(); targetInput = event["target"] button = targetInput.previousSibling.getElementsByClassName("text")[0] button.innerHTML = chunk(fileName, 40) fillDetectedFilelist(this.files[0]) }); } function setError(element) { element.classList.add("has-error") element.classList.remove("has-success") } function setSuccess(element) { element.classList.add("has-success") element.classList.remove("has-error") } function validateForm() { valid = true /* 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") tracker = document.querySelector(".trackerGroup .detectedTracker").parentElement 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") if(validtracker.indexOf(torrentObject.announce) < 0) { valid = false setError(tracker) } else { setSuccess(tracker) } if(file.value.length <= 0) { valid = false setError(file_label) } else { setSuccess(file_label) } if(category.value < 0) { valid = false setError(category_label) } else { setSuccess(category_label) } if(subcategory.value < 0) { valid = false setError(category_label) } else { setSuccess(category_label) } if(torrentname.value.length <= 0) { valid = false setError(name_label) } else { setSuccess(name_label) } if(description.value.length <= 0) { valid = false setError(description_label) } else { setSuccess(description_label) } return valid; } 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 }; // 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; }