mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-15 01:33:07 -07:00
Support removing tracker from all torrents in WebUI/WebAPI
Closes #20661. PR #21056.
This commit is contained in:
parent
d19f7b12d9
commit
d2b2afad23
8 changed files with 132 additions and 8 deletions
|
@ -969,13 +969,34 @@ void TorrentsController::removeTrackersAction()
|
||||||
{
|
{
|
||||||
requireParams({u"hash"_s, u"urls"_s});
|
requireParams({u"hash"_s, u"urls"_s});
|
||||||
|
|
||||||
const auto id = BitTorrent::TorrentID::fromString(params()[u"hash"_s]);
|
const QString hashParam = params()[u"hash"_s];
|
||||||
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->getTorrent(id);
|
const QStringList urlsParam = params()[u"urls"_s].split(u'|', Qt::SkipEmptyParts);
|
||||||
if (!torrent)
|
|
||||||
throw APIError(APIErrorType::NotFound);
|
|
||||||
|
|
||||||
const QStringList urls = params()[u"urls"_s].split(u'|');
|
QStringList urls;
|
||||||
torrent->removeTrackers(urls);
|
urls.reserve(urlsParam.size());
|
||||||
|
for (const QString &urlStr : urlsParam)
|
||||||
|
urls << QUrl::fromPercentEncoding(urlStr.toLatin1());
|
||||||
|
|
||||||
|
QList<BitTorrent::Torrent *> torrents;
|
||||||
|
|
||||||
|
if (hashParam == u"*"_s)
|
||||||
|
{
|
||||||
|
// remove trackers from all torrents
|
||||||
|
torrents = BitTorrent::Session::instance()->torrents();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// remove trackers from specified torrent
|
||||||
|
const auto id = BitTorrent::TorrentID::fromString(hashParam);
|
||||||
|
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->getTorrent(id);
|
||||||
|
if (!torrent)
|
||||||
|
throw APIError(APIErrorType::NotFound);
|
||||||
|
|
||||||
|
torrents.append(torrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BitTorrent::Torrent *const torrent : asConst(torrents))
|
||||||
|
torrent->removeTrackers(urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentsController::addPeersAction()
|
void TorrentsController::addPeersAction()
|
||||||
|
|
52
src/webui/www/private/confirmtrackerdeletion.html
Normal file
52
src/webui/www/private/confirmtrackerdeletion.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="${LANG}">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>QBT_TR(Remove tracker)QBT_TR[CONTEXT=confirmDeletionDlg]</title>
|
||||||
|
<link rel="stylesheet" href="css/style.css?v=${CACHEID}" type="text/css">
|
||||||
|
<script src="scripts/lib/MooTools-Core-1.6.0-compat-compressed.js"></script>
|
||||||
|
<script src="scripts/lib/MooTools-More-1.6.0-compat-compressed.js"></script>
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const host = new URI().getData("host");
|
||||||
|
const urls = new URI().getData("urls");
|
||||||
|
$("confirmDeleteTrackerText").textContent = "QBT_TR(Are you sure you want to remove tracker %1 from all torrents?)QBT_TR[CONTEXT=TrackersFilterWidget]".replace("%1", `"${host}"`);
|
||||||
|
|
||||||
|
$("cancelBtn").focus();
|
||||||
|
$("cancelBtn").addEvent("click", (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
window.parent.qBittorrent.Client.closeWindows();
|
||||||
|
});
|
||||||
|
$("confirmBtn").addEvent("click", (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const cmd = "api/v2/torrents/removeTrackers";
|
||||||
|
new Request({
|
||||||
|
url: cmd,
|
||||||
|
method: "post",
|
||||||
|
data: {
|
||||||
|
hash: "*",
|
||||||
|
urls: urls,
|
||||||
|
},
|
||||||
|
onComplete: function() {
|
||||||
|
window.parent.qBittorrent.Client.closeWindows();
|
||||||
|
}
|
||||||
|
}).send();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div style="padding: 10px 10px 0px 10px;">
|
||||||
|
<p id="confirmDeleteTrackerText"></p>
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<input type="button" id="cancelBtn" value="QBT_TR(Cancel)QBT_TR[CONTEXT=MainWindow]">
|
||||||
|
<input type="button" id="confirmBtn" value="QBT_TR(Remove)QBT_TR[CONTEXT=MainWindow]">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -228,7 +228,8 @@
|
||||||
<li><a href="#deleteTorrentsByTag"><img src="images/list-remove.svg" alt="QBT_TR(Remove torrents)QBT_TR[CONTEXT=TagFilterWidget]"> QBT_TR(Remove torrents)QBT_TR[CONTEXT=TagFilterWidget]</a></li>
|
<li><a href="#deleteTorrentsByTag"><img src="images/list-remove.svg" alt="QBT_TR(Remove torrents)QBT_TR[CONTEXT=TagFilterWidget]"> QBT_TR(Remove torrents)QBT_TR[CONTEXT=TagFilterWidget]</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul id="trackersFilterMenu" class="contextMenu">
|
<ul id="trackersFilterMenu" class="contextMenu">
|
||||||
<li><a href="#startTorrentsByTracker"><img src="images/torrent-start.svg" alt="QBT_TR(Start torrents)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Start torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
<li><a href="#deleteTracker"><img src="images/edit-clear.svg" alt="QBT_TR(Remove tracker)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Remove tracker)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
||||||
|
<li class="separator"><a href="#startTorrentsByTracker"><img src="images/torrent-start.svg" alt="QBT_TR(Start torrents)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Start torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
||||||
<li><a href="#stopTorrentsByTracker"><img src="images/torrent-stop.svg" alt="QBT_TR(Stop torrents)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Stop torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
<li><a href="#stopTorrentsByTracker"><img src="images/torrent-stop.svg" alt="QBT_TR(Stop torrents)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Stop torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
||||||
<li><a href="#deleteTorrentsByTracker"><img src="images/list-remove.svg" alt="QBT_TR(Remove torrents)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Remove torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
<li><a href="#deleteTorrentsByTracker"><img src="images/list-remove.svg" alt="QBT_TR(Remove torrents)QBT_TR[CONTEXT=TrackerFiltersList]"> QBT_TR(Remove torrents)QBT_TR[CONTEXT=TrackerFiltersList]</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -644,6 +644,12 @@ window.addEventListener("DOMContentLoaded", () => {
|
||||||
trackerFilterList.appendChild(createLink(TRACKERS_ALL, "QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]", torrentsCount));
|
trackerFilterList.appendChild(createLink(TRACKERS_ALL, "QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]", torrentsCount));
|
||||||
trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, "QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]", trackerlessTorrentsCount));
|
trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, "QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]", trackerlessTorrentsCount));
|
||||||
|
|
||||||
|
// Remove unused trackers
|
||||||
|
for (const [key, { trackerTorrentMap }] of trackerList) {
|
||||||
|
if (trackerTorrentMap.size === 0)
|
||||||
|
trackerList.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
// Sort trackers by hostname
|
// Sort trackers by hostname
|
||||||
const sortedList = [];
|
const sortedList = [];
|
||||||
trackerList.forEach(({ host, trackerTorrentMap }, hash) => {
|
trackerList.forEach(({ host, trackerTorrentMap }, hash) => {
|
||||||
|
|
|
@ -36,6 +36,7 @@ window.qBittorrent.ContextMenu ??= (() => {
|
||||||
TorrentsTableContextMenu: TorrentsTableContextMenu,
|
TorrentsTableContextMenu: TorrentsTableContextMenu,
|
||||||
CategoriesFilterContextMenu: CategoriesFilterContextMenu,
|
CategoriesFilterContextMenu: CategoriesFilterContextMenu,
|
||||||
TagsFilterContextMenu: TagsFilterContextMenu,
|
TagsFilterContextMenu: TagsFilterContextMenu,
|
||||||
|
TrackersFilterContextMenu: TrackersFilterContextMenu,
|
||||||
SearchPluginsTableContextMenu: SearchPluginsTableContextMenu,
|
SearchPluginsTableContextMenu: SearchPluginsTableContextMenu,
|
||||||
RssFeedContextMenu: RssFeedContextMenu,
|
RssFeedContextMenu: RssFeedContextMenu,
|
||||||
RssArticleContextMenu: RssArticleContextMenu,
|
RssArticleContextMenu: RssArticleContextMenu,
|
||||||
|
@ -604,6 +605,17 @@ window.qBittorrent.ContextMenu ??= (() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const TrackersFilterContextMenu = new Class({
|
||||||
|
Extends: ContextMenu,
|
||||||
|
updateMenuItems: function() {
|
||||||
|
const id = Number(this.options.element.id);
|
||||||
|
if ((id !== TRACKERS_ALL) && (id !== TRACKERS_TRACKERLESS))
|
||||||
|
this.showItem("deleteTracker");
|
||||||
|
else
|
||||||
|
this.hideItem("deleteTracker");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const SearchPluginsTableContextMenu = new Class({
|
const SearchPluginsTableContextMenu = new Class({
|
||||||
Extends: ContextMenu,
|
Extends: ContextMenu,
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ let deleteTorrentsByTagFN = function() {};
|
||||||
let startTorrentsByTrackerFN = function() {};
|
let startTorrentsByTrackerFN = function() {};
|
||||||
let stopTorrentsByTrackerFN = function() {};
|
let stopTorrentsByTrackerFN = function() {};
|
||||||
let deleteTorrentsByTrackerFN = function() {};
|
let deleteTorrentsByTrackerFN = function() {};
|
||||||
|
let deleteTrackerFN = function() {};
|
||||||
let copyNameFN = function() {};
|
let copyNameFN = function() {};
|
||||||
let copyInfohashFN = function(policy) {};
|
let copyInfohashFN = function(policy) {};
|
||||||
let copyMagnetLinkFN = function() {};
|
let copyMagnetLinkFN = function() {};
|
||||||
|
@ -1134,6 +1135,33 @@ const initializeWindows = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deleteTrackerFN = function(trackerHash) {
|
||||||
|
const trackerHashInt = Number.parseInt(trackerHash, 10);
|
||||||
|
if ((trackerHashInt === TRACKERS_ALL) || (trackerHashInt === TRACKERS_TRACKERLESS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const tracker = trackerList.get(trackerHashInt);
|
||||||
|
const host = tracker.host;
|
||||||
|
const urls = [...tracker.trackerTorrentMap.keys()];
|
||||||
|
|
||||||
|
new MochaUI.Window({
|
||||||
|
id: "confirmDeletionPage",
|
||||||
|
title: "QBT_TR(Remove tracker)QBT_TR[CONTEXT=confirmDeletionDlg]",
|
||||||
|
loadMethod: "iframe",
|
||||||
|
contentURL: new URI("confirmtrackerdeletion.html").setData("host", host).setData("urls", urls.map(encodeURIComponent).join("|")).toString(),
|
||||||
|
scrollbars: false,
|
||||||
|
resizable: true,
|
||||||
|
maximizable: false,
|
||||||
|
padding: 10,
|
||||||
|
width: 424,
|
||||||
|
height: 100,
|
||||||
|
onCloseComplete: function() {
|
||||||
|
updateMainData();
|
||||||
|
setTrackerFilter(TRACKERS_ALL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
copyNameFN = function() {
|
copyNameFN = function() {
|
||||||
const selectedRows = torrentsTable.selectedRowsIds();
|
const selectedRows = torrentsTable.selectedRowsIds();
|
||||||
const names = [];
|
const names = [];
|
||||||
|
|
|
@ -153,10 +153,13 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const trackersFilterContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
const trackersFilterContextMenu = new window.qBittorrent.ContextMenu.TrackersFilterContextMenu({
|
||||||
targets: ".trackersFilterContextMenuTarget",
|
targets: ".trackersFilterContextMenuTarget",
|
||||||
menu: "trackersFilterMenu",
|
menu: "trackersFilterMenu",
|
||||||
actions: {
|
actions: {
|
||||||
|
deleteTracker: function(element, ref) {
|
||||||
|
deleteTrackerFN(element.id);
|
||||||
|
},
|
||||||
startTorrentsByTracker: function(element, ref) {
|
startTorrentsByTracker: function(element, ref) {
|
||||||
startTorrentsByTrackerFN(element.id);
|
startTorrentsByTrackerFN(element.id);
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<file>private/confirmfeeddeletion.html</file>
|
<file>private/confirmfeeddeletion.html</file>
|
||||||
<file>private/confirmruleclear.html</file>
|
<file>private/confirmruleclear.html</file>
|
||||||
<file>private/confirmruledeletion.html</file>
|
<file>private/confirmruledeletion.html</file>
|
||||||
|
<file>private/confirmtrackerdeletion.html</file>
|
||||||
<file>private/css/Core.css</file>
|
<file>private/css/Core.css</file>
|
||||||
<file>private/css/dynamicTable.css</file>
|
<file>private/css/dynamicTable.css</file>
|
||||||
<file>private/css/Layout.css</file>
|
<file>private/css/Layout.css</file>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue