Allow torrents to override default share limit action

PR #20528.
This commit is contained in:
Vladimir Golovnev
2024-03-12 14:08:59 +03:00
committed by GitHub
parent 773cb1e55d
commit d5e41bf679
23 changed files with 477 additions and 256 deletions

View File

@@ -32,6 +32,7 @@ add_library(qbt_base STATIC
bittorrent/session.h
bittorrent/sessionimpl.h
bittorrent/sessionstatus.h
bittorrent/sharelimitaction.h
bittorrent/speedmonitor.h
bittorrent/sslparameters.h
bittorrent/torrent.h

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -51,6 +51,7 @@ const QString PARAM_UPLOADLIMIT = u"upload_limit"_s;
const QString PARAM_DOWNLOADLIMIT = u"download_limit"_s;
const QString PARAM_SEEDINGTIMELIMIT = u"seeding_time_limit"_s;
const QString PARAM_INACTIVESEEDINGTIMELIMIT = u"inactive_seeding_time_limit"_s;
const QString PARAM_SHARELIMITACTION = u"share_limit_action"_s;
const QString PARAM_RATIOLIMIT = u"ratio_limit"_s;
const QString PARAM_SSL_CERTIFICATE = u"ssl_certificate"_s;
const QString PARAM_SSL_PRIVATEKEY = u"ssl_private_key"_s;
@@ -96,10 +97,10 @@ namespace
}
template <typename Enum>
Enum getEnum(const QJsonObject &jsonObj, const QString &key)
Enum getEnum(const QJsonObject &jsonObj, const QString &key, const Enum defaultValue = {})
{
const QJsonValue jsonVal = jsonObj.value(key);
return Utils::String::toEnum<Enum>(jsonVal.toString(), {});
return Utils::String::toEnum<Enum>(jsonVal.toString(), defaultValue);
}
}
@@ -127,6 +128,7 @@ BitTorrent::AddTorrentParams BitTorrent::parseAddTorrentParams(const QJsonObject
.seedingTimeLimit = jsonObj.value(PARAM_SEEDINGTIMELIMIT).toInt(Torrent::USE_GLOBAL_SEEDING_TIME),
.inactiveSeedingTimeLimit = jsonObj.value(PARAM_INACTIVESEEDINGTIMELIMIT).toInt(Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME),
.ratioLimit = jsonObj.value(PARAM_RATIOLIMIT).toDouble(Torrent::USE_GLOBAL_RATIO),
.shareLimitAction = getEnum<ShareLimitAction>(jsonObj, PARAM_SHARELIMITACTION, ShareLimitAction::Default),
.sslParameters =
{
.certificate = QSslCertificate(jsonObj.value(PARAM_SSL_CERTIFICATE).toString().toLatin1()),
@@ -146,12 +148,13 @@ QJsonObject BitTorrent::serializeAddTorrentParams(const AddTorrentParams &params
{PARAM_SAVEPATH, params.savePath.data()},
{PARAM_DOWNLOADPATH, params.downloadPath.data()},
{PARAM_OPERATINGMODE, Utils::String::fromEnum(params.addForced
? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged)},
? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged)},
{PARAM_SKIPCHECKING, params.skipChecking},
{PARAM_UPLOADLIMIT, params.uploadLimit},
{PARAM_DOWNLOADLIMIT, params.downloadLimit},
{PARAM_SEEDINGTIMELIMIT, params.seedingTimeLimit},
{PARAM_INACTIVESEEDINGTIMELIMIT, params.inactiveSeedingTimeLimit},
{PARAM_SHARELIMITACTION, Utils::String::fromEnum(params.shareLimitAction)},
{PARAM_RATIOLIMIT, params.ratioLimit},
{PARAM_SSL_CERTIFICATE, QString::fromLatin1(params.sslParameters.certificate.toPem())},
{PARAM_SSL_PRIVATEKEY, QString::fromLatin1(params.sslParameters.privateKey.toPem())},

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -36,6 +36,7 @@
#include "base/path.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sslparameters.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -70,6 +71,7 @@ namespace BitTorrent
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
SSLParameters sslParameters;
friend bool operator==(const AddTorrentParams &lhs, const AddTorrentParams &rhs) = default;

View File

@@ -231,14 +231,16 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
torrentParams.firstLastPiecePriority = resumeDataRoot.dict_find_int_value("qBt-firstLastPiecePriority");
torrentParams.seedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-seedingTimeLimit", Torrent::USE_GLOBAL_SEEDING_TIME);
torrentParams.inactiveSeedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-inactiveSeedingTimeLimit", Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME);
torrentParams.shareLimitAction = Utils::String::toEnum(
fromLTString(resumeDataRoot.dict_find_string_value("qBt-shareLimitAction")), ShareLimitAction::Default);
torrentParams.savePath = Profile::instance()->fromPortablePath(
Path(fromLTString(resumeDataRoot.dict_find_string_value("qBt-savePath"))));
Path(fromLTString(resumeDataRoot.dict_find_string_value("qBt-savePath"))));
torrentParams.useAutoTMM = torrentParams.savePath.isEmpty();
if (!torrentParams.useAutoTMM)
{
torrentParams.downloadPath = Profile::instance()->fromPortablePath(
Path(fromLTString(resumeDataRoot.dict_find_string_value("qBt-downloadPath"))));
Path(fromLTString(resumeDataRoot.dict_find_string_value("qBt-downloadPath"))));
}
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
@@ -261,7 +263,7 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
// === END REPLACEMENT CODE === //
torrentParams.stopCondition = Utils::String::toEnum(
fromLTString(resumeDataRoot.dict_find_string_value("qBt-stopCondition")), Torrent::StopCondition::None);
fromLTString(resumeDataRoot.dict_find_string_value("qBt-stopCondition")), Torrent::StopCondition::None);
torrentParams.sslParameters =
{
.certificate = QSslCertificate(toByteArray(resumeDataRoot.dict_find_string_value(KEY_SSL_CERTIFICATE))),
@@ -418,6 +420,8 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
data["qBt-ratioLimit"] = static_cast<int>(resumeData.ratioLimit * 1000);
data["qBt-seedingTimeLimit"] = resumeData.seedingTimeLimit;
data["qBt-inactiveSeedingTimeLimit"] = resumeData.inactiveSeedingTimeLimit;
data["qBt-shareLimitAction"] = Utils::String::fromEnum(resumeData.shareLimitAction).toStdString();
data["qBt-category"] = resumeData.category.toStdString();
data["qBt-tags"] = setToEntryList(resumeData.tags);
data["qBt-name"] = resumeData.name.toStdString();

View File

@@ -67,7 +67,7 @@ namespace
{
const QString DB_CONNECTION_NAME = u"ResumeDataStorage"_s;
const int DB_VERSION = 6;
const int DB_VERSION = 7;
const QString DB_TABLE_META = u"meta"_s;
const QString DB_TABLE_TORRENTS = u"torrents"_s;
@@ -138,6 +138,7 @@ namespace
const Column DB_COLUMN_RATIO_LIMIT = makeColumn("ratio_limit");
const Column DB_COLUMN_SEEDING_TIME_LIMIT = makeColumn("seeding_time_limit");
const Column DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT = makeColumn("inactive_seeding_time_limit");
const Column DB_COLUMN_SHARE_LIMIT_ACTION = makeColumn("share_limit_action");
const Column DB_COLUMN_HAS_OUTER_PIECES_PRIORITY = makeColumn("has_outer_pieces_priority");
const Column DB_COLUMN_HAS_SEED_STATUS = makeColumn("has_seed_status");
const Column DB_COLUMN_OPERATING_MODE = makeColumn("operating_mode");
@@ -234,13 +235,15 @@ namespace
resumeData.ratioLimit = query.value(DB_COLUMN_RATIO_LIMIT.name).toInt() / 1000.0;
resumeData.seedingTimeLimit = query.value(DB_COLUMN_SEEDING_TIME_LIMIT.name).toInt();
resumeData.inactiveSeedingTimeLimit = query.value(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.name).toInt();
resumeData.shareLimitAction = Utils::String::toEnum<ShareLimitAction>(
query.value(DB_COLUMN_SHARE_LIMIT_ACTION.name).toString(), ShareLimitAction::Default);
resumeData.contentLayout = Utils::String::toEnum<TorrentContentLayout>(
query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
resumeData.operatingMode = Utils::String::toEnum<TorrentOperatingMode>(
query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
resumeData.stopCondition = Utils::String::toEnum(
query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
resumeData.sslParameters =
{
.certificate = QSslCertificate(query.value(DB_COLUMN_SSL_CERTIFICATE.name).toByteArray()),
@@ -540,6 +543,7 @@ void BitTorrent::DBResumeDataStorage::createDB() const
makeColumnDefinition(DB_COLUMN_RATIO_LIMIT, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_SEEDING_TIME_LIMIT, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_SHARE_LIMIT_ACTION, "TEXT NOT NULL DEFAULT `Default`"),
makeColumnDefinition(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_HAS_SEED_STATUS, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_OPERATING_MODE, "TEXT NOT NULL"),
@@ -623,6 +627,9 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_DH_PARAMS, "TEXT");
}
if (fromVersion <= 6)
addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SHARE_LIMIT_ACTION, "TEXTNOT NULL DEFAULT `Default`");
const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
if (!query.prepare(updateMetaVersionQuery))
throw RuntimeError(query.lastError().text());
@@ -801,6 +808,7 @@ namespace
DB_COLUMN_RATIO_LIMIT,
DB_COLUMN_SEEDING_TIME_LIMIT,
DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT,
DB_COLUMN_SHARE_LIMIT_ACTION,
DB_COLUMN_HAS_OUTER_PIECES_PRIORITY,
DB_COLUMN_HAS_SEED_STATUS,
DB_COLUMN_OPERATING_MODE,
@@ -863,6 +871,7 @@ namespace
query.bindValue(DB_COLUMN_RATIO_LIMIT.placeholder, static_cast<int>(m_resumeData.ratioLimit * 1000));
query.bindValue(DB_COLUMN_SEEDING_TIME_LIMIT.placeholder, m_resumeData.seedingTimeLimit);
query.bindValue(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.placeholder, m_resumeData.inactiveSeedingTimeLimit);
query.bindValue(DB_COLUMN_SHARE_LIMIT_ACTION.placeholder, Utils::String::fromEnum(m_resumeData.shareLimitAction));
query.bindValue(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.placeholder, m_resumeData.firstLastPiecePriority);
query.bindValue(DB_COLUMN_HAS_SEED_STATUS.placeholder, m_resumeData.hasFinishedStatus);
query.bindValue(DB_COLUMN_OPERATING_MODE.placeholder, Utils::String::fromEnum(m_resumeData.operatingMode));

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2021-2024 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
#include "base/path.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sslparameters.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -62,6 +63,8 @@ namespace BitTorrent
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
SSLParameters sslParameters;
};
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -36,20 +36,11 @@
#include "base/tagset.h"
#include "addtorrentparams.h"
#include "categoryoptions.h"
#include "sharelimitaction.h"
#include "trackerentry.h"
class QString;
// These values should remain unchanged when adding new items
// so as not to break the existing user settings.
enum MaxRatioAction
{
Pause = 0,
Remove = 1,
DeleteFiles = 3,
EnableSuperSeeding = 2
};
enum DeleteOption
{
DeleteTorrent,
@@ -209,6 +200,9 @@ namespace BitTorrent
virtual void setGlobalMaxSeedingMinutes(int minutes) = 0;
virtual int globalMaxInactiveSeedingMinutes() const = 0;
virtual void setGlobalMaxInactiveSeedingMinutes(int minutes) = 0;
virtual ShareLimitAction shareLimitAction() const = 0;
virtual void setShareLimitAction(ShareLimitAction act) = 0;
virtual QString getDHTBootstrapNodes() const = 0;
virtual void setDHTBootstrapNodes(const QString &nodes) = 0;
virtual bool isDHTEnabled() const = 0;
@@ -446,9 +440,6 @@ namespace BitTorrent
virtual const CacheStatus &cacheStatus() const = 0;
virtual bool isListening() const = 0;
virtual MaxRatioAction maxRatioAction() const = 0;
virtual void setMaxRatioAction(MaxRatioAction act) = 0;
virtual void banIP(const QString &ip) = 0;
virtual bool isKnownTorrent(const InfoHash &infoHash) const = 0;

View File

@@ -492,7 +492,8 @@ SessionImpl::SessionImpl(QObject *parent)
, m_seedChokingAlgorithm(BITTORRENT_SESSION_KEY(u"SeedChokingAlgorithm"_s), SeedChokingAlgorithm::FastestUpload
, clampValue(SeedChokingAlgorithm::RoundRobin, SeedChokingAlgorithm::AntiLeech))
, m_storedTags(BITTORRENT_SESSION_KEY(u"Tags"_s))
, m_maxRatioAction(BITTORRENT_SESSION_KEY(u"MaxRatioAction"_s), Pause)
, m_shareLimitAction(BITTORRENT_SESSION_KEY(u"ShareLimitAction"_s), ShareLimitAction::Stop
, [](const ShareLimitAction action) { return (action == ShareLimitAction::Default) ? ShareLimitAction::Stop : action; })
, m_savePath(BITTORRENT_SESSION_KEY(u"DefaultSavePath"_s), specialFolderLocation(SpecialFolder::Downloads))
, m_downloadPath(BITTORRENT_SESSION_KEY(u"TempPath"_s), (savePath() / Path(u"temp"_s)))
, m_isDownloadPathEnabled(BITTORRENT_SESSION_KEY(u"TempPathEnabled"_s), false)
@@ -2219,9 +2220,7 @@ void SessionImpl::populateAdditionalTrackers()
void SessionImpl::processShareLimits()
{
qDebug("Processing share limits...");
const auto resolveLimitValue = []<typename T>(const T limit, const T useGlobalLimit, const T globalLimit) -> T
const auto effectiveLimit = []<typename T>(const T limit, const T useGlobalLimit, const T globalLimit) -> T
{
return (limit == useGlobalLimit) ? globalLimit : limit;
};
@@ -2234,107 +2233,56 @@ void SessionImpl::processShareLimits()
if (!torrent->isFinished() || torrent->isForced())
continue;
if (const qreal ratioLimit = resolveLimitValue(torrent->ratioLimit(), Torrent::USE_GLOBAL_RATIO, globalMaxRatio());
ratioLimit >= 0)
const qreal ratioLimit = effectiveLimit(torrent->ratioLimit(), Torrent::USE_GLOBAL_RATIO, globalMaxRatio());
const int seedingTimeLimit = effectiveLimit(torrent->seedingTimeLimit(), Torrent::USE_GLOBAL_SEEDING_TIME, globalMaxSeedingMinutes());
const int inactiveSeedingTimeLimit = effectiveLimit(torrent->inactiveSeedingTimeLimit(), Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME, globalMaxInactiveSeedingMinutes());
bool reached = false;
QString description;
if (const qreal ratio = torrent->realRatio();
(ratioLimit >= 0) && (ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit))
{
const qreal ratio = torrent->realRatio();
qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit);
if ((ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit))
{
const QString description = tr("Torrent reached the share ratio limit.");
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
if (m_maxRatioAction == Remove)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent."), torrentName));
deleteTorrent(torrentID);
}
else if (m_maxRatioAction == DeleteFiles)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent and deleted its content."), torrentName));
deleteTorrent(torrentID, DeleteTorrentAndFiles);
}
else if ((m_maxRatioAction == Pause) && !torrent->isPaused())
{
torrent->pause();
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Torrent paused."), torrentName));
}
else if ((m_maxRatioAction == EnableSuperSeeding) && !torrent->isPaused() && !torrent->superSeeding())
{
torrent->setSuperSeeding(true);
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Super seeding enabled."), torrentName));
}
continue;
}
reached = true;
description = tr("Torrent reached the share ratio limit.");
}
else if (const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60;
(seedingTimeLimit >= 0) && (seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit))
{
reached = true;
description = tr("Torrent reached the seeding time limit.");
}
else if (const qlonglong inactiveSeedingTimeInMinutes = torrent->timeSinceActivity() / 60;
(inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes <= Torrent::MAX_INACTIVE_SEEDING_TIME) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit))
{
reached = true;
description = tr("Torrent reached the inactive seeding time limit.");
}
if (const int seedingTimeLimit = resolveLimitValue(torrent->seedingTimeLimit(), Torrent::USE_GLOBAL_SEEDING_TIME, globalMaxSeedingMinutes());
seedingTimeLimit >= 0)
if (reached)
{
const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60;
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
const ShareLimitAction shareLimitAction = (torrent->shareLimitAction() == ShareLimitAction::Default) ? m_shareLimitAction : torrent->shareLimitAction();
if ((seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit))
if (shareLimitAction == ShareLimitAction::Remove)
{
const QString description = tr("Torrent reached the seeding time limit.");
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
if (m_maxRatioAction == Remove)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent."), torrentName));
deleteTorrent(torrentID);
}
else if (m_maxRatioAction == DeleteFiles)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent and deleted its content."), torrentName));
deleteTorrent(torrentID, DeleteTorrentAndFiles);
}
else if ((m_maxRatioAction == Pause) && !torrent->isPaused())
{
torrent->pause();
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Torrent paused."), torrentName));
}
else if ((m_maxRatioAction == EnableSuperSeeding) && !torrent->isPaused() && !torrent->superSeeding())
{
torrent->setSuperSeeding(true);
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Super seeding enabled."), torrentName));
}
continue;
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removing torrent."), torrentName));
deleteTorrent(torrentID);
}
}
if (const int inactiveSeedingTimeLimit = resolveLimitValue(torrent->inactiveSeedingTimeLimit(), Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME, globalMaxInactiveSeedingMinutes());
inactiveSeedingTimeLimit >= 0)
{
const qlonglong inactiveSeedingTimeInMinutes = torrent->timeSinceActivity() / 60;
if ((inactiveSeedingTimeInMinutes <= Torrent::MAX_INACTIVE_SEEDING_TIME) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit))
else if (shareLimitAction == ShareLimitAction::RemoveWithContent)
{
const QString description = tr("Torrent reached the inactive seeding time limit.");
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
if (m_maxRatioAction == Remove)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent."), torrentName));
deleteTorrent(torrentID);
}
else if (m_maxRatioAction == DeleteFiles)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent and deleted its content."), torrentName));
deleteTorrent(torrentID, DeleteTorrentAndFiles);
}
else if ((m_maxRatioAction == Pause) && !torrent->isPaused())
{
torrent->pause();
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Torrent paused."), torrentName));
}
else if ((m_maxRatioAction == EnableSuperSeeding) && !torrent->isPaused() && !torrent->superSeeding())
{
torrent->setSuperSeeding(true);
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Super seeding enabled."), torrentName));
}
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removing torrent and deleting its content."), torrentName));
deleteTorrent(torrentID, DeleteTorrentAndFiles);
}
else if ((shareLimitAction == ShareLimitAction::Stop) && !torrent->isPaused())
{
torrent->pause();
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Torrent paused."), torrentName));
}
else if ((shareLimitAction == ShareLimitAction::EnableSuperSeeding) && !torrent->isPaused() && !torrent->superSeeding())
{
torrent->setSuperSeeding(true);
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Super seeding enabled."), torrentName));
}
}
}
@@ -2654,6 +2602,7 @@ LoadTorrentParams SessionImpl::initLoadTorrentParams(const AddTorrentParams &add
loadTorrentParams.ratioLimit = addTorrentParams.ratioLimit;
loadTorrentParams.seedingTimeLimit = addTorrentParams.seedingTimeLimit;
loadTorrentParams.inactiveSeedingTimeLimit = addTorrentParams.inactiveSeedingTimeLimit;
loadTorrentParams.shareLimitAction = addTorrentParams.shareLimitAction;
loadTorrentParams.sslParameters = addTorrentParams.sslParameters;
const QString category = addTorrentParams.category;
@@ -4832,14 +4781,16 @@ bool SessionImpl::isListening() const
return m_nativeSessionExtension->isSessionListening();
}
MaxRatioAction SessionImpl::maxRatioAction() const
ShareLimitAction SessionImpl::shareLimitAction() const
{
return static_cast<MaxRatioAction>(m_maxRatioAction.get());
return m_shareLimitAction;
}
void SessionImpl::setMaxRatioAction(const MaxRatioAction act)
void SessionImpl::setShareLimitAction(const ShareLimitAction act)
{
m_maxRatioAction = static_cast<int>(act);
Q_ASSERT(act != ShareLimitAction::Default);
m_shareLimitAction = act;
}
bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const

View File

@@ -176,6 +176,9 @@ namespace BitTorrent
void setGlobalMaxSeedingMinutes(int minutes) override;
int globalMaxInactiveSeedingMinutes() const override;
void setGlobalMaxInactiveSeedingMinutes(int minutes) override;
ShareLimitAction shareLimitAction() const override;
void setShareLimitAction(ShareLimitAction act) override;
QString getDHTBootstrapNodes() const override;
void setDHTBootstrapNodes(const QString &nodes) override;
bool isDHTEnabled() const override;
@@ -413,9 +416,6 @@ namespace BitTorrent
const CacheStatus &cacheStatus() const override;
bool isListening() const override;
MaxRatioAction maxRatioAction() const override;
void setMaxRatioAction(MaxRatioAction act) override;
void banIP(const QString &ip) override;
bool isKnownTorrent(const InfoHash &infoHash) const override;
@@ -692,7 +692,7 @@ namespace BitTorrent
CachedSettingValue<ChokingAlgorithm> m_chokingAlgorithm;
CachedSettingValue<SeedChokingAlgorithm> m_seedChokingAlgorithm;
CachedSettingValue<QStringList> m_storedTags;
CachedSettingValue<int> m_maxRatioAction;
CachedSettingValue<ShareLimitAction> m_shareLimitAction;
CachedSettingValue<Path> m_savePath;
CachedSettingValue<Path> m_downloadPath;
CachedSettingValue<bool> m_isDownloadPathEnabled;

View File

@@ -0,0 +1,57 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
#include <QMetaEnum>
namespace BitTorrent
{
// Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised
// since `Q_NAMESPACE` cannot be used when the same namespace resides at different files.
// https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/#comment-143779
inline namespace ShareLimitActionNS
{
Q_NAMESPACE
// These values should remain unchanged when adding new items
// so as not to break the existing user settings.
enum class ShareLimitAction
{
Default = -1, // special value
Stop = 0,
Remove = 1,
RemoveWithContent = 3,
EnableSuperSeeding = 2
};
Q_ENUM_NS(ShareLimitAction)
}
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -37,6 +37,7 @@
#include "base/3rdparty/expected.hpp"
#include "base/pathfwd.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "torrentcontenthandler.h"
class QBitArray;
@@ -212,9 +213,16 @@ namespace BitTorrent
virtual int piecesHave() const = 0;
virtual qreal progress() const = 0;
virtual QDateTime addedTime() const = 0;
// Share limits
virtual qreal ratioLimit() const = 0;
virtual void setRatioLimit(qreal limit) = 0;
virtual int seedingTimeLimit() const = 0;
virtual void setSeedingTimeLimit(int limit) = 0;
virtual int inactiveSeedingTimeLimit() const = 0;
virtual void setInactiveSeedingTimeLimit(int limit) = 0;
virtual ShareLimitAction shareLimitAction() const = 0;
virtual void setShareLimitAction(ShareLimitAction action) = 0;
virtual PathList filePaths() const = 0;
@@ -287,9 +295,6 @@ namespace BitTorrent
virtual void forceReannounce(int index = -1) = 0;
virtual void forceDHTAnnounce() = 0;
virtual void forceRecheck() = 0;
virtual void setRatioLimit(qreal limit) = 0;
virtual void setSeedingTimeLimit(int limit) = 0;
virtual void setInactiveSeedingTimeLimit(int limit) = 0;
virtual void setUploadLimit(int limit) = 0;
virtual void setDownloadLimit(int limit) = 0;
virtual void setSuperSeeding(bool enable) = 0;

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -298,6 +298,7 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
, m_ratioLimit(params.ratioLimit)
, m_seedingTimeLimit(params.seedingTimeLimit)
, m_inactiveSeedingTimeLimit(params.inactiveSeedingTimeLimit)
, m_shareLimitAction(params.shareLimitAction)
, m_operatingMode(params.operatingMode)
, m_contentLayout(params.contentLayout)
, m_hasFinishedStatus(params.hasFinishedStatus)
@@ -2143,6 +2144,7 @@ void TorrentImpl::prepareResumeData(const lt::add_torrent_params &params)
.ratioLimit = m_ratioLimit,
.seedingTimeLimit = m_seedingTimeLimit,
.inactiveSeedingTimeLimit = m_inactiveSeedingTimeLimit,
.shareLimitAction = m_shareLimitAction,
.sslParameters = m_sslParams
};
@@ -2618,6 +2620,21 @@ void TorrentImpl::setInactiveSeedingTimeLimit(int limit)
}
}
ShareLimitAction TorrentImpl::shareLimitAction() const
{
return m_shareLimitAction;
}
void TorrentImpl::setShareLimitAction(const ShareLimitAction action)
{
if (m_shareLimitAction != action)
{
m_shareLimitAction = action;
deferredRequestResumeData();
m_session->handleTorrentShareLimitChanged(this);
}
}
void TorrentImpl::setUploadLimit(const int limit)
{
const int cleanValue = cleanLimitValue(limit);

View File

@@ -139,9 +139,15 @@ namespace BitTorrent
int piecesHave() const override;
qreal progress() const override;
QDateTime addedTime() const override;
qreal ratioLimit() const override;
void setRatioLimit(qreal limit) override;
int seedingTimeLimit() const override;
void setSeedingTimeLimit(int limit) override;
int inactiveSeedingTimeLimit() const override;
void setInactiveSeedingTimeLimit(int limit) override;
ShareLimitAction shareLimitAction() const override;
void setShareLimitAction(ShareLimitAction action) override;
Path filePath(int index) const override;
Path actualFilePath(int index) const override;
@@ -223,9 +229,6 @@ namespace BitTorrent
void forceRecheck() override;
void renameFile(int index, const Path &path) override;
void prioritizeFiles(const QVector<DownloadPriority> &priorities) override;
void setRatioLimit(qreal limit) override;
void setSeedingTimeLimit(int limit) override;
void setInactiveSeedingTimeLimit(int limit) override;
void setUploadLimit(int limit) override;
void setDownloadLimit(int limit) override;
void setSuperSeeding(bool enable) override;
@@ -356,16 +359,17 @@ namespace BitTorrent
Path m_downloadPath;
QString m_category;
TagSet m_tags;
qreal m_ratioLimit;
int m_seedingTimeLimit;
int m_inactiveSeedingTimeLimit;
TorrentOperatingMode m_operatingMode;
TorrentContentLayout m_contentLayout;
bool m_hasFinishedStatus;
qreal m_ratioLimit = 0;
int m_seedingTimeLimit = 0;
int m_inactiveSeedingTimeLimit = 0;
ShareLimitAction m_shareLimitAction = ShareLimitAction::Default;
TorrentOperatingMode m_operatingMode = TorrentOperatingMode::AutoManaged;
TorrentContentLayout m_contentLayout = TorrentContentLayout::Original;
bool m_hasFinishedStatus = false;
bool m_hasMissingFiles = false;
bool m_hasFirstLastPiecePriority = false;
bool m_useAutoTMM;
bool m_isStopped;
bool m_useAutoTMM = false;
bool m_isStopped = false;
StopCondition m_stopCondition = StopCondition::None;
SSLParameters m_sslParams;