diff --git a/WebAPI_Changelog.md b/WebAPI_Changelog.md index 23272bb5a..375e24d69 100644 --- a/WebAPI_Changelog.md +++ b/WebAPI_Changelog.md @@ -8,6 +8,10 @@ * Add `torrents/saveMetadata` endpoint for saving retrieved torrent metadata to a .torrent file * `torrents/add` allows adding a torrent with metadata previously retrieved via `torrents/fetchMetadata` or `torrents/parseMetadata` * `torrents/add` allows specifying a torrent's file priorities +* [#22698](https://github.com/qbittorrent/qBittorrent/pull/22698) + * `torrents/addTrackers` and `torrents/removeTrackers` now accept `hash=all` and adds/removes the tracker to/from *all* torrents + * For compatibility, `torrents/removeTrackers` still accepts `hash=*` internally we transform it into `all` + * Allow passing a pipe (`|`) separated list of hashes in `hash` for `torrents/addTrackers` and `torrents/removeTrackers` ## 2.11.8 diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index f7c6118a0..fc2d6d4cb 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -1116,16 +1116,10 @@ void TorrentsController::addAction() void TorrentsController::addTrackersAction() { requireParams({u"hash"_s, u"urls"_s}); + const QList trackers = BitTorrent::parseTrackerEntries(params()[u"urls"_s]); + const QStringList idStrings = params()[u"hash"_s].split(u'|'); - const auto id = BitTorrent::TorrentID::fromString(params()[u"hash"_s]); - BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->getTorrent(id); - if (!torrent) - throw APIError(APIErrorType::NotFound); - - const QList entries = BitTorrent::parseTrackerEntries(params()[u"urls"_s]); - torrent->addTrackers(entries); - - setResult(QString()); + applyToTorrents(idStrings, [&trackers](BitTorrent::Torrent *const torrent) { torrent->addTrackers(trackers); }); } void TorrentsController::editTrackerAction() @@ -1187,7 +1181,10 @@ void TorrentsController::removeTrackersAction() { requireParams({u"hash"_s, u"urls"_s}); - const QString hashParam = params()[u"hash"_s]; + QString hash = params()[u"hash"_s]; + if (hash == u"*"_s) + hash = u"all"_s; + const QStringList idStrings = hash.split(u'|', Qt::SkipEmptyParts); const QStringList urlsParam = params()[u"urls"_s].split(u'|', Qt::SkipEmptyParts); QStringList urls; @@ -1195,28 +1192,7 @@ void TorrentsController::removeTrackersAction() for (const QString &urlStr : urlsParam) urls << QUrl::fromPercentEncoding(urlStr.toLatin1()); - QList 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); - - setResult(QString()); + applyToTorrents(idStrings, [&urls](BitTorrent::Torrent *const torrent) { torrent->removeTrackers(urls); }); } void TorrentsController::addPeersAction() diff --git a/src/webui/www/private/scripts/prop-trackers.js b/src/webui/www/private/scripts/prop-trackers.js index 7214895b4..945688aef 100644 --- a/src/webui/www/private/scripts/prop-trackers.js +++ b/src/webui/www/private/scripts/prop-trackers.js @@ -180,6 +180,11 @@ window.qBittorrent.PropTrackers ??= (() => { const addTrackerFN = () => { if (current_hash.length === 0) return; + + const selectedTorrents = torrentsTable.selectedRowsIds(); + if (selectedTorrents.length !== 0) + current_hash = selectedTorrents.map(encodeURIComponent).join("|"); + new MochaUI.Window({ id: "trackersPage", icon: "images/qbittorrent-tray.svg", @@ -229,6 +234,10 @@ window.qBittorrent.PropTrackers ??= (() => { if (current_hash.length === 0) return; + const selectedTorrents = torrentsTable.selectedRowsIds(); + if (selectedTorrents.length !== 0) + current_hash = selectedTorrents.map(encodeURIComponent).join("|"); + fetch("api/v2/torrents/removeTrackers", { method: "POST", body: new URLSearchParams({