diff --git a/src/app/upgrade.cpp b/src/app/upgrade.cpp index 15e077724..45d129dcf 100644 --- a/src/app/upgrade.cpp +++ b/src/app/upgrade.cpp @@ -32,6 +32,7 @@ #include #include +#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(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; } diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index e11620935..3120422d6 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -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 diff --git a/src/base/bittorrent/addtorrentparams.cpp b/src/base/bittorrent/addtorrentparams.cpp index 14d62e422..8784c047e 100644 --- a/src/base/bittorrent/addtorrentparams.cpp +++ b/src/base/bittorrent/addtorrentparams.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * * 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 - 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(jsonVal.toString(), {}); + return Utils::String::toEnum(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(jsonObj, PARAM_SHARELIMITACTION, ShareLimitAction::Default), .sslParameters = { .certificate = QSslCertificate(jsonObj.value(PARAM_SSL_CERTIFICATE).toString().toLatin1()), @@ -146,12 +148,13 @@ QJsonObject BitTorrent::serializeAddTorrentParams(const AddTorrentParams ¶ms {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())}, diff --git a/src/base/bittorrent/addtorrentparams.h b/src/base/bittorrent/addtorrentparams.h index b68475a31..60107d122 100644 --- a/src/base/bittorrent/addtorrentparams.h +++ b/src/base/bittorrent/addtorrentparams.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * * 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; diff --git a/src/base/bittorrent/bencoderesumedatastorage.cpp b/src/base/bittorrent/bencoderesumedatastorage.cpp index 97d80ff07..4107c5aa9 100644 --- a/src/base/bittorrent/bencoderesumedatastorage.cpp +++ b/src/base/bittorrent/bencoderesumedatastorage.cpp @@ -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(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(); diff --git a/src/base/bittorrent/dbresumedatastorage.cpp b/src/base/bittorrent/dbresumedatastorage.cpp index d2a9bc7ad..bb0efbdaf 100644 --- a/src/base/bittorrent/dbresumedatastorage.cpp +++ b/src/base/bittorrent/dbresumedatastorage.cpp @@ -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( + query.value(DB_COLUMN_SHARE_LIMIT_ACTION.name).toString(), ShareLimitAction::Default); resumeData.contentLayout = Utils::String::toEnum( - 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( - 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(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)); diff --git a/src/base/bittorrent/loadtorrentparams.h b/src/base/bittorrent/loadtorrentparams.h index 63c7ce7d4..b84a9eb41 100644 --- a/src/base/bittorrent/loadtorrentparams.h +++ b/src/base/bittorrent/loadtorrentparams.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2021 Vladimir Golovnev + * Copyright (C) 2021-2024 Vladimir Golovnev * * 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; }; } diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 54296562d..3cb6b36d8 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * 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; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 356a2f13e..8f156f733 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -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 = [](const T limit, const T useGlobalLimit, const T globalLimit) -> T + const auto effectiveLimit = [](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(m_maxRatioAction.get()); + return m_shareLimitAction; } -void SessionImpl::setMaxRatioAction(const MaxRatioAction act) +void SessionImpl::setShareLimitAction(const ShareLimitAction act) { - m_maxRatioAction = static_cast(act); + Q_ASSERT(act != ShareLimitAction::Default); + + m_shareLimitAction = act; } bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index d99a46af5..bed9f8b33 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -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 m_chokingAlgorithm; CachedSettingValue m_seedChokingAlgorithm; CachedSettingValue m_storedTags; - CachedSettingValue m_maxRatioAction; + CachedSettingValue m_shareLimitAction; CachedSettingValue m_savePath; CachedSettingValue m_downloadPath; CachedSettingValue m_isDownloadPathEnabled; diff --git a/src/base/bittorrent/sharelimitaction.h b/src/base/bittorrent/sharelimitaction.h new file mode 100644 index 000000000..c12b8ac34 --- /dev/null +++ b/src/base/bittorrent/sharelimitaction.h @@ -0,0 +1,57 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015-2024 Vladimir Golovnev + * Copyright (C) 2006 Christophe Dumez + * + * 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 + +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) + } +} diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index 01c1a1492..8ac33b7bb 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * 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; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 3e3bb090a..1ef806e09 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * 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 ¶ms) .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); diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 2a4d49030..636bf7f25 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -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 &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; diff --git a/src/gui/addtorrentparamswidget.cpp b/src/gui/addtorrentparamswidget.cpp index 1a4dfce4b..38b4bbd23 100644 --- a/src/gui/addtorrentparamswidget.cpp +++ b/src/gui/addtorrentparamswidget.cpp @@ -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() diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 9453d1474..c442f29e7 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -1,7 +1,7 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2023-2024 Vladimir Golovnev * Copyright (C) 2024 Jonathan Ketchker - * Copyright (C) 2023 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -45,6 +45,7 @@ #include #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 actIndex = + const QHash 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 actIndex = + const QVector 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()); diff --git a/src/gui/torrentoptionsdialog.cpp b/src/gui/torrentoptionsdialog.cpp index 525ca1c44..b15483e13 100644 --- a/src/gui/torrentoptionsdialog.cpp +++ b/src/gui/torrentoptionsdialog.cpp @@ -82,6 +82,7 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVectorratioLimit(); 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 QVectorinactiveSeedingTimeLimit() != 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 QVectortorrentShareLimitsWidget->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 QVectortorrentShareLimitsWidget->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 shareLimitAction = m_ui->torrentShareLimitsWidget->shareLimitAction(); + m_initialValues.shareLimitAction != shareLimitAction) + { + torrent->setShareLimitAction(shareLimitAction.value()); + } + if (!torrent->isPrivate()) { if (m_initialValues.disableDHT != m_ui->checkDisableDHT->checkState()) diff --git a/src/gui/torrentoptionsdialog.h b/src/gui/torrentoptionsdialog.h index bfe20bd3f..b601cb422 100644 --- a/src/gui/torrentoptionsdialog.h +++ b/src/gui/torrentoptionsdialog.h @@ -35,6 +35,7 @@ #include +#include "base/bittorrent/sharelimitaction.h" #include "base/path.h" #include "base/settingvalue.h" @@ -87,6 +88,7 @@ private: std::optional ratio; std::optional seedingTime; std::optional inactiveSeedingTime; + std::optional shareLimitAction; int upSpeedLimit; int downSpeedLimit; Qt::CheckState autoTMM; diff --git a/src/gui/torrentsharelimitswidget.cpp b/src/gui/torrentsharelimitswidget.cpp index 6300d5f18..797845664 100644 --- a/src/gui/torrentsharelimitswidget.cpp +++ b/src/gui/torrentsharelimitswidget.cpp @@ -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 TorrentShareLimitsWidget::inactiveSeedingTimeLimit() const } } +std::optional 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(); diff --git a/src/gui/torrentsharelimitswidget.h b/src/gui/torrentsharelimitswidget.h index c20523ea8..b99a830b6 100644 --- a/src/gui/torrentsharelimitswidget.h +++ b/src/gui/torrentsharelimitswidget.h @@ -32,6 +32,8 @@ #include +#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 ratioLimit() const; std::optional seedingTimeLimit() const; std::optional inactiveSeedingTimeLimit() const; + std::optional shareLimitAction() const; private: void refreshRatioLimitControls(); diff --git a/src/gui/torrentsharelimitswidget.ui b/src/gui/torrentsharelimitswidget.ui index 310c6482e..9a58a54e1 100644 --- a/src/gui/torrentsharelimitswidget.ui +++ b/src/gui/torrentsharelimitswidget.ui @@ -6,47 +6,13 @@ 0 0 - 365 - 106 + 445 + 132 - - 0 - - - 0 - - - 0 - - - 0 - - - - - - -1 - - - - Default - - - - - Unlimited - - - - - Set to - - - - + @@ -69,58 +35,6 @@ - - - - Seeding time: - - - - - - - false - - - min - - - 9999999 - - - 1440 - - - - - - - Inactive seeding time: - - - - - - - -1 - - - - Default - - - - - Unlimited - - - - - Set to - - - - @@ -137,6 +51,36 @@ + + + + Ratio: + + + + + + + Inactive seeding time: + + + + + + + false + + + min + + + 9999999 + + + 1440 + + + @@ -153,15 +97,115 @@ - - + + + + -1 + + + + Default + + + + + Unlimited + + + + + Set to + + + + + + + + -1 + + + + Default + + + + + Unlimited + + + + + Set to + + + + + + - Ratio: + Seeding time: + + + + + + Action when the limit is reached: + + + + + + + -1 + + + + Default + + + + + Stop torrent + + + + + Remove torrent + + + + + Remove torrent and its content + + + + + Enable super seeding for torrent + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index 21b1f58ae..06d6b54c7 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -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(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(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()); diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 44c1b719a..ec94daa26 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -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 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()),