diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 92c6fd9f4..3b49123ce 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -291,6 +291,67 @@ namespace return {}; } #endif + +#ifdef QBT_USES_LIBTORRENT2 + TrackerEntryUpdateInfo getTrackerEntryUpdateInfo(const lt::announce_entry &nativeEntry, const lt::info_hash_t &hashes) +#else + TrackerEntryUpdateInfo getTrackerEntryUpdateInfo(const lt::announce_entry &nativeEntry) +#endif + { + TrackerEntryUpdateInfo result {}; + int numUpdating = 0; + int numWorking = 0; + int numNotWorking = 0; +#ifdef QBT_USES_LIBTORRENT2 + const auto numEndpoints = static_cast(nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1)); + for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints) + { + for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2}) + { + if (hashes.has(protocolVersion)) + { + const lt::announce_infohash &infoHash = endpoint.info_hashes[protocolVersion]; + + if (!result.hasMessages) + result.hasMessages = !infoHash.message.empty(); + + if (infoHash.updating) + ++numUpdating; + else if (infoHash.fails > 0) + ++numNotWorking; + else if (nativeEntry.verified) + ++numWorking; + } + } + } +#else + const auto numEndpoints = static_cast(nativeEntry.endpoints.size()); + for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints) + { + if (!result.hasMessages) + result.hasMessages = !endpoint.message.empty(); + + if (endpoint.updating) + ++numUpdating; + else if (endpoint.fails > 0) + ++numNotWorking; + else if (nativeEntry.verified) + ++numWorking; + } +#endif + + if (numEndpoints > 0) + { + if (numUpdating > 0) + result.status = TrackerEntry::Updating; + else if (numWorking > 0) + result.status = TrackerEntry::Working; + else if (numNotWorking == numEndpoints) + result.status = TrackerEntry::NotWorking; + } + + return result; + } } const int addTorrentParamsId = qRegisterMetaType(); @@ -4033,16 +4094,6 @@ void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const Loa m_resumeDataStorage->store(torrent->id(), data); } -void Session::handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl) -{ - emit trackerSuccess(torrent, trackerUrl); -} - -void Session::handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl) -{ - emit trackerError(torrent, trackerUrl); -} - bool Session::addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, const MoveStorageMode mode) { Q_ASSERT(torrent); @@ -4233,11 +4284,6 @@ void Session::loadCategories() } } -void Session::handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl) -{ - emit trackerWarning(torrent, trackerUrl); -} - bool Session::hasPerTorrentRatioLimit() const { return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent) @@ -4562,6 +4608,8 @@ void Session::readAlerts() const std::vector alerts = getPendingAlerts(); for (const lt::alert *a : alerts) handleAlert(a); + + processTrackerStatuses(); } void Session::handleAlert(const lt::alert *a) @@ -4581,9 +4629,6 @@ void Session::handleAlert(const lt::alert *a) case lt::save_resume_data_failed_alert::alert_type: case lt::torrent_paused_alert::alert_type: case lt::torrent_resumed_alert::alert_type: - case lt::tracker_error_alert::alert_type: - case lt::tracker_reply_alert::alert_type: - case lt::tracker_warning_alert::alert_type: case lt::fastresume_rejected_alert::alert_type: case lt::torrent_checked_alert::alert_type: case lt::metadata_received_alert::alert_type: @@ -4596,6 +4641,11 @@ void Session::handleAlert(const lt::alert *a) case lt::session_stats_alert::alert_type: handleSessionStatsAlert(static_cast(a)); break; + case lt::tracker_error_alert::alert_type: + case lt::tracker_reply_alert::alert_type: + case lt::tracker_warning_alert::alert_type: + handleTrackerAlert(static_cast(a)); + break; case lt::file_error_alert::alert_type: handleFileErrorAlert(static_cast(a)); break; @@ -5133,3 +5183,50 @@ void Session::handleSocks5Alert(const lt::socks5_alert *p) const , Log::WARNING); } } + +void Session::handleTrackerAlert(const lt::tracker_alert *a) +{ + TorrentImpl *torrent = m_torrents.value(a->handle.info_hash()); + if (!torrent) + return; + + const QByteArray trackerURL {a->tracker_url()}; + m_updatedTrackerEntries[torrent].insert(trackerURL); + + if (a->type() == lt::tracker_reply_alert::alert_type) + { + const int numPeers = static_cast(a)->num_peers; + torrent->updatePeerCount(trackerURL, a->local_endpoint, numPeers); + } +} + +void Session::processTrackerStatuses() +{ + QHash> updateInfos; + + for (auto it = m_updatedTrackerEntries.cbegin(); it != m_updatedTrackerEntries.cend(); ++it) + { + TorrentImpl *torrent = it.key(); + const QSet &updatedTrackers = it.value(); + + const std::vector trackerList = torrent->nativeHandle().trackers(); + for (const lt::announce_entry &announceEntry : trackerList) + { + const auto trackerURL = QByteArray::fromRawData(announceEntry.url.c_str(), announceEntry.url.size()); + if (!updatedTrackers.contains(trackerURL)) + continue; + +#ifdef QBT_USES_LIBTORRENT2 + const TrackerEntryUpdateInfo updateInfo = getTrackerEntryUpdateInfo(announceEntry, torrent->nativeHandle().info_hashes()); +#else + const TrackerEntryUpdateInfo updateInfo = getTrackerEntryUpdateInfo(announceEntry); +#endif + if ((updateInfo.status == TrackerEntry::Working) || (updateInfo.status == TrackerEntry::NotWorking)) + updateInfos[torrent][QString::fromUtf8(trackerURL)] = updateInfo; + } + } + + m_updatedTrackerEntries.clear(); + if (!updateInfos.isEmpty()) + emit trackerEntriesUpdated(updateInfos); +} diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 6ff71559d..7c9aeb1d6 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -203,6 +203,12 @@ namespace BitTorrent } disk; }; + struct TrackerEntryUpdateInfo + { + TrackerEntry::Status status = TrackerEntry::NotContacted; + bool hasMessages = false; + }; + class Session final : public QObject { Q_OBJECT @@ -498,9 +504,6 @@ namespace BitTorrent void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector &newUrlSeeds); void handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector &urlSeeds); void handleTorrentResumeDataReady(TorrentImpl *const torrent, const LoadTorrentParams &data); - void handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl); - void handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl); - void handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl); bool addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, MoveStorageMode mode); @@ -544,6 +547,7 @@ namespace BitTorrent void trackersRemoved(Torrent *torrent, const QVector &trackers); void trackerSuccess(Torrent *torrent, const QString &tracker); void trackerWarning(Torrent *torrent, const QString &tracker); + void trackerEntriesUpdated(const QHash> &updateInfos); private slots: void configureDeferred(); @@ -606,6 +610,7 @@ namespace BitTorrent #if defined(Q_OS_WIN) void applyOSMemoryPriority() const; #endif + void processTrackerStatuses(); bool loadTorrent(LoadTorrentParams params); LoadTorrentParams initLoadTorrentParams(const AddTorrentParams &addTorrentParams); @@ -636,6 +641,7 @@ namespace BitTorrent void handleStorageMovedAlert(const lt::storage_moved_alert *p); void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p); void handleSocks5Alert(const lt::socks5_alert *p) const; + void handleTrackerAlert(const lt::tracker_alert *a); void createTorrent(const lt::torrent_handle &nativeHandle); @@ -793,6 +799,8 @@ namespace BitTorrent QMap m_categories; QSet m_tags; + QHash> m_updatedTrackerEntries; + // I/O errored torrents QSet m_recentErroredTorrents; QTimer *m_recentErroredTorrentsTimer = nullptr; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 413e15aa2..8543f33c7 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -69,7 +69,7 @@ using namespace BitTorrent; namespace { - lt::announce_entry makeNativeAnnouncerEntry(const QString &url, const int tier) + lt::announce_entry makeNativeAnnounceEntry(const QString &url, const int tier) { lt::announce_entry entry {url.toStdString()}; entry.tier = tier; @@ -536,7 +536,7 @@ void TorrentImpl::addTrackers(const QVector &trackers) { if (!currentTrackers.contains(tracker)) { - m_nativeHandle.add_tracker(makeNativeAnnouncerEntry(tracker.url, tracker.tier)); + m_nativeHandle.add_tracker(makeNativeAnnounceEntry(tracker.url, tracker.tier)); newTrackers << tracker; } } @@ -560,7 +560,7 @@ void TorrentImpl::replaceTrackers(const QVector &trackers) for (const TrackerEntry &tracker : trackers) { - nativeTrackers.emplace_back(makeNativeAnnouncerEntry(tracker.url, tracker.tier)); + nativeTrackers.emplace_back(makeNativeAnnounceEntry(tracker.url, tracker.tier)); if (!currentTrackers.removeOne(tracker)) newTrackers << tracker; @@ -1484,6 +1484,11 @@ void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileN endReceivedMetadataHandling(savePath, fileNames); } +void TorrentImpl::updatePeerCount(const QString &trackerUrl, const lt::tcp::endpoint &endpoint, const int count) +{ + m_trackerPeerCounts[trackerUrl][endpoint] = count; +} + void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathList &fileNames) { Q_ASSERT(m_filePaths.isEmpty()); @@ -1665,46 +1670,6 @@ void TorrentImpl::handleMoveStorageJobFinished(const bool hasOutstandingJob) } } -void TorrentImpl::handleTrackerReplyAlert(const lt::tracker_reply_alert *p) -{ - const QString trackerUrl = p->tracker_url(); - m_trackerPeerCounts[trackerUrl][p->local_endpoint] = p->num_peers; - - m_session->handleTorrentTrackerReply(this, trackerUrl); -} - -void TorrentImpl::handleTrackerWarningAlert(const lt::tracker_warning_alert *p) -{ - const QString trackerUrl = p->tracker_url(); - m_session->handleTorrentTrackerWarning(this, trackerUrl); -} - -void TorrentImpl::handleTrackerErrorAlert(const lt::tracker_error_alert *p) -{ - // Starting with libtorrent 1.2.x each tracker has multiple local endpoints from which - // an announce is attempted. Some endpoints might succeed while others might fail. - // Emit the signal only if all endpoints have failed. - const std::vector trackerList = m_nativeHandle.trackers(); - const auto iter = std::find_if(trackerList.cbegin(), trackerList.cend(), [p](const lt::announce_entry &entry) - { - return (entry.url == p->tracker_url()); - }); - - if (iter == trackerList.cend()) - return; - - const QString trackerURL = QString::fromStdString(iter->url); - -#ifdef QBT_USES_LIBTORRENT2 - const TrackerEntry entry = fromNativeAnnounceEntry(*iter, m_nativeHandle.info_hashes(), m_trackerPeerCounts[trackerURL]); -#else - const TrackerEntry entry = fromNativeAnnounceEntry(*iter, m_trackerPeerCounts[trackerURL]); -#endif - - if (entry.status == TrackerEntry::NotWorking) - m_session->handleTorrentTrackerError(this, trackerURL); -} - void TorrentImpl::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p) { Q_UNUSED(p); @@ -2014,15 +1979,6 @@ void TorrentImpl::handleAlert(const lt::alert *a) case lt::torrent_resumed_alert::alert_type: handleTorrentResumedAlert(static_cast(a)); break; - case lt::tracker_error_alert::alert_type: - handleTrackerErrorAlert(static_cast(a)); - break; - case lt::tracker_reply_alert::alert_type: - handleTrackerReplyAlert(static_cast(a)); - break; - case lt::tracker_warning_alert::alert_type: - handleTrackerWarningAlert(static_cast(a)); - break; case lt::metadata_received_alert::alert_type: handleMetadataReceivedAlert(static_cast(a)); break; diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 190e6793e..1a2f3223b 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -239,6 +239,7 @@ namespace BitTorrent void saveResumeData(); void handleMoveStorageJobFinished(bool hasOutstandingJob); void fileSearchFinished(const Path &savePath, const PathList &fileNames); + void updatePeerCount(const QString &trackerUrl, const lt::tcp::endpoint &endpoint, int count); private: using EventTrigger = std::function; @@ -263,9 +264,6 @@ namespace BitTorrent void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p); void handleTorrentPausedAlert(const lt::torrent_paused_alert *p); void handleTorrentResumedAlert(const lt::torrent_resumed_alert *p); - void handleTrackerErrorAlert(const lt::tracker_error_alert *p); - void handleTrackerReplyAlert(const lt::tracker_reply_alert *p); - void handleTrackerWarningAlert(const lt::tracker_warning_alert *p); bool isMoveInProgress() const; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 2f205e3c7..b96575aa1 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -243,13 +243,7 @@ MainWindow::MainWindow(QWidget *parent) connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackersAdded, m_transferListFiltersWidget, &TransferListFiltersWidget::addTrackers); connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackersRemoved, m_transferListFiltersWidget, &TransferListFiltersWidget::removeTrackers); connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerlessStateChanged, m_transferListFiltersWidget, &TransferListFiltersWidget::changeTrackerless); - - connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerSuccess - , m_transferListFiltersWidget, qOverload(&TransferListFiltersWidget::trackerSuccess)); - connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerError - , m_transferListFiltersWidget, qOverload(&TransferListFiltersWidget::trackerError)); - connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerWarning - , m_transferListFiltersWidget, qOverload(&TransferListFiltersWidget::trackerWarning)); + connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerEntriesUpdated, m_transferListFiltersWidget, &TransferListFiltersWidget::trackerEntriesUpdated); #ifdef Q_OS_MACOS // Increase top spacing to avoid tab overlapping diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index f26f40dd4..2fe3becc4 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -385,13 +385,13 @@ void TrackerFiltersList::addItem(const QString &tracker, const BitTorrent::Torre updateGeometry(); } -void TrackerFiltersList::removeItem(const QString &tracker, const BitTorrent::TorrentID &id) +void TrackerFiltersList::removeItem(const QString &trackerURL, const BitTorrent::TorrentID &id) { - const QString host = getHost(tracker); + const QString host = getHost(trackerURL); QSet torrentIDs = m_trackers.value(host); - if (torrentIDs.empty()) return; + torrentIDs.remove(id); int row = 0; @@ -400,7 +400,34 @@ void TrackerFiltersList::removeItem(const QString &tracker, const BitTorrent::To if (!host.isEmpty()) { // Remove from 'Error' and 'Warning' view - trackerSuccess(id, tracker); + const auto errorHashesIt = m_errors.find(id); + if (errorHashesIt != m_errors.end()) + { + QSet &errored = errorHashesIt.value(); + errored.remove(trackerURL); + if (errored.isEmpty()) + { + m_errors.erase(errorHashesIt); + item(ERROR_ROW)->setText(tr("Error (%1)").arg(m_errors.size())); + if (currentRow() == ERROR_ROW) + applyFilter(ERROR_ROW); + } + } + + const auto warningHashesIt = m_warnings.find(id); + if (warningHashesIt != m_warnings.end()) + { + QSet &warned = *warningHashesIt; + warned.remove(trackerURL); + if (warned.isEmpty()) + { + m_warnings.erase(warningHashesIt); + item(WARNING_ROW)->setText(tr("Warning (%1)").arg(m_warnings.size())); + if (currentRow() == WARNING_ROW) + applyFilter(WARNING_ROW); + } + } + row = rowFromTracker(host); trackerItem = item(row); @@ -458,58 +485,64 @@ void TrackerFiltersList::setDownloadTrackerFavicon(bool value) } } -void TrackerFiltersList::trackerSuccess(const BitTorrent::TorrentID &id, const QString &tracker) +void TrackerFiltersList::handleTrackerEntriesUpdated(const QHash> &updateInfos) { - const auto errorHashesIter = m_errors.find(id); - if (errorHashesIter != m_errors.end()) + for (auto torrentsIt = updateInfos.cbegin(); torrentsIt != updateInfos.cend(); ++torrentsIt) { - QSet &errored = *errorHashesIter; - errored.remove(tracker); - if (errored.empty()) - { - m_errors.erase(errorHashesIter); - item(ERROR_ROW)->setText(tr("Error (%1)").arg(m_errors.size())); - if (currentRow() == ERROR_ROW) - applyFilter(ERROR_ROW); - } - } + const BitTorrent::TorrentID id = torrentsIt.key()->id(); + const QHash &infos = torrentsIt.value(); - const auto warningHashesIter = m_warnings.find(id); - if (warningHashesIter != m_warnings.end()) - { - QSet &warned = *warningHashesIter; - warned.remove(tracker); - if (warned.empty()) + auto errorHashesIt = m_errors.find(id); + auto warningHashesIt = m_warnings.find(id); + + for (auto trackerIt = infos.cbegin(); trackerIt != infos.cend(); ++trackerIt) { - m_warnings.erase(warningHashesIter); - item(WARNING_ROW)->setText(tr("Warning (%1)").arg(m_warnings.size())); - if (currentRow() == WARNING_ROW) - applyFilter(WARNING_ROW); + const QString &trackerURL = trackerIt.key(); + const BitTorrent::TrackerEntryUpdateInfo &updateInfo = trackerIt.value(); + + if (updateInfo.status == BitTorrent::TrackerEntry::Working) + { + if (errorHashesIt != m_errors.end()) + { + QSet &errored = errorHashesIt.value(); + errored.remove(trackerURL); + } + + if (!updateInfo.hasMessages) + { + if (warningHashesIt != m_warnings.end()) + { + QSet &warned = *warningHashesIt; + warned.remove(trackerURL); + } + } + else + { + if (warningHashesIt == m_warnings.end()) + warningHashesIt = m_warnings.insert(id, {}); + warningHashesIt.value().insert(trackerURL); + } + } + else if (updateInfo.status == BitTorrent::TrackerEntry::NotWorking) + { + if (errorHashesIt == m_errors.end()) + errorHashesIt = m_errors.insert(id, {}); + errorHashesIt.value().insert(trackerURL); + } } - } -} -void TrackerFiltersList::trackerError(const BitTorrent::TorrentID &id, const QString &tracker) -{ - QSet &trackers {m_errors[id]}; - if (trackers.contains(tracker)) - return; + if ((errorHashesIt != m_errors.end()) && errorHashesIt.value().isEmpty()) + m_errors.erase(errorHashesIt); + if ((warningHashesIt != m_warnings.end()) && warningHashesIt.value().isEmpty()) + m_warnings.erase(warningHashesIt); + } - trackers.insert(tracker); item(ERROR_ROW)->setText(tr("Error (%1)").arg(m_errors.size())); + item(WARNING_ROW)->setText(tr("Warning (%1)").arg(m_warnings.size())); + if (currentRow() == ERROR_ROW) applyFilter(ERROR_ROW); -} - -void TrackerFiltersList::trackerWarning(const BitTorrent::TorrentID &id, const QString &tracker) -{ - QSet &trackers {m_warnings[id]}; - if (trackers.contains(tracker)) - return; - - trackers.insert(tracker); - item(WARNING_ROW)->setText(tr("Warning (%1)").arg(m_warnings.size())); - if (currentRow() == WARNING_ROW) + else if (currentRow() == WARNING_ROW) applyFilter(WARNING_ROW); } @@ -732,13 +765,6 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi connect(statusLabel, &QCheckBox::toggled, pref, &Preferences::setStatusFilterState); connect(trackerLabel, &QCheckBox::toggled, m_trackerFilters, &TrackerFiltersList::toggleFilter); connect(trackerLabel, &QCheckBox::toggled, pref, &Preferences::setTrackerFilterState); - - connect(this, qOverload(&TransferListFiltersWidget::trackerSuccess) - , m_trackerFilters, &TrackerFiltersList::trackerSuccess); - connect(this, qOverload(&TransferListFiltersWidget::trackerError) - , m_trackerFilters, &TrackerFiltersList::trackerError); - connect(this, qOverload(&TransferListFiltersWidget::trackerWarning) - , m_trackerFilters, &TrackerFiltersList::trackerWarning); } void TransferListFiltersWidget::setDownloadTrackerFavicon(bool value) @@ -763,19 +789,9 @@ void TransferListFiltersWidget::changeTrackerless(const BitTorrent::Torrent *tor m_trackerFilters->changeTrackerless(trackerless, torrent->id()); } -void TransferListFiltersWidget::trackerSuccess(const BitTorrent::Torrent *torrent, const QString &tracker) -{ - emit trackerSuccess(torrent->id(), tracker); -} - -void TransferListFiltersWidget::trackerWarning(const BitTorrent::Torrent *torrent, const QString &tracker) -{ - emit trackerWarning(torrent->id(), tracker); -} - -void TransferListFiltersWidget::trackerError(const BitTorrent::Torrent *torrent, const QString &tracker) +void TransferListFiltersWidget::trackerEntriesUpdated(const QHash> &updateInfos) { - emit trackerError(torrent->id(), tracker); + m_trackerFilters->handleTrackerEntriesUpdated(updateInfos); } void TransferListFiltersWidget::onCategoryFilterStateChanged(bool enabled) diff --git a/src/gui/transferlistfilterswidget.h b/src/gui/transferlistfilterswidget.h index 21e468421..c60f6a4ef 100644 --- a/src/gui/transferlistfilterswidget.h +++ b/src/gui/transferlistfilterswidget.h @@ -33,6 +33,7 @@ #include #include "base/bittorrent/infohash.h" +#include "base/bittorrent/session.h" #include "base/bittorrent/trackerentry.h" #include "base/path.h" @@ -41,11 +42,6 @@ class QResizeEvent; class TransferListWidget; -namespace BitTorrent -{ - class Torrent; -} - namespace Net { struct DownloadResult; @@ -107,14 +103,10 @@ public: // Redefine addItem() to make sure the list stays sorted void addItem(const QString &tracker, const BitTorrent::TorrentID &id); - void removeItem(const QString &tracker, const BitTorrent::TorrentID &id); + void removeItem(const QString &trackerURL, const BitTorrent::TorrentID &id); void changeTrackerless(bool trackerless, const BitTorrent::TorrentID &id); void setDownloadTrackerFavicon(bool value); - -public slots: - void trackerSuccess(const BitTorrent::TorrentID &id, const QString &tracker); - void trackerError(const BitTorrent::TorrentID &id, const QString &tracker); - void trackerWarning(const BitTorrent::TorrentID &id, const QString &tracker); + void handleTrackerEntriesUpdated(const QHash> &updateInfos); private slots: void handleFavicoDownloadFinished(const Net::DownloadResult &result); @@ -155,14 +147,7 @@ public slots: void addTrackers(const BitTorrent::Torrent *torrent, const QVector &trackers); void removeTrackers(const BitTorrent::Torrent *torrent, const QVector &trackers); void changeTrackerless(const BitTorrent::Torrent *torrent, bool trackerless); - void trackerSuccess(const BitTorrent::Torrent *torrent, const QString &tracker); - void trackerWarning(const BitTorrent::Torrent *torrent, const QString &tracker); - void trackerError(const BitTorrent::Torrent *torrent, const QString &tracker); - -signals: - void trackerSuccess(const BitTorrent::TorrentID &id, const QString &tracker); - void trackerError(const BitTorrent::TorrentID &id, const QString &tracker); - void trackerWarning(const BitTorrent::TorrentID &id, const QString &tracker); + void trackerEntriesUpdated(const QHash> &updateInfos); private slots: void onCategoryFilterStateChanged(bool enabled);