Skip to content

Commit

Permalink
Support fetching tracker list from URL
Browse files Browse the repository at this point in the history
Trackers specified at the URL will be added to newly added public torrents.

This feature is adapted from qBittorrent-Enhanced-Edition to allow for automatically adding trackers retrieved from a URL. @ngosang's trackerlist repo is a good example, however I've opted not to include a default URL.

Partially addresses #14535.
PR #21828.
  • Loading branch information
Piccirello authored Jan 8, 2025
1 parent 4f3d779 commit 4fc36b9
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/base/bittorrent/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ namespace BitTorrent
virtual Path finishedTorrentExportDirectory() const = 0;
virtual void setFinishedTorrentExportDirectory(const Path &path) = 0;

virtual bool isAddTrackersFromURLEnabled() const = 0;
virtual void setAddTrackersFromURLEnabled(bool enabled) = 0;
virtual QString additionalTrackersURL() const = 0;
virtual void setAdditionalTrackersURL(const QString &url) = 0;
virtual QString additionalTrackersFromURL() const = 0;

virtual int globalDownloadSpeedLimit() const = 0;
virtual void setGlobalDownloadSpeedLimit(int limit) = 0;
virtual int globalUploadSpeedLimit() const = 0;
Expand Down
108 changes: 108 additions & 0 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#include "base/algorithm.h"
#include "base/global.h"
#include "base/logger.h"
#include "base/net/downloadmanager.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/preferences.h"
#include "base/profile.h"
Expand Down Expand Up @@ -463,6 +464,8 @@ SessionImpl::SessionImpl(QObject *parent)
, m_blockPeersOnPrivilegedPorts(BITTORRENT_SESSION_KEY(u"BlockPeersOnPrivilegedPorts"_s), false)
, m_isAddTrackersEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersEnabled"_s), false)
, m_additionalTrackers(BITTORRENT_SESSION_KEY(u"AdditionalTrackers"_s))
, m_isAddTrackersFromURLEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersFromURLEnabled"_s), false)
, m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r;})
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s), -1, lowerLimited(-1))
, m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s), -1, lowerLimited(-1))
Expand Down Expand Up @@ -617,6 +620,15 @@ SessionImpl::SessionImpl(QObject *parent)
enableTracker(isTrackerEnabled());

prepareStartup();

m_updateTrackersFromURLTimer = new QTimer(this);
m_updateTrackersFromURLTimer->setInterval(24h);
connect(m_updateTrackersFromURLTimer, &QTimer::timeout, this, &SessionImpl::updateTrackersFromURL);
if (isAddTrackersFromURLEnabled())
{
updateTrackersFromURL();
m_updateTrackersFromURLTimer->start();
}
}

SessionImpl::~SessionImpl()
Expand Down Expand Up @@ -2268,6 +2280,11 @@ void SessionImpl::populateAdditionalTrackers()
m_additionalTrackerEntries = parseTrackerEntries(additionalTrackers());
}

void SessionImpl::populateAdditionalTrackersFromURL()
{
m_additionalTrackerEntriesFromURL = parseTrackerEntries(additionalTrackersFromURL());
}

void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
{
if (!torrent->isFinished() || torrent->isForced())
Expand Down Expand Up @@ -2887,6 +2904,21 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
}
}

if (isAddTrackersFromURLEnabled() && !(hasMetadata && p.ti->priv()))
{
const auto maxTierIter = std::max_element(p.tracker_tiers.cbegin(), p.tracker_tiers.cend());
const int baseTier = (maxTierIter != p.tracker_tiers.cend()) ? (*maxTierIter + 1) : 0;

p.trackers.reserve(p.trackers.size() + static_cast<std::size_t>(m_additionalTrackerEntriesFromURL.size()));
p.tracker_tiers.reserve(p.trackers.size() + static_cast<std::size_t>(m_additionalTrackerEntriesFromURL.size()));
p.tracker_tiers.resize(p.trackers.size(), 0);
for (const TrackerEntry &trackerEntry : asConst(m_additionalTrackerEntriesFromURL))
{
p.trackers.emplace_back(trackerEntry.url.toStdString());
p.tracker_tiers.emplace_back(Utils::Number::clampingAdd(trackerEntry.tier, baseTier));
}
}

p.upload_limit = addTorrentParams.uploadLimit;
p.download_limit = addTorrentParams.downloadLimit;

Expand Down Expand Up @@ -3879,6 +3911,82 @@ void SessionImpl::setAdditionalTrackers(const QString &trackers)
populateAdditionalTrackers();
}

bool SessionImpl::isAddTrackersFromURLEnabled() const
{
return m_isAddTrackersFromURLEnabled;
}

void SessionImpl::setAddTrackersFromURLEnabled(const bool enabled)
{
if (enabled != isAddTrackersFromURLEnabled())
{
m_isAddTrackersFromURLEnabled = enabled;
if (enabled)
{
updateTrackersFromURL();
m_updateTrackersFromURLTimer->start();
}
else
{
m_updateTrackersFromURLTimer->stop();
setAdditionalTrackersFromURL({});
}
}
}

QString SessionImpl::additionalTrackersURL() const
{
return m_additionalTrackersURL;
}

void SessionImpl::setAdditionalTrackersURL(const QString &url)
{
if (url != additionalTrackersURL())
{
m_additionalTrackersURL = url.trimmed();
if (isAddTrackersFromURLEnabled())
updateTrackersFromURL();
}
}

QString SessionImpl::additionalTrackersFromURL() const
{
return m_additionalTrackersFromURL;
}

void SessionImpl::setAdditionalTrackersFromURL(const QString &trackers)
{
if (trackers != additionalTrackersFromURL())
{
m_additionalTrackersFromURL = trackers;
populateAdditionalTrackersFromURL();
}
}

void SessionImpl::updateTrackersFromURL()
{
const QString url = additionalTrackersURL();
if (url.isEmpty())
{
setAdditionalTrackersFromURL({});
}
else
{
Net::DownloadManager::instance()->download(Net::DownloadRequest(url)
, Preferences::instance()->useProxyForGeneralPurposes(), this, [this](const Net::DownloadResult &result)
{
if (result.status == Net::DownloadStatus::Success)
{
setAdditionalTrackersFromURL(QString::fromUtf8(result.data));
LogMsg(tr("Tracker list updated"), Log::INFO);
return;
}

LogMsg(tr("Failed to update tracker list. Reason: \"%1\"").arg(result.errorString), Log::WARNING);
});
}
}

bool SessionImpl::isIPFilteringEnabled() const
{
return m_isIPFilteringEnabled;
Expand Down
17 changes: 17 additions & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,12 @@ namespace BitTorrent
m_asyncWorker->start(std::forward<Func>(func));
}

bool isAddTrackersFromURLEnabled() const override;
void setAddTrackersFromURLEnabled(bool enabled) override;
QString additionalTrackersURL() const override;
void setAdditionalTrackersURL(const QString &url) override;
QString additionalTrackersFromURL() const override;

signals:
void addTorrentAlertsReceived(qsizetype count);

Expand Down Expand Up @@ -596,6 +602,8 @@ namespace BitTorrent
void saveTorrentsQueue();
void removeTorrentsQueue();

void populateAdditionalTrackersFromURL();

std::vector<lt::alert *> getPendingAlerts(lt::time_duration time = lt::time_duration::zero()) const;

void moveTorrentStorage(const MoveStorageJob &job) const;
Expand All @@ -614,6 +622,9 @@ namespace BitTorrent

void handleRemovedTorrent(const TorrentID &torrentID, const QString &partfileRemoveError = {});

void setAdditionalTrackersFromURL(const QString &trackers);
void updateTrackersFromURL();

CachedSettingValue<QString> m_DHTBootstrapNodes;
CachedSettingValue<bool> m_isDHTEnabled;
CachedSettingValue<bool> m_isLSDEnabled;
Expand Down Expand Up @@ -676,6 +687,8 @@ namespace BitTorrent
CachedSettingValue<bool> m_blockPeersOnPrivilegedPorts;
CachedSettingValue<bool> m_isAddTrackersEnabled;
CachedSettingValue<QString> m_additionalTrackers;
CachedSettingValue<bool> m_isAddTrackersFromURLEnabled;
CachedSettingValue<QString> m_additionalTrackersURL;
CachedSettingValue<qreal> m_globalMaxRatio;
CachedSettingValue<int> m_globalMaxSeedingMinutes;
CachedSettingValue<int> m_globalMaxInactiveSeedingMinutes;
Expand Down Expand Up @@ -749,6 +762,9 @@ namespace BitTorrent
bool m_IPFilteringConfigured = false;
mutable bool m_listenInterfaceConfigured = false;

QString m_additionalTrackersFromURL;
QTimer *m_updateTrackersFromURLTimer = nullptr;

bool m_isRestored = false;
bool m_isPaused = isStartPaused();

Expand All @@ -759,6 +775,7 @@ namespace BitTorrent

int m_numResumeData = 0;
QList<TrackerEntry> m_additionalTrackerEntries;
QList<TrackerEntry> m_additionalTrackerEntriesFromURL;
QList<QRegularExpression> m_excludedFileNamesRegExpList;

// Statistics
Expand Down
11 changes: 11 additions & 0 deletions src/gui/optionsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "base/bittorrent/sharelimitaction.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/net/downloadmanager.h"
#include "base/net/portforwarder.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/path.h"
Expand Down Expand Up @@ -1151,6 +1152,10 @@ void OptionsDialog::loadBittorrentTabOptions()
m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled());
m_ui->textTrackers->setPlainText(session->additionalTrackers());

m_ui->checkAddTrackersFromURL->setChecked(session->isAddTrackersFromURLEnabled());
m_ui->textTrackersURL->setText(session->additionalTrackersURL());
m_ui->textTrackersFromURL->setPlainText(session->additionalTrackersFromURL());

connect(m_ui->checkDHT, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkPeX, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkLSD, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
Expand Down Expand Up @@ -1184,6 +1189,9 @@ void OptionsDialog::loadBittorrentTabOptions()

connect(m_ui->checkEnableAddTrackers, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textTrackers, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton);

connect(m_ui->checkAddTrackersFromURL, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textTrackersURL, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
}

void OptionsDialog::saveBittorrentTabOptions() const
Expand Down Expand Up @@ -1221,6 +1229,9 @@ void OptionsDialog::saveBittorrentTabOptions() const

session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());

session->setAddTrackersFromURLEnabled(m_ui->checkAddTrackersFromURL->isChecked());
session->setAdditionalTrackersURL(m_ui->textTrackersURL->text());
}

void OptionsDialog::loadRSSTabOptions()
Expand Down
43 changes: 43 additions & 0 deletions src/gui/optionsdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -3148,6 +3148,49 @@ Disable encryption: Only connect to peers without protocol encryption</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="checkAddTrackersFromURL">
<property name="title">
<string>Automatically append trackers from URL to new downloads:</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="checkAddTrackersFromURLLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_21">
<item>
<widget class="QLabel" name="labelCustomizeTrackersListUrl">
<property name="text">
<string>URL:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="textTrackersURL"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labeltrackersFromURL">
<property name="text">
<string>Fetched trackers</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="textTrackersFromURL">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
Expand Down
7 changes: 7 additions & 0 deletions src/webui/api/appcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ void AppController::preferencesAction()
// Add trackers
data[u"add_trackers_enabled"_s] = session->isAddTrackersEnabled();
data[u"add_trackers"_s] = session->additionalTrackers();
data[u"add_trackers_from_url_enabled"_s] = session->isAddTrackersFromURLEnabled();
data[u"add_trackers_url"_s] = session->additionalTrackersURL();
data[u"add_trackers_url_list"_s] = session->additionalTrackersFromURL();

// WebUI
// HTTP Server
Expand Down Expand Up @@ -863,6 +866,10 @@ void AppController::setPreferencesAction()
session->setAddTrackersEnabled(it.value().toBool());
if (hasKey(u"add_trackers"_s))
session->setAdditionalTrackers(it.value().toString());
if (hasKey(u"add_trackers_from_url_enabled"_s))
session->setAddTrackersFromURLEnabled(it.value().toBool());
if (hasKey(u"add_trackers_url"_s))
session->setAdditionalTrackersURL(it.value().toString());

// WebUI
// HTTP Server
Expand Down
29 changes: 29 additions & 0 deletions src/webui/www/private/views/preferences.html
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,23 @@
</legend>
<textarea id="add_trackers_textarea" rows="5" cols="70" aria-labelledby="addTrackersLabel"></textarea>
</fieldset>

<fieldset class="settings">
<legend>
<input type="checkbox" id="addTrackersFromURLCheckbox" onclick="qBittorrent.Preferences.updateAddTrackersFromURLEnabled();">
<label for="addTrackersFromURLCheckbox">QBT_TR(Automatically append trackers from URL to new downloads:)QBT_TR[CONTEXT=OptionsDialog]</label>
</legend>
<div class="formRow">
<label for="addTrackersURL">QBT_TR(URL:)QBT_TR[CONTEXT=OptionsDialog]</label>
<input type="text" id="addTrackersURL" style="width: 40em;">
</div>
<div class="formRow">
<fieldset class="settings">
<legend id="fetchedTrackersFromURLLabel">QBT_TR(Fetched trackers)QBT_TR[CONTEXT=OptionsDialog]</legend>
<textarea id="addTrackersURLListTextarea" aria-labelledby="fetchedTrackersFromURLLabel" rows="5" cols="70" readonly></textarea>
</fieldset>
</div>
</fieldset>
</div>

<div id="RSSTab" class="PrefTab invisible">
Expand Down Expand Up @@ -1736,6 +1753,7 @@
updateSlowTorrentsSettings: updateSlowTorrentsSettings,
updateMaxRatioTimeEnabled: updateMaxRatioTimeEnabled,
updateAddTrackersEnabled: updateAddTrackersEnabled,
updateAddTrackersFromURLEnabled: updateAddTrackersFromURLEnabled,
updateHttpsSettings: updateHttpsSettings,
updateBypasssAuthSettings: updateBypasssAuthSettings,
updateAlternativeWebUISettings: updateAlternativeWebUISettings,
Expand Down Expand Up @@ -2016,6 +2034,11 @@
$("add_trackers_textarea").disabled = !isAddTrackersEnabled;
};

const updateAddTrackersFromURLEnabled = () => {
const isAddTrackersFromURLEnabled = $("addTrackersFromURLCheckbox").checked;
$("addTrackersURL").disabled = !isAddTrackersFromURLEnabled;
};

// WebUI tab
const updateHttpsSettings = () => {
const isUseHttpsEnabled = $("use_https_checkbox").checked;
Expand Down Expand Up @@ -2442,7 +2465,11 @@
// Add trackers
$("add_trackers_checkbox").checked = pref.add_trackers_enabled;
$("add_trackers_textarea").value = pref.add_trackers;
$("addTrackersFromURLCheckbox").checked = pref.add_trackers_from_url_enabled;
$("addTrackersURLListTextarea").value = pref.add_trackers_url_list;
$("addTrackersURL").value = pref.add_trackers_url;
updateAddTrackersEnabled();
updateAddTrackersFromURLEnabled();

// RSS Tab
$("enable_fetching_rss_feeds_checkbox").checked = pref.rss_processing_enabled;
Expand Down Expand Up @@ -2876,6 +2903,8 @@
// Add trackers
settings["add_trackers_enabled"] = $("add_trackers_checkbox").checked;
settings["add_trackers"] = $("add_trackers_textarea").value;
settings["add_trackers_from_url_enabled"] = $("addTrackersFromURLCheckbox").checked;
settings["add_trackers_url"] = $("addTrackersURL").value;

// RSS Tab
settings["rss_processing_enabled"] = $("enable_fetching_rss_feeds_checkbox").checked;
Expand Down

0 comments on commit 4fc36b9

Please sign in to comment.