Revamp tracker entries handling

PR #17017.
This commit is contained in:
Vladimir Golovnev
2022-05-22 09:09:11 +03:00
committed by GitHub
parent 8c0cd09823
commit 7e0cd223fd
22 changed files with 366 additions and 334 deletions

View File

@@ -1495,6 +1495,7 @@ void MainWindow::showFiltersSidebar(const bool show)
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::trackersChanged, m_transferListFiltersWidget, &TransferListFiltersWidget::refreshTrackers);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerlessStateChanged, m_transferListFiltersWidget, &TransferListFiltersWidget::changeTrackerless);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerEntriesUpdated, m_transferListFiltersWidget, &TransferListFiltersWidget::trackerEntriesUpdated);
}

View File

@@ -473,18 +473,7 @@ void TrackerListWidget::deleteSelectedTrackers()
delete item;
}
// Iterate over the trackers and remove the selected ones
const QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
QVector<BitTorrent::TrackerEntry> remainingTrackers;
remainingTrackers.reserve(trackers.size());
for (const BitTorrent::TrackerEntry &entry : trackers)
{
if (!urlsToRemove.contains(entry.url))
remainingTrackers.push_back(entry);
}
torrent->replaceTrackers(remainingTrackers);
torrent->removeTrackers(urlsToRemove);
if (!torrent->isPaused())
torrent->forceReannounce();

View File

@@ -38,6 +38,7 @@
#include <QUrl>
#include <QVBoxLayout>
#include "base/algorithm.h"
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrent.h"
#include "base/global.h"
@@ -376,7 +377,8 @@ TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *tran
auto *warningTracker = new QListWidgetItem(this);
warningTracker->setData(Qt::DisplayRole, tr("Warning (0)"));
warningTracker->setData(Qt::DecorationRole, style()->standardIcon(QStyle::SP_MessageBoxWarning));
m_trackers[NULL_HOST] = {};
m_trackers[NULL_HOST] = {{}, noTracker};
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
toggleFilter(Preferences::instance()->getTrackerFilterState());
@@ -388,6 +390,70 @@ TrackerFiltersList::~TrackerFiltersList()
Utils::Fs::removeFile(iconPath);
}
void TrackerFiltersList::addTrackers(const BitTorrent::Torrent *torrent, const QVector<BitTorrent::TrackerEntry> &trackers)
{
const BitTorrent::TorrentID torrentID = torrent->id();
for (const BitTorrent::TrackerEntry &tracker : trackers)
addItem(tracker.url, torrentID);
}
void TrackerFiltersList::removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers)
{
const BitTorrent::TorrentID torrentID = torrent->id();
for (const QString &tracker : trackers)
removeItem(tracker, torrentID);
}
void TrackerFiltersList::refreshTrackers(const BitTorrent::Torrent *torrent)
{
const BitTorrent::TorrentID torrentID = torrent->id();
m_errors.remove(torrentID);
m_warnings.remove(torrentID);
Algorithm::removeIf(m_trackers, [this, &torrentID](const QString &host, TrackerData &trackerData)
{
QSet<BitTorrent::TorrentID> &torrentIDs = trackerData.torrents;
if (!torrentIDs.remove(torrentID))
return false;
QListWidgetItem *trackerItem = trackerData.item;
if (!host.isEmpty() && torrentIDs.isEmpty())
{
if (currentItem() == trackerItem)
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
delete trackerItem;
return true;
}
trackerItem->setText(u"%1 (%2)"_qs.arg((host.isEmpty() ? tr("Trackerless") : host), QString::number(torrentIDs.size())));
return false;
});
const QVector<BitTorrent::TrackerEntry> trackerEntries = torrent->trackers();
const bool isTrackerless = trackerEntries.isEmpty();
if (isTrackerless)
{
addItem(NULL_HOST, torrentID);
}
else
{
for (const BitTorrent::TrackerEntry &trackerEntry : trackerEntries)
addItem(trackerEntry.url, torrentID);
}
updateGeometry();
}
void TrackerFiltersList::changeTrackerless(const BitTorrent::Torrent *torrent, const bool trackerless)
{
if (trackerless)
addItem(NULL_HOST, torrent->id());
else
removeItem(NULL_HOST, torrent->id());
}
void TrackerFiltersList::addItem(const QString &tracker, const BitTorrent::TorrentID &id)
{
const QString host = getHost(tracker);
@@ -400,9 +466,7 @@ void TrackerFiltersList::addItem(const QString &tracker, const BitTorrent::Torre
if (trackersIt->torrents.contains(id))
return;
trackerItem = (host == NULL_HOST)
? item(TRACKERLESS_ROW)
: trackersIt->item;
trackerItem = trackersIt->item;
}
else
{
@@ -421,15 +485,7 @@ void TrackerFiltersList::addItem(const QString &tracker, const BitTorrent::Torre
QSet<BitTorrent::TorrentID> &torrentIDs = trackersIt->torrents;
torrentIDs.insert(id);
if (host == NULL_HOST)
{
trackerItem->setText(tr("Trackerless (%1)").arg(torrentIDs.size()));
if (currentRow() == TRACKERLESS_ROW)
applyFilter(TRACKERLESS_ROW);
return;
}
trackerItem->setText(u"%1 (%2)"_qs.arg(host, QString::number(torrentIDs.size())));
trackerItem->setText(u"%1 (%2)"_qs.arg(((host == NULL_HOST) ? tr("Trackerless") : host), QString::number(torrentIDs.size())));
if (exists)
{
if (item(currentRow()) == trackerItem)
@@ -496,7 +552,7 @@ void TrackerFiltersList::removeItem(const QString &trackerURL, const BitTorrent:
trackerItem = m_trackers.value(host).item;
if (torrentIDs.empty())
if (torrentIDs.isEmpty())
{
if (currentItem() == trackerItem)
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
@@ -521,14 +577,6 @@ void TrackerFiltersList::removeItem(const QString &trackerURL, const BitTorrent:
applyFilter(currentRow());
}
void TrackerFiltersList::changeTrackerless(const bool trackerless, const BitTorrent::TorrentID &id)
{
if (trackerless)
addItem(NULL_HOST, id);
else
removeItem(NULL_HOST, id);
}
void TrackerFiltersList::setDownloadTrackerFavicon(bool value)
{
if (value == m_downloadTrackerFavicon) return;
@@ -549,49 +597,51 @@ void TrackerFiltersList::setDownloadTrackerFavicon(bool value)
}
}
void TrackerFiltersList::handleTrackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QHash<QString, BitTorrent::TrackerEntryUpdateInfo>> &updateInfos)
void TrackerFiltersList::handleTrackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos)
{
for (auto torrentsIt = updateInfos.cbegin(); torrentsIt != updateInfos.cend(); ++torrentsIt)
{
const BitTorrent::TorrentID id = torrentsIt.key()->id();
const QHash<QString, BitTorrent::TrackerEntryUpdateInfo> &infos = torrentsIt.value();
const BitTorrent::Torrent *torrent = torrentsIt.key();
const QSet<QString> &trackerURLs = torrentsIt.value();
const BitTorrent::TorrentID id = torrent->id();
auto errorHashesIt = m_errors.find(id);
auto warningHashesIt = m_warnings.find(id);
for (auto trackerIt = infos.cbegin(); trackerIt != infos.cend(); ++trackerIt)
const QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
for (const BitTorrent::TrackerEntry &trackerEntry : trackers)
{
const QString &trackerURL = trackerIt.key();
const BitTorrent::TrackerEntryUpdateInfo &updateInfo = trackerIt.value();
if (!trackerURLs.contains(trackerEntry.url))
continue;
if (updateInfo.status == BitTorrent::TrackerEntry::Working)
if (trackerEntry.status == BitTorrent::TrackerEntry::Working)
{
if (errorHashesIt != m_errors.end())
{
QSet<QString> &errored = errorHashesIt.value();
errored.remove(trackerURL);
errored.remove(trackerEntry.url);
}
if (!updateInfo.hasMessages)
if (trackerEntry.message.isEmpty())
{
if (warningHashesIt != m_warnings.end())
{
QSet<QString> &warned = *warningHashesIt;
warned.remove(trackerURL);
warned.remove(trackerEntry.url);
}
}
else
{
if (warningHashesIt == m_warnings.end())
warningHashesIt = m_warnings.insert(id, {});
warningHashesIt.value().insert(trackerURL);
warningHashesIt.value().insert(trackerEntry.url);
}
}
else if (updateInfo.status == BitTorrent::TrackerEntry::NotWorking)
else if (trackerEntry.status == BitTorrent::TrackerEntry::NotWorking)
{
if (errorHashesIt == m_errors.end())
errorHashesIt = m_errors.insert(id, {});
errorHashesIt.value().insert(trackerURL);
errorHashesIt.value().insert(trackerEntry.url);
}
}
@@ -680,13 +730,13 @@ void TrackerFiltersList::applyFilter(const int row)
void TrackerFiltersList::handleNewTorrent(BitTorrent::Torrent *const torrent)
{
const BitTorrent::TorrentID torrentID {torrent->id()};
const QVector<QString> trackerURLs {torrent->trackerURLs()};
for (const QString &trackerURL : trackerURLs)
addItem(trackerURL, torrentID);
const BitTorrent::TorrentID torrentID = torrent->id();
const QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
for (const BitTorrent::TrackerEntry &tracker : trackers)
addItem(tracker.url, torrentID);
// Check for trackerless torrent
if (trackerURLs.isEmpty())
if (trackers.isEmpty())
addItem(NULL_HOST, torrentID);
item(ALL_ROW)->setText(tr("All (%1)", "this is for the tracker filter").arg(++m_totalTorrents));
@@ -694,13 +744,13 @@ void TrackerFiltersList::handleNewTorrent(BitTorrent::Torrent *const torrent)
void TrackerFiltersList::torrentAboutToBeDeleted(BitTorrent::Torrent *const torrent)
{
const BitTorrent::TorrentID torrentID {torrent->id()};
const QVector<QString> trackerURLs {torrent->trackerURLs()};
for (const QString &trackerURL : trackerURLs)
removeItem(trackerURL, torrentID);
const BitTorrent::TorrentID torrentID = torrent->id();
const QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
for (const BitTorrent::TrackerEntry &tracker : trackers)
removeItem(tracker.url, torrentID);
// Check for trackerless torrent
if (trackerURLs.isEmpty())
if (trackers.isEmpty())
removeItem(NULL_HOST, torrentID);
item(ALL_ROW)->setText(tr("All (%1)", "this is for the tracker filter").arg(--m_totalTorrents));
@@ -838,22 +888,25 @@ void TransferListFiltersWidget::setDownloadTrackerFavicon(bool value)
void TransferListFiltersWidget::addTrackers(const BitTorrent::Torrent *torrent, const QVector<BitTorrent::TrackerEntry> &trackers)
{
for (const BitTorrent::TrackerEntry &tracker : trackers)
m_trackerFilters->addItem(tracker.url, torrent->id());
m_trackerFilters->addTrackers(torrent, trackers);
}
void TransferListFiltersWidget::removeTrackers(const BitTorrent::Torrent *torrent, const QVector<BitTorrent::TrackerEntry> &trackers)
void TransferListFiltersWidget::removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers)
{
for (const BitTorrent::TrackerEntry &tracker : trackers)
m_trackerFilters->removeItem(tracker.url, torrent->id());
m_trackerFilters->removeTrackers(torrent, trackers);
}
void TransferListFiltersWidget::refreshTrackers(const BitTorrent::Torrent *torrent)
{
m_trackerFilters->refreshTrackers(torrent);
}
void TransferListFiltersWidget::changeTrackerless(const BitTorrent::Torrent *torrent, const bool trackerless)
{
m_trackerFilters->changeTrackerless(trackerless, torrent->id());
m_trackerFilters->changeTrackerless(torrent, trackerless);
}
void TransferListFiltersWidget::trackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QHash<QString, BitTorrent::TrackerEntryUpdateInfo>> &updateInfos)
void TransferListFiltersWidget::trackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos)
{
m_trackerFilters->handleTrackerEntriesUpdated(updateInfos);
}

View File

@@ -124,12 +124,12 @@ public:
TrackerFiltersList(QWidget *parent, TransferListWidget *transferList, bool downloadFavicon);
~TrackerFiltersList() override;
// Redefine addItem() to make sure the list stays sorted
void addItem(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 addTrackers(const BitTorrent::Torrent *torrent, const QVector<BitTorrent::TrackerEntry> &trackers);
void removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers);
void refreshTrackers(const BitTorrent::Torrent *torrent);
void changeTrackerless(const BitTorrent::Torrent *torrent, bool trackerless);
void handleTrackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos);
void setDownloadTrackerFavicon(bool value);
void handleTrackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QHash<QString, BitTorrent::TrackerEntryUpdateInfo>> &updateInfos);
private slots:
void handleFavicoDownloadFinished(const Net::DownloadResult &result);
@@ -141,6 +141,9 @@ private:
void applyFilter(int row) override;
void handleNewTorrent(BitTorrent::Torrent *const torrent) override;
void torrentAboutToBeDeleted(BitTorrent::Torrent *const torrent) override;
void addItem(const QString &tracker, const BitTorrent::TorrentID &id);
void removeItem(const QString &trackerURL, const BitTorrent::TorrentID &id);
QString trackerFromRow(int row) const;
int rowFromTracker(const QString &tracker) const;
QSet<BitTorrent::TorrentID> getTorrentIDs(int row) const;
@@ -174,9 +177,10 @@ public:
public slots:
void addTrackers(const BitTorrent::Torrent *torrent, const QVector<BitTorrent::TrackerEntry> &trackers);
void removeTrackers(const BitTorrent::Torrent *torrent, const QVector<BitTorrent::TrackerEntry> &trackers);
void removeTrackers(const BitTorrent::Torrent *torrent, const QStringList &trackers);
void refreshTrackers(const BitTorrent::Torrent *torrent);
void changeTrackerless(const BitTorrent::Torrent *torrent, bool trackerless);
void trackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QHash<QString, BitTorrent::TrackerEntryUpdateInfo>> &updateInfos);
void trackerEntriesUpdated(const QHash<BitTorrent::Torrent *, QSet<QString>> &updateInfos);
private slots:
void onCategoryFilterStateChanged(bool enabled);