Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-set a torrent's parameters based on metadata #20502

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_library(qbt_base STATIC
bittorrent/torrentdescriptor.h
bittorrent/torrentimpl.h
bittorrent/torrentinfo.h
bittorrent/torrentparamrules.h
bittorrent/tracker.h
bittorrent/trackerentry.h
concepts/explicitlyconvertibleto.h
Expand Down Expand Up @@ -148,6 +149,7 @@ add_library(qbt_base STATIC
bittorrent/torrentdescriptor.cpp
bittorrent/torrentimpl.cpp
bittorrent/torrentinfo.cpp
bittorrent/torrentparamrules.cpp
bittorrent/tracker.cpp
bittorrent/trackerentry.cpp
exceptions.cpp
Expand Down
9 changes: 7 additions & 2 deletions src/base/addtorrentmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "base/bittorrent/infohash.h"
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrentdescriptor.h"
#include "base/bittorrent/torrentparamrules.h"
#include "base/logger.h"
#include "base/net/downloadmanager.h"
#include "base/preferences.h"
Expand Down Expand Up @@ -177,15 +178,15 @@ void AddTorrentManager::releaseTorrentFileGuard(const QString &source)
}

bool AddTorrentManager::processTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr
, const BitTorrent::AddTorrentParams &addTorrentParams)
, BitTorrent::AddTorrentParams addTorrentParams)
{
const BitTorrent::InfoHash infoHash = torrentDescr.infoHash();

const bool hasMetadata = torrentDescr.info().has_value();
if (BitTorrent::Torrent *torrent = btSession()->findTorrent(infoHash))
{
// a duplicate torrent is being added

const bool hasMetadata = torrentDescr.info().has_value();
if (hasMetadata)
{
// Trying to set metadata to existing torrent in case if it has none
Expand Down Expand Up @@ -213,5 +214,9 @@ bool AddTorrentManager::processTorrent(const QString &source, const BitTorrent::
return false;
}

// If metadata is not available now, rules will be applied after it is downloaded.
if (hasMetadata)
btSession()->applyTorrentParamRules(torrentDescr, &addTorrentParams);

return addTorrentToSession(source, torrentDescr, addTorrentParams);
}
2 changes: 1 addition & 1 deletion src/base/addtorrentmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class AddTorrentManager : public ApplicationComponent<QObject>
void onSessionTorrentAdded(BitTorrent::Torrent *torrent);
void onSessionAddTorrentFailed(const BitTorrent::InfoHash &infoHash, const QString &reason);
bool processTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr
, const BitTorrent::AddTorrentParams &addTorrentParams);
, BitTorrent::AddTorrentParams addTorrentParams);

BitTorrent::Session *m_btSession = nullptr;
QHash<QString, BitTorrent::AddTorrentParams> m_downloadedTorrents;
Expand Down
2 changes: 2 additions & 0 deletions src/base/bittorrent/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <QtContainerFwd>
#include <QObject>

#include "base/bittorrent/torrentparamrules.h"
#include "base/pathfwd.h"
#include "base/tagset.h"
#include "addtorrentparams.h"
Expand Down Expand Up @@ -452,6 +453,7 @@ namespace BitTorrent
virtual void banIP(const QString &ip) = 0;

virtual bool isKnownTorrent(const InfoHash &infoHash) const = 0;
virtual void applyTorrentParamRules(const TorrentDescriptor &torrentDescr, AddTorrentParams *params) const = 0;
virtual bool addTorrent(const TorrentDescriptor &torrentDescr, const AddTorrentParams &params = {}) = 0;
virtual bool deleteTorrent(const TorrentID &id, DeleteOption deleteOption = DeleteOption::DeleteTorrent) = 0;
virtual bool downloadMetadata(const TorrentDescriptor &torrentDescr) = 0;
Expand Down
50 changes: 50 additions & 0 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ using namespace std::chrono_literals;
using namespace BitTorrent;

const Path CATEGORIES_FILE_NAME {u"categories.json"_s};
const Path TORRENT_PARAM_RULES_FILE_NAME {u"auto_torrent_customizer_rules.json"_s};
const int MAX_PROCESSING_RESUMEDATA_COUNT = 50;
const int STATISTICS_SAVE_INTERVAL = std::chrono::milliseconds(15min).count();

Expand Down Expand Up @@ -580,6 +581,9 @@ SessionImpl::SessionImpl(QObject *parent)
connect(m_ioThread.get(), &QThread::finished, m_fileSearcher, &QObject::deleteLater);
connect(m_fileSearcher, &FileSearcher::searchFinished, this, &SessionImpl::fileSearchFinished);

m_torrentParamRules = new TorrentParamRules(this);
loadTorrentParamRules();

m_ioThread->start();

initMetrics();
Expand Down Expand Up @@ -4842,6 +4846,11 @@ void SessionImpl::setMaxRatioAction(const MaxRatioAction act)
m_maxRatioAction = static_cast<int>(act);
}

void SessionImpl::applyTorrentParamRules(const TorrentDescriptor &torrentDescr, AddTorrentParams *params) const
{
m_torrentParamRules->apply(torrentDescr, params);
}

bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const
{
const bool isHybrid = infoHash.isHybrid();
Expand Down Expand Up @@ -4939,6 +4948,8 @@ void SessionImpl::handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const

void SessionImpl::handleTorrentMetadataReceived(TorrentImpl *const torrent)
{
qDebug() << "Metadata received for " << torrent->name();
m_torrentParamRules->apply(torrent);
if (!torrentExportDirectory().isEmpty())
exportTorrentFile(torrent, torrentExportDirectory());

Expand Down Expand Up @@ -5200,6 +5211,45 @@ void SessionImpl::loadCategories()
}
}

void SessionImpl::loadTorrentParamRules()
{
const Path path = specialFolderLocation(SpecialFolder::Config) / TORRENT_PARAM_RULES_FILE_NAME;
const QString pathStr = path.toString();
if (!path.exists())
{
LogMsg(tr("Auto torrent customizer rules not found at \"%1\"").arg(pathStr), Log::INFO);
return;
}

constexpr int fileMaxSize = 1024 * 1024;
const auto readResult = Utils::IO::readFile(path, fileMaxSize);
if (!readResult)
{
LogMsg(tr("Failed to read auto torrent customizer rules file \"%1\"").arg(readResult.error().message), Log::WARNING);
return;
}

QJsonParseError jsonError;
const auto jsonDoc = QJsonDocument::fromJson(readResult.value(), &jsonError);
if (jsonError.error != QJsonParseError::NoError)
{
LogMsg(tr("Failed to parse auto torrent customizer rules file: \"%1\". Error: \"%2\"")
.arg(pathStr, jsonError.errorString()), Log::WARNING);
return;
}

if (!jsonDoc.isObject())
{
LogMsg(tr("Failed to load auto torrent customizer rules from \"%1\". Error: \"Invalid data format\"")
.arg(pathStr), Log::WARNING);
return;
}

m_torrentParamRules->clearRules();
const size_t numRules = m_torrentParamRules->loadRulesFromJson(jsonDoc.object());
LogMsg(tr("Loaded %1 auto torrent customizer rule(s) from \"%2\"", nullptr, numRules).arg(numRules).arg(pathStr), Log::INFO);
}

bool SessionImpl::hasPerTorrentRatioLimit() const
{
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent)
Expand Down
4 changes: 4 additions & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ namespace BitTorrent
void banIP(const QString &ip) override;

bool isKnownTorrent(const InfoHash &infoHash) const override;
void applyTorrentParamRules(const TorrentDescriptor &torrentDescr, AddTorrentParams *params) const override;
bool addTorrent(const TorrentDescriptor &torrentDescr, const AddTorrentParams &params = {}) override;
bool deleteTorrent(const TorrentID &id, DeleteOption deleteOption = DeleteTorrent) override;
bool downloadMetadata(const TorrentDescriptor &torrentDescr) override;
Expand Down Expand Up @@ -584,6 +585,8 @@ namespace BitTorrent
void upgradeCategories();
DownloadPathOption resolveCategoryDownloadPathOption(const QString &categoryName, const std::optional<DownloadPathOption> &option) const;

void loadTorrentParamRules();

void saveStatistics() const;
void loadStatistics();

Expand Down Expand Up @@ -753,6 +756,7 @@ namespace BitTorrent
QThreadPool *m_asyncWorker = nullptr;
ResumeDataStorage *m_resumeDataStorage = nullptr;
FileSearcher *m_fileSearcher = nullptr;
TorrentParamRules *m_torrentParamRules = nullptr;

QHash<TorrentID, lt::torrent_handle> m_downloadedMetadata;

Expand Down
Loading