WebUI: Improve accuracy of trackers list
[qBittorrent.git] / src / webui / www / private / scripts / mocha-init.js
blobbc429eff363b4e0d61b960ddfcb2f8cfa4f37838
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2008 Christophe Dumez <chris@qbittorrent.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 /* -----------------------------------------------------------------
31 ATTACH MOCHA LINK EVENTS
32 Notes: Here is where you define your windows and the events that open them.
33 If you are not using links to run Mocha methods you can remove this function.
35 If you need to add link events to links within windows you are creating, do
36 it in the onContentLoaded function of the new window.
38 ----------------------------------------------------------------- */
39 'use strict';
41 const LocalPreferences = new window.qBittorrent.LocalPreferences.LocalPreferencesClass();
43 let saveWindowSize = function() {};
44 let loadWindowWidth = function() {};
45 let loadWindowHeight = function() {};
46 let showDownloadPage = function() {};
47 let globalUploadLimitFN = function() {};
48 let uploadLimitFN = function() {};
49 let shareRatioFN = function() {};
50 let toggleSequentialDownloadFN = function() {};
51 let toggleFirstLastPiecePrioFN = function() {};
52 let setSuperSeedingFN = function() {};
53 let setForceStartFN = function() {};
54 let globalDownloadLimitFN = function() {};
55 let StatisticsLinkFN = function() {};
56 let downloadLimitFN = function() {};
57 let deleteFN = function() {};
58 let stopFN = function() {};
59 let startFN = function() {};
60 let autoTorrentManagementFN = function() {};
61 let recheckFN = function() {};
62 let reannounceFN = function() {};
63 let setLocationFN = function() {};
64 let renameFN = function() {};
65 let renameFilesFN = function() {};
66 let torrentNewCategoryFN = function() {};
67 let torrentSetCategoryFN = function() {};
68 let createCategoryFN = function() {};
69 let createSubcategoryFN = function() {};
70 let editCategoryFN = function() {};
71 let removeCategoryFN = function() {};
72 let deleteUnusedCategoriesFN = function() {};
73 let startTorrentsByCategoryFN = function() {};
74 let stopTorrentsByCategoryFN = function() {};
75 let deleteTorrentsByCategoryFN = function() {};
76 let torrentAddTagsFN = function() {};
77 let torrentSetTagsFN = function() {};
78 let torrentRemoveAllTagsFN = function() {};
79 let createTagFN = function() {};
80 let removeTagFN = function() {};
81 let deleteUnusedTagsFN = function() {};
82 let startTorrentsByTagFN = function() {};
83 let stopTorrentsByTagFN = function() {};
84 let deleteTorrentsByTagFN = function() {};
85 let startTorrentsByTrackerFN = function() {};
86 let stopTorrentsByTrackerFN = function() {};
87 let deleteTorrentsByTrackerFN = function() {};
88 let copyNameFN = function() {};
89 let copyInfohashFN = function(policy) {};
90 let copyMagnetLinkFN = function() {};
91 let copyIdFN = function() {};
92 let copyCommentFN = function() {};
93 let setQueuePositionFN = function() {};
94 let exportTorrentFN = function() {};
96 const initializeWindows = function() {
97 saveWindowSize = function(windowId) {
98 const size = $(windowId).getSize();
99 LocalPreferences.set('window_' + windowId + '_width', size.x);
100 LocalPreferences.set('window_' + windowId + '_height', size.y);
103 loadWindowWidth = function(windowId, defaultValue) {
104 return LocalPreferences.get('window_' + windowId + '_width', defaultValue);
107 loadWindowHeight = function(windowId, defaultValue) {
108 return LocalPreferences.get('window_' + windowId + '_height', defaultValue);
111 function addClickEvent(el, fn) {
112 ['Link', 'Button'].each(function(item) {
113 if ($(el + item)) {
114 $(el + item).addEvent('click', fn);
119 addClickEvent('download', function(e) {
120 new Event(e).stop();
121 showDownloadPage();
124 showDownloadPage = function(urls) {
125 const id = 'downloadPage';
126 let contentUri = new URI('download.html');
128 if (urls && (urls.length > 0)) {
129 contentUri.setData("urls", urls.map(encodeURIComponent).join("|"));
132 new MochaUI.Window({
133 id: id,
134 title: "QBT_TR(Download from URLs)QBT_TR[CONTEXT=downloadFromURL]",
135 loadMethod: 'iframe',
136 contentURL: contentUri.toString(),
137 addClass: 'windowFrame', // fixes iframe scrolling on iOS Safari
138 scrollbars: true,
139 maximizable: false,
140 closable: true,
141 paddingVertical: 0,
142 paddingHorizontal: 0,
143 width: loadWindowWidth(id, 500),
144 height: loadWindowHeight(id, 600),
145 onResize: function() {
146 saveWindowSize(id);
149 updateMainData();
152 addClickEvent('preferences', function(e) {
153 new Event(e).stop();
154 const id = 'preferencesPage';
155 new MochaUI.Window({
156 id: id,
157 title: "QBT_TR(Options)QBT_TR[CONTEXT=OptionsDialog]",
158 loadMethod: 'xhr',
159 toolbar: true,
160 contentURL: new URI("views/preferences.html").toString(),
161 require: {
162 css: ['css/Tabs.css']
164 toolbarURL: 'views/preferencesToolbar.html',
165 maximizable: false,
166 closable: true,
167 paddingVertical: 0,
168 paddingHorizontal: 0,
169 width: loadWindowWidth(id, 700),
170 height: loadWindowHeight(id, 600),
171 onResize: function() {
172 saveWindowSize(id);
177 addClickEvent('upload', function(e) {
178 new Event(e).stop();
179 const id = 'uploadPage';
180 new MochaUI.Window({
181 id: id,
182 title: "QBT_TR(Upload local torrent)QBT_TR[CONTEXT=HttpServer]",
183 loadMethod: 'iframe',
184 contentURL: new URI("upload.html").toString(),
185 addClass: 'windowFrame', // fixes iframe scrolling on iOS Safari
186 scrollbars: true,
187 maximizable: false,
188 paddingVertical: 0,
189 paddingHorizontal: 0,
190 width: loadWindowWidth(id, 500),
191 height: loadWindowHeight(id, 460),
192 onResize: function() {
193 saveWindowSize(id);
196 updateMainData();
199 globalUploadLimitFN = function() {
200 new MochaUI.Window({
201 id: 'uploadLimitPage',
202 title: "QBT_TR(Global Upload Speed Limit)QBT_TR[CONTEXT=MainWindow]",
203 loadMethod: 'iframe',
204 contentURL: new URI("uploadlimit.html").setData("hashes", "global").toString(),
205 scrollbars: false,
206 resizable: false,
207 maximizable: false,
208 paddingVertical: 0,
209 paddingHorizontal: 0,
210 width: 424,
211 height: 80
215 uploadLimitFN = function() {
216 const hashes = torrentsTable.selectedRowsIds();
217 if (hashes.length) {
218 new MochaUI.Window({
219 id: 'uploadLimitPage',
220 title: "QBT_TR(Torrent Upload Speed Limiting)QBT_TR[CONTEXT=TransferListWidget]",
221 loadMethod: 'iframe',
222 contentURL: new URI("uploadlimit.html").setData("hashes", hashes.join("|")).toString(),
223 scrollbars: false,
224 resizable: false,
225 maximizable: false,
226 paddingVertical: 0,
227 paddingHorizontal: 0,
228 width: 424,
229 height: 80
234 shareRatioFN = function() {
235 const hashes = torrentsTable.selectedRowsIds();
236 if (hashes.length) {
237 let shareRatio = null;
238 let torrentsHaveSameShareRatio = true;
240 // check if all selected torrents have same share ratio
241 for (let i = 0; i < hashes.length; ++i) {
242 const hash = hashes[i];
243 const row = torrentsTable.rows[hash].full_data;
244 const origValues = row.ratio_limit + "|" + row.seeding_time_limit + "|" + row.inactive_seeding_time_limit + "|"
245 + row.max_ratio + "|" + row.max_seeding_time + "|" + row.max_inactive_seeding_time;
247 // initialize value
248 if (shareRatio === null)
249 shareRatio = origValues;
251 if (origValues !== shareRatio) {
252 torrentsHaveSameShareRatio = false;
253 break;
257 // if all torrents have same share ratio, display that share ratio. else use the default
258 const orig = torrentsHaveSameShareRatio ? shareRatio : "";
259 new MochaUI.Window({
260 id: 'shareRatioPage',
261 title: "QBT_TR(Torrent Upload/Download Ratio Limiting)QBT_TR[CONTEXT=UpDownRatioDialog]",
262 loadMethod: 'iframe',
263 contentURL: new URI("shareratio.html").setData("hashes", hashes.join("|")).setData("orig", orig).toString(),
264 scrollbars: false,
265 maximizable: false,
266 paddingVertical: 0,
267 paddingHorizontal: 0,
268 width: 424,
269 height: 175
274 toggleSequentialDownloadFN = function() {
275 const hashes = torrentsTable.selectedRowsIds();
276 if (hashes.length) {
277 new Request({
278 url: 'api/v2/torrents/toggleSequentialDownload',
279 method: 'post',
280 data: {
281 hashes: hashes.join("|")
283 }).send();
284 updateMainData();
288 toggleFirstLastPiecePrioFN = function() {
289 const hashes = torrentsTable.selectedRowsIds();
290 if (hashes.length) {
291 new Request({
292 url: 'api/v2/torrents/toggleFirstLastPiecePrio',
293 method: 'post',
294 data: {
295 hashes: hashes.join("|")
297 }).send();
298 updateMainData();
302 setSuperSeedingFN = function(val) {
303 const hashes = torrentsTable.selectedRowsIds();
304 if (hashes.length) {
305 new Request({
306 url: 'api/v2/torrents/setSuperSeeding',
307 method: 'post',
308 data: {
309 value: val,
310 hashes: hashes.join("|")
312 }).send();
313 updateMainData();
317 setForceStartFN = function() {
318 const hashes = torrentsTable.selectedRowsIds();
319 if (hashes.length) {
320 new Request({
321 url: 'api/v2/torrents/setForceStart',
322 method: 'post',
323 data: {
324 value: 'true',
325 hashes: hashes.join("|")
327 }).send();
328 updateMainData();
332 globalDownloadLimitFN = function() {
333 new MochaUI.Window({
334 id: 'downloadLimitPage',
335 title: "QBT_TR(Global Download Speed Limit)QBT_TR[CONTEXT=MainWindow]",
336 loadMethod: 'iframe',
337 contentURL: new URI("downloadlimit.html").setData("hashes", "global").toString(),
338 scrollbars: false,
339 resizable: false,
340 maximizable: false,
341 paddingVertical: 0,
342 paddingHorizontal: 0,
343 width: 424,
344 height: 80
348 StatisticsLinkFN = function() {
349 const id = 'statisticspage';
350 new MochaUI.Window({
351 id: id,
352 title: 'QBT_TR(Statistics)QBT_TR[CONTEXT=StatsDialog]',
353 loadMethod: 'xhr',
354 contentURL: new URI("views/statistics.html").toString(),
355 maximizable: false,
356 padding: 10,
357 width: loadWindowWidth(id, 275),
358 height: loadWindowHeight(id, 370),
359 onResize: function() {
360 saveWindowSize(id);
365 downloadLimitFN = function() {
366 const hashes = torrentsTable.selectedRowsIds();
367 if (hashes.length) {
368 new MochaUI.Window({
369 id: 'downloadLimitPage',
370 title: "QBT_TR(Torrent Download Speed Limiting)QBT_TR[CONTEXT=TransferListWidget]",
371 loadMethod: 'iframe',
372 contentURL: new URI("downloadlimit.html").setData("hashes", hashes.join("|")).toString(),
373 scrollbars: false,
374 resizable: false,
375 maximizable: false,
376 paddingVertical: 0,
377 paddingHorizontal: 0,
378 width: 424,
379 height: 80
384 deleteFN = function(deleteFiles = false) {
385 const hashes = torrentsTable.selectedRowsIds();
386 if (hashes.length) {
387 new MochaUI.Window({
388 id: 'confirmDeletionPage',
389 title: "QBT_TR(Remove torrent(s))QBT_TR[CONTEXT=confirmDeletionDlg]",
390 loadMethod: 'iframe',
391 contentURL: new URI("confirmdeletion.html").setData("hashes", hashes.join("|")).setData("deleteFiles", deleteFiles).toString(),
392 scrollbars: false,
393 resizable: true,
394 maximizable: false,
395 padding: 10,
396 width: 424,
397 height: 160
399 updateMainData();
403 addClickEvent('delete', function(e) {
404 new Event(e).stop();
405 deleteFN();
408 stopFN = function() {
409 const hashes = torrentsTable.selectedRowsIds();
410 if (hashes.length) {
411 new Request({
412 url: 'api/v2/torrents/stop',
413 method: 'post',
414 data: {
415 hashes: hashes.join("|")
417 }).send();
418 updateMainData();
422 startFN = function() {
423 const hashes = torrentsTable.selectedRowsIds();
424 if (hashes.length) {
425 new Request({
426 url: 'api/v2/torrents/start',
427 method: 'post',
428 data: {
429 hashes: hashes.join("|")
431 }).send();
432 updateMainData();
436 autoTorrentManagementFN = function() {
437 const hashes = torrentsTable.selectedRowsIds();
438 if (hashes.length) {
439 let enable = false;
440 hashes.each(function(hash, index) {
441 const row = torrentsTable.rows[hash];
442 if (!row.full_data.auto_tmm)
443 enable = true;
445 new Request({
446 url: 'api/v2/torrents/setAutoManagement',
447 method: 'post',
448 data: {
449 hashes: hashes.join("|"),
450 enable: enable
452 }).send();
453 updateMainData();
457 recheckFN = function() {
458 const hashes = torrentsTable.selectedRowsIds();
459 if (hashes.length) {
460 new Request({
461 url: 'api/v2/torrents/recheck',
462 method: 'post',
463 data: {
464 hashes: hashes.join("|"),
466 }).send();
467 updateMainData();
471 reannounceFN = function() {
472 const hashes = torrentsTable.selectedRowsIds();
473 if (hashes.length) {
474 new Request({
475 url: 'api/v2/torrents/reannounce',
476 method: 'post',
477 data: {
478 hashes: hashes.join("|"),
480 }).send();
481 updateMainData();
485 setLocationFN = function() {
486 const hashes = torrentsTable.selectedRowsIds();
487 if (hashes.length) {
488 const hash = hashes[0];
489 const row = torrentsTable.rows[hash];
491 new MochaUI.Window({
492 id: 'setLocationPage',
493 title: "QBT_TR(Set location)QBT_TR[CONTEXT=TransferListWidget]",
494 loadMethod: 'iframe',
495 contentURL: new URI("setlocation.html").setData("hashes", hashes.join('|')).setData("path", encodeURIComponent(row.full_data.save_path)).toString(),
496 scrollbars: false,
497 resizable: true,
498 maximizable: false,
499 paddingVertical: 0,
500 paddingHorizontal: 0,
501 width: 400,
502 height: 130
507 renameFN = function() {
508 const hashes = torrentsTable.selectedRowsIds();
509 if (hashes.length == 1) {
510 const hash = hashes[0];
511 const row = torrentsTable.rows[hash];
512 if (row) {
513 new MochaUI.Window({
514 id: 'renamePage',
515 title: "QBT_TR(Rename)QBT_TR[CONTEXT=TransferListWidget]",
516 loadMethod: 'iframe',
517 contentURL: new URI("rename.html").setData("hash", hash).setData("name", row.full_data.name).toString(),
518 scrollbars: false,
519 resizable: true,
520 maximizable: false,
521 paddingVertical: 0,
522 paddingHorizontal: 0,
523 width: 400,
524 height: 100
530 renameFilesFN = function() {
531 const hashes = torrentsTable.selectedRowsIds();
532 if (hashes.length == 1) {
533 const hash = hashes[0];
534 const row = torrentsTable.rows[hash];
535 if (row) {
536 new MochaUI.Window({
537 id: 'multiRenamePage',
538 title: "QBT_TR(Renaming)QBT_TR[CONTEXT=TransferListWidget]",
539 data: { hash: hash, selectedRows: [] },
540 loadMethod: 'xhr',
541 contentURL: 'rename_files.html',
542 scrollbars: false,
543 resizable: true,
544 maximizable: false,
545 paddingVertical: 0,
546 paddingHorizontal: 0,
547 width: 800,
548 height: 420,
549 resizeLimit: { 'x': [800], 'y': [420] }
555 torrentNewCategoryFN = function() {
556 const action = "set";
557 const hashes = torrentsTable.selectedRowsIds();
558 if (hashes.length) {
559 new MochaUI.Window({
560 id: 'newCategoryPage',
561 title: "QBT_TR(New Category)QBT_TR[CONTEXT=TransferListWidget]",
562 loadMethod: 'iframe',
563 contentURL: new URI("newcategory.html").setData("action", action).setData("hashes", hashes.join('|')).toString(),
564 scrollbars: false,
565 resizable: true,
566 maximizable: false,
567 paddingVertical: 0,
568 paddingHorizontal: 0,
569 width: 400,
570 height: 150
575 torrentSetCategoryFN = function(categoryHash) {
576 const hashes = torrentsTable.selectedRowsIds();
577 if (hashes.length <= 0)
578 return;
580 const categoryName = category_list.has(categoryHash)
581 ? category_list.get(categoryHash).name
582 : '';
583 new Request({
584 url: 'api/v2/torrents/setCategory',
585 method: 'post',
586 data: {
587 hashes: hashes.join("|"),
588 category: categoryName
590 }).send();
593 createCategoryFN = function() {
594 const action = "create";
595 new MochaUI.Window({
596 id: 'newCategoryPage',
597 title: "QBT_TR(New Category)QBT_TR[CONTEXT=CategoryFilterWidget]",
598 loadMethod: 'iframe',
599 contentURL: new URI("newcategory.html").setData("action", action).toString(),
600 scrollbars: false,
601 resizable: true,
602 maximizable: false,
603 paddingVertical: 0,
604 paddingHorizontal: 0,
605 width: 400,
606 height: 150
608 updateMainData();
611 createSubcategoryFN = function(categoryHash) {
612 const action = "createSubcategory";
613 const categoryName = category_list.get(categoryHash).name + "/";
614 new MochaUI.Window({
615 id: 'newSubcategoryPage',
616 title: "QBT_TR(New Category)QBT_TR[CONTEXT=CategoryFilterWidget]",
617 loadMethod: 'iframe',
618 contentURL: new URI("newcategory.html").setData("action", action).setData("categoryName", categoryName).toString(),
619 scrollbars: false,
620 resizable: true,
621 maximizable: false,
622 paddingVertical: 0,
623 paddingHorizontal: 0,
624 width: 400,
625 height: 150
627 updateMainData();
630 editCategoryFN = function(categoryHash) {
631 const action = "edit";
632 const category = category_list.get(categoryHash);
633 new MochaUI.Window({
634 id: 'editCategoryPage',
635 title: "QBT_TR(Edit Category)QBT_TR[CONTEXT=TransferListWidget]",
636 loadMethod: 'iframe',
637 contentURL: new URI('newcategory.html').setData("action", action).setData("categoryName", category.name).setData("savePath", category.savePath).toString(),
638 scrollbars: false,
639 resizable: true,
640 maximizable: false,
641 paddingVertical: 0,
642 paddingHorizontal: 0,
643 width: 400,
644 height: 150
646 updateMainData();
649 removeCategoryFN = function(categoryHash) {
650 const categoryName = category_list.get(categoryHash).name;
651 new Request({
652 url: 'api/v2/torrents/removeCategories',
653 method: 'post',
654 data: {
655 categories: categoryName
657 }).send();
658 setCategoryFilter(CATEGORIES_ALL);
661 deleteUnusedCategoriesFN = function() {
662 const categories = [];
663 category_list.forEach((category, hash) => {
664 if (torrentsTable.getFilteredTorrentsNumber('all', hash, TAGS_ALL, TRACKERS_ALL) === 0)
665 categories.push(category.name);
668 new Request({
669 url: 'api/v2/torrents/removeCategories',
670 method: 'post',
671 data: {
672 categories: categories.join('\n')
674 }).send();
675 setCategoryFilter(CATEGORIES_ALL);
678 startTorrentsByCategoryFN = function(categoryHash) {
679 const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL, TRACKERS_ALL);
680 if (hashes.length) {
681 new Request({
682 url: 'api/v2/torrents/start',
683 method: 'post',
684 data: {
685 hashes: hashes.join("|")
687 }).send();
688 updateMainData();
692 stopTorrentsByCategoryFN = function(categoryHash) {
693 const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL, TRACKERS_ALL);
694 if (hashes.length) {
695 new Request({
696 url: 'api/v2/torrents/stop',
697 method: 'post',
698 data: {
699 hashes: hashes.join("|")
701 }).send();
702 updateMainData();
706 deleteTorrentsByCategoryFN = function(categoryHash) {
707 const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL, TRACKERS_ALL);
708 if (hashes.length) {
709 new MochaUI.Window({
710 id: 'confirmDeletionPage',
711 title: "QBT_TR(Remove torrent(s))QBT_TR[CONTEXT=confirmDeletionDlg]",
712 loadMethod: 'iframe',
713 contentURL: new URI("confirmdeletion.html").setData("hashes", hashes.join("|")).toString(),
714 scrollbars: false,
715 resizable: true,
716 maximizable: false,
717 padding: 10,
718 width: 424,
719 height: 160
721 updateMainData();
725 torrentAddTagsFN = function() {
726 const action = "set";
727 const hashes = torrentsTable.selectedRowsIds();
728 if (hashes.length) {
729 new MochaUI.Window({
730 id: 'newTagPage',
731 title: "QBT_TR(Add Tags)QBT_TR[CONTEXT=TransferListWidget]",
732 loadMethod: 'iframe',
733 contentURL: new URI("newtag.html").setData("action", action).setData("hashes", hashes.join("|")).toString(),
734 scrollbars: false,
735 resizable: true,
736 maximizable: false,
737 paddingVertical: 0,
738 paddingHorizontal: 0,
739 width: 250,
740 height: 100
745 torrentSetTagsFN = function(tagHash, isSet) {
746 const hashes = torrentsTable.selectedRowsIds();
747 if (hashes.length <= 0)
748 return;
750 const tagName = tagList.has(tagHash) ? tagList.get(tagHash).name : '';
751 new Request({
752 url: (isSet ? 'api/v2/torrents/addTags' : 'api/v2/torrents/removeTags'),
753 method: 'post',
754 data: {
755 hashes: hashes.join("|"),
756 tags: tagName,
758 }).send();
761 torrentRemoveAllTagsFN = function() {
762 const hashes = torrentsTable.selectedRowsIds();
763 if (hashes.length) {
764 new Request({
765 url: ('api/v2/torrents/removeTags'),
766 method: 'post',
767 data: {
768 hashes: hashes.join("|"),
770 }).send();
774 createTagFN = function() {
775 const action = "create";
776 new MochaUI.Window({
777 id: 'newTagPage',
778 title: "QBT_TR(New Tag)QBT_TR[CONTEXT=TagFilterWidget]",
779 loadMethod: 'iframe',
780 contentURL: new URI("newtag.html").setData("action", action).toString(),
781 scrollbars: false,
782 resizable: true,
783 maximizable: false,
784 paddingVertical: 0,
785 paddingHorizontal: 0,
786 width: 250,
787 height: 100
789 updateMainData();
792 removeTagFN = function(tagHash) {
793 const tagName = tagList.get(tagHash).name;
794 new Request({
795 url: 'api/v2/torrents/deleteTags',
796 method: 'post',
797 data: {
798 tags: tagName
800 }).send();
801 setTagFilter(TAGS_ALL);
804 deleteUnusedTagsFN = function() {
805 const tags = [];
806 tagList.forEach((tag, hash) => {
807 if (torrentsTable.getFilteredTorrentsNumber('all', CATEGORIES_ALL, hash, TRACKERS_ALL) === 0)
808 tags.push(tag.name);
810 new Request({
811 url: 'api/v2/torrents/deleteTags',
812 method: 'post',
813 data: {
814 tags: tags.join(',')
816 }).send();
817 setTagFilter(TAGS_ALL);
820 startTorrentsByTagFN = function(tagHash) {
821 const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash, TRACKERS_ALL);
822 if (hashes.length) {
823 new Request({
824 url: 'api/v2/torrents/start',
825 method: 'post',
826 data: {
827 hashes: hashes.join("|")
829 }).send();
830 updateMainData();
834 stopTorrentsByTagFN = function(tagHash) {
835 const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash, TRACKERS_ALL);
836 if (hashes.length) {
837 new Request({
838 url: 'api/v2/torrents/stop',
839 method: 'post',
840 data: {
841 hashes: hashes.join("|")
843 }).send();
844 updateMainData();
848 deleteTorrentsByTagFN = function(tagHash) {
849 const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash, TRACKERS_ALL);
850 if (hashes.length) {
851 new MochaUI.Window({
852 id: 'confirmDeletionPage',
853 title: "QBT_TR(Remove torrent(s))QBT_TR[CONTEXT=confirmDeletionDlg]",
854 loadMethod: 'iframe',
855 contentURL: new URI("confirmdeletion.html").setData("hashes", hashes.join("|")).toString(),
856 scrollbars: false,
857 resizable: true,
858 maximizable: false,
859 padding: 10,
860 width: 424,
861 height: 160
863 updateMainData();
867 startTorrentsByTrackerFN = function(trackerHash) {
868 const trackerHashInt = Number.parseInt(trackerHash, 10);
869 let hashes = [];
870 switch (trackerHashInt) {
871 case TRACKERS_ALL:
872 hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
873 break;
874 case TRACKERS_TRACKERLESS:
875 hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
876 break;
877 default: {
878 const uniqueTorrents = new Set();
879 for (const torrents of trackerList.get(trackerHashInt).trackerTorrentMap.values()) {
880 for (const torrent of torrents) {
881 uniqueTorrents.add(torrent);
884 hashes = [...uniqueTorrents];
885 break;
889 if (hashes.length > 0) {
890 new Request({
891 url: 'api/v2/torrents/start',
892 method: 'post',
893 data: {
894 hashes: hashes.join("|")
896 }).send();
897 updateMainData();
901 stopTorrentsByTrackerFN = function(trackerHash) {
902 const trackerHashInt = Number.parseInt(trackerHash, 10);
903 let hashes = [];
904 switch (trackerHashInt) {
905 case TRACKERS_ALL:
906 hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
907 break;
908 case TRACKERS_TRACKERLESS:
909 hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
910 break;
911 default: {
912 const uniqueTorrents = new Set();
913 for (const torrents of trackerList.get(trackerHashInt).trackerTorrentMap.values()) {
914 for (const torrent of torrents) {
915 uniqueTorrents.add(torrent);
918 hashes = [...uniqueTorrents];
919 break;
923 if (hashes.length) {
924 new Request({
925 url: 'api/v2/torrents/stop',
926 method: 'post',
927 data: {
928 hashes: hashes.join("|")
930 }).send();
931 updateMainData();
935 deleteTorrentsByTrackerFN = function(trackerHash) {
936 const trackerHashInt = Number.parseInt(trackerHash, 10);
937 let hashes = [];
938 switch (trackerHashInt) {
939 case TRACKERS_ALL:
940 hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
941 break;
942 case TRACKERS_TRACKERLESS:
943 hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
944 break;
945 default: {
946 const uniqueTorrents = new Set();
947 for (const torrents of trackerList.get(trackerHashInt).trackerTorrentMap.values()) {
948 for (const torrent of torrents) {
949 uniqueTorrents.add(torrent);
952 hashes = [...uniqueTorrents];
953 break;
957 if (hashes.length) {
958 new MochaUI.Window({
959 id: 'confirmDeletionPage',
960 title: "QBT_TR(Remove torrent(s))QBT_TR[CONTEXT=confirmDeletionDlg]",
961 loadMethod: 'iframe',
962 contentURL: new URI("confirmdeletion.html").setData("hashes", hashes.join("|")).toString(),
963 scrollbars: false,
964 resizable: true,
965 maximizable: false,
966 padding: 10,
967 width: 424,
968 height: 160,
969 onCloseComplete: function() {
970 updateMainData();
971 setTrackerFilter(TRACKERS_ALL);
977 copyNameFN = function() {
978 const selectedRows = torrentsTable.selectedRowsIds();
979 const names = [];
980 if (selectedRows.length > 0) {
981 const rows = torrentsTable.getFilteredAndSortedRows();
982 for (let i = 0; i < selectedRows.length; ++i) {
983 const hash = selectedRows[i];
984 names.push(rows[hash].full_data.name);
987 return names.join("\n");
990 copyInfohashFN = function(policy) {
991 const selectedRows = torrentsTable.selectedRowsIds();
992 const infohashes = [];
993 if (selectedRows.length > 0) {
994 const rows = torrentsTable.getFilteredAndSortedRows();
995 switch (policy) {
996 case 1:
997 for (const id of selectedRows) {
998 const infohash = rows[id].full_data.infohash_v1;
999 if (infohash !== "")
1000 infohashes.push(infohash);
1002 break;
1003 case 2:
1004 for (const id of selectedRows) {
1005 const infohash = rows[id].full_data.infohash_v2;
1006 if (infohash !== "")
1007 infohashes.push(infohash);
1009 break;
1012 return infohashes.join("\n");
1015 copyMagnetLinkFN = function() {
1016 const selectedRows = torrentsTable.selectedRowsIds();
1017 const magnets = [];
1018 if (selectedRows.length > 0) {
1019 const rows = torrentsTable.getFilteredAndSortedRows();
1020 for (let i = 0; i < selectedRows.length; ++i) {
1021 const hash = selectedRows[i];
1022 magnets.push(rows[hash].full_data.magnet_uri);
1025 return magnets.join("\n");
1028 copyIdFN = function() {
1029 return torrentsTable.selectedRowsIds().join("\n");
1032 copyCommentFN = function() {
1033 const selectedRows = torrentsTable.selectedRowsIds();
1034 const comments = [];
1035 if (selectedRows.length > 0) {
1036 const rows = torrentsTable.getFilteredAndSortedRows();
1037 for (let i = 0; i < selectedRows.length; ++i) {
1038 const hash = selectedRows[i];
1039 const comment = rows[hash].full_data.comment;
1040 if (comment && (comment !== ""))
1041 comments.push(comment);
1044 return comments.join("\n---------\n");
1047 exportTorrentFN = async function() {
1048 const hashes = torrentsTable.selectedRowsIds();
1049 for (const hash of hashes) {
1050 const row = torrentsTable.rows.get(hash);
1051 if (!row)
1052 continue;
1054 const name = row.full_data.name;
1055 const url = new URI("api/v2/torrents/export");
1056 url.setData("hash", hash);
1058 // download response to file
1059 const element = document.createElement("a");
1060 element.setAttribute("href", url);
1061 element.setAttribute("download", (name + ".torrent"));
1062 document.body.appendChild(element);
1063 element.click();
1064 document.body.removeChild(element);
1066 // https://stackoverflow.com/questions/53560991/automatic-file-downloads-limited-to-10-files-on-chrome-browser
1067 await window.qBittorrent.Misc.sleep(200);
1071 addClickEvent('stopAll', (e) => {
1072 new Event(e).stop();
1074 if (confirm('QBT_TR(Would you like to stop all torrents?)QBT_TR[CONTEXT=MainWindow]')) {
1075 new Request({
1076 url: 'api/v2/torrents/stop',
1077 method: 'post',
1078 data: {
1079 hashes: "all"
1081 }).send();
1082 updateMainData();
1086 addClickEvent('startAll', (e) => {
1087 new Event(e).stop();
1089 if (confirm('QBT_TR(Would you like to start all torrents?)QBT_TR[CONTEXT=MainWindow]')) {
1090 new Request({
1091 url: 'api/v2/torrents/start',
1092 method: 'post',
1093 data: {
1094 hashes: "all"
1096 }).send();
1097 updateMainData();
1101 ['stop', 'start', 'recheck'].each(function(item) {
1102 addClickEvent(item, function(e) {
1103 new Event(e).stop();
1104 const hashes = torrentsTable.selectedRowsIds();
1105 if (hashes.length) {
1106 hashes.each(function(hash, index) {
1107 new Request({
1108 url: 'api/v2/torrents/' + item,
1109 method: 'post',
1110 data: {
1111 hashes: hash
1113 }).send();
1115 updateMainData();
1120 ['decreasePrio', 'increasePrio', 'topPrio', 'bottomPrio'].each(function(item) {
1121 addClickEvent(item, function(e) {
1122 new Event(e).stop();
1123 setQueuePositionFN(item);
1127 setQueuePositionFN = function(cmd) {
1128 const hashes = torrentsTable.selectedRowsIds();
1129 if (hashes.length) {
1130 new Request({
1131 url: 'api/v2/torrents/' + cmd,
1132 method: 'post',
1133 data: {
1134 hashes: hashes.join("|")
1136 }).send();
1137 updateMainData();
1141 addClickEvent('about', function(e) {
1142 new Event(e).stop();
1143 const id = 'aboutpage';
1144 new MochaUI.Window({
1145 id: id,
1146 title: 'QBT_TR(About qBittorrent)QBT_TR[CONTEXT=AboutDialog]',
1147 loadMethod: 'xhr',
1148 contentURL: new URI("views/about.html").toString(),
1149 require: {
1150 css: ['css/Tabs.css']
1152 toolbar: true,
1153 toolbarURL: 'views/aboutToolbar.html',
1154 padding: 10,
1155 width: loadWindowWidth(id, 550),
1156 height: loadWindowHeight(id, 360),
1157 onResize: function() {
1158 saveWindowSize(id);
1163 addClickEvent('logout', function(e) {
1164 new Event(e).stop();
1165 new Request({
1166 url: 'api/v2/auth/logout',
1167 method: 'post',
1168 onSuccess: function() {
1169 window.location.reload(true);
1171 }).send();
1174 addClickEvent('shutdown', function(e) {
1175 new Event(e).stop();
1176 if (confirm('QBT_TR(Are you sure you want to quit qBittorrent?)QBT_TR[CONTEXT=MainWindow]')) {
1177 new Request({
1178 url: 'api/v2/app/shutdown',
1179 method: 'post',
1180 onSuccess: function() {
1181 const shutdownMessage = 'QBT_TR(%1 has been shutdown)QBT_TR[CONTEXT=HttpServer]'.replace("%1", window.qBittorrent.Client.mainTitle());
1182 document.write(`<!doctype html><html lang="${LANG}"><head> <meta charset="UTF-8"> <meta name="color-scheme" content="light dark"> <title>${shutdownMessage}</title> <style>* {font-family: Arial, Helvetica, sans-serif;}</style></head><body> <h1 style="text-align: center;">${shutdownMessage}</h1></body></html>`);
1183 document.close();
1184 window.stop();
1185 window.qBittorrent.Client.stop();
1187 }).send();
1191 // Deactivate menu header links
1192 $$('a.returnFalse').each(function(el) {
1193 el.addEvent('click', function(e) {
1194 new Event(e).stop();