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
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 477 additions and 256 deletions

View file

@ -32,6 +32,7 @@
#include <QCoreApplication>
#include <QMetaEnum>
#include "base/bittorrent/sharelimitaction.h"
#include "base/bittorrent/torrentcontentlayout.h"
#include "base/global.h"
#include "base/logger.h"
@ -45,7 +46,7 @@
namespace
{
const int MIGRATION_VERSION = 6;
const int MIGRATION_VERSION = 7;
const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_s;
void exportWebUIHttpsFiles()
@ -437,6 +438,36 @@ namespace
settingsStorage->storeValue(key, u"zh_CN"_s);
}
}
void migrateShareLimitActionSettings()
{
auto *settingsStorage = SettingsStorage::instance();
const auto oldKey = u"BitTorrent/Session/MaxRatioAction"_s;
const auto newKey = u"BitTorrent/Session/ShareLimitAction"_s;
const auto value = settingsStorage->loadValue<int>(oldKey);
switch (value)
{
case 0:
settingsStorage->storeValue(newKey, BitTorrent::ShareLimitAction::Stop);
break;
case 1:
settingsStorage->storeValue(newKey, BitTorrent::ShareLimitAction::Remove);
break;
case 2:
settingsStorage->storeValue(newKey, BitTorrent::ShareLimitAction::EnableSuperSeeding);
break;
case 3:
settingsStorage->storeValue(newKey, BitTorrent::ShareLimitAction::RemoveWithContent);
break;
default:
LogMsg(QCoreApplication::translate("Upgrade", "Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
.arg(oldKey, QString::number(value)), Log::WARNING);
break;
}
settingsStorage->removeValue(oldKey);
}
}
bool upgrade()
@ -475,6 +506,9 @@ bool upgrade()
if (version < 6)
migrateProxySettings();
if (version < 7)
migrateShareLimitActionSettings();
version = MIGRATION_VERSION;
}

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()),
@ -152,6 +154,7 @@ QJsonObject BitTorrent::serializeAddTorrentParams(const AddTorrentParams &params
{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,6 +231,8 @@ 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"))));
@ -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,6 +235,8 @@ 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);
resumeData.operatingMode = Utils::String::toEnum<TorrentOperatingMode>(
@ -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,108 +2233,57 @@ 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 ratio = torrent->realRatio();
qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit);
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());
if ((ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit))
bool reached = false;
QString description;
if (const qreal ratio = torrent->realRatio();
(ratioLimit >= 0) && (ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit))
{
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 (reached)
{
const QString description = tr("Torrent reached the share ratio limit.");
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
const ShareLimitAction shareLimitAction = (torrent->shareLimitAction() == ShareLimitAction::Default) ? m_shareLimitAction : torrent->shareLimitAction();
if (m_maxRatioAction == Remove)
if (shareLimitAction == ShareLimitAction::Remove)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent."), torrentName));
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removing torrent."), torrentName));
deleteTorrent(torrentID);
}
else if (m_maxRatioAction == DeleteFiles)
else if (shareLimitAction == ShareLimitAction::RemoveWithContent)
{
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removed torrent and deleted its content."), torrentName));
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Removing torrent and deleting its content."), torrentName));
deleteTorrent(torrentID, DeleteTorrentAndFiles);
}
else if ((m_maxRatioAction == Pause) && !torrent->isPaused())
else if ((shareLimitAction == ShareLimitAction::Stop) && !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())
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));
}
continue;
}
}
if (const int seedingTimeLimit = resolveLimitValue(torrent->seedingTimeLimit(), Torrent::USE_GLOBAL_SEEDING_TIME, globalMaxSeedingMinutes());
seedingTimeLimit >= 0)
{
const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60;
if ((seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit))
{
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;
}
}
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))
{
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));
}
}
}
}
}
@ -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;

View file

@ -147,6 +147,7 @@ BitTorrent::AddTorrentParams AddTorrentParamsWidget::addTorrentParams() const
addTorrentParams.ratioLimit = m_ui->torrentShareLimitsWidget->ratioLimit().value();
addTorrentParams.seedingTimeLimit = m_ui->torrentShareLimitsWidget->seedingTimeLimit().value();
addTorrentParams.inactiveSeedingTimeLimit = m_ui->torrentShareLimitsWidget->inactiveSeedingTimeLimit().value();
addTorrentParams.shareLimitAction = m_ui->torrentShareLimitsWidget->shareLimitAction().value();
return addTorrentParams;
}
@ -272,6 +273,7 @@ void AddTorrentParamsWidget::populate()
m_ui->torrentShareLimitsWidget->setRatioLimit(m_addTorrentParams.ratioLimit);
m_ui->torrentShareLimitsWidget->setSeedingTimeLimit(m_addTorrentParams.seedingTimeLimit);
m_ui->torrentShareLimitsWidget->setInactiveSeedingTimeLimit(m_addTorrentParams.inactiveSeedingTimeLimit);
m_ui->torrentShareLimitsWidget->setShareLimitAction(m_addTorrentParams.shareLimitAction);
}
void AddTorrentParamsWidget::loadCustomSavePathOptions()

View file

@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2024 Jonathan Ketchker
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -45,6 +45,7 @@
#include <QTranslator>
#include "base/bittorrent/session.h"
#include "base/bittorrent/sharelimitaction.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/net/portforwarder.h"
@ -1110,14 +1111,14 @@ void OptionsDialog::loadBittorrentTabOptions()
}
m_ui->comboRatioLimitAct->setEnabled((session->globalMaxSeedingMinutes() >= 0) || (session->globalMaxRatio() >= 0.) || (session->globalMaxInactiveSeedingMinutes() >= 0));
const QHash<MaxRatioAction, int> actIndex =
const QHash<BitTorrent::ShareLimitAction, int> actIndex =
{
{Pause, 0},
{Remove, 1},
{DeleteFiles, 2},
{EnableSuperSeeding, 3}
{BitTorrent::ShareLimitAction::Stop, 0},
{BitTorrent::ShareLimitAction::Remove, 1},
{BitTorrent::ShareLimitAction::RemoveWithContent, 2},
{BitTorrent::ShareLimitAction::EnableSuperSeeding, 3}
};
m_ui->comboRatioLimitAct->setCurrentIndex(actIndex.value(session->maxRatioAction()));
m_ui->comboRatioLimitAct->setCurrentIndex(actIndex.value(session->shareLimitAction()));
m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled());
m_ui->textTrackers->setPlainText(session->additionalTrackers());
@ -1181,14 +1182,14 @@ void OptionsDialog::saveBittorrentTabOptions() const
session->setGlobalMaxRatio(getMaxRatio());
session->setGlobalMaxSeedingMinutes(getMaxSeedingMinutes());
session->setGlobalMaxInactiveSeedingMinutes(getMaxInactiveSeedingMinutes());
const QVector<MaxRatioAction> actIndex =
const QVector<BitTorrent::ShareLimitAction> actIndex =
{
Pause,
Remove,
DeleteFiles,
EnableSuperSeeding
BitTorrent::ShareLimitAction::Stop,
BitTorrent::ShareLimitAction::Remove,
BitTorrent::ShareLimitAction::RemoveWithContent,
BitTorrent::ShareLimitAction::EnableSuperSeeding
};
session->setMaxRatioAction(actIndex.value(m_ui->comboRatioLimitAct->currentIndex()));
session->setShareLimitAction(actIndex.value(m_ui->comboRatioLimitAct->currentIndex()));
session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());

View file

@ -82,6 +82,7 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector<BitTor
bool allSameRatio = true;
bool allSameSeedingTime = true;
bool allSameInactiveSeedingTime = true;
bool allSameShareLimitAction = true;
bool allTorrentsArePrivate = true;
bool allSameDHT = true;
bool allSamePEX = true;
@ -103,6 +104,7 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector<BitTor
const qreal firstTorrentRatio = torrents[0]->ratioLimit();
const int firstTorrentSeedingTime = torrents[0]->seedingTimeLimit();
const int firstTorrentInactiveSeedingTime = torrents[0]->inactiveSeedingTimeLimit();
const BitTorrent::ShareLimitAction firstTorrentShareLimitAction = torrents[0]->shareLimitAction();
const bool isFirstTorrentDHTDisabled = torrents[0]->isDHTDisabled();
const bool isFirstTorrentPEXDisabled = torrents[0]->isPEXDisabled();
@ -160,6 +162,11 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector<BitTor
if (torrent->inactiveSeedingTimeLimit() != firstTorrentInactiveSeedingTime)
allSameInactiveSeedingTime = false;
}
if (allSameShareLimitAction)
{
if (torrent->shareLimitAction() != firstTorrentShareLimitAction)
allSameShareLimitAction = false;
}
if (allTorrentsArePrivate)
{
if (!torrent->isPrivate())
@ -289,6 +296,8 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector<BitTor
m_ui->torrentShareLimitsWidget->setSeedingTimeLimit(firstTorrentSeedingTime);
if (allSameInactiveSeedingTime)
m_ui->torrentShareLimitsWidget->setInactiveSeedingTimeLimit(firstTorrentInactiveSeedingTime);
if (allSameShareLimitAction)
m_ui->torrentShareLimitsWidget->setShareLimitAction(firstTorrentShareLimitAction);
if (!allTorrentsArePrivate)
{
@ -340,6 +349,7 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector<BitTor
.ratio = m_ui->torrentShareLimitsWidget->ratioLimit(),
.seedingTime = m_ui->torrentShareLimitsWidget->seedingTimeLimit(),
.inactiveSeedingTime = m_ui->torrentShareLimitsWidget->inactiveSeedingTimeLimit(),
.shareLimitAction = m_ui->torrentShareLimitsWidget->shareLimitAction(),
.upSpeedLimit = m_ui->spinUploadLimit->value(),
.downSpeedLimit = m_ui->spinDownloadLimit->value(),
.autoTMM = m_ui->checkAutoTMM->checkState(),
@ -440,6 +450,12 @@ void TorrentOptionsDialog::accept()
torrent->setInactiveSeedingTimeLimit(inactiveSeedingTimeLimit.value());
}
if (const std::optional<BitTorrent::ShareLimitAction> shareLimitAction = m_ui->torrentShareLimitsWidget->shareLimitAction();
m_initialValues.shareLimitAction != shareLimitAction)
{
torrent->setShareLimitAction(shareLimitAction.value());
}
if (!torrent->isPrivate())
{
if (m_initialValues.disableDHT != m_ui->checkDisableDHT->checkState())

View file

@ -35,6 +35,7 @@
#include <QDialog>
#include "base/bittorrent/sharelimitaction.h"
#include "base/path.h"
#include "base/settingvalue.h"
@ -87,6 +88,7 @@ private:
std::optional<qreal> ratio;
std::optional<int> seedingTime;
std::optional<int> inactiveSeedingTime;
std::optional<BitTorrent::ShareLimitAction> shareLimitAction;
int upSpeedLimit;
int downSpeedLimit;
Qt::CheckState autoTMM;

View file

@ -40,6 +40,16 @@ namespace
UnlimitedModeIndex,
AssignedModeIndex
};
enum ShareLimitActionIndex
{
UninitializedActionIndex = -1,
DefaultActionIndex,
StopActionIndex,
RemoveActionIndex,
RemoveWithContentActionIndex,
SuperSeedingActionIndex
};
}
TorrentShareLimitsWidget::TorrentShareLimitsWidget(QWidget *parent)
@ -119,6 +129,29 @@ void TorrentShareLimitsWidget::setInactiveSeedingTimeLimit(const int inactiveSee
}
}
void TorrentShareLimitsWidget::setShareLimitAction(const BitTorrent::ShareLimitAction action)
{
switch (action)
{
case BitTorrent::ShareLimitAction::Default:
default:
m_ui->comboBoxAction->setCurrentIndex(DefaultActionIndex);
break;
case BitTorrent::ShareLimitAction::Stop:
m_ui->comboBoxAction->setCurrentIndex(StopActionIndex);
break;
case BitTorrent::ShareLimitAction::Remove:
m_ui->comboBoxAction->setCurrentIndex(RemoveActionIndex);
break;
case BitTorrent::ShareLimitAction::RemoveWithContent:
m_ui->comboBoxAction->setCurrentIndex(RemoveWithContentActionIndex);
break;
case BitTorrent::ShareLimitAction::EnableSuperSeeding:
m_ui->comboBoxAction->setCurrentIndex(SuperSeedingActionIndex);
break;
}
}
void TorrentShareLimitsWidget::setDefaultLimits(const qreal ratioLimit, const int seedingTimeLimit, const int inactiveSeedingTimeLimit)
{
if (m_defaultRatioLimit != ratioLimit)
@ -185,6 +218,25 @@ std::optional<int> TorrentShareLimitsWidget::inactiveSeedingTimeLimit() const
}
}
std::optional<BitTorrent::ShareLimitAction> TorrentShareLimitsWidget::shareLimitAction() const
{
switch (m_ui->comboBoxAction->currentIndex())
{
case DefaultActionIndex:
return BitTorrent::ShareLimitAction::Default;
case StopActionIndex:
return BitTorrent::ShareLimitAction::Stop;
case RemoveActionIndex:
return BitTorrent::ShareLimitAction::Remove;
case RemoveWithContentActionIndex:
return BitTorrent::ShareLimitAction::RemoveWithContent;
case SuperSeedingActionIndex:
return BitTorrent::ShareLimitAction::EnableSuperSeeding;
default:
return std::nullopt;
}
}
void TorrentShareLimitsWidget::refreshRatioLimitControls()
{
const auto index = m_ui->comboBoxRatioMode->currentIndex();

View file

@ -32,6 +32,8 @@
#include <QWidget>
#include "base/bittorrent/sharelimitaction.h"
namespace Ui
{
class TorrentShareLimitsWidget;
@ -49,12 +51,14 @@ public:
void setRatioLimit(qreal ratioLimit);
void setSeedingTimeLimit(int seedingTimeLimit);
void setInactiveSeedingTimeLimit(int inactiveSeedingTimeLimit);
void setShareLimitAction(BitTorrent::ShareLimitAction action);
void setDefaultLimits(qreal ratioLimit, int seedingTimeLimit, int inactiveSeedingTimeLimit);
std::optional<qreal> ratioLimit() const;
std::optional<int> seedingTimeLimit() const;
std::optional<int> inactiveSeedingTimeLimit() const;
std::optional<BitTorrent::ShareLimitAction> shareLimitAction() const;
private:
void refreshRatioLimitControls();

View file

@ -6,47 +6,13 @@
<rect>
<x>0</x>
<y>0</y>
<width>365</width>
<height>106</height>
<width>445</width>
<height>132</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxRatioMode">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>Unlimited</string>
</property>
</item>
<item>
<property name="text">
<string>Set to</string>
</property>
</item>
</widget>
</item>
<layout class="QGridLayout" name="limitsLayout">
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxInactiveSeedingTimeMode">
<property name="currentIndex">
@ -69,58 +35,6 @@
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelSeedingTime">
<property name="text">
<string>Seeding time:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="spinBoxInactiveSeedingTimeValue">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string extracomment="minutes"> min</string>
</property>
<property name="maximum">
<number>9999999</number>
</property>
<property name="value">
<number>1440</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelInactiveSeedingTime">
<property name="text">
<string>Inactive seeding time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxSeedingTimeMode">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>Unlimited</string>
</property>
</item>
<item>
<property name="text">
<string>Set to</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="spinBoxSeedingTimeValue">
<property name="enabled">
@ -137,6 +51,36 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelRatio">
<property name="text">
<string>Ratio:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelInactiveSeedingTime">
<property name="text">
<string>Inactive seeding time:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="spinBoxInactiveSeedingTimeValue">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string extracomment="minutes"> min</string>
</property>
<property name="maximum">
<number>9999999</number>
</property>
<property name="value">
<number>1440</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QDoubleSpinBox" name="spinBoxRatioValue">
<property name="enabled">
@ -153,15 +97,115 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelRatio">
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxSeedingTimeMode">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string>Ratio:</string>
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>Unlimited</string>
</property>
</item>
<item>
<property name="text">
<string>Set to</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxRatioMode">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>Unlimited</string>
</property>
</item>
<item>
<property name="text">
<string>Set to</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelSeedingTime">
<property name="text">
<string>Seeding time:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="actionLayout">
<item>
<widget class="QLabel" name="labelAction">
<property name="text">
<string>Action when the limit is reached:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxAction">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>Stop torrent</string>
</property>
</item>
<item>
<property name="text">
<string>Remove torrent</string>
</property>
</item>
<item>
<property name="text">
<string>Remove torrent and its content</string>
</property>
</item>
<item>
<property name="text">
<string>Enable super seeding for torrent</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="actionLayoutSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

View file

@ -288,7 +288,7 @@ void AppController::preferencesAction()
data[u"max_seeding_time"_s] = session->globalMaxSeedingMinutes();
data[u"max_inactive_seeding_time_enabled"_s] = (session->globalMaxInactiveSeedingMinutes() >= 0.);
data[u"max_inactive_seeding_time"_s] = session->globalMaxInactiveSeedingMinutes();
data[u"max_ratio_act"_s] = session->maxRatioAction();
data[u"max_ratio_act"_s] = static_cast<int>(session->shareLimitAction());
// Add trackers
data[u"add_trackers_enabled"_s] = session->isAddTrackersEnabled();
data[u"add_trackers"_s] = session->additionalTrackers();
@ -812,7 +812,24 @@ void AppController::setPreferencesAction()
? m[u"max_inactive_seeding_time"_s].toInt() : -1);
}
if (hasKey(u"max_ratio_act"_s))
session->setMaxRatioAction(static_cast<MaxRatioAction>(it.value().toInt()));
{
switch (it.value().toInt())
{
default:
case 0:
session->setShareLimitAction(BitTorrent::ShareLimitAction::Stop);
break;
case 1:
session->setShareLimitAction(BitTorrent::ShareLimitAction::Remove);
break;
case 2:
session->setShareLimitAction(BitTorrent::ShareLimitAction::EnableSuperSeeding);
break;
case 3:
session->setShareLimitAction(BitTorrent::ShareLimitAction::RemoveWithContent);
break;
}
}
// Add trackers
if (hasKey(u"add_trackers_enabled"_s))
session->setAddTrackersEnabled(it.value().toBool());

View file

@ -697,6 +697,7 @@ void TorrentsController::addAction()
const double ratioLimit = parseDouble(params()[u"ratioLimit"_s]).value_or(BitTorrent::Torrent::USE_GLOBAL_RATIO);
const int seedingTimeLimit = parseInt(params()[u"seedingTimeLimit"_s]).value_or(BitTorrent::Torrent::USE_GLOBAL_SEEDING_TIME);
const int inactiveSeedingTimeLimit = parseInt(params()[u"inactiveSeedingTimeLimit"_s]).value_or(BitTorrent::Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME);
const BitTorrent::ShareLimitAction shareLimitAction = Utils::String::toEnum(params()[u"shareLimitAction"_s], BitTorrent::ShareLimitAction::Default);
const std::optional<bool> autoTMM = parseBool(params()[u"autoTMM"_s]);
const QString stopConditionParam = params()[u"stopCondition"_s];
@ -751,6 +752,7 @@ void TorrentsController::addAction()
.seedingTimeLimit = seedingTimeLimit,
.inactiveSeedingTimeLimit = inactiveSeedingTimeLimit,
.ratioLimit = ratioLimit,
.shareLimitAction = shareLimitAction,
.sslParameters =
{
.certificate = QSslCertificate(params()[KEY_PROP_SSL_CERTIFICATE].toLatin1()),