Skip to content

Commit

Permalink
WebAPI: optionally include trackers list in torrent info response
Browse files Browse the repository at this point in the history
This PR adds an optional parameter includeTrackers to the Torrent info endpoint /torrents/info to include the trackers list of each torrent in the response under the key trackers.

PR #22128.
  • Loading branch information
zze0s authored Jan 17, 2025
1 parent 4686d67 commit 76e1040
Showing 1 changed file with 42 additions and 21 deletions.
63 changes: 42 additions & 21 deletions src/webui/api/torrentscontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ const QString KEY_PROP_SSL_PRIVATEKEY = u"ssl_private_key"_s;
const QString KEY_PROP_SSL_DHPARAMS = u"ssl_dh_params"_s;
const QString KEY_PROP_HAS_METADATA = u"has_metadata"_s;
const QString KEY_PROP_PROGRESS = u"progress"_s;
const QString KEY_PROP_TRACKERS = u"trackers"_s;


// File keys
Expand Down Expand Up @@ -248,6 +249,31 @@ namespace
return {dht, pex, lsd};
}

QJsonArray getTrackers(const BitTorrent::Torrent *const torrent)
{
QJsonArray trackerList;

for (const BitTorrent::TrackerEntryStatus &tracker : asConst(torrent->trackers()))
{
const bool isNotWorking = (tracker.state == BitTorrent::TrackerEndpointState::NotWorking)
|| (tracker.state == BitTorrent::TrackerEndpointState::TrackerError)
|| (tracker.state == BitTorrent::TrackerEndpointState::Unreachable);
trackerList << QJsonObject
{
{KEY_TRACKER_URL, tracker.url},
{KEY_TRACKER_TIER, tracker.tier},
{KEY_TRACKER_STATUS, static_cast<int>((isNotWorking ? BitTorrent::TrackerEndpointState::NotWorking : tracker.state))},
{KEY_TRACKER_MSG, tracker.message},
{KEY_TRACKER_PEERS_COUNT, tracker.numPeers},
{KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds},
{KEY_TRACKER_LEECHES_COUNT, tracker.numLeeches},
{KEY_TRACKER_DOWNLOADED_COUNT, tracker.numDownloaded}
};
}

return trackerList;
}

QList<BitTorrent::TorrentID> toTorrentIDs(const QStringList &idStrings)
{
QList<BitTorrent::TorrentID> idList;
Expand Down Expand Up @@ -304,6 +330,7 @@ void TorrentsController::countAction()
// - tag (string): torrent tag for filtering by it (empty string means "untagged"; no "tag" param presented means "any tag")
// - hashes (string): filter by hashes, can contain multiple hashes separated by |
// - private (bool): filter torrents that are from private trackers (true) or not (false). Empty means any torrent (no filtering)
// - includeTrackers (bool): include trackers in list output (true) or not (false). Empty means not included
// - sort (string): name of column for sorting by its value
// - reverse (bool): enable reverse sorting
// - limit (int): set limit number of torrents returned (if greater than 0, otherwise - unlimited)
Expand All @@ -319,6 +346,7 @@ void TorrentsController::infoAction()
int offset {params()[u"offset"_s].toInt()};
const QStringList hashes {params()[u"hashes"_s].split(u'|', Qt::SkipEmptyParts)};
const std::optional<bool> isPrivate = parseBool(params()[u"private"_s]);
const bool includeTrackers = parseBool(params()[u"includeTrackers"_s]).value_or(false);

std::optional<TorrentIDSet> idSet;
if (!hashes.isEmpty())
Expand All @@ -332,8 +360,15 @@ void TorrentsController::infoAction()
QVariantList torrentList;
for (const BitTorrent::Torrent *torrent : asConst(BitTorrent::Session::instance()->torrents()))
{
if (torrentFilter.match(torrent))
torrentList.append(serialize(*torrent));
if (!torrentFilter.match(torrent))
continue;

QVariantMap serializedTorrent = serialize(*torrent);

if (includeTrackers)
serializedTorrent.insert(KEY_PROP_TRACKERS, getTrackers(torrent));

torrentList.append(serializedTorrent);
}

if (torrentList.isEmpty())
Expand Down Expand Up @@ -531,27 +566,13 @@ void TorrentsController::trackersAction()
if (!torrent)
throw APIError(APIErrorType::NotFound);

QJsonArray trackerList = getStickyTrackers(torrent);
QJsonArray trackersList = getStickyTrackers(torrent);

for (const BitTorrent::TrackerEntryStatus &tracker : asConst(torrent->trackers()))
{
const bool isNotWorking = (tracker.state == BitTorrent::TrackerEndpointState::NotWorking)
|| (tracker.state == BitTorrent::TrackerEndpointState::TrackerError)
|| (tracker.state == BitTorrent::TrackerEndpointState::Unreachable);
trackerList << QJsonObject
{
{KEY_TRACKER_URL, tracker.url},
{KEY_TRACKER_TIER, tracker.tier},
{KEY_TRACKER_STATUS, static_cast<int>((isNotWorking ? BitTorrent::TrackerEndpointState::NotWorking : tracker.state))},
{KEY_TRACKER_MSG, tracker.message},
{KEY_TRACKER_PEERS_COUNT, tracker.numPeers},
{KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds},
{KEY_TRACKER_LEECHES_COUNT, tracker.numLeeches},
{KEY_TRACKER_DOWNLOADED_COUNT, tracker.numDownloaded}
};
}
// merge QJsonArray
for (const auto &tracker : asConst(getTrackers(torrent)))
trackersList.append(tracker);

setResult(trackerList);
setResult(trackersList);
}

// Returns the web seeds for a torrent in JSON format.
Expand Down

0 comments on commit 76e1040

Please sign in to comment.