Browse Source

Merge pull request #12748 from Piccirello/webui_sidebar_trackers

Add Trackers section to Web UI sidebar
adaptive-webui-19844
Mike Tzou 5 years ago committed by GitHub
parent
commit
1839e3d96a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/webui/api/serialize/serialize_torrent.cpp
  2. 1
      src/webui/api/serialize/serialize_torrent.h
  3. 33
      src/webui/api/synccontroller.cpp
  4. 5
      src/webui/www/private/index.html
  5. 100
      src/webui/www/private/scripts/client.js
  6. 27
      src/webui/www/private/scripts/dynamicTable.js
  7. 108
      src/webui/www/private/scripts/mocha-init.js
  8. 36
      src/webui/www/private/views/filters.html

2
src/webui/api/serialize/serialize_torrent.cpp

@ -32,6 +32,7 @@
#include "base/bittorrent/infohash.h" #include "base/bittorrent/infohash.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
#include "base/bittorrent/trackerentry.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
namespace namespace
@ -110,6 +111,7 @@ QVariantMap serialize(const BitTorrent::TorrentHandle &torrent)
{KEY_TORRENT_ADDED_ON, torrent.addedTime().toSecsSinceEpoch()}, {KEY_TORRENT_ADDED_ON, torrent.addedTime().toSecsSinceEpoch()},
{KEY_TORRENT_COMPLETION_ON, torrent.completedTime().toSecsSinceEpoch()}, {KEY_TORRENT_COMPLETION_ON, torrent.completedTime().toSecsSinceEpoch()},
{KEY_TORRENT_TRACKER, torrent.currentTracker()}, {KEY_TORRENT_TRACKER, torrent.currentTracker()},
{KEY_TORRENT_TRACKERS_COUNT, torrent.trackers().size()},
{KEY_TORRENT_DL_LIMIT, torrent.downloadLimit()}, {KEY_TORRENT_DL_LIMIT, torrent.downloadLimit()},
{KEY_TORRENT_UP_LIMIT, torrent.uploadLimit()}, {KEY_TORRENT_UP_LIMIT, torrent.uploadLimit()},
{KEY_TORRENT_AMOUNT_DOWNLOADED, torrent.totalDownload()}, {KEY_TORRENT_AMOUNT_DOWNLOADED, torrent.totalDownload()},

1
src/webui/api/serialize/serialize_torrent.h

@ -61,6 +61,7 @@ const char KEY_TORRENT_SAVE_PATH[] = "save_path";
const char KEY_TORRENT_ADDED_ON[] = "added_on"; const char KEY_TORRENT_ADDED_ON[] = "added_on";
const char KEY_TORRENT_COMPLETION_ON[] = "completion_on"; const char KEY_TORRENT_COMPLETION_ON[] = "completion_on";
const char KEY_TORRENT_TRACKER[] = "tracker"; const char KEY_TORRENT_TRACKER[] = "tracker";
const char KEY_TORRENT_TRACKERS_COUNT[] = "trackers_count";
const char KEY_TORRENT_DL_LIMIT[] = "dl_limit"; const char KEY_TORRENT_DL_LIMIT[] = "dl_limit";
const char KEY_TORRENT_UP_LIMIT[] = "up_limit"; const char KEY_TORRENT_UP_LIMIT[] = "up_limit";
const char KEY_TORRENT_AMOUNT_DOWNLOADED[] = "downloaded"; const char KEY_TORRENT_AMOUNT_DOWNLOADED[] = "downloaded";

33
src/webui/api/synccontroller.cpp

@ -39,6 +39,7 @@
#include "base/bittorrent/peerinfo.h" #include "base/bittorrent/peerinfo.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
#include "base/bittorrent/trackerentry.h"
#include "base/global.h" #include "base/global.h"
#include "base/net/geoipmanager.h" #include "base/net/geoipmanager.h"
#include "base/preferences.h" #include "base/preferences.h"
@ -242,9 +243,27 @@ namespace
processMap(prevData[i.key()].toMap(), i.value().toMap(), map); processMap(prevData[i.key()].toMap(), i.value().toMap(), map);
// existing list item found - remove it from prevData // existing list item found - remove it from prevData
prevData.remove(i.key()); prevData.remove(i.key());
if (!map.isEmpty()) if (!map.isEmpty()) {
// changed list item found - append its changes to syncData // changed list item found - append its changes to syncData
syncData[i.key()] = map; syncData[i.key()] = map;
}
}
break;
case QVariant::StringList:
if (!prevData.contains(i.key())) {
// new list item found - append it to syncData
syncData[i.key()] = i.value();
}
else {
QVariantList list;
QVariantList removedList;
processList(prevData[i.key()].toList(), i.value().toList(), list, removedList);
// existing list item found - remove it from prevData
prevData.remove(i.key());
if (!list.isEmpty() || !removedList.isEmpty()) {
// changed list item found - append entire list to syncData
syncData[i.key()] = i.value();
}
} }
break; break;
default: default:
@ -354,6 +373,8 @@ SyncController::~SyncController()
// - "torrents_removed": a list of hashes of removed torrents // - "torrents_removed": a list of hashes of removed torrents
// - "categories": map of categories info // - "categories": map of categories info
// - "categories_removed": list of removed categories // - "categories_removed": list of removed categories
// - "trackers": dictionary contains information about trackers
// - "trackers_removed": a list of removed trackers
// - "server_state": map contains information about the state of the server // - "server_state": map contains information about the state of the server
// The keys of the 'torrents' dictionary are hashes of torrents. // The keys of the 'torrents' dictionary are hashes of torrents.
// Each value of the 'torrents' dictionary contains map. The map can contain following keys: // Each value of the 'torrents' dictionary contains map. The map can contain following keys:
@ -414,6 +435,7 @@ void SyncController::maindataAction()
QVariantMap lastAcceptedResponse = sessionManager()->session()->getData(QLatin1String("syncMainDataLastAcceptedResponse")).toMap(); QVariantMap lastAcceptedResponse = sessionManager()->session()->getData(QLatin1String("syncMainDataLastAcceptedResponse")).toMap();
QVariantHash torrents; QVariantHash torrents;
QHash<QString, QStringList> trackers;
for (const BitTorrent::TorrentHandle *torrent : asConst(session->torrents())) { for (const BitTorrent::TorrentHandle *torrent : asConst(session->torrents())) {
const BitTorrent::InfoHash torrentHash = torrent->hash(); const BitTorrent::InfoHash torrentHash = torrent->hash();
@ -439,6 +461,9 @@ void SyncController::maindataAction()
} }
} }
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers()))
trackers[tracker.url()] << torrentHash;
torrents[torrentHash] = map; torrents[torrentHash] = map;
} }
data["torrents"] = torrents; data["torrents"] = torrents;
@ -459,6 +484,12 @@ void SyncController::maindataAction()
tags << tag; tags << tag;
data["tags"] = tags; data["tags"] = tags;
QVariantHash trackersHash;
for (auto i = trackers.constBegin(); i != trackers.constEnd(); ++i) {
trackersHash[i.key()] = i.value();
}
data["trackers"] = trackersHash;
QVariantMap serverState = getTransferInfo(); QVariantMap serverState = getTransferInfo();
serverState[KEY_TRANSFER_FREESPACEONDISK] = getFreeDiskSpace(); serverState[KEY_TRANSFER_FREESPACEONDISK] = getFreeDiskSpace();
serverState[KEY_SYNC_MAINDATA_QUEUEING] = session->isQueueingSystemEnabled(); serverState[KEY_SYNC_MAINDATA_QUEUEING] = session->isQueueingSystemEnabled();

5
src/webui/www/private/index.html

@ -186,6 +186,11 @@
<li><a href="#pauseTorrentsByTag"><img src="images/qbt-theme/media-playback-pause.svg" alt="QBT_TR(Pause torrents)QBT_TR[CONTEXT=TagFilterWidget]"/> QBT_TR(Pause torrents)QBT_TR[CONTEXT=TagFilterWidget]</a></li> <li><a href="#pauseTorrentsByTag"><img src="images/qbt-theme/media-playback-pause.svg" alt="QBT_TR(Pause torrents)QBT_TR[CONTEXT=TagFilterWidget]"/> QBT_TR(Pause torrents)QBT_TR[CONTEXT=TagFilterWidget]</a></li>
<li><a href="#deleteTorrentsByTag"><img src="images/qbt-theme/edit-delete.svg" alt="QBT_TR(Delete torrents)QBT_TR[CONTEXT=TagFilterWidget]"/> QBT_TR(Delete torrents)QBT_TR[CONTEXT=TagFilterWidget]</a></li> <li><a href="#deleteTorrentsByTag"><img src="images/qbt-theme/edit-delete.svg" alt="QBT_TR(Delete torrents)QBT_TR[CONTEXT=TagFilterWidget]"/> QBT_TR(Delete torrents)QBT_TR[CONTEXT=TagFilterWidget]</a></li>
</ul> </ul>
<ul id="trackersFilterMenu" class="contextMenu">
<li><a href="#resumeTorrentsByTracker"><img src="images/qbt-theme/media-playback-start.svg" alt="QBT_TR(Resume torrents)QBT_TR[CONTEXT=TrackerFiltersList]"/> QBT_TR(Resume torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
<li><a href="#pauseTorrentsByTracker"><img src="images/qbt-theme/media-playback-pause.svg" alt="QBT_TR(Pause torrents)QBT_TR[CONTEXT=TrackerFiltersList]"/> QBT_TR(Pause torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
<li><a href="#deleteTorrentsByTracker"><img src="images/qbt-theme/edit-delete.svg" alt="QBT_TR(Delete torrents)QBT_TR[CONTEXT=TrackerFiltersList]"/> QBT_TR(Delete torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
</ul>
<ul id="torrentTrackersMenu" class="contextMenu"> <ul id="torrentTrackersMenu" class="contextMenu">
<li><a href="#AddTracker"><img src="images/qbt-theme/list-add.svg" alt="QBT_TR(Add a new tracker...)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Add a new tracker...)QBT_TR[CONTEXT=TrackerListWidget]</a></li> <li><a href="#AddTracker"><img src="images/qbt-theme/list-add.svg" alt="QBT_TR(Add a new tracker...)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Add a new tracker...)QBT_TR[CONTEXT=TrackerListWidget]</a></li>
<li class="separator"><a href="#EditTracker"><img src="images/qbt-theme/document-edit.svg" alt="QBT_TR(Edit tracker URL...)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Edit tracker URL...)QBT_TR[CONTEXT=TrackerListWidget]</a></li> <li class="separator"><a href="#EditTracker"><img src="images/qbt-theme/document-edit.svg" alt="QBT_TR(Edit tracker URL...)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Edit tracker URL...)QBT_TR[CONTEXT=TrackerListWidget]</a></li>

100
src/webui/www/private/scripts/client.js

@ -39,6 +39,7 @@ let syncRequestInProgress = false;
let clipboardEvent; let clipboardEvent;
/* Categories filter */
const CATEGORIES_ALL = 1; const CATEGORIES_ALL = 1;
const CATEGORIES_UNCATEGORIZED = 2; const CATEGORIES_UNCATEGORIZED = 2;
@ -47,6 +48,7 @@ let category_list = {};
let selected_category = CATEGORIES_ALL; let selected_category = CATEGORIES_ALL;
let setCategoryFilter = function() {}; let setCategoryFilter = function() {};
/* Tags filter */
const TAGS_ALL = 1; const TAGS_ALL = 1;
const TAGS_UNTAGGED = 2; const TAGS_UNTAGGED = 2;
@ -55,6 +57,16 @@ let tagList = {};
let selectedTag = TAGS_ALL; let selectedTag = TAGS_ALL;
let setTagFilter = function() {}; let setTagFilter = function() {};
/* Trackers filter */
const TRACKERS_ALL = 1;
const TRACKERS_TRACKERLESS = 2;
const trackerList = new Map();
let selectedTracker = TRACKERS_ALL;
let setTrackerFilter = function() {};
/* All filters */
let selected_filter = LocalPreferences.get('selected_filter', 'all'); let selected_filter = LocalPreferences.get('selected_filter', 'all');
let setFilter = function() {}; let setFilter = function() {};
let toggleFilterDisplay = function() {}; let toggleFilterDisplay = function() {};
@ -69,6 +81,11 @@ const loadSelectedTag = function() {
}; };
loadSelectedTag(); loadSelectedTag();
const loadSelectedTracker = function() {
selectedTracker = LocalPreferences.get('selected_tracker', TRACKERS_ALL);
};
loadSelectedTracker();
function genHash(string) { function genHash(string) {
let hash = 0; let hash = 0;
for (let i = 0; i < string.length; ++i) { for (let i = 0; i < string.length; ++i) {
@ -174,6 +191,14 @@ window.addEvent('load', function() {
updateMainData(); updateMainData();
}; };
setTrackerFilter = function(hash) {
selectedTracker = hash.toString();
LocalPreferences.set('selected_tracker', selectedTracker);
highlightSelectedTracker();
if (torrentsTable.tableBody !== undefined)
updateMainData();
};
setFilter = function(f) { setFilter = function(f) {
// Visually Select the right filter // Visually Select the right filter
$("all_filter").removeClass("selectedFilter"); $("all_filter").removeClass("selectedFilter");
@ -335,7 +360,7 @@ window.addEvent('load', function() {
}; };
const updateFilter = function(filter, filterTitle) { const updateFilter = function(filter, filterTitle) {
$(filter + '_filter').firstChild.childNodes[1].nodeValue = filterTitle.replace('%1', torrentsTable.getFilteredTorrentsNumber(filter, CATEGORIES_ALL, TAGS_ALL)); $(filter + '_filter').firstChild.childNodes[1].nodeValue = filterTitle.replace('%1', torrentsTable.getFilteredTorrentsNumber(filter, CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL));
}; };
const updateFiltersList = function() { const updateFiltersList = function() {
@ -462,6 +487,51 @@ window.addEvent('load', function() {
children[i].className = (children[i].id === selectedTag) ? "selectedFilter" : ""; children[i].className = (children[i].id === selectedTag) ? "selectedFilter" : "";
}; };
const updateTrackerList = function() {
const trackerFilterList = $('trackerFilterList');
if (trackerFilterList === null)
return;
while (trackerFilterList.firstChild !== null)
trackerFilterList.removeChild(trackerFilterList.firstChild);
const createLink = function(hash, text, count) {
const html = '<a href="#" onclick="setTrackerFilter(' + hash + ');return false;">'
+ '<img src="images/qbt-theme/network-server.svg"/>'
+ window.qBittorrent.Misc.escapeHtml(text.replace("%1", count)) + '</a>';
const el = new Element('li', {
id: hash,
html: html
});
window.qBittorrent.Filters.trackersFilterContextMenu.addTarget(el);
return el;
};
const torrentsCount = torrentsTable.getRowIds().length;
trackerFilterList.appendChild(createLink(TRACKERS_ALL, 'QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]', torrentsCount));
let trackerlessTorrentsCount = 0;
for (const key in torrentsTable.rows) {
if (torrentsTable.rows.hasOwnProperty(key) && (torrentsTable.rows[key]['full_data'].trackers_count === 0))
trackerlessTorrentsCount += 1;
}
trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, 'QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]', trackerlessTorrentsCount));
for (const [hash, tracker] of trackerList)
trackerFilterList.appendChild(createLink(hash, tracker.url + ' (%1)', tracker.torrents.length));
highlightSelectedTracker();
};
const highlightSelectedTracker = function() {
const trackerFilterList = $('trackerFilterList');
if (!trackerFilterList)
return;
const children = trackerFilterList.childNodes;
for (const child of children)
child.className = (child.id === selectedTracker) ? "selectedFilter" : "";
};
let syncMainDataTimer; let syncMainDataTimer;
const syncMainData = function() { const syncMainData = function() {
const url = new URI('api/v2/sync/maindata'); const url = new URI('api/v2/sync/maindata');
@ -484,6 +554,7 @@ window.addEvent('load', function() {
let torrentsTableSelectedRows; let torrentsTableSelectedRows;
let update_categories = false; let update_categories = false;
let updateTags = false; let updateTags = false;
let updateTrackers = false;
const full_update = (response['full_update'] === true); const full_update = (response['full_update'] === true);
if (full_update) { if (full_update) {
torrentsTableSelectedRows = torrentsTable.selectedRowsIds(); torrentsTableSelectedRows = torrentsTable.selectedRowsIds();
@ -538,6 +609,25 @@ window.addEvent('load', function() {
} }
updateTags = true; updateTags = true;
} }
if (response['trackers']) {
for (const tracker in response['trackers']) {
const torrents = response['trackers'][tracker];
const hash = genHash(tracker);
trackerList.set(hash, {
url: tracker,
torrents: torrents
});
}
updateTrackers = true;
}
if (response['trackers_removed']) {
for (let i = 0; i < response['trackers_removed'].length; ++i) {
const tracker = response['trackers_removed'][i];
const hash = genHash(tracker);
trackerList.delete(hash);
}
updateTrackers = true;
}
if (response['torrents']) { if (response['torrents']) {
let updateTorrentList = false; let updateTorrentList = false;
for (const key in response['torrents']) { for (const key in response['torrents']) {
@ -582,6 +672,8 @@ window.addEvent('load', function() {
updateTagList(); updateTagList();
window.qBittorrent.TransferList.contextMenu.updateTagsSubMenu(tagList); window.qBittorrent.TransferList.contextMenu.updateTagsSubMenu(tagList);
} }
if (updateTrackers)
updateTrackerList();
if (full_update) if (full_update)
// re-select previously selected rows // re-select previously selected rows
@ -656,10 +748,10 @@ window.addEvent('load', function() {
break; break;
default: { default: {
$('connectionStatus').src = 'images/skin/disconnected.svg'; $('connectionStatus').src = 'images/skin/disconnected.svg';
$('connectionStatus').alt = 'QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]'; $('connectionStatus').alt = 'QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]';
} }
break; break;
} }
if (queueing_enabled != serverState.queueing) { if (queueing_enabled != serverState.queueing) {
queueing_enabled = serverState.queueing; queueing_enabled = serverState.queueing;
@ -695,7 +787,7 @@ window.addEvent('load', function() {
if (enabled) { if (enabled) {
$('alternativeSpeedLimits').src = 'images/slow.svg'; $('alternativeSpeedLimits').src = 'images/slow.svg';
$('alternativeSpeedLimits').alt = 'QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]'; $('alternativeSpeedLimits').alt = 'QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]';
} }
else { else {
$('alternativeSpeedLimits').src = 'images/slow_off.svg'; $('alternativeSpeedLimits').src = 'images/slow_off.svg';
$('alternativeSpeedLimits').alt = 'QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]'; $('alternativeSpeedLimits').alt = 'QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]';

27
src/webui/www/private/scripts/dynamicTable.js

@ -1198,7 +1198,7 @@ window.qBittorrent.DynamicTable = (function() {
}; };
}, },
applyFilter: function(row, filterName, categoryHash, tagHash, filterTerms) { applyFilter: function(row, filterName, categoryHash, tagHash, trackerHash, filterTerms) {
const state = row['full_data'].state; const state = row['full_data'].state;
const name = row['full_data'].name.toLowerCase(); const name = row['full_data'].name.toLowerCase();
let inactive = false; let inactive = false;
@ -1291,6 +1291,21 @@ window.qBittorrent.DynamicTable = (function() {
} }
} }
const trackerHashInt = Number.parseInt(trackerHash, 10);
switch (trackerHashInt) {
case TRACKERS_ALL:
break; // do nothing
case TRACKERS_TRACKERLESS:
if (row['full_data'].trackers_count !== 0)
return false;
break;
default:
const tracker = trackerList.get(trackerHashInt)
if (tracker && !tracker.torrents.includes(row['full_data'].rowId))
return false
break;
}
if ((filterTerms !== undefined) && (filterTerms !== null) if ((filterTerms !== undefined) && (filterTerms !== null)
&& (filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(name, filterTerms)) && (filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(name, filterTerms))
return false; return false;
@ -1298,21 +1313,21 @@ window.qBittorrent.DynamicTable = (function() {
return true; return true;
}, },
getFilteredTorrentsNumber: function(filterName, categoryHash, tagHash) { getFilteredTorrentsNumber: function(filterName, categoryHash, tagHash, trackerHash) {
let cnt = 0; let cnt = 0;
const rows = this.rows.getValues(); const rows = this.rows.getValues();
for (let i = 0; i < rows.length; ++i) for (let i = 0; i < rows.length; ++i)
if (this.applyFilter(rows[i], filterName, categoryHash, tagHash, null)) ++cnt; if (this.applyFilter(rows[i], filterName, categoryHash, tagHash, trackerHash, null)) ++cnt;
return cnt; return cnt;
}, },
getFilteredTorrentsHashes: function(filterName, categoryHash, tagHash) { getFilteredTorrentsHashes: function(filterName, categoryHash, tagHash, trackerHash) {
const rowsHashes = []; const rowsHashes = [];
const rows = this.rows.getValues(); const rows = this.rows.getValues();
for (let i = 0; i < rows.length; ++i) for (let i = 0; i < rows.length; ++i)
if (this.applyFilter(rows[i], filterName, categoryHash, tagHash, null)) if (this.applyFilter(rows[i], filterName, categoryHash, tagHash, trackerHash, null))
rowsHashes.push(rows[i]['rowId']); rowsHashes.push(rows[i]['rowId']);
return rowsHashes; return rowsHashes;
@ -1326,7 +1341,7 @@ window.qBittorrent.DynamicTable = (function() {
const filterTerms = (filterText.length > 0) ? filterText.split(" ") : null; const filterTerms = (filterText.length > 0) ? filterText.split(" ") : null;
for (let i = 0; i < rows.length; ++i) { for (let i = 0; i < rows.length; ++i) {
if (this.applyFilter(rows[i], selected_filter, selected_category, selectedTag, filterTerms)) { if (this.applyFilter(rows[i], selected_filter, selected_category, selectedTag, selectedTracker, filterTerms)) {
filteredRows.push(rows[i]); filteredRows.push(rows[i]);
filteredRows[rows[i].rowId] = rows[i]; filteredRows[rows[i].rowId] = rows[i];
} }

108
src/webui/www/private/scripts/mocha-init.js

@ -80,6 +80,9 @@ let deleteUnusedTagsFN = function() {};
let startTorrentsByTagFN = function() {}; let startTorrentsByTagFN = function() {};
let pauseTorrentsByTagFN = function() {}; let pauseTorrentsByTagFN = function() {};
let deleteTorrentsByTagFN = function() {}; let deleteTorrentsByTagFN = function() {};
let resumeTorrentsByTrackerFN = function() {};
let pauseTorrentsByTrackerFN = function() {};
let deleteTorrentsByTrackerFN = function() {};
let copyNameFN = function() {}; let copyNameFN = function() {};
let copyMagnetLinkFN = function() {}; let copyMagnetLinkFN = function() {};
let copyHashFN = function() {}; let copyHashFN = function() {};
@ -609,7 +612,7 @@ const initializeWindows = function() {
deleteUnusedCategoriesFN = function() { deleteUnusedCategoriesFN = function() {
const categories = []; const categories = [];
for (const hash in category_list) { for (const hash in category_list) {
if (torrentsTable.getFilteredTorrentsNumber('all', hash, TAGS_ALL) === 0) if (torrentsTable.getFilteredTorrentsNumber('all', hash, TAGS_ALL, TRACKERS_ALL) === 0)
categories.push(category_list[hash].name); categories.push(category_list[hash].name);
} }
new Request({ new Request({
@ -623,7 +626,7 @@ const initializeWindows = function() {
}; };
startTorrentsByCategoryFN = function(categoryHash) { startTorrentsByCategoryFN = function(categoryHash) {
const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL); const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL, TRACKERS_ALL);
if (hashes.length) { if (hashes.length) {
new Request({ new Request({
url: 'api/v2/torrents/resume', url: 'api/v2/torrents/resume',
@ -637,7 +640,7 @@ const initializeWindows = function() {
}; };
pauseTorrentsByCategoryFN = function(categoryHash) { pauseTorrentsByCategoryFN = function(categoryHash) {
const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL); const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL, TRACKERS_ALL);
if (hashes.length) { if (hashes.length) {
new Request({ new Request({
url: 'api/v2/torrents/pause', url: 'api/v2/torrents/pause',
@ -651,7 +654,7 @@ const initializeWindows = function() {
}; };
deleteTorrentsByCategoryFN = function(categoryHash) { deleteTorrentsByCategoryFN = function(categoryHash) {
const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL); const hashes = torrentsTable.getFilteredTorrentsHashes('all', categoryHash, TAGS_ALL, TRACKERS_ALL);
if (hashes.length) { if (hashes.length) {
new MochaUI.Window({ new MochaUI.Window({
id: 'confirmDeletionPage', id: 'confirmDeletionPage',
@ -750,7 +753,7 @@ const initializeWindows = function() {
deleteUnusedTagsFN = function() { deleteUnusedTagsFN = function() {
const tags = []; const tags = [];
for (const hash in tagList) { for (const hash in tagList) {
if (torrentsTable.getFilteredTorrentsNumber('all', CATEGORIES_ALL, hash) === 0) if (torrentsTable.getFilteredTorrentsNumber('all', CATEGORIES_ALL, hash, TRACKERS_ALL) === 0)
tags.push(tagList[hash].name); tags.push(tagList[hash].name);
} }
new Request({ new Request({
@ -764,7 +767,7 @@ const initializeWindows = function() {
}; };
startTorrentsByTagFN = function(tagHash) { startTorrentsByTagFN = function(tagHash) {
const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash); const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash, TRACKERS_ALL);
if (hashes.length) { if (hashes.length) {
new Request({ new Request({
url: 'api/v2/torrents/resume', url: 'api/v2/torrents/resume',
@ -778,7 +781,7 @@ const initializeWindows = function() {
}; };
pauseTorrentsByTagFN = function(tagHash) { pauseTorrentsByTagFN = function(tagHash) {
const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash); const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash, TRACKERS_ALL);
if (hashes.length) { if (hashes.length) {
new Request({ new Request({
url: 'api/v2/torrents/pause', url: 'api/v2/torrents/pause',
@ -792,7 +795,7 @@ const initializeWindows = function() {
}; };
deleteTorrentsByTagFN = function(tagHash) { deleteTorrentsByTagFN = function(tagHash) {
const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash); const hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, tagHash, TRACKERS_ALL);
if (hashes.length) { if (hashes.length) {
new MochaUI.Window({ new MochaUI.Window({
id: 'confirmDeletionPage', id: 'confirmDeletionPage',
@ -810,6 +813,95 @@ const initializeWindows = function() {
} }
}; };
resumeTorrentsByTrackerFN = function(trackerHash) {
const trackerHashInt = Number.parseInt(trackerHash, 10);
let hashes = [];
switch (trackerHashInt) {
case TRACKERS_ALL:
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
break;
case TRACKERS_TRACKERLESS:
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
break;
default:
hashes = trackerList.get(trackerHashInt).torrents
break;
}
if (hashes.length > 0) {
new Request({
url: 'api/v2/torrents/resume',
method: 'post',
data: {
hashes: hashes.join("|")
}
}).send();
updateMainData();
}
};
pauseTorrentsByTrackerFN = function(trackerHash) {
const trackerHashInt = Number.parseInt(trackerHash, 10);
let hashes = [];
switch (trackerHashInt) {
case TRACKERS_ALL:
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
break;
case TRACKERS_TRACKERLESS:
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
break;
default:
hashes = trackerList.get(trackerHashInt).torrents
break;
}
if (hashes.length) {
new Request({
url: 'api/v2/torrents/pause',
method: 'post',
data: {
hashes: hashes.join("|")
}
}).send();
updateMainData();
}
};
deleteTorrentsByTrackerFN = function(trackerHash) {
const trackerHashInt = Number.parseInt(trackerHash, 10);
let hashes = [];
switch (trackerHashInt) {
case TRACKERS_ALL:
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
break;
case TRACKERS_TRACKERLESS:
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
break;
default:
hashes = trackerList.get(trackerHashInt).torrents
break;
}
if (hashes.length) {
new MochaUI.Window({
id: 'confirmDeletionPage',
title: "QBT_TR(Deletion confirmation)QBT_TR[CONTEXT=confirmDeletionDlg]",
loadMethod: 'iframe',
contentURL: 'confirmdeletion.html?hashes=' + hashes.join("|"),
scrollbars: false,
resizable: false,
maximizable: false,
padding: 10,
width: 424,
height: 140,
onCloseComplete: function() {
updateMainData();
setTrackerFilter(TRACKERS_ALL);
}
});
}
};
copyNameFN = function() { copyNameFN = function() {
const selectedRows = torrentsTable.selectedRowsIds(); const selectedRows = torrentsTable.selectedRowsIds();
const names = []; const names = [];

36
src/webui/www/private/views/filters.html

@ -31,6 +31,13 @@
<ul class="filterList" id="tagFilterList"> <ul class="filterList" id="tagFilterList">
</ul> </ul>
</div> </div>
<div class="filterWrapper">
<span class="filterTitle" onclick="toggleFilterDisplay('tracker');">
<img src="images/qbt-theme/go-down.svg">QBT_TR(Trackers)QBT_TR[CONTEXT=TransferListFiltersWidget]
</span>
<ul class="filterList" id="trackerFilterList">
</ul>
</div>
<script> <script>
'use strict'; 'use strict';
@ -43,7 +50,8 @@
const exports = function() { const exports = function() {
return { return {
categoriesFilterContextMenu: categoriesFilterContextMenu, categoriesFilterContextMenu: categoriesFilterContextMenu,
tagsFilterContextMenu: tagsFilterContextMenu tagsFilterContextMenu: tagsFilterContextMenu,
trackersFilterContextMenu: trackersFilterContextMenu
}; };
}; };
@ -114,6 +122,29 @@
} }
}); });
const trackersFilterContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
targets: '.trackersFilterContextMenuTarget',
menu: 'trackersFilterMenu',
actions: {
resumeTorrentsByTracker: function(element, ref) {
resumeTorrentsByTrackerFN(element.id);
},
pauseTorrentsByTracker: function(element, ref) {
pauseTorrentsByTrackerFN(element.id);
},
deleteTorrentsByTracker: function(element, ref) {
deleteTorrentsByTrackerFN(element.id);
}
},
offsets: {
x: -15,
y: 2
},
onShow: function() {
this.options.element.firstChild.click();
}
});
if (LocalPreferences.get('filter_status_collapsed') === "true") if (LocalPreferences.get('filter_status_collapsed') === "true")
toggleFilterDisplay('status'); toggleFilterDisplay('status');
@ -123,6 +154,9 @@
if (LocalPreferences.get('filter_tag_collapsed') === "true") if (LocalPreferences.get('filter_tag_collapsed') === "true")
toggleFilterDisplay('tag'); toggleFilterDisplay('tag');
if (LocalPreferences.get('filter_tracker_collapsed') === "true")
toggleFilterDisplay('tracker');
return exports(); return exports();
})(); })();
</script> </script>

Loading…
Cancel
Save