Skip to content

Commit 4967f97

Browse files
authored
WebUI: Improve accuracy of trackers list
This PR fixes various accounting issues with the trackers list. Removing a torrent would not update the trackers list, nor would removing a tracker from a torrent. And removing a tracker with a shared host but unique url (e.g. example.com/1 and example.com/2) would erroneously remove the tracker's host from the list. Closes #20053. Closes #20054. PR #20601.
1 parent eb9e98a commit 4967f97

File tree

3 files changed

+66
-38
lines changed

3 files changed

+66
-38
lines changed

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

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ let setTagFilter = function() {};
116116
const TRACKERS_ALL = 1;
117117
const TRACKERS_TRACKERLESS = 2;
118118

119+
/** @type Map<number, {host: string, trackerTorrentMap: Map<string, string[]>}> **/
119120
const trackerList = new Map();
120121

121122
let selectedTracker = LocalPreferences.get('selected_tracker', TRACKERS_ALL);
@@ -623,11 +624,20 @@ window.addEventListener("DOMContentLoaded", function() {
623624

624625
// Sort trackers by hostname
625626
const sortedList = [];
626-
trackerList.forEach((tracker, hash) => sortedList.push({
627-
trackerHost: getHost(tracker.url),
628-
trackerHash: hash,
629-
trackerCount: tracker.torrents.length
630-
}));
627+
trackerList.forEach(({ host, trackerTorrentMap }, hash) => {
628+
const uniqueTorrents = new Set();
629+
for (const torrents of trackerTorrentMap.values()) {
630+
for (const torrent of torrents) {
631+
uniqueTorrents.add(torrent);
632+
}
633+
}
634+
635+
sortedList.push({
636+
trackerHost: host,
637+
trackerHash: hash,
638+
trackerCount: uniqueTorrents.size,
639+
});
640+
});
631641
sortedList.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare(left.trackerHost, right.trackerHost));
632642
for (const { trackerHost, trackerHash, trackerCount } of sortedList)
633643
trackerFilterList.appendChild(createLink(trackerHash, (trackerHost + ' (%1)'), trackerCount));
@@ -760,40 +770,28 @@ window.addEventListener("DOMContentLoaded", function() {
760770
updateTags = true;
761771
}
762772
if (response['trackers']) {
763-
for (const tracker in response['trackers']) {
764-
const torrents = response['trackers'][tracker];
765-
const hash = window.qBittorrent.Client.genHash(getHost(tracker));
766-
767-
// the reason why we need the merge here is because the WebUI api returned trackers may have different url for the same tracker host.
768-
// for example, some private trackers use diff urls for each torrent from the same tracker host.
769-
// then we got the response of `trackers` from qBittorrent api will like:
770-
// {
771-
// "trackers": {
772-
// "https://example.com/announce?passkey=identify_info1": ["hash1"],
773-
// "https://example.com/announce?passkey=identify_info2": ["hash2"],
774-
// "https://example.com/announce?passkey=identify_info3": ["hash3"]
775-
// }
776-
// }
777-
// after getHost(), those torrents all belongs to `example.com`
778-
let merged_torrents = torrents;
779-
if (trackerList.has(hash)) {
780-
merged_torrents = trackerList.get(hash).torrents.concat(torrents);
781-
// deduplicate is needed when the webui opens in multi tabs
782-
merged_torrents = merged_torrents.filter((item, pos) => merged_torrents.indexOf(item) === pos);
773+
for (const [tracker, torrents] of Object.entries(response['trackers'])) {
774+
const host = getHost(tracker);
775+
const hash = window.qBittorrent.Client.genHash(host);
776+
777+
let trackerListItem = trackerList.get(hash);
778+
if (trackerListItem === undefined) {
779+
trackerListItem = { host: host, trackerTorrentMap: new Map() };
780+
trackerList.set(hash, trackerListItem);
783781
}
784782

785-
trackerList.set(hash, {
786-
url: tracker,
787-
torrents: merged_torrents
788-
});
783+
trackerListItem.trackerTorrentMap.set(tracker, [...torrents]);
789784
}
790785
updateTrackers = true;
791786
}
792787
if (response['trackers_removed']) {
793788
for (let i = 0; i < response['trackers_removed'].length; ++i) {
794789
const tracker = response['trackers_removed'][i];
795790
const hash = window.qBittorrent.Client.genHash(getHost(tracker));
796-
trackerList.delete(hash);
791+
const trackerListEntry = trackerList.get(hash);
792+
if (trackerListEntry) {
793+
trackerListEntry.trackerTorrentMap.delete(tracker);
794+
}
797795
}
798796
updateTrackers = true;
799797
}

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,8 +1435,17 @@ window.qBittorrent.DynamicTable = (function() {
14351435
break;
14361436
default: {
14371437
const tracker = trackerList.get(trackerHashInt);
1438-
if (tracker && !tracker.torrents.includes(row['full_data'].rowId))
1439-
return false;
1438+
if (tracker) {
1439+
let found = false;
1440+
for (const torrents of tracker.trackerTorrentMap.values()) {
1441+
if (torrents.includes(row['full_data'].rowId)) {
1442+
found = true;
1443+
break;
1444+
}
1445+
}
1446+
if (!found)
1447+
return false;
1448+
}
14401449
break;
14411450
}
14421451
}

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -874,9 +874,16 @@ const initializeWindows = function() {
874874
case TRACKERS_TRACKERLESS:
875875
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
876876
break;
877-
default:
878-
hashes = trackerList.get(trackerHashInt).torrents;
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);
882+
}
883+
}
884+
hashes = [...uniqueTorrents];
879885
break;
886+
}
880887
}
881888

882889
if (hashes.length > 0) {
@@ -901,9 +908,16 @@ const initializeWindows = function() {
901908
case TRACKERS_TRACKERLESS:
902909
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
903910
break;
904-
default:
905-
hashes = trackerList.get(trackerHashInt).torrents;
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);
916+
}
917+
}
918+
hashes = [...uniqueTorrents];
906919
break;
920+
}
907921
}
908922

909923
if (hashes.length) {
@@ -928,9 +942,16 @@ const initializeWindows = function() {
928942
case TRACKERS_TRACKERLESS:
929943
hashes = torrentsTable.getFilteredTorrentsHashes('all', CATEGORIES_ALL, TAGS_ALL, TRACKERS_TRACKERLESS);
930944
break;
931-
default:
932-
hashes = trackerList.get(trackerHashInt).torrents;
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);
950+
}
951+
}
952+
hashes = [...uniqueTorrents];
933953
break;
954+
}
934955
}
935956

936957
if (hashes.length) {

0 commit comments

Comments
 (0)