mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-16 02:03:07 -07:00
Improve tracker entries handling
PR #19468. * Use QHash to map tracker endpoints * Don't clear numPeers unexpectedly * Remove outdated tracker entry endpoints * Move presentation logic from Core to GUI code * Show all endpoints per tracker in tree structure --------- Co-authored-by: Kacper Michajłow <kasper93@gmail.com>
This commit is contained in:
parent
34d30ed031
commit
c805606524
8 changed files with 176 additions and 91 deletions
|
@ -5920,7 +5920,7 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *a)
|
||||||
if (!torrent)
|
if (!torrent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QMap<TrackerEntry::Endpoint, int> &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())];
|
QHash<TrackerEntry::Endpoint, int> &updateInfo = m_updatedTrackerEntries[torrent->nativeHandle()][std::string(a->tracker_url())];
|
||||||
|
|
||||||
if (a->type() == lt::tracker_reply_alert::alert_type)
|
if (a->type() == lt::tracker_reply_alert::alert_type)
|
||||||
{
|
{
|
||||||
|
@ -6004,7 +6004,7 @@ void SessionImpl::processTrackerStatuses()
|
||||||
if (updatedTrackersIter == updatedTrackers.end())
|
if (updatedTrackersIter == updatedTrackers.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const QMap<TrackerEntry::Endpoint, int> &updateInfo = updatedTrackersIter.value();
|
const QHash<TrackerEntry::Endpoint, int> &updateInfo = updatedTrackersIter.value();
|
||||||
TrackerEntry trackerEntry = torrent->updateTrackerEntry(announceEntry, updateInfo);
|
TrackerEntry trackerEntry = torrent->updateTrackerEntry(announceEntry, updateInfo);
|
||||||
const QString url = trackerEntry.url;
|
const QString url = trackerEntry.url;
|
||||||
updatedTrackerEntries.emplace(url, std::move(trackerEntry));
|
updatedTrackerEntries.emplace(url, std::move(trackerEntry));
|
||||||
|
|
|
@ -746,7 +746,7 @@ namespace BitTorrent
|
||||||
|
|
||||||
// This field holds amounts of peers reported by trackers in their responses to announces
|
// This field holds amounts of peers reported by trackers in their responses to announces
|
||||||
// (torrent.tracker_name.tracker_local_endpoint.num_peers)
|
// (torrent.tracker_name.tracker_local_endpoint.num_peers)
|
||||||
QHash<lt::torrent_handle, QHash<std::string, QMap<TrackerEntry::Endpoint, int>>> m_updatedTrackerEntries;
|
QHash<lt::torrent_handle, QHash<std::string, QHash<TrackerEntry::Endpoint, int>>> m_updatedTrackerEntries;
|
||||||
|
|
||||||
// I/O errored torrents
|
// I/O errored torrents
|
||||||
QSet<TorrentID> m_recentErroredTorrents;
|
QSet<TorrentID> m_recentErroredTorrents;
|
||||||
|
|
|
@ -80,16 +80,26 @@ namespace
|
||||||
|
|
||||||
#ifdef QBT_USES_LIBTORRENT2
|
#ifdef QBT_USES_LIBTORRENT2
|
||||||
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
|
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
|
||||||
, const lt::info_hash_t &hashes, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
, const lt::info_hash_t &hashes, const QHash<TrackerEntry::Endpoint, int> &updateInfo)
|
||||||
#else
|
#else
|
||||||
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
|
void updateTrackerEntry(TrackerEntry &trackerEntry, const lt::announce_entry &nativeEntry
|
||||||
, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
, const QHash<TrackerEntry::Endpoint, int> &updateInfo)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
Q_ASSERT(trackerEntry.url == QString::fromStdString(nativeEntry.url));
|
Q_ASSERT(trackerEntry.url == QString::fromStdString(nativeEntry.url));
|
||||||
|
|
||||||
trackerEntry.tier = nativeEntry.tier;
|
trackerEntry.tier = nativeEntry.tier;
|
||||||
|
|
||||||
|
// remove outdated endpoints
|
||||||
|
trackerEntry.stats.removeIf([&nativeEntry](const decltype(trackerEntry.stats)::iterator &iter)
|
||||||
|
{
|
||||||
|
return std::none_of(nativeEntry.endpoints.cbegin(), nativeEntry.endpoints.cend()
|
||||||
|
, [&endpoint = iter.key()](const auto &existingEndpoint)
|
||||||
|
{
|
||||||
|
return (endpoint == existingEndpoint.local_endpoint);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
int numUpdating = 0;
|
int numUpdating = 0;
|
||||||
int numWorking = 0;
|
int numWorking = 0;
|
||||||
int numNotWorking = 0;
|
int numNotWorking = 0;
|
||||||
|
@ -99,13 +109,17 @@ namespace
|
||||||
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size()) * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
|
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size()) * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
|
||||||
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
||||||
{
|
{
|
||||||
|
const auto endpointName = QString::fromStdString((std::stringstream() << endpoint.local_endpoint).str());
|
||||||
|
|
||||||
for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
|
for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
|
||||||
{
|
{
|
||||||
if (hashes.has(protocolVersion))
|
if (hashes.has(protocolVersion))
|
||||||
{
|
{
|
||||||
const lt::announce_infohash &infoHash = endpoint.info_hashes[protocolVersion];
|
const lt::announce_infohash &infoHash = endpoint.info_hashes[protocolVersion];
|
||||||
|
|
||||||
TrackerEntry::EndpointStats trackerEndpoint;
|
TrackerEntry::EndpointStats &trackerEndpoint = trackerEntry.stats[endpoint.local_endpoint][(protocolVersion == lt::protocol_version::V1) ? 1 : 2];
|
||||||
|
|
||||||
|
trackerEndpoint.name = endpointName;
|
||||||
trackerEndpoint.numPeers = updateInfo.value(endpoint.local_endpoint, trackerEndpoint.numPeers);
|
trackerEndpoint.numPeers = updateInfo.value(endpoint.local_endpoint, trackerEndpoint.numPeers);
|
||||||
trackerEndpoint.numSeeds = infoHash.scrape_complete;
|
trackerEndpoint.numSeeds = infoHash.scrape_complete;
|
||||||
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
|
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
|
||||||
|
@ -131,20 +145,18 @@ namespace
|
||||||
trackerEndpoint.status = TrackerEntry::NotContacted;
|
trackerEndpoint.status = TrackerEntry::NotContacted;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString trackerMessage = QString::fromStdString(infoHash.message);
|
if (!infoHash.message.empty())
|
||||||
const QString errorMessage = QString::fromLocal8Bit(infoHash.last_error.message().c_str());
|
{
|
||||||
trackerEndpoint.message = (!trackerMessage.isEmpty() ? trackerMessage : errorMessage);
|
trackerEndpoint.message = QString::fromStdString(infoHash.message);
|
||||||
|
if (firstTrackerMessage.isEmpty())
|
||||||
trackerEntry.stats[endpoint.local_endpoint][(protocolVersion == lt::protocol_version::V1) ? 1 : 2] = trackerEndpoint;
|
firstTrackerMessage = trackerEndpoint.message;
|
||||||
trackerEntry.numPeers = std::max(trackerEntry.numPeers, trackerEndpoint.numPeers);
|
}
|
||||||
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, trackerEndpoint.numSeeds);
|
else if (infoHash.last_error)
|
||||||
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, trackerEndpoint.numLeeches);
|
{
|
||||||
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, trackerEndpoint.numDownloaded);
|
trackerEndpoint.message = QString::fromLocal8Bit(infoHash.last_error.message());
|
||||||
|
if (firstErrorMessage.isEmpty())
|
||||||
if (firstTrackerMessage.isEmpty())
|
firstErrorMessage = trackerEndpoint.message;
|
||||||
firstTrackerMessage = trackerMessage;
|
}
|
||||||
if (firstErrorMessage.isEmpty())
|
|
||||||
firstErrorMessage = errorMessage;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +164,9 @@ namespace
|
||||||
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
|
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
|
||||||
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
||||||
{
|
{
|
||||||
TrackerEntry::EndpointStats trackerEndpoint;
|
TrackerEntry::EndpointStats &trackerEndpoint = trackerEntry.stats[endpoint.local_endpoint][1];
|
||||||
|
|
||||||
|
trackerEndpoint.name = QString::fromStdString((std::stringstream() << endpoint.local_endpoint).str());
|
||||||
trackerEndpoint.numPeers = updateInfo.value(endpoint.local_endpoint, trackerEndpoint.numPeers);
|
trackerEndpoint.numPeers = updateInfo.value(endpoint.local_endpoint, trackerEndpoint.numPeers);
|
||||||
trackerEndpoint.numSeeds = endpoint.scrape_complete;
|
trackerEndpoint.numSeeds = endpoint.scrape_complete;
|
||||||
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
|
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
|
||||||
|
@ -178,20 +192,18 @@ namespace
|
||||||
trackerEndpoint.status = TrackerEntry::NotContacted;
|
trackerEndpoint.status = TrackerEntry::NotContacted;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString trackerMessage = QString::fromStdString(endpoint.message);
|
if (!endpoint.message.empty())
|
||||||
const QString errorMessage = QString::fromLocal8Bit(endpoint.last_error.message().c_str());
|
{
|
||||||
trackerEndpoint.message = (!trackerMessage.isEmpty() ? trackerMessage : errorMessage);
|
trackerEndpoint.message = QString::fromStdString(endpoint.message);
|
||||||
|
if (firstTrackerMessage.isEmpty())
|
||||||
trackerEntry.stats[endpoint.local_endpoint][1] = trackerEndpoint;
|
firstTrackerMessage = trackerEndpoint.message;
|
||||||
trackerEntry.numPeers = std::max(trackerEntry.numPeers, trackerEndpoint.numPeers);
|
}
|
||||||
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, trackerEndpoint.numSeeds);
|
else if (endpoint.last_error)
|
||||||
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, trackerEndpoint.numLeeches);
|
{
|
||||||
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, trackerEndpoint.numDownloaded);
|
trackerEndpoint.message = QString::fromLocal8Bit(endpoint.last_error.message());
|
||||||
|
if (firstErrorMessage.isEmpty())
|
||||||
if (firstTrackerMessage.isEmpty())
|
firstErrorMessage = trackerEndpoint.message;
|
||||||
firstTrackerMessage = trackerMessage;
|
}
|
||||||
if (firstErrorMessage.isEmpty())
|
|
||||||
firstErrorMessage = errorMessage;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1603,7 +1615,7 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN
|
||||||
endReceivedMetadataHandling(savePath, fileNames);
|
endReceivedMetadataHandling(savePath, fileNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap<TrackerEntry::Endpoint, int> &updateInfo)
|
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QHash<TrackerEntry::Endpoint, int> &updateInfo)
|
||||||
{
|
{
|
||||||
const auto it = std::find_if(m_trackerEntries.begin(), m_trackerEntries.end()
|
const auto it = std::find_if(m_trackerEntries.begin(), m_trackerEntries.end()
|
||||||
, [&announceEntry](const TrackerEntry &trackerEntry)
|
, [&announceEntry](const TrackerEntry &trackerEntry)
|
||||||
|
|
|
@ -264,7 +264,7 @@ namespace BitTorrent
|
||||||
void saveResumeData(lt::resume_data_flags_t flags = {});
|
void saveResumeData(lt::resume_data_flags_t flags = {});
|
||||||
void handleMoveStorageJobFinished(const Path &path, MoveStorageContext context, bool hasOutstandingJob);
|
void handleMoveStorageJobFinished(const Path &path, MoveStorageContext context, bool hasOutstandingJob);
|
||||||
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
|
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
|
||||||
TrackerEntry updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap<TrackerEntry::Endpoint, int> &updateInfo);
|
TrackerEntry updateTrackerEntry(const lt::announce_entry &announceEntry, const QHash<TrackerEntry::Endpoint, int> &updateInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using EventTrigger = std::function<void ()>;
|
using EventTrigger = std::function<void ()>;
|
||||||
|
|
|
@ -57,20 +57,15 @@ namespace BitTorrent
|
||||||
int numLeeches = -1;
|
int numLeeches = -1;
|
||||||
int numDownloaded = -1;
|
int numDownloaded = -1;
|
||||||
QString message {};
|
QString message {};
|
||||||
|
QString name {};
|
||||||
};
|
};
|
||||||
|
|
||||||
QString url {};
|
QString url {};
|
||||||
int tier = 0;
|
int tier = 0;
|
||||||
|
Status status = NotContacted;
|
||||||
|
QString message {};
|
||||||
|
|
||||||
QHash<Endpoint, QHash<int, EndpointStats>> stats {};
|
QHash<Endpoint, QHash<int, EndpointStats>> stats {};
|
||||||
|
|
||||||
// Deprecated fields
|
|
||||||
Status status = NotContacted;
|
|
||||||
int numPeers = -1;
|
|
||||||
int numSeeds = -1;
|
|
||||||
int numLeeches = -1;
|
|
||||||
int numDownloaded = -1;
|
|
||||||
QString message {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QVector<TrackerEntry> parseTrackerEntries(QStringView str);
|
QVector<TrackerEntry> parseTrackerEntries(QStringView str);
|
||||||
|
|
|
@ -60,15 +60,17 @@
|
||||||
TrackerListWidget::TrackerListWidget(PropertiesWidget *properties)
|
TrackerListWidget::TrackerListWidget(PropertiesWidget *properties)
|
||||||
: m_properties(properties)
|
: m_properties(properties)
|
||||||
{
|
{
|
||||||
|
#ifdef QBT_USES_LIBTORRENT2
|
||||||
|
setColumnHidden(COL_PROTOCOL, true); // Must be set before calling loadSettings()
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set header
|
// Set header
|
||||||
// Must be set before calling loadSettings() otherwise the header is reset on restart
|
// Must be set before calling loadSettings() otherwise the header is reset on restart
|
||||||
setHeaderLabels(headerLabels());
|
setHeaderLabels(headerLabels());
|
||||||
// Load settings
|
// Load settings
|
||||||
loadSettings();
|
loadSettings();
|
||||||
// Graphical settings
|
// Graphical settings
|
||||||
setRootIsDecorated(false);
|
|
||||||
setAllColumnsShowFocus(true);
|
setAllColumnsShowFocus(true);
|
||||||
setItemsExpandable(false);
|
|
||||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
header()->setFirstSectionMovable(true);
|
header()->setFirstSectionMovable(true);
|
||||||
header()->setStretchLastSection(false); // Must be set after loadSettings() in order to work
|
header()->setStretchLastSection(false); // Must be set after loadSettings() in order to work
|
||||||
|
@ -80,8 +82,10 @@ TrackerListWidget::TrackerListWidget(PropertiesWidget *properties)
|
||||||
// its size is 0, because explicitly 'showing' the column isn't enough
|
// its size is 0, because explicitly 'showing' the column isn't enough
|
||||||
// in the above scenario.
|
// in the above scenario.
|
||||||
for (int i = 0; i < COL_COUNT; ++i)
|
for (int i = 0; i < COL_COUNT; ++i)
|
||||||
|
{
|
||||||
if ((columnWidth(i) <= 0) && !isColumnHidden(i))
|
if ((columnWidth(i) <= 0) && !isColumnHidden(i))
|
||||||
resizeColumnToContents(i);
|
resizeColumnToContents(i);
|
||||||
|
}
|
||||||
// Context menu
|
// Context menu
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(this, &QWidget::customContextMenuRequested, this, &TrackerListWidget::showTrackerListMenu);
|
connect(this, &QWidget::customContextMenuRequested, this, &TrackerListWidget::showTrackerListMenu);
|
||||||
|
@ -93,13 +97,13 @@ TrackerListWidget::TrackerListWidget(PropertiesWidget *properties)
|
||||||
connect(header(), &QHeaderView::sortIndicatorChanged, this, &TrackerListWidget::saveSettings);
|
connect(header(), &QHeaderView::sortIndicatorChanged, this, &TrackerListWidget::saveSettings);
|
||||||
|
|
||||||
// Set DHT, PeX, LSD items
|
// Set DHT, PeX, LSD items
|
||||||
m_DHTItem = new QTreeWidgetItem({ u""_s, u"** [DHT] **"_s, u""_s, u"0"_s, u""_s, u""_s, u"0"_s });
|
m_DHTItem = new QTreeWidgetItem({ u"** [DHT] **"_s });
|
||||||
insertTopLevelItem(0, m_DHTItem);
|
insertTopLevelItem(0, m_DHTItem);
|
||||||
setRowColor(0, QColorConstants::Svg::grey);
|
setRowColor(0, QColorConstants::Svg::grey);
|
||||||
m_PEXItem = new QTreeWidgetItem({ u""_s, u"** [PeX] **"_s, u""_s, u"0"_s, u""_s, u""_s, u"0"_s });
|
m_PEXItem = new QTreeWidgetItem({ u"** [PeX] **"_s });
|
||||||
insertTopLevelItem(1, m_PEXItem);
|
insertTopLevelItem(1, m_PEXItem);
|
||||||
setRowColor(1, QColorConstants::Svg::grey);
|
setRowColor(1, QColorConstants::Svg::grey);
|
||||||
m_LSDItem = new QTreeWidgetItem({ u""_s, u"** [LSD] **"_s, u""_s, u"0"_s, u""_s, u""_s, u"0"_s });
|
m_LSDItem = new QTreeWidgetItem({ u"** [LSD] **"_s });
|
||||||
insertTopLevelItem(2, m_LSDItem);
|
insertTopLevelItem(2, m_LSDItem);
|
||||||
setRowColor(2, QColorConstants::Svg::grey);
|
setRowColor(2, QColorConstants::Svg::grey);
|
||||||
|
|
||||||
|
@ -134,6 +138,22 @@ TrackerListWidget::TrackerListWidget(PropertiesWidget *properties)
|
||||||
connect(copyHotkey, &QShortcut::activated, this, &TrackerListWidget::copyTrackerUrl);
|
connect(copyHotkey, &QShortcut::activated, this, &TrackerListWidget::copyTrackerUrl);
|
||||||
|
|
||||||
connect(this, &QAbstractItemView::doubleClicked, this, &TrackerListWidget::editSelectedTracker);
|
connect(this, &QAbstractItemView::doubleClicked, this, &TrackerListWidget::editSelectedTracker);
|
||||||
|
connect(this, &QTreeWidget::itemExpanded, this, [](QTreeWidgetItem *item)
|
||||||
|
{
|
||||||
|
item->setText(COL_PEERS, QString());
|
||||||
|
item->setText(COL_SEEDS, QString());
|
||||||
|
item->setText(COL_LEECHES, QString());
|
||||||
|
item->setText(COL_TIMES_DOWNLOADED, QString());
|
||||||
|
item->setText(COL_MSG, QString());
|
||||||
|
});
|
||||||
|
connect(this, &QTreeWidget::itemCollapsed, this, [](QTreeWidgetItem *item)
|
||||||
|
{
|
||||||
|
item->setText(COL_PEERS, item->data(COL_PEERS, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_SEEDS, item->data(COL_SEEDS, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_LEECHES, item->data(COL_LEECHES, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_TIMES_DOWNLOADED, item->data(COL_TIMES_DOWNLOADED, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_MSG, item->data(COL_MSG, Qt::UserRole).toString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackerListWidget::~TrackerListWidget()
|
TrackerListWidget::~TrackerListWidget()
|
||||||
|
@ -364,6 +384,33 @@ void TrackerListWidget::loadTrackers()
|
||||||
|
|
||||||
loadStickyItems(torrent);
|
loadStickyItems(torrent);
|
||||||
|
|
||||||
|
const auto setAlignment = [](QTreeWidgetItem *item)
|
||||||
|
{
|
||||||
|
for (const TrackerListColumn col : {COL_TIER, COL_PROTOCOL, COL_PEERS, COL_SEEDS, COL_LEECHES, COL_TIMES_DOWNLOADED})
|
||||||
|
item->setTextAlignment(col, (Qt::AlignRight | Qt::AlignVCenter));
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto prettyCount = [](const int val)
|
||||||
|
{
|
||||||
|
return (val > -1) ? QString::number(val) : tr("N/A");
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto toString = [](const BitTorrent::TrackerEntry::Status status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case BitTorrent::TrackerEntry::Status::Working:
|
||||||
|
return tr("Working");
|
||||||
|
case BitTorrent::TrackerEntry::Status::Updating:
|
||||||
|
return tr("Updating...");
|
||||||
|
case BitTorrent::TrackerEntry::Status::NotWorking:
|
||||||
|
return tr("Not working");
|
||||||
|
case BitTorrent::TrackerEntry::Status::NotContacted:
|
||||||
|
return tr("Not contacted yet");
|
||||||
|
}
|
||||||
|
return tr("Invalid status!");
|
||||||
|
};
|
||||||
|
|
||||||
// Load actual trackers information
|
// Load actual trackers information
|
||||||
QStringList oldTrackerURLs = m_trackerItems.keys();
|
QStringList oldTrackerURLs = m_trackerItems.keys();
|
||||||
|
|
||||||
|
@ -385,45 +432,59 @@ void TrackerListWidget::loadTrackers()
|
||||||
oldTrackerURLs.removeOne(trackerURL);
|
oldTrackerURLs.removeOne(trackerURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
item->setText(COL_TIER, QString::number(entry.tier));
|
int peersMax = -1;
|
||||||
|
int seedsMax = -1;
|
||||||
|
int leechesMax = -1;
|
||||||
|
int downloadedMax = -1;
|
||||||
|
|
||||||
switch (entry.status)
|
int index = 0;
|
||||||
|
for (const auto &endpoint : entry.stats)
|
||||||
{
|
{
|
||||||
case BitTorrent::TrackerEntry::Working:
|
for (auto it = endpoint.cbegin(), end = endpoint.cend(); it != end; ++it)
|
||||||
item->setText(COL_STATUS, tr("Working"));
|
{
|
||||||
break;
|
const int protocolVersion = it.key();
|
||||||
case BitTorrent::TrackerEntry::Updating:
|
const BitTorrent::TrackerEntry::EndpointStats &protocolStats = it.value();
|
||||||
item->setText(COL_STATUS, tr("Updating..."));
|
|
||||||
break;
|
peersMax = std::max(peersMax, protocolStats.numPeers);
|
||||||
case BitTorrent::TrackerEntry::NotWorking:
|
seedsMax = std::max(seedsMax, protocolStats.numSeeds);
|
||||||
item->setText(COL_STATUS, tr("Not working"));
|
leechesMax = std::max(leechesMax, protocolStats.numLeeches);
|
||||||
break;
|
downloadedMax = std::max(downloadedMax, protocolStats.numDownloaded);
|
||||||
case BitTorrent::TrackerEntry::NotContacted:
|
|
||||||
item->setText(COL_STATUS, tr("Not contacted yet"));
|
QTreeWidgetItem *child = (index < item->childCount()) ? item->child(index) : new QTreeWidgetItem(item);
|
||||||
break;
|
child->setText(COL_URL, protocolStats.name);
|
||||||
|
child->setText(COL_PROTOCOL, tr("v%1").arg(protocolVersion));
|
||||||
|
child->setText(COL_STATUS, toString(protocolStats.status));
|
||||||
|
child->setText(COL_PEERS, prettyCount(protocolStats.numPeers));
|
||||||
|
child->setText(COL_SEEDS, prettyCount(protocolStats.numSeeds));
|
||||||
|
child->setText(COL_LEECHES, prettyCount(protocolStats.numLeeches));
|
||||||
|
child->setText(COL_TIMES_DOWNLOADED, prettyCount(protocolStats.numDownloaded));
|
||||||
|
child->setText(COL_MSG, protocolStats.message);
|
||||||
|
child->setToolTip(COL_MSG, protocolStats.message);
|
||||||
|
setAlignment(child);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item->setText(COL_MSG, entry.message);
|
while (item->childCount() != index)
|
||||||
item->setToolTip(COL_MSG, entry.message);
|
delete item->takeChild(index);
|
||||||
item->setText(COL_PEERS, ((entry.numPeers > -1)
|
|
||||||
? QString::number(entry.numPeers)
|
|
||||||
: tr("N/A")));
|
|
||||||
item->setText(COL_SEEDS, ((entry.numSeeds > -1)
|
|
||||||
? QString::number(entry.numSeeds)
|
|
||||||
: tr("N/A")));
|
|
||||||
item->setText(COL_LEECHES, ((entry.numLeeches > -1)
|
|
||||||
? QString::number(entry.numLeeches)
|
|
||||||
: tr("N/A")));
|
|
||||||
item->setText(COL_TIMES_DOWNLOADED, ((entry.numDownloaded > -1)
|
|
||||||
? QString::number(entry.numDownloaded)
|
|
||||||
: tr("N/A")));
|
|
||||||
|
|
||||||
const Qt::Alignment alignment = (Qt::AlignRight | Qt::AlignVCenter);
|
item->setText(COL_TIER, QString::number(entry.tier));
|
||||||
item->setTextAlignment(COL_TIER, alignment);
|
item->setText(COL_STATUS, toString(entry.status));
|
||||||
item->setTextAlignment(COL_PEERS, alignment);
|
|
||||||
item->setTextAlignment(COL_SEEDS, alignment);
|
item->setData(COL_PEERS, Qt::UserRole, prettyCount(peersMax));
|
||||||
item->setTextAlignment(COL_LEECHES, alignment);
|
item->setData(COL_SEEDS, Qt::UserRole, prettyCount(seedsMax));
|
||||||
item->setTextAlignment(COL_TIMES_DOWNLOADED, alignment);
|
item->setData(COL_LEECHES, Qt::UserRole, prettyCount(leechesMax));
|
||||||
|
item->setData(COL_TIMES_DOWNLOADED, Qt::UserRole, prettyCount(downloadedMax));
|
||||||
|
item->setData(COL_MSG, Qt::UserRole, entry.message);
|
||||||
|
if (!item->isExpanded())
|
||||||
|
{
|
||||||
|
item->setText(COL_PEERS, item->data(COL_PEERS, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_SEEDS, item->data(COL_SEEDS, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_LEECHES, item->data(COL_LEECHES, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_TIMES_DOWNLOADED, item->data(COL_TIMES_DOWNLOADED, Qt::UserRole).toString());
|
||||||
|
item->setText(COL_MSG, item->data(COL_MSG, Qt::UserRole).toString());
|
||||||
|
}
|
||||||
|
setAlignment(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove old trackers
|
// Remove old trackers
|
||||||
|
@ -617,8 +678,9 @@ QStringList TrackerListWidget::headerLabels()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
tr("Tier")
|
tr("URL/Announce endpoint")
|
||||||
, tr("URL")
|
, tr("Tier")
|
||||||
|
, tr("Protocol")
|
||||||
, tr("Status")
|
, tr("Status")
|
||||||
, tr("Peers")
|
, tr("Peers")
|
||||||
, tr("Seeds")
|
, tr("Seeds")
|
||||||
|
|
|
@ -46,8 +46,9 @@ class TrackerListWidget : public QTreeWidget
|
||||||
public:
|
public:
|
||||||
enum TrackerListColumn
|
enum TrackerListColumn
|
||||||
{
|
{
|
||||||
COL_TIER,
|
|
||||||
COL_URL,
|
COL_URL,
|
||||||
|
COL_TIER,
|
||||||
|
COL_PROTOCOL,
|
||||||
COL_STATUS,
|
COL_STATUS,
|
||||||
COL_PEERS,
|
COL_PEERS,
|
||||||
COL_SEEDS,
|
COL_SEEDS,
|
||||||
|
|
|
@ -483,16 +483,31 @@ void TorrentsController::trackersAction()
|
||||||
|
|
||||||
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers()))
|
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers()))
|
||||||
{
|
{
|
||||||
|
int numPeers = -1;
|
||||||
|
int numSeeds = -1;
|
||||||
|
int numLeeches = -1;
|
||||||
|
int numDownloaded = -1;
|
||||||
|
for (const auto &endpoint : tracker.stats)
|
||||||
|
{
|
||||||
|
for (const auto &protocolStat : endpoint)
|
||||||
|
{
|
||||||
|
numPeers = std::max(numPeers, protocolStat.numPeers);
|
||||||
|
numSeeds = std::max(numSeeds, protocolStat.numSeeds);
|
||||||
|
numLeeches = std::max(numLeeches, protocolStat.numLeeches);
|
||||||
|
numDownloaded = std::max(numDownloaded, protocolStat.numDownloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trackerList << QJsonObject
|
trackerList << QJsonObject
|
||||||
{
|
{
|
||||||
{KEY_TRACKER_URL, tracker.url},
|
{KEY_TRACKER_URL, tracker.url},
|
||||||
{KEY_TRACKER_TIER, tracker.tier},
|
{KEY_TRACKER_TIER, tracker.tier},
|
||||||
{KEY_TRACKER_STATUS, static_cast<int>(tracker.status)},
|
{KEY_TRACKER_STATUS, static_cast<int>(tracker.status)},
|
||||||
{KEY_TRACKER_MSG, tracker.message},
|
{KEY_TRACKER_MSG, tracker.message},
|
||||||
{KEY_TRACKER_PEERS_COUNT, tracker.numPeers},
|
{KEY_TRACKER_PEERS_COUNT, numPeers},
|
||||||
{KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds},
|
{KEY_TRACKER_SEEDS_COUNT, numSeeds},
|
||||||
{KEY_TRACKER_LEECHES_COUNT, tracker.numLeeches},
|
{KEY_TRACKER_LEECHES_COUNT, numLeeches},
|
||||||
{KEY_TRACKER_DOWNLOADED_COUNT, tracker.numDownloaded}
|
{KEY_TRACKER_DOWNLOADED_COUNT, numDownloaded}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue