├── .gitignore ├── webstore ├── options.png ├── extension.png ├── promo-440.png └── rightclick.png ├── source ├── images │ ├── buttons.png │ ├── chrome.png │ ├── icon128.png │ ├── icon16.png │ ├── icon32.png │ ├── icon48.png │ ├── progress.png │ └── dir_buttons.png ├── background.html ├── css │ ├── basket.css │ ├── downloadMagnet.css │ ├── options.css │ ├── downloadTorrent.css │ └── popup.css ├── basket.html ├── manifest.json ├── downloadMagnet.html ├── js │ ├── basket.js │ ├── inject.js │ ├── torrentParsing.js │ ├── downloadMagnet.js │ ├── events.js │ ├── bencode.js │ ├── popup.js │ ├── class.js │ ├── options.js │ ├── downloadTorrent.js │ ├── background.js │ └── jquery-3.2.1.min.js ├── popup.html ├── downloadTorrent.html └── options.html ├── README.md ├── .eslintrc.json └── COPYING /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | *.txt 3 | -------------------------------------------------------------------------------- /webstore/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/webstore/options.png -------------------------------------------------------------------------------- /webstore/extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/webstore/extension.png -------------------------------------------------------------------------------- /webstore/promo-440.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/webstore/promo-440.png -------------------------------------------------------------------------------- /source/images/buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/buttons.png -------------------------------------------------------------------------------- /source/images/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/chrome.png -------------------------------------------------------------------------------- /source/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/icon128.png -------------------------------------------------------------------------------- /source/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/icon16.png -------------------------------------------------------------------------------- /source/images/icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/icon32.png -------------------------------------------------------------------------------- /source/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/icon48.png -------------------------------------------------------------------------------- /webstore/rightclick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/webstore/rightclick.png -------------------------------------------------------------------------------- /source/images/progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/progress.png -------------------------------------------------------------------------------- /source/images/dir_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodaDaCoda/chrome-transmission-remote-plus/HEAD/source/images/dir_buttons.png -------------------------------------------------------------------------------- /source/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /source/css/basket.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | margin: 0; 5 | padding: 0; 6 | background: #f8fcfe; 7 | -webkit-user-select: none; 8 | } 9 | 10 | #dropbox { 11 | width: 100%; 12 | height: 100%; 13 | background: url(../images/icon128.png) no-repeat 0 0; 14 | -webkit-background-size: 100%; 15 | } 16 | 17 | #dropbox:hover { 18 | opacity: .8; 19 | } 20 | 21 | #hFile { 22 | visibility: hidden; 23 | position: fixed; 24 | height: 0; 25 | } 26 | -------------------------------------------------------------------------------- /source/basket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Upload Basket 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /source/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Remote Transmission ++", 3 | "version": "1.0.9", 4 | "manifest_version": 2, 5 | "background": { 6 | "page": "background.html" 7 | }, 8 | "browser_action": { 9 | "default_icon": "images/icon32.png", 10 | "default_popup": "popup.html" 11 | }, 12 | "content_scripts": [ { 13 | "js": [ 14 | "js/jquery-3.2.1.min.js", 15 | "js/inject.js" 16 | ], 17 | "matches": [ "http://*/*", "https://*/*" ] 18 | } ], 19 | "description": "Download and manage torrents on a remote Transmission client.", 20 | "icons": { 21 | "128": "images/icon128.png", 22 | "16": "images/icon16.png", 23 | "32": "images/icon32.png", 24 | "48": "images/icon48.png" 25 | }, 26 | "minimum_chrome_version": "23", 27 | "options_page": "options.html", 28 | "permissions": [ "http://*/", "https://*/", "contextMenus", "notifications", "tabs" ] 29 | } 30 | -------------------------------------------------------------------------------- /source/css/downloadMagnet.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 13px 13px 0 13px; 4 | background-color: #f2f1f0; 5 | color: #222; 6 | font: 15px Tahoma, Geneva, 'Ubuntu', sans-serif; 7 | } 8 | 9 | select, button { 10 | height: 29px; 11 | font: 15px Tahoma, Geneva, 'Ubuntu', sans-serif; 12 | } 13 | 14 | .clear { 15 | clear: both; 16 | } 17 | 18 | #container { 19 | margin: 0; 20 | padding: 0; 21 | list-style-type: none; 22 | } 23 | 24 | #container li { 25 | margin-bottom: 10px; 26 | } 27 | 28 | #downloadLabel { 29 | line-height: 29px; 30 | } 31 | 32 | #downloadLocations { 33 | float: right; 34 | width: 100%; 35 | vertical-align: middle; 36 | } 37 | 38 | #new { 39 | display: none; 40 | } 41 | 42 | #newLabelDirectoryRow { 43 | display: flex; 44 | } 45 | 46 | #newDirectory { 47 | flex-grow: 1; 48 | } 49 | 50 | #cancel { 51 | float: right; 52 | width: 85px; 53 | } 54 | 55 | #save { 56 | float: right; 57 | width: 85px; 58 | margin-left: 15px; 59 | } 60 | -------------------------------------------------------------------------------- /source/downloadMagnet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Save Magnet 5 | 6 | 7 | 8 | 9 | 10 | 11 | 28 | 29 | 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /source/js/basket.js: -------------------------------------------------------------------------------- 1 | 2 | function addTorrent(file) { 3 | var dirs = (localStorage.dLocation === 'dlcustom') ? JSON.parse(localStorage.dirs) : []; 4 | 5 | parseTorrent(file, function (torrent) { 6 | if (torrent !== null) { 7 | chrome.windows.create({url: 'downloadTorrent.html', type: 'popup', width: 852, height: 583}, function (w) { 8 | encodeFile(file, function (data) { 9 | chrome.tabs.sendMessage(w.tabs[0].id, {torrent: torrent, data: data, dirs: dirs}); 10 | }); 11 | }); 12 | } else { 13 | alert('This isn\'t a torrent file.'); 14 | } 15 | }); 16 | } 17 | 18 | function drop(e) { 19 | var files = e.dataTransfer.files; 20 | 21 | if (files.length > 5) { 22 | alert('Select no more than 5 files!'); 23 | } else { 24 | for (let i = 0, file; file = files[i]; ++i) { 25 | if (file.fileSize > 200000) { 26 | alert('File too large! Are you sure it\'s a torrent?'); 27 | continue; 28 | } 29 | 30 | addTorrent(file); 31 | } 32 | } 33 | 34 | e.stopPropagation(); 35 | e.preventDefault(); 36 | } 37 | 38 | function discard(e) { 39 | e.stopPropagation(); 40 | e.preventDefault(); 41 | } 42 | 43 | (function () { 44 | var dropbox = jQuery('#dropbox'); 45 | 46 | window.onUnload = function () { 47 | chrome.browserAction.setBadgeText({text: ''}); 48 | }; 49 | 50 | dropbox.addEventListener('dragenter', discard, false); 51 | dropbox.addEventListener('dragover', discard, false); 52 | dropbox.addEventListener('drop', drop, false); 53 | 54 | dropbox.addEventListener('click', function () { 55 | jQuery('#hFile').click(); 56 | }, false); 57 | }()); 58 | -------------------------------------------------------------------------------- /source/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | popup 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | 35 |
36 |
No torrents
37 | 38 |
39 | 40 |
41 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /source/downloadTorrent.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Save Torrent 5 | 6 | 7 | 8 | 9 | 10 | 11 | 52 | 53 | 54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /source/js/inject.js: -------------------------------------------------------------------------------- 1 | // array of regular expressions that dictate what is a valid torrent download url 2 | var TORRENT_LINKS = [ 3 | /^magnet:/i, 4 | /\.torrent$/i, 5 | /torrents\.php\?action=download/i, 6 | /\?.*info_hash=/i, 7 | /bt-chat\.com.*download/i, 8 | /torrentreactor\.net.*download/i, 9 | /vertor\.com.*download/i, 10 | /seedpeer\.com.*download/i, 11 | /torrentzap\.com.*download/i, 12 | /limetorrents\.com.*download/i, 13 | /h33t\.com.*download/i, 14 | /ahashare\.com.*download/i, 15 | /1337x\.org.*download/i, 16 | /bitenova\.nl.*download/i, 17 | /bibliotik\.org.*download/i, 18 | /demonoid\.me.*download\//i, 19 | /alivetorrents\.com\/dl\//i, 20 | /newtorrents\.info\/down\.php/i, 21 | /mininova\.org\/get/i, 22 | /kickasstorrents\.com\/torrents/i, 23 | /iptorrents\.com\/download\.php\/*\//i, 24 | ]; 25 | 26 | // open up a session with the background page 27 | var port = chrome.runtime.connect({name: 'inject'}); 28 | 29 | /* ================================================================================= 30 | clickTorrent(event e) 31 | 32 | // checks the link to see if it's a torrent download link, and sends it to be downloaded if so 33 | 34 | parameters 35 | e: event variable sent by the event that was triggered 36 | 37 | returns 38 | nothing 39 | ================================================================================= */ 40 | function clickTorrent(e) { 41 | var url = this.href; 42 | for (let i = 0; i < TORRENT_LINKS.length; i++) { 43 | if (TORRENT_LINKS[i].test(url)) { 44 | // begin download of torrent 45 | port.postMessage({url: url, method: 'torrent-add'}); 46 | 47 | // stop any further events and the default action of downloading locally 48 | e.preventDefault(); 49 | e.stopPropagation(); 50 | return; 51 | } 52 | } 53 | } 54 | 55 | jQuery(function ($) { 56 | $('body').on('click', 'a', clickTorrent); 57 | }); 58 | -------------------------------------------------------------------------------- /source/css/options.css: -------------------------------------------------------------------------------- 1 | body, input, select, button { 2 | color: #222; 3 | font: 13px Tahoma, Geneva, 'Ubuntu', sans-serif; 4 | } 5 | 6 | input, select { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | select { 12 | height: 19px; 13 | } 14 | 15 | button { 16 | margin: 0; 17 | padding: 0 10px; 18 | } 19 | 20 | div.clear { 21 | clear: both; 22 | } 23 | 24 | #container { 25 | width: 700px; 26 | margin: 0 auto; 27 | } 28 | 29 | #container fieldset { 30 | margin-bottom: 20px; 31 | border-radius: 5px; 32 | } 33 | 34 | #container fieldset legend { 35 | font-weight: bold; 36 | } 37 | 38 | #container fieldset ul { 39 | margin: 0; 40 | padding: 0; 41 | list-style-type: none; 42 | } 43 | 44 | #container fieldset ul li { 45 | line-height: 19px; 46 | margin: 15px 0; 47 | } 48 | 49 | #container fieldset ul li span.small { 50 | font-size: 9px; 51 | } 52 | 53 | #container fieldset ul li label.section { 54 | float: left; 55 | width: 155px; 56 | margin-right: 15px; 57 | text-align: right; 58 | } 59 | label.sectionheader{ 60 | font-weight: bold; 61 | } 62 | 63 | #container fieldset ul li div.options { 64 | float: left; 65 | width: 504px; 66 | } 67 | 68 | #ip, #path { 69 | width: 102px; 70 | } 71 | 72 | #port { 73 | width: 40px; 74 | } 75 | 76 | #customdirs { 77 | table-layout: fixed; 78 | border-spacing: 5px; 79 | } 80 | 81 | #customdirs th, td { 82 | padding: 0; 83 | } 84 | 85 | #customdirs input.label { 86 | width: 140px; 87 | } 88 | 89 | #customdirs input.dir { 90 | width: 276px; 91 | } 92 | 93 | #customdirs tr.addcustom { 94 | height: 30px; 95 | vertical-align: top; 96 | } 97 | 98 | #customdirs div.button { 99 | float: left; 100 | width: 16px; 101 | height: 12px; 102 | background-image: url(../images/dir_buttons.png); 103 | cursor: pointer; 104 | } 105 | 106 | #customdirs div.button.up { 107 | background-position: 0 0; 108 | } 109 | 110 | #customdirs div.button.down { 111 | background-position: -16px 0; 112 | } 113 | 114 | #customdirs div.button.remove { 115 | background-position: -32px 0; 116 | } 117 | 118 | #save { 119 | margin-left: 10px; 120 | } 121 | 122 | #saved { 123 | display: none; 124 | } 125 | -------------------------------------------------------------------------------- /source/js/torrentParsing.js: -------------------------------------------------------------------------------- 1 | /* exported parseTorrent */ 2 | /** 3 | * Parses the torrent into a javascript object 4 | * @param {String} torrent - a torrent file 5 | * @param {Function} callback - where to send the parsed torrent object 6 | */ 7 | function parseTorrent(torrent, callback) { 8 | var reader = new FileReader(); 9 | reader.onload = function () { 10 | var worker = new Worker('js/bencode.js'); 11 | worker.onmessage = function (ev) { 12 | if (ev.data.split) { 13 | let data = ev.data.split(':'); 14 | switch (true) { 15 | case data[0] === 'debug': 16 | console.debug(data[1]); // eslint-disable-line no-console 17 | break; 18 | default: 19 | break; 20 | } 21 | } else { 22 | callback(ev.data); 23 | } 24 | }; 25 | worker.onerror = function (event) { 26 | throw new Error(event.message + ' (' + event.filename + ':' + event.lineno + ')'); 27 | }; 28 | worker.postMessage(reader.result); 29 | }; 30 | 31 | reader.readAsBinaryString(new Blob([torrent], {type: 'application/octet-stream'})); 32 | } 33 | 34 | /* exported encodeFile */ 35 | /** 36 | * Encodes a file into base64 37 | * @param {String} file - file 38 | * @param {Function} callback - where to send the base64 encoded file 39 | */ 40 | function encodeFile(file, callback) { 41 | // callback(btoa(unescape(encodeURIComponent( file )))); 42 | var reader = new FileReader(); 43 | 44 | reader.onload = function () { 45 | // assume base64 and just split to get data 46 | // data:[][;charset=][;base64], 47 | var parts = reader.result.split(',', 2); 48 | callback(parts[1]); 49 | }; 50 | 51 | reader.readAsDataURL(file); 52 | } 53 | 54 | /* exported getFile */ 55 | /* 56 | * Downloads a file 57 | * @param {String} url - URL of the file to download and encode 58 | * @param {Functino} callback - where to send the downloaded file 59 | */ 60 | function getFile(url, callback) { 61 | var xhr = new XMLHttpRequest(); 62 | xhr.open('GET', url, true); 63 | xhr.responseType = 'blob'; 64 | xhr.onload = function () { 65 | if (this.status === 200) { 66 | callback(this.response); 67 | } 68 | }; 69 | xhr.send(); 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remote Transmission ++ 2 | 3 | Based on Remote Transmission Plus 4 | 5 | ## Features 6 | * Click a torrent link to download it using a remote Transmission client 7 | * click on most torrent links to automatically send it to Transmission 8 | * right-click any link to send to Transmission 9 | * custom download directories 10 | * browser icon notification badges: add, dup, fail 11 | * hold down ALT, CTRL, or SHIFT to download the torrent file locally 12 | 13 | 14 | * Remote Control 15 | * notifications when a torrent download completes 16 | * filter by name and status 17 | * pause and resume torrents 18 | * remove torrents (double-click) with data (CTRL + double-click) 19 | * toggle turtle mode 20 | 21 | 22 | ## Changelog 23 | 24 | 2018-01-25 v1.0.8 25 | * Fix popup not appearing correctly on OSX (thanks wader) 26 | 27 | 2017-10-02 v1.0.7 28 | * Fix notification on completed torrent (thanks slokhorst) 29 | 30 | 2017-10-02 v1.0.6 31 | * Fix adding torrents in the paused state (thanks slokhorst) 32 | 33 | 2017-10-01 v1.0.5 34 | * Update to jQuery v3.2.1 (thanks slokhorst) 35 | * Fix some options not being saved (thanks slokhorst) 36 | 37 | 2017-03-13 v1.0.4 38 | * Fix "download directory path is not absolute" error. (Closes issue #28) (thanks zsorizs) 39 | * Fix configuration resetting to defaults when opened. (thanks zsorizs) 40 | * Fix saving of default click action. (thanks zsorizs) 41 | 42 | 2016-02-03 v1.0.3 43 | * Fix capturing links for dynamically loaded content 44 | 45 | 2015-06-06 V1.0.1 46 | * Fix for last version erasing settings 47 | 48 | 2015-06-03 v1.0.0 49 | * Add support for adding new custom location from save popup (thanks wader) 50 | 51 | 2015-04-15 v0.9.9.9 52 | * Ensure clients' filters are not changed erroneously 53 | 54 | 2015-04-13 v0.9.9.8 55 | * Fixed filtering (presumably broken for some time due to RPC changes) 56 | * Added a filtering category 'Active' to filter out stopped/completed torrents. (Closes issue #10). 57 | 58 | 2015-04-12 v0.9.9.7 59 | * Give the popup a minimum height so the buttons are always clickable (thanks jonathantribouharet) 60 | * Clear all previous torrents on error (thanks jonathantribouharet) hopefully stops torrents showing up multiple times. 61 | 62 | ## Credits / Contributors 63 | * dz0ny 64 | * (probably) the original developer 65 | * cherepanov 66 | * This extension is based upon his improvements dz0ny's work 67 | * sakim 68 | * r04r 69 | * mjbnz 70 | * jonathantribouharet 71 | * wader 72 | * zsorizs 73 | * iancorbitt 74 | * slokhorst 75 | -------------------------------------------------------------------------------- /source/css/downloadTorrent.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 13px 13px 0 13px; 4 | background-color: #f2f1f0; 5 | color: #222; 6 | font: 15px Tahoma, Geneva, 'Ubuntu', sans-serif; 7 | } 8 | 9 | select, button { 10 | height: 29px; 11 | font: 15px Tahoma, Geneva, 'Ubuntu', sans-serif; 12 | } 13 | 14 | .clear { 15 | clear: both; 16 | } 17 | 18 | #container { 19 | overflow: auto; 20 | margin: 0; 21 | padding: 0; 22 | list-style-type: none; 23 | } 24 | 25 | #container li { 26 | margin-bottom: 10px; 27 | } 28 | 29 | #torrentName { 30 | font-size: 18px; 31 | font-weight: bold; 32 | } 33 | 34 | #downloadLabel { 35 | line-height: 29px; 36 | } 37 | 38 | #downloadLocations { 39 | float: right; 40 | width: 705px; 41 | vertical-align: middle; 42 | } 43 | 44 | #filesContainer { 45 | overflow: auto; 46 | height: 394px; 47 | border: 1px solid #a0a09f; 48 | -webkit-border-radius: 2px; 49 | background-color: #fff; 50 | } 51 | 52 | #new { 53 | display: none; 54 | } 55 | 56 | #newLabelDirectoryRow { 57 | display: flex; 58 | } 59 | 60 | #newDirectory { 61 | flex-grow: 1; 62 | } 63 | 64 | #files { 65 | table-layout: fixed; 66 | width: 100%; 67 | border-spacing: 0; 68 | } 69 | 70 | #files tr { 71 | margin: 0; 72 | padding: 0; 73 | background-color: #ddd; 74 | } 75 | 76 | #files tr:nth-child(2n) { 77 | background-color: #eee; 78 | } 79 | 80 | #files th, #files td { 81 | padding-left: 3px; 82 | } 83 | 84 | #files th { 85 | height: 24px; 86 | border-bottom: 1px solid #a0a09f; 87 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0.43, #f9f9f9), color-stop(0.72, #eae9e7)); 88 | text-align: left; 89 | font-weight: normal; 90 | } 91 | 92 | #files td { 93 | height: 23px; 94 | } 95 | 96 | #files th.checkAll, #files td.checkAll { 97 | width: 5%; 98 | overflow: hidden; 99 | white-space: nowrap; 100 | } 101 | 102 | #files th.name, #files td.name { 103 | width: 65%; 104 | overflow: hidden; 105 | white-space: nowrap; 106 | border-left: 1px solid #d2cfcc; 107 | } 108 | 109 | #files th.size { 110 | width: 15%; 111 | border-left: 1px solid #d2cfcc; 112 | } 113 | 114 | #files td.size { 115 | border-left: 1px solid #bdbdbd; 116 | } 117 | 118 | #files th.priority { 119 | width: 15%; 120 | border-left: 1px solid #d2cfcc; 121 | } 122 | 123 | #files td.priority { 124 | border-left: 1px solid #bdbdbd; 125 | } 126 | 127 | #cancel { 128 | float: right; 129 | width: 85px; 130 | } 131 | 132 | #save { 133 | float: right; 134 | width: 85px; 135 | margin-left: 15px; 136 | } 137 | 138 | .listChkBox { 139 | width: 29px; 140 | height: 29px; 141 | } 142 | 143 | .prioChkBox { 144 | width: 10px; 145 | height: 10px; 146 | } 147 | -------------------------------------------------------------------------------- /source/js/downloadMagnet.js: -------------------------------------------------------------------------------- 1 | /* global decodeBytes */ 2 | 3 | var selectNewDirectoryIndex = 1; 4 | const TAG_DOWNLOAD_DIR = 1; 5 | var port = chrome.runtime.connect({name: 'downloadMagnet'}); 6 | 7 | function decodeString(s) { 8 | var r; 9 | try { 10 | r = decodeURIComponent(escape(s)); 11 | } catch (e) { 12 | r = decodeBytes(s, 'cp1251'); 13 | } 14 | return r; 15 | } 16 | 17 | // populate the download popup with the torrent information 18 | chrome.runtime.sendMessage({method: 'get-torrent-info', page: 'magnet'}, function (request) { 19 | var select = jQuery('#downloadLocations'); 20 | var newLabel = jQuery('#newLabel'); 21 | var newDirectory = jQuery('#newDirectory'); 22 | var addToCustomLocations = jQuery('#addToCustomLocations'); 23 | 24 | // add the list of download directories 25 | console.log(request.dirs.length); 26 | if (request.dirs.length === 0) { 27 | select.disabled = 'disabled'; 28 | } else { 29 | for (let i = 0; i < request.dirs.length; i++) { 30 | select.append(jQuery('