Allow to set torrent share limits per category

PR #23577.
This commit is contained in:
Vladimir Golovnev
2025-12-21 19:48:31 +03:00
committed by GitHub
parent 1c231ce014
commit b5d16dfeee
31 changed files with 480 additions and 283 deletions

View File

@@ -32,7 +32,7 @@
#include <QCoreApplication>
#include <QMetaEnum>
#include "base/bittorrent/sharelimitaction.h"
#include "base/bittorrent/sharelimits.h"
#include "base/bittorrent/torrentcontentlayout.h"
#include "base/global.h"
#include "base/logger.h"

View File

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

View File

@@ -125,9 +125,9 @@ BitTorrent::AddTorrentParams BitTorrent::parseAddTorrentParams(const QJsonObject
.useAutoTMM = getOptionalBool(jsonObj, PARAM_AUTOTMM),
.uploadLimit = jsonObj.value(PARAM_UPLOADLIMIT).toInt(-1),
.downloadLimit = jsonObj.value(PARAM_DOWNLOADLIMIT).toInt(-1),
.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),
.seedingTimeLimit = jsonObj.value(PARAM_SEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT),
.inactiveSeedingTimeLimit = jsonObj.value(PARAM_INACTIVESEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT),
.ratioLimit = jsonObj.value(PARAM_RATIOLIMIT).toDouble(DEFAULT_RATIO_LIMIT),
.shareLimitAction = getEnum<ShareLimitAction>(jsonObj, PARAM_SHARELIMITACTION, ShareLimitAction::Default),
.sslParameters =
{

View File

@@ -36,7 +36,7 @@
#include "base/path.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "sslparameters.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -68,9 +68,9 @@ namespace BitTorrent
std::optional<bool> useAutoTMM;
int uploadLimit = -1;
int downloadLimit = -1;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
qreal ratioLimit = DEFAULT_RATIO_LIMIT;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
SSLParameters sslParameters;

View File

@@ -239,8 +239,8 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
torrentParams.comment = fromLTString(resumeDataRoot.dict_find_string_value("qBt-comment"));
torrentParams.hasFinishedStatus = resumeDataRoot.dict_find_int_value("qBt-seedStatus");
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.seedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-seedingTimeLimit", DEFAULT_SEEDING_TIME_LIMIT);
torrentParams.inactiveSeedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-inactiveSeedingTimeLimit", DEFAULT_SEEDING_TIME_LIMIT);
torrentParams.shareLimitAction = Utils::String::toEnum(
fromLTString(resumeDataRoot.dict_find_string_value("qBt-shareLimitAction")), ShareLimitAction::Default);
@@ -283,7 +283,7 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
const lt::string_view ratioLimitString = resumeDataRoot.dict_find_string_value("qBt-ratioLimit");
if (ratioLimitString.empty())
torrentParams.ratioLimit = resumeDataRoot.dict_find_int_value("qBt-ratioLimit", Torrent::USE_GLOBAL_RATIO * 1000) / 1000.0;
torrentParams.ratioLimit = resumeDataRoot.dict_find_int_value("qBt-ratioLimit", DEFAULT_RATIO_LIMIT * 1000) / 1000.0;
else
torrentParams.ratioLimit = fromLTString(ratioLimitString).toDouble();

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2021-2025 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
@@ -32,10 +32,16 @@
#include <QJsonValue>
#include "base/global.h"
#include "base/utils/string.h"
const QString OPTION_SAVEPATH = u"save_path"_s;
const QString OPTION_DOWNLOADPATH = u"download_path"_s;
const QString OPTION_RATIOLIMIT = u"ratio_limit"_s;
const QString OPTION_SEEDINGTIMELIMIT = u"seeding_time_limit"_s;
const QString OPTION_INACTIVESEEDINGTIMELIMIT = u"inactive_seeding_time_limit"_s;
const QString OPTION_SHARELIMITACTION = u"share_limit_action"_s;
BitTorrent::CategoryOptions BitTorrent::CategoryOptions::fromJSON(const QJsonObject &jsonObj)
{
CategoryOptions options;
@@ -47,6 +53,11 @@ BitTorrent::CategoryOptions BitTorrent::CategoryOptions::fromJSON(const QJsonObj
else if (downloadPathValue.isString())
options.downloadPath = {true, Path(downloadPathValue.toString())};
options.ratioLimit = jsonObj.value(OPTION_RATIOLIMIT).toDouble(DEFAULT_RATIO_LIMIT);
options.seedingTimeLimit = jsonObj.value(OPTION_SEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT);
options.inactiveSeedingTimeLimit = jsonObj.value(OPTION_INACTIVESEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT);
options.shareLimitAction = Utils::String::toEnum<ShareLimitAction>(jsonObj.value(OPTION_SHARELIMITACTION).toString(), ShareLimitAction::Default);
return options;
}
@@ -63,12 +74,10 @@ QJsonObject BitTorrent::CategoryOptions::toJSON() const
return {
{OPTION_SAVEPATH, savePath.data()},
{OPTION_DOWNLOADPATH, downloadPathValue}
{OPTION_DOWNLOADPATH, downloadPathValue},
{OPTION_RATIOLIMIT, ratioLimit},
{OPTION_SEEDINGTIMELIMIT, seedingTimeLimit},
{OPTION_INACTIVESEEDINGTIMELIMIT, inactiveSeedingTimeLimit},
{OPTION_SHARELIMITACTION, Utils::String::fromEnum(shareLimitAction)}
};
}
bool BitTorrent::operator==(const BitTorrent::CategoryOptions &left, const BitTorrent::CategoryOptions &right)
{
return ((left.savePath == right.savePath)
&& (left.downloadPath == right.downloadPath));
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2021-2025 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 "downloadpathoption.h"
#include "sharelimits.h"
class QJsonObject;
@@ -44,9 +45,14 @@ namespace BitTorrent
Path savePath;
std::optional<DownloadPathOption> downloadPath;
qreal ratioLimit = DEFAULT_RATIO_LIMIT;
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
static CategoryOptions fromJSON(const QJsonObject &jsonObj);
QJsonObject toJSON() const;
};
bool operator==(const CategoryOptions &left, const CategoryOptions &right);
friend bool operator==(const CategoryOptions &, const CategoryOptions &) = default;
};
}

View File

@@ -34,7 +34,7 @@
#include "base/path.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "sslparameters.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -61,9 +61,9 @@ namespace BitTorrent
bool addToQueueTop = false; // only for new torrents
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
qreal ratioLimit = DEFAULT_RATIO_LIMIT;
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
SSLParameters sslParameters;

View File

@@ -37,7 +37,7 @@
#include "addtorrenterror.h"
#include "addtorrentparams.h"
#include "categoryoptions.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "torrentcontentremoveoption.h"
#include "trackerentry.h"
#include "trackerentrystatus.h"
@@ -158,12 +158,16 @@ namespace BitTorrent
virtual QStringList categories() const = 0;
virtual CategoryOptions categoryOptions(const QString &categoryName) const = 0;
virtual bool setCategoryOptions(const QString &categoryName, const CategoryOptions &options) = 0;
virtual Path categorySavePath(const QString &categoryName) const = 0;
virtual Path categorySavePath(const QString &categoryName, const CategoryOptions &options) const = 0;
virtual Path categoryDownloadPath(const QString &categoryName) const = 0;
virtual Path categoryDownloadPath(const QString &categoryName, const CategoryOptions &options) const = 0;
virtual qreal categoryRatioLimit(const QString &categoryName) const = 0;
virtual int categorySeedingTimeLimit(const QString &categoryName) const = 0;
virtual int categoryInactiveSeedingTimeLimit(const QString &categoryName) const = 0;
virtual ShareLimitAction categoryShareLimitAction(const QString &categoryName) const = 0;
virtual bool addCategory(const QString &name, const CategoryOptions &options = {}) = 0;
virtual bool editCategory(const QString &name, const CategoryOptions &options) = 0;
virtual bool removeCategory(const QString &name) = 0;
virtual bool useCategoryPathsInManualMode() const = 0;
virtual void setUseCategoryPathsInManualMode(bool value) = 0;

View File

@@ -513,9 +513,9 @@ SessionImpl::SessionImpl(QObject *parent)
, m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r; })
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s)
, Torrent::NO_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_SEEDING_TIME_LIMIT))
, NO_SEEDING_TIME_LIMIT, lowerLimited(NO_SEEDING_TIME_LIMIT))
, m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s)
, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT))
, NO_SEEDING_TIME_LIMIT, lowerLimited(NO_SEEDING_TIME_LIMIT))
, m_isAddTorrentToQueueTop(BITTORRENT_SESSION_KEY(u"AddTorrentToTopOfQueue"_s), false)
, m_isAddTorrentStopped(BITTORRENT_SESSION_KEY(u"AddTorrentStopped"_s), false)
, m_torrentStopCondition(BITTORRENT_SESSION_KEY(u"TorrentStopCondition"_s), Torrent::StopCondition::None)
@@ -972,6 +972,62 @@ Path SessionImpl::categoryDownloadPath(const QString &categoryName, const Catego
return (basePath / path);
}
qreal SessionImpl::categoryRatioLimit(const QString &categoryName) const
{
if (categoryName.isEmpty())
return globalMaxRatio();
if (const auto ratioLimit = categoryOptions(categoryName).ratioLimit;
ratioLimit != DEFAULT_RATIO_LIMIT)
{
return ratioLimit;
}
return categoryRatioLimit(parentCategoryName(categoryName));
}
int SessionImpl::categorySeedingTimeLimit(const QString &categoryName) const
{
if (categoryName.isEmpty())
return globalMaxSeedingMinutes();
if (const auto seedingTimeLimit = categoryOptions(categoryName).seedingTimeLimit;
seedingTimeLimit != DEFAULT_SEEDING_TIME_LIMIT)
{
return seedingTimeLimit;
}
return categorySeedingTimeLimit(parentCategoryName(categoryName));
}
int SessionImpl::categoryInactiveSeedingTimeLimit(const QString &categoryName) const
{
if (categoryName.isEmpty())
return globalMaxInactiveSeedingMinutes();
if (const auto inactiveSeedingTimeLimit = categoryOptions(categoryName).inactiveSeedingTimeLimit;
inactiveSeedingTimeLimit != DEFAULT_SEEDING_TIME_LIMIT)
{
return inactiveSeedingTimeLimit;
}
return categoryInactiveSeedingTimeLimit(parentCategoryName(categoryName));
}
ShareLimitAction SessionImpl::categoryShareLimitAction(const QString &categoryName) const
{
if (categoryName.isEmpty())
return shareLimitAction();
if (const auto shareLimitAction = categoryOptions(categoryName).shareLimitAction;
shareLimitAction != ShareLimitAction::Default)
{
return shareLimitAction;
}
return categoryShareLimitAction(parentCategoryName(categoryName));
}
DownloadPathOption SessionImpl::resolveCategoryDownloadPathOption(const QString &categoryName, const std::optional<DownloadPathOption> &option) const
{
if (categoryName.isEmpty())
@@ -1008,9 +1064,9 @@ bool SessionImpl::addCategory(const QString &name, const CategoryOptions &option
return true;
}
bool SessionImpl::editCategory(const QString &name, const CategoryOptions &options)
bool SessionImpl::setCategoryOptions(const QString &categoryName, const CategoryOptions &options)
{
const auto it = m_categories.find(name);
const auto it = m_categories.find(categoryName);
if (it == m_categories.end())
return false;
@@ -1018,14 +1074,15 @@ bool SessionImpl::editCategory(const QString &name, const CategoryOptions &optio
if (options == currentOptions)
return false;
if (isDisableAutoTMMWhenCategorySavePathChanged())
if (isDisableAutoTMMWhenCategorySavePathChanged()
&& ((options.savePath != currentOptions.savePath) || (options.downloadPath != currentOptions.downloadPath)))
{
// This should be done before changing the category options
// to prevent the torrent from being moved at the new save path.
for (TorrentImpl *const torrent : asConst(m_torrents))
{
if (torrent->category() == name)
if (torrent->category() == categoryName)
torrent->setAutoTMMEnabled(false);
}
}
@@ -1035,11 +1092,11 @@ bool SessionImpl::editCategory(const QString &name, const CategoryOptions &optio
for (TorrentImpl *const torrent : asConst(m_torrents))
{
if (torrent->category() == name)
if (torrent->category() == categoryName)
torrent->handleCategoryOptionsChanged();
}
emit categoryOptionsChanged(name);
emit categoryOptionsChanged(categoryName);
return true;
}
@@ -1235,7 +1292,7 @@ qreal SessionImpl::globalMaxRatio() const
void SessionImpl::setGlobalMaxRatio(qreal ratio)
{
if (ratio < 0)
ratio = Torrent::NO_RATIO_LIMIT;
ratio = NO_RATIO_LIMIT;
if (ratio != globalMaxRatio())
{
@@ -1251,7 +1308,7 @@ int SessionImpl::globalMaxSeedingMinutes() const
void SessionImpl::setGlobalMaxSeedingMinutes(int minutes)
{
minutes = std::max(minutes, Torrent::NO_SEEDING_TIME_LIMIT);
minutes = std::max(minutes, NO_SEEDING_TIME_LIMIT);
if (minutes != globalMaxSeedingMinutes())
{
@@ -1267,7 +1324,7 @@ int SessionImpl::globalMaxInactiveSeedingMinutes() const
void SessionImpl::setGlobalMaxInactiveSeedingMinutes(int minutes)
{
minutes = std::max(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT);
minutes = std::max(minutes, NO_SEEDING_TIME_LIMIT);
if (minutes != globalMaxInactiveSeedingMinutes())
{
@@ -2310,14 +2367,9 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
if (!torrent->isFinished() || torrent->isForced())
return;
const auto effectiveLimit = []<typename T>(const T limit, const T useGlobalLimit, const T globalLimit) -> T
{
return (limit == useGlobalLimit) ? globalLimit : limit;
};
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());
const qreal ratioLimit = torrent->effectiveRatioLimit();
const int seedingTimeLimit = torrent->effectiveSeedingTimeLimit();
const int inactiveSeedingTimeLimit = torrent->effectiveInactiveSeedingTimeLimit();
bool reached = false;
QString description;
@@ -2344,7 +2396,7 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
if (reached)
{
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
const ShareLimitAction shareLimitAction = (torrent->shareLimitAction() == ShareLimitAction::Default) ? m_shareLimitAction : torrent->shareLimitAction();
const ShareLimitAction shareLimitAction = torrent->effectiveShareLimitAction();
if (shareLimitAction == ShareLimitAction::Remove)
{
@@ -5172,9 +5224,9 @@ bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const
void SessionImpl::updateSeedingLimitTimer()
{
if ((globalMaxRatio() == Torrent::NO_RATIO_LIMIT) && !hasPerTorrentRatioLimit()
&& (globalMaxSeedingMinutes() == Torrent::NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit()
&& (globalMaxInactiveSeedingMinutes() == Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT) && !hasPerTorrentInactiveSeedingTimeLimit())
if ((globalMaxRatio() == NO_RATIO_LIMIT) && !hasPerTorrentRatioLimit()
&& (globalMaxSeedingMinutes() == NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit()
&& (globalMaxInactiveSeedingMinutes() == NO_SEEDING_TIME_LIMIT) && !hasPerTorrentInactiveSeedingTimeLimit())
{
if (m_seedingLimitTimer->isActive())
m_seedingLimitTimer->stop();

View File

@@ -149,12 +149,16 @@ namespace BitTorrent
QStringList categories() const override;
CategoryOptions categoryOptions(const QString &categoryName) const override;
bool setCategoryOptions(const QString &categoryName, const CategoryOptions &options) override;
Path categorySavePath(const QString &categoryName) const override;
Path categorySavePath(const QString &categoryName, const CategoryOptions &options) const override;
Path categoryDownloadPath(const QString &categoryName) const override;
Path categoryDownloadPath(const QString &categoryName, const CategoryOptions &options) const override;
qreal categoryRatioLimit(const QString &categoryName) const override;
int categorySeedingTimeLimit(const QString &categoryName) const override;
int categoryInactiveSeedingTimeLimit(const QString &categoryName) const override;
ShareLimitAction categoryShareLimitAction(const QString &categoryName) const override;
bool addCategory(const QString &name, const CategoryOptions &options = {}) override;
bool editCategory(const QString &name, const CategoryOptions &options) override;
bool removeCategory(const QString &name) override;
bool useCategoryPathsInManualMode() const override;
void setUseCategoryPathsInManualMode(bool value) override;

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -33,6 +33,12 @@
namespace BitTorrent
{
inline const qreal DEFAULT_RATIO_LIMIT = -2;
inline const qreal NO_RATIO_LIMIT = -1;
inline const int DEFAULT_SEEDING_TIME_LIMIT = -2;
inline const int NO_SEEDING_TIME_LIMIT = -1;
// 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

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -44,15 +44,6 @@ namespace BitTorrent
// Torrent
const qreal Torrent::USE_GLOBAL_RATIO = -2;
const qreal Torrent::NO_RATIO_LIMIT = -1;
const int Torrent::USE_GLOBAL_SEEDING_TIME = -2;
const int Torrent::NO_SEEDING_TIME_LIMIT = -1;
const int Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME = -2;
const int Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT = -1;
const qreal Torrent::MAX_RATIO = std::numeric_limits<qreal>::infinity();
TorrentID Torrent::id() const

View File

@@ -37,7 +37,7 @@
#include "base/3rdparty/expected.hpp"
#include "base/pathfwd.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "torrentannouncestatus.h"
#include "torrentcontenthandler.h"
@@ -125,15 +125,6 @@ namespace BitTorrent
};
Q_ENUM(StopCondition)
static const qreal USE_GLOBAL_RATIO;
static const qreal NO_RATIO_LIMIT;
static const int USE_GLOBAL_SEEDING_TIME;
static const int NO_SEEDING_TIME_LIMIT;
static const int USE_GLOBAL_INACTIVE_SEEDING_TIME;
static const int NO_INACTIVE_SEEDING_TIME_LIMIT;
static const qreal MAX_RATIO;
using TorrentContentHandler::TorrentContentHandler;
@@ -236,6 +227,10 @@ namespace BitTorrent
virtual void setInactiveSeedingTimeLimit(int limit) = 0;
virtual ShareLimitAction shareLimitAction() const = 0;
virtual void setShareLimitAction(ShareLimitAction action) = 0;
virtual qreal effectiveRatioLimit() const = 0;
virtual int effectiveSeedingTimeLimit() const = 0;
virtual int effectiveInactiveSeedingTimeLimit() const = 0;
virtual ShareLimitAction effectiveShareLimitAction() const = 0;
virtual PathList filePaths() const = 0;
virtual PathList actualFilePaths() const = 0;
@@ -279,9 +274,6 @@ namespace BitTorrent
virtual bool isLSDDisabled() const = 0;
virtual QBitArray pieces() const = 0;
virtual qreal distributedCopies() const = 0;
virtual qreal maxRatio() const = 0;
virtual int maxSeedingTime() const = 0;
virtual int maxInactiveSeedingTime() const = 0;
virtual qreal realRatio() const = 0;
virtual qreal popularity() const = 0;
virtual int uploadPayloadRate() const = 0;

View File

@@ -1338,16 +1338,16 @@ qlonglong TorrentImpl::eta() const
if (isFinished())
{
const qreal maxRatioValue = maxRatio();
const int maxSeedingTimeValue = maxSeedingTime();
const int maxInactiveSeedingTimeValue = maxInactiveSeedingTime();
if ((maxRatioValue < 0) && (maxSeedingTimeValue < 0) && (maxInactiveSeedingTimeValue < 0)) return MAX_ETA;
const qreal maxRatioValue = effectiveRatioLimit();
const int maxSeedingTimeValue = effectiveSeedingTimeLimit();
const int maxInactiveSeedingTimeValue = effectiveInactiveSeedingTimeLimit();
if ((maxRatioValue < 0) && (maxSeedingTimeValue < 0) && (maxInactiveSeedingTimeValue < 0))
return MAX_ETA;
qlonglong ratioEta = MAX_ETA;
if ((speedAverage.upload > 0) && (maxRatioValue >= 0))
{
qlonglong realDL = totalDownload();
if (realDL <= 0)
realDL = wantedSize();
@@ -1479,30 +1479,38 @@ qreal TorrentImpl::distributedCopies() const
return m_nativeStatus.distributed_copies;
}
qreal TorrentImpl::maxRatio() const
qreal TorrentImpl::effectiveRatioLimit() const
{
if (m_ratioLimit == USE_GLOBAL_RATIO)
return m_session->globalMaxRatio();
if (m_ratioLimit == DEFAULT_RATIO_LIMIT)
return m_session->categoryRatioLimit(category());
return m_ratioLimit;
}
int TorrentImpl::maxSeedingTime() const
int TorrentImpl::effectiveSeedingTimeLimit() const
{
if (m_seedingTimeLimit == USE_GLOBAL_SEEDING_TIME)
return m_session->globalMaxSeedingMinutes();
if (m_seedingTimeLimit == DEFAULT_SEEDING_TIME_LIMIT)
return m_session->categorySeedingTimeLimit(category());
return m_seedingTimeLimit;
}
int TorrentImpl::maxInactiveSeedingTime() const
int TorrentImpl::effectiveInactiveSeedingTimeLimit() const
{
if (m_inactiveSeedingTimeLimit == USE_GLOBAL_INACTIVE_SEEDING_TIME)
return m_session->globalMaxInactiveSeedingMinutes();
if (m_inactiveSeedingTimeLimit == DEFAULT_SEEDING_TIME_LIMIT)
return m_session->categoryInactiveSeedingTimeLimit(category());
return m_inactiveSeedingTimeLimit;
}
ShareLimitAction TorrentImpl::effectiveShareLimitAction() const
{
if (m_shareLimitAction == ShareLimitAction::Default)
return m_session->categoryShareLimitAction(category());
return m_shareLimitAction;
}
qreal TorrentImpl::realRatio() const
{
const int64_t upload = m_nativeStatus.all_time_upload;
@@ -2623,7 +2631,7 @@ void TorrentImpl::updateProgress()
void TorrentImpl::setRatioLimit(qreal limit)
{
if (limit < USE_GLOBAL_RATIO)
if (limit < DEFAULT_RATIO_LIMIT)
limit = NO_RATIO_LIMIT;
if (m_ratioLimit != limit)
@@ -2636,7 +2644,7 @@ void TorrentImpl::setRatioLimit(qreal limit)
void TorrentImpl::setSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_SEEDING_TIME)
if (limit < DEFAULT_SEEDING_TIME_LIMIT)
limit = NO_SEEDING_TIME_LIMIT;
if (m_seedingTimeLimit != limit)
@@ -2649,8 +2657,8 @@ void TorrentImpl::setSeedingTimeLimit(int limit)
void TorrentImpl::setInactiveSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME)
limit = NO_INACTIVE_SEEDING_TIME_LIMIT;
if (limit < DEFAULT_SEEDING_TIME_LIMIT)
limit = NO_SEEDING_TIME_LIMIT;
if (m_inactiveSeedingTimeLimit != limit)
{

View File

@@ -156,6 +156,10 @@ namespace BitTorrent
void setInactiveSeedingTimeLimit(int limit) override;
ShareLimitAction shareLimitAction() const override;
void setShareLimitAction(ShareLimitAction action) override;
qreal effectiveRatioLimit() const override;
int effectiveSeedingTimeLimit() const override;
int effectiveInactiveSeedingTimeLimit() const override;
ShareLimitAction effectiveShareLimitAction() const override;
Path filePath(int index) const override;
Path actualFilePath(int index) const override;
@@ -205,9 +209,6 @@ namespace BitTorrent
bool isLSDDisabled() const override;
QBitArray pieces() const override;
qreal distributedCopies() const override;
qreal maxRatio() const override;
int maxSeedingTime() const override;
int maxInactiveSeedingTime() const override;
qreal realRatio() const override;
qreal popularity() const override;
int uploadPayloadRate() const override;

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2023-2025 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
@@ -190,6 +190,7 @@ void AddTorrentParamsWidget::populate()
}
populateDefaultPaths();
resetShareLimitsWidgetDefaults();
});
m_ui->savePathEdit->disconnect(this);
@@ -270,6 +271,7 @@ void AddTorrentParamsWidget::populate()
m_addTorrentParams.addToQueueTop = data.toBool();
});
resetShareLimitsWidgetDefaults();
m_ui->torrentShareLimitsWidget->setRatioLimit(m_addTorrentParams.ratioLimit);
m_ui->torrentShareLimitsWidget->setSeedingTimeLimit(m_addTorrentParams.seedingTimeLimit);
m_ui->torrentShareLimitsWidget->setInactiveSeedingTimeLimit(m_addTorrentParams.inactiveSeedingTimeLimit);
@@ -418,3 +420,11 @@ void AddTorrentParamsWidget::populateSavePathOptions()
populateDefaultPaths();
}
void AddTorrentParamsWidget::resetShareLimitsWidgetDefaults()
{
const auto *btSession = BitTorrent::Session::instance();
m_ui->torrentShareLimitsWidget->setDefaults((m_addTorrentParams.category.isEmpty() ? TorrentShareLimitsWidget::UsedDefaults::Global : TorrentShareLimitsWidget::UsedDefaults::Category)
, btSession->categoryRatioLimit(m_addTorrentParams.category), btSession->categorySeedingTimeLimit(m_addTorrentParams.category)
, btSession->categoryInactiveSeedingTimeLimit(m_addTorrentParams.category), btSession->categoryShareLimitAction(m_addTorrentParams.category));
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2023-2025 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
@@ -57,7 +57,7 @@ private:
void populateDefaultPaths();
void populateDefaultDownloadPath();
void populateSavePathOptions();
void resetShareLimitsWidgetDefaults();
Ui::AddTorrentParamsWidget *m_ui;
BitTorrent::AddTorrentParams m_addTorrentParams;

View File

@@ -48,7 +48,7 @@
#include <QTranslator>
#include "base/bittorrent/session.h"
#include "base/bittorrent/sharelimitaction.h"
#include "base/bittorrent/sharelimits.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/net/downloadmanager.h"

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017, 2021 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2017-2025 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
@@ -32,11 +32,12 @@
#include <QPushButton>
#include "base/bittorrent/session.h"
#include "base/utils/fs.h"
#include "base/bittorrent/torrent.h"
#include "torrentsharelimitswidget.h"
#include "ui_torrentcategorydialog.h"
TorrentCategoryDialog::TorrentCategoryDialog(QWidget *parent)
: QDialog {parent}
: QDialog(parent)
, m_ui {new Ui::TorrentCategoryDialog}
{
m_ui->setupUi(this);
@@ -56,6 +57,15 @@ TorrentCategoryDialog::TorrentCategoryDialog(QWidget *parent)
connect(m_ui->textCategoryName, &QLineEdit::textChanged, this, &TorrentCategoryDialog::categoryNameChanged);
connect(m_ui->comboUseDownloadPath, &QComboBox::currentIndexChanged, this, &TorrentCategoryDialog::useDownloadPathChanged);
resetShareLimitsWidgetDefaults();
}
TorrentCategoryDialog::TorrentCategoryDialog(QWidget *parent, const QString &categoryName, const BitTorrent::CategoryOptions &categoryOptions)
: TorrentCategoryDialog(parent)
{
setCategoryName(categoryName);
setCategoryOptions(categoryOptions);
}
TorrentCategoryDialog::~TorrentCategoryDialog()
@@ -73,8 +83,7 @@ QString TorrentCategoryDialog::createCategory(QWidget *parent, const QString &pa
newCategoryName += u'/';
newCategoryName += tr("New Category");
TorrentCategoryDialog dialog {parent};
dialog.setCategoryName(newCategoryName);
TorrentCategoryDialog dialog {parent, newCategoryName, {}};
while (dialog.exec() == TorrentCategoryDialog::Accepted)
{
newCategoryName = dialog.categoryName();
@@ -110,14 +119,12 @@ void TorrentCategoryDialog::editCategory(QWidget *parent, const QString &categor
Q_ASSERT(Session::instance()->categories().contains(categoryName));
auto *dialog = new TorrentCategoryDialog(parent);
auto *dialog = new TorrentCategoryDialog(parent, categoryName, Session::instance()->categoryOptions(categoryName));
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setCategoryNameEditable(false);
dialog->setCategoryName(categoryName);
dialog->setCategoryOptions(Session::instance()->categoryOptions(categoryName));
connect(dialog, &TorrentCategoryDialog::accepted, parent, [dialog, categoryName]()
{
Session::instance()->editCategory(categoryName, dialog->categoryOptions());
Session::instance()->setCategoryOptions(categoryName, dialog->categoryOptions());
});
dialog->open();
}
@@ -149,6 +156,11 @@ BitTorrent::CategoryOptions TorrentCategoryDialog::categoryOptions() const
else if (m_ui->comboUseDownloadPath->currentIndex() == 2)
categoryOptions.downloadPath = {false, {}};
categoryOptions.ratioLimit = m_ui->torrentShareLimitsWidget->ratioLimit().value_or(BitTorrent::DEFAULT_RATIO_LIMIT);
categoryOptions.seedingTimeLimit = m_ui->torrentShareLimitsWidget->seedingTimeLimit().value_or(BitTorrent::DEFAULT_SEEDING_TIME_LIMIT);
categoryOptions.inactiveSeedingTimeLimit = m_ui->torrentShareLimitsWidget->inactiveSeedingTimeLimit().value_or(BitTorrent::DEFAULT_SEEDING_TIME_LIMIT);
categoryOptions.shareLimitAction = m_ui->torrentShareLimitsWidget->shareLimitAction().value_or(BitTorrent::ShareLimitAction::Default);
return categoryOptions;
}
@@ -165,6 +177,11 @@ void TorrentCategoryDialog::setCategoryOptions(const BitTorrent::CategoryOptions
m_ui->comboUseDownloadPath->setCurrentIndex(0);
m_ui->comboDownloadPath->setSelectedPath({});
}
m_ui->torrentShareLimitsWidget->setRatioLimit(categoryOptions.ratioLimit);
m_ui->torrentShareLimitsWidget->setSeedingTimeLimit(categoryOptions.seedingTimeLimit);
m_ui->torrentShareLimitsWidget->setInactiveSeedingTimeLimit(categoryOptions.inactiveSeedingTimeLimit);
m_ui->torrentShareLimitsWidget->setShareLimitAction(categoryOptions.shareLimitAction);
}
void TorrentCategoryDialog::categoryNameChanged(const QString &categoryName)
@@ -177,6 +194,13 @@ void TorrentCategoryDialog::categoryNameChanged(const QString &categoryName)
if (useDownloadPath)
m_ui->comboDownloadPath->setPlaceholder(btSession->categoryDownloadPath(categoryName, categoryOptions()));
const QString parentCategoryName = BitTorrent::Session::parentCategoryName(categoryName);
if (m_parentCategoryName != parentCategoryName)
{
m_parentCategoryName = parentCategoryName;
resetShareLimitsWidgetDefaults();
}
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!categoryName.isEmpty());
}
@@ -195,3 +219,11 @@ void TorrentCategoryDialog::useDownloadPathChanged(const int index)
const Path categoryPath = btSession->categoryDownloadPath(categoryName, categoryOptions());
m_ui->comboDownloadPath->setPlaceholder(useDownloadPath ? categoryPath : Path());
}
void TorrentCategoryDialog::resetShareLimitsWidgetDefaults()
{
const auto *btSession = BitTorrent::Session::instance();
m_ui->torrentShareLimitsWidget->setDefaults((m_parentCategoryName.isEmpty() ? TorrentShareLimitsWidget::UsedDefaults::Global : TorrentShareLimitsWidget::UsedDefaults::Category)
, btSession->categoryRatioLimit(m_parentCategoryName), btSession->categorySeedingTimeLimit(m_parentCategoryName)
, btSession->categoryInactiveSeedingTimeLimit(m_parentCategoryName), btSession->categoryShareLimitAction(m_parentCategoryName));
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017, 2021 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2017-2025 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
@@ -52,6 +52,7 @@ public:
static void editCategory(QWidget *parent, const QString &categoryName);
explicit TorrentCategoryDialog(QWidget *parent = nullptr);
TorrentCategoryDialog(QWidget *parent, const QString &categoryName, const BitTorrent::CategoryOptions &categoryOptions);
~TorrentCategoryDialog() override;
void setCategoryNameEditable(bool editable);
@@ -65,6 +66,9 @@ private slots:
void useDownloadPathChanged(int index);
private:
void resetShareLimitsWidgetDefaults();
Ui::TorrentCategoryDialog *m_ui = nullptr;
Path m_lastEnteredDownloadPath;
QString m_parentCategoryName;
};

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>493</width>
<height>208</height>
<height>268</height>
</rect>
</property>
<property name="windowTitle">
@@ -140,6 +140,18 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="torrentShareLimitsBox">
<property name="title">
<string>Torrent share limits</string>
</property>
<layout class="QVBoxLayout" name="torrentShareLimitsBoxLayout">
<item>
<widget class="TorrentShareLimitsWidget" name="torrentShareLimitsWidget" native="true"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -172,6 +184,12 @@
<header>gui/fspathedit.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TorrentShareLimitsWidget</class>
<extends>QWidget</extends>
<header>gui/torrentsharelimitswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@@ -347,9 +347,9 @@ void TorrentCreatorDialog::handleCreationSuccess(const BitTorrent::TorrentCreato
params.skipChecking = true;
if (m_ui->checkIgnoreShareLimits->isChecked())
{
params.ratioLimit = BitTorrent::Torrent::NO_RATIO_LIMIT;
params.seedingTimeLimit = BitTorrent::Torrent::NO_SEEDING_TIME_LIMIT;
params.inactiveSeedingTimeLimit = BitTorrent::Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT;
params.ratioLimit = BitTorrent::NO_RATIO_LIMIT;
params.seedingTimeLimit = BitTorrent::NO_SEEDING_TIME_LIMIT;
params.inactiveSeedingTimeLimit = BitTorrent::NO_SEEDING_TIME_LIMIT;
}
params.useAutoTMM = false; // otherwise if it is on by default, it will overwrite `savePath` to the default save path

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2024-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2020 thalieht
* Copyright (C) 2011 Christian Kandeler
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
@@ -289,7 +289,12 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QList<BitTorre
, this, &TorrentOptionsDialog::handleDownSpeedLimitChanged);
}
m_ui->torrentShareLimitsWidget->setDefaultLimits(session->globalMaxRatio(), session->globalMaxSeedingMinutes(), session->globalMaxInactiveSeedingMinutes());
if (m_allSameCategory)
{
m_ui->torrentShareLimitsWidget->setDefaults((firstTorrentCategory.isEmpty() ? TorrentShareLimitsWidget::UsedDefaults::Global : TorrentShareLimitsWidget::UsedDefaults::Category)
, session->categoryRatioLimit(firstTorrentCategory), session->categorySeedingTimeLimit(firstTorrentCategory)
, session->categoryInactiveSeedingTimeLimit(firstTorrentCategory), session->categoryShareLimitAction(firstTorrentCategory));
}
if (allSameRatio)
m_ui->torrentShareLimitsWidget->setRatioLimit(firstTorrentRatio);
if (allSameSeedingTime)
@@ -477,30 +482,37 @@ void TorrentOptionsDialog::accept()
void TorrentOptionsDialog::handleCategoryChanged([[maybe_unused]] const int index)
{
if (m_ui->checkAutoTMM->checkState() == Qt::Checked)
{
if (!m_allSameCategory && (m_ui->comboCategory->currentIndex() == 0))
{
m_ui->savePath->setSelectedPath({});
}
else
{
const Path savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->comboCategory->currentText());
m_ui->savePath->setSelectedPath(savePath);
const Path downloadPath = BitTorrent::Session::instance()->categoryDownloadPath(m_ui->comboCategory->currentText());
m_ui->downloadPath->setSelectedPath(downloadPath);
m_ui->checkUseDownloadPath->setChecked(!downloadPath.isEmpty());
}
}
const auto *btSession = BitTorrent::Session::instance();
if (!m_allSameCategory && (m_ui->comboCategory->currentIndex() == 0))
{
if (m_ui->checkAutoTMM->checkState() == Qt::Checked)
m_ui->savePath->setSelectedPath({});
m_ui->comboCategory->clearEditText();
m_ui->comboCategory->lineEdit()->setPlaceholderText(m_currentCategoriesString);
m_ui->torrentShareLimitsWidget->setDefaults(TorrentShareLimitsWidget::UsedDefaults::Global
, BitTorrent::DEFAULT_RATIO_LIMIT, BitTorrent::DEFAULT_SEEDING_TIME_LIMIT
, BitTorrent::DEFAULT_SEEDING_TIME_LIMIT, BitTorrent::ShareLimitAction::Default);
}
else
{
const QString categoryName = m_ui->comboCategory->currentText();
if (m_ui->checkAutoTMM->checkState() == Qt::Checked)
{
const Path savePath = btSession->categorySavePath(categoryName);
m_ui->savePath->setSelectedPath(savePath);
const Path downloadPath = btSession->categoryDownloadPath(categoryName);
m_ui->downloadPath->setSelectedPath(downloadPath);
m_ui->checkUseDownloadPath->setChecked(!downloadPath.isEmpty());
}
m_ui->comboCategory->lineEdit()->setPlaceholderText(QString());
m_ui->torrentShareLimitsWidget->setDefaults((categoryName.isEmpty() ? TorrentShareLimitsWidget::UsedDefaults::Global : TorrentShareLimitsWidget::UsedDefaults::Category)
, btSession->categoryRatioLimit(categoryName), btSession->categorySeedingTimeLimit(categoryName)
, btSession->categoryInactiveSeedingTimeLimit(categoryName), btSession->categoryShareLimitAction(categoryName));
}
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2024-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2020 thalieht
* Copyright (C) 2011 Christian Kandeler
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
@@ -35,7 +35,7 @@
#include <QDialog>
#include "base/bittorrent/sharelimitaction.h"
#include "base/bittorrent/sharelimits.h"
#include "base/path.h"
#include "base/settingvalue.h"

View File

@@ -52,6 +52,29 @@ namespace
RemoveWithContentActionIndex,
SuperSeedingActionIndex
};
QString shareLimitActionName(const BitTorrent::ShareLimitAction shareLimitAction)
{
switch (shareLimitAction)
{
case BitTorrent::ShareLimitAction::Stop:
return TorrentShareLimitsWidget::tr("Stop torrent");
case BitTorrent::ShareLimitAction::Remove:
return TorrentShareLimitsWidget::tr("Remove torrent");
case BitTorrent::ShareLimitAction::RemoveWithContent:
return TorrentShareLimitsWidget::tr("Remove torrent and its content");
case BitTorrent::ShareLimitAction::EnableSuperSeeding:
return TorrentShareLimitsWidget::tr("Enable super seeding for torrent");
case BitTorrent::ShareLimitAction::Default:
return TorrentShareLimitsWidget::tr("Default");
}
return {};
}
}
TorrentShareLimitsWidget::TorrentShareLimitsWidget(QWidget *parent)
@@ -60,6 +83,30 @@ TorrentShareLimitsWidget::TorrentShareLimitsWidget(QWidget *parent)
{
m_ui->setupUi(this);
m_ui->comboBoxRatioMode->addItem({});
m_ui->comboBoxRatioMode->addItem(tr("Unlimited"));
m_ui->comboBoxRatioMode->addItem(tr("Set to"));
m_ui->comboBoxRatioMode->setCurrentIndex(UninitializedModeIndex);
m_ui->comboBoxSeedingTimeMode->addItem({});
m_ui->comboBoxSeedingTimeMode->addItem(tr("Unlimited"));
m_ui->comboBoxSeedingTimeMode->addItem(tr("Set to"));
m_ui->comboBoxSeedingTimeMode->setCurrentIndex(UninitializedModeIndex);
m_ui->comboBoxInactiveSeedingTimeMode->addItem({});
m_ui->comboBoxInactiveSeedingTimeMode->addItem(tr("Unlimited"));
m_ui->comboBoxInactiveSeedingTimeMode->addItem(tr("Set to"));
m_ui->comboBoxInactiveSeedingTimeMode->setCurrentIndex(UninitializedModeIndex);
m_ui->comboBoxAction->addItem({});
m_ui->comboBoxAction->addItem(shareLimitActionName(BitTorrent::ShareLimitAction::Stop));
m_ui->comboBoxAction->addItem(shareLimitActionName(BitTorrent::ShareLimitAction::Remove));
m_ui->comboBoxAction->addItem(shareLimitActionName(BitTorrent::ShareLimitAction::RemoveWithContent));
m_ui->comboBoxAction->addItem(shareLimitActionName(BitTorrent::ShareLimitAction::EnableSuperSeeding));
m_ui->comboBoxAction->setCurrentIndex(UninitializedActionIndex);
resetDefaultItemsText();
m_ui->spinBoxRatioValue->setEnabled(false);
m_ui->spinBoxRatioValue->setMaximum(std::numeric_limits<int>::max());
m_ui->spinBoxRatioValue->setSuffix({});
@@ -71,9 +118,25 @@ TorrentShareLimitsWidget::TorrentShareLimitsWidget(QWidget *parent)
m_ui->spinBoxInactiveSeedingTimeValue->setSuffix({});
m_ui->spinBoxInactiveSeedingTimeValue->clear();
connect(m_ui->comboBoxRatioMode, &QComboBox::currentIndexChanged, this, &TorrentShareLimitsWidget::refreshRatioLimitControls);
connect(m_ui->comboBoxSeedingTimeMode, &QComboBox::currentIndexChanged, this, &TorrentShareLimitsWidget::refreshSeedingTimeLimitControls);
connect(m_ui->comboBoxInactiveSeedingTimeMode, &QComboBox::currentIndexChanged, this, &TorrentShareLimitsWidget::refreshInactiveSeedingTimeLimitControls);
int prevIndex = UninitializedModeIndex;
connect(m_ui->comboBoxRatioMode, &QComboBox::currentIndexChanged, this
, [this, prevIndex](const int currentIndex) mutable
{
onRatioLimitModeChanged(currentIndex, prevIndex);
prevIndex = currentIndex;
});
connect(m_ui->comboBoxSeedingTimeMode, &QComboBox::currentIndexChanged, this
, [this, prevIndex](const int currentIndex) mutable
{
onSeedingTimeLimitModeChanged(currentIndex, prevIndex);
prevIndex = currentIndex;
});
connect(m_ui->comboBoxInactiveSeedingTimeMode, &QComboBox::currentIndexChanged, this
, [this, prevIndex](const int currentIndex) mutable
{
onInactiveSeedingTimeLimitModeChanged(currentIndex, prevIndex);
prevIndex = currentIndex;
});
}
TorrentShareLimitsWidget::~TorrentShareLimitsWidget()
@@ -83,11 +146,11 @@ TorrentShareLimitsWidget::~TorrentShareLimitsWidget()
void TorrentShareLimitsWidget::setRatioLimit(const qreal ratioLimit)
{
if (ratioLimit == BitTorrent::Torrent::USE_GLOBAL_RATIO)
if (ratioLimit == BitTorrent::DEFAULT_RATIO_LIMIT)
{
m_ui->comboBoxRatioMode->setCurrentIndex(DefaultModeIndex);
}
else if (ratioLimit == BitTorrent::Torrent::NO_RATIO_LIMIT)
else if (ratioLimit == BitTorrent::NO_RATIO_LIMIT)
{
m_ui->comboBoxRatioMode->setCurrentIndex(UnlimitedModeIndex);
}
@@ -100,11 +163,11 @@ void TorrentShareLimitsWidget::setRatioLimit(const qreal ratioLimit)
void TorrentShareLimitsWidget::setSeedingTimeLimit(const int seedingTimeLimit)
{
if (seedingTimeLimit == BitTorrent::Torrent::USE_GLOBAL_SEEDING_TIME)
if (seedingTimeLimit == BitTorrent::DEFAULT_SEEDING_TIME_LIMIT)
{
m_ui->comboBoxSeedingTimeMode->setCurrentIndex(DefaultModeIndex);
}
else if (seedingTimeLimit == BitTorrent::Torrent::NO_SEEDING_TIME_LIMIT)
else if (seedingTimeLimit == BitTorrent::NO_SEEDING_TIME_LIMIT)
{
m_ui->comboBoxSeedingTimeMode->setCurrentIndex(UnlimitedModeIndex);
}
@@ -117,11 +180,11 @@ void TorrentShareLimitsWidget::setSeedingTimeLimit(const int seedingTimeLimit)
void TorrentShareLimitsWidget::setInactiveSeedingTimeLimit(const int inactiveSeedingTimeLimit)
{
if (inactiveSeedingTimeLimit == BitTorrent::Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME)
if (inactiveSeedingTimeLimit == BitTorrent::DEFAULT_SEEDING_TIME_LIMIT)
{
m_ui->comboBoxInactiveSeedingTimeMode->setCurrentIndex(DefaultModeIndex);
}
else if (inactiveSeedingTimeLimit == BitTorrent::Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT)
else if (inactiveSeedingTimeLimit == BitTorrent::NO_SEEDING_TIME_LIMIT)
{
m_ui->comboBoxInactiveSeedingTimeMode->setCurrentIndex(UnlimitedModeIndex);
}
@@ -155,25 +218,56 @@ void TorrentShareLimitsWidget::setShareLimitAction(const BitTorrent::ShareLimitA
}
}
void TorrentShareLimitsWidget::setDefaultLimits(const qreal ratioLimit, const int seedingTimeLimit, const int inactiveSeedingTimeLimit)
void TorrentShareLimitsWidget::setDefaults(UsedDefaults usedDefaults
, const qreal ratioLimit, const int seedingTimeLimit
, const int inactiveSeedingTimeLimit, const BitTorrent::ShareLimitAction action)
{
if (m_defaultRatioLimit != ratioLimit)
{
m_defaultRatioLimit = ratioLimit;
refreshRatioLimitControls();
if (m_ui->comboBoxRatioMode->currentIndex() == DefaultModeIndex)
{
if (m_defaultRatioLimit >= 0)
{
m_ui->spinBoxRatioValue->setValue(m_defaultRatioLimit);
}
else
{
m_ui->spinBoxRatioValue->clear();
}
}
if (m_defaultSeedingTimeLimit != seedingTimeLimit)
{
m_defaultSeedingTimeLimit = seedingTimeLimit;
refreshSeedingTimeLimitControls();
if (m_ui->comboBoxSeedingTimeMode->currentIndex() == DefaultModeIndex)
{
if (m_defaultSeedingTimeLimit >= 0)
{
m_ui->spinBoxSeedingTimeValue->setValue(m_defaultSeedingTimeLimit);
m_ui->spinBoxSeedingTimeValue->setSuffix(tr(" min"));
}
else
{
m_ui->spinBoxSeedingTimeValue->setSuffix({});
m_ui->spinBoxSeedingTimeValue->clear();
}
}
if (m_defaultInactiveSeedingTimeLimit != inactiveSeedingTimeLimit)
{
m_defaultInactiveSeedingTimeLimit = inactiveSeedingTimeLimit;
refreshInactiveSeedingTimeLimitControls();
if (m_ui->comboBoxInactiveSeedingTimeMode->currentIndex() == DefaultModeIndex)
{
if (m_defaultInactiveSeedingTimeLimit >= 0)
{
m_ui->spinBoxInactiveSeedingTimeValue->setValue(m_defaultInactiveSeedingTimeLimit);
m_ui->spinBoxInactiveSeedingTimeValue->setSuffix(tr(" min"));
}
else
{
m_ui->spinBoxInactiveSeedingTimeValue->setSuffix({});
m_ui->spinBoxInactiveSeedingTimeValue->clear();
}
}
m_defaultShareLimitAction = action;
m_usedDefaults = usedDefaults;
resetDefaultItemsText();
}
std::optional<qreal> TorrentShareLimitsWidget::ratioLimit() const
@@ -181,9 +275,9 @@ std::optional<qreal> TorrentShareLimitsWidget::ratioLimit() const
switch (m_ui->comboBoxRatioMode->currentIndex())
{
case DefaultModeIndex:
return BitTorrent::Torrent::USE_GLOBAL_RATIO;
return BitTorrent::DEFAULT_RATIO_LIMIT;
case UnlimitedModeIndex:
return BitTorrent::Torrent::NO_RATIO_LIMIT;
return BitTorrent::NO_RATIO_LIMIT;
case AssignedModeIndex:
return m_ui->spinBoxRatioValue->value();
default:
@@ -196,9 +290,9 @@ std::optional<int> TorrentShareLimitsWidget::seedingTimeLimit() const
switch (m_ui->comboBoxSeedingTimeMode->currentIndex())
{
case DefaultModeIndex:
return BitTorrent::Torrent::USE_GLOBAL_SEEDING_TIME;
return BitTorrent::DEFAULT_SEEDING_TIME_LIMIT;
case UnlimitedModeIndex:
return BitTorrent::Torrent::NO_SEEDING_TIME_LIMIT;
return BitTorrent::NO_SEEDING_TIME_LIMIT;
case AssignedModeIndex:
return m_ui->spinBoxSeedingTimeValue->value();
default:
@@ -211,9 +305,9 @@ std::optional<int> TorrentShareLimitsWidget::inactiveSeedingTimeLimit() const
switch (m_ui->comboBoxInactiveSeedingTimeMode->currentIndex())
{
case DefaultModeIndex:
return BitTorrent::Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
return BitTorrent::DEFAULT_SEEDING_TIME_LIMIT;
case UnlimitedModeIndex:
return BitTorrent::Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT;
return BitTorrent::NO_SEEDING_TIME_LIMIT;
case AssignedModeIndex:
return m_ui->spinBoxInactiveSeedingTimeValue->value();
default:
@@ -240,68 +334,97 @@ std::optional<BitTorrent::ShareLimitAction> TorrentShareLimitsWidget::shareLimit
}
}
void TorrentShareLimitsWidget::refreshRatioLimitControls()
void TorrentShareLimitsWidget::onRatioLimitModeChanged(const int currentIndex, const int previousIndex)
{
const auto index = m_ui->comboBoxRatioMode->currentIndex();
m_ui->spinBoxRatioValue->setEnabled(currentIndex == AssignedModeIndex);
m_ui->spinBoxRatioValue->setEnabled(index == AssignedModeIndex);
if (index == AssignedModeIndex)
if (previousIndex == AssignedModeIndex)
m_ratioLimit = m_ui->spinBoxRatioValue->value();
if (currentIndex == AssignedModeIndex)
{
m_ui->spinBoxRatioValue->setValue(m_ratioLimit);
}
else if ((index == DefaultModeIndex) && (m_defaultRatioLimit >= 0))
else if ((currentIndex == DefaultModeIndex) && (m_defaultRatioLimit >= 0))
{
m_ui->spinBoxRatioValue->setValue(m_defaultRatioLimit);
}
else
{
m_ratioLimit = m_ui->spinBoxRatioValue->value();
m_ui->spinBoxRatioValue->clear();
}
}
void TorrentShareLimitsWidget::refreshSeedingTimeLimitControls()
void TorrentShareLimitsWidget::onSeedingTimeLimitModeChanged(const int currentIndex, const int previousIndex)
{
const auto index = m_ui->comboBoxSeedingTimeMode->currentIndex();
m_ui->spinBoxSeedingTimeValue->setEnabled(currentIndex == AssignedModeIndex);
m_ui->spinBoxSeedingTimeValue->setEnabled(index == AssignedModeIndex);
if (index == AssignedModeIndex)
if (previousIndex == AssignedModeIndex)
m_seedingTimeLimit = m_ui->spinBoxSeedingTimeValue->value();
if (currentIndex == AssignedModeIndex)
{
m_ui->spinBoxSeedingTimeValue->setValue(m_seedingTimeLimit);
m_ui->spinBoxSeedingTimeValue->setSuffix(tr(" min"));
}
else if ((index == DefaultModeIndex) && (m_defaultSeedingTimeLimit >= 0))
else if ((currentIndex == DefaultModeIndex) && (m_defaultSeedingTimeLimit >= 0))
{
m_ui->spinBoxSeedingTimeValue->setValue(m_defaultSeedingTimeLimit);
m_ui->spinBoxSeedingTimeValue->setSuffix(tr(" min"));
}
else
{
m_seedingTimeLimit = m_ui->spinBoxSeedingTimeValue->value();
m_ui->spinBoxSeedingTimeValue->setSuffix({});
m_ui->spinBoxSeedingTimeValue->clear();
}
}
void TorrentShareLimitsWidget::refreshInactiveSeedingTimeLimitControls()
void TorrentShareLimitsWidget::onInactiveSeedingTimeLimitModeChanged(const int currentIndex, const int previousIndex)
{
const auto index = m_ui->comboBoxInactiveSeedingTimeMode->currentIndex();
m_ui->spinBoxInactiveSeedingTimeValue->setEnabled(currentIndex == AssignedModeIndex);
m_ui->spinBoxInactiveSeedingTimeValue->setEnabled(index == AssignedModeIndex);
if (index == AssignedModeIndex)
if (previousIndex == AssignedModeIndex)
m_inactiveSeedingTimeLimit = m_ui->spinBoxInactiveSeedingTimeValue->value();
if (currentIndex == AssignedModeIndex)
{
m_ui->spinBoxInactiveSeedingTimeValue->setValue(m_inactiveSeedingTimeLimit);
m_ui->spinBoxInactiveSeedingTimeValue->setSuffix(tr(" min"));
}
else if ((index == DefaultModeIndex) && (m_defaultInactiveSeedingTimeLimit >= 0))
else if ((currentIndex == DefaultModeIndex) && (m_defaultInactiveSeedingTimeLimit >= 0))
{
m_ui->spinBoxInactiveSeedingTimeValue->setValue(m_defaultInactiveSeedingTimeLimit);
m_ui->spinBoxInactiveSeedingTimeValue->setSuffix(tr(" min"));
}
else
{
m_inactiveSeedingTimeLimit = m_ui->spinBoxInactiveSeedingTimeValue->value();
m_ui->spinBoxInactiveSeedingTimeValue->setSuffix({});
m_ui->spinBoxInactiveSeedingTimeValue->clear();
}
}
void TorrentShareLimitsWidget::resetDefaultItemsText()
{
if (m_usedDefaults == UsedDefaults::Global)
{
m_ui->comboBoxRatioMode->setItemText(DefaultModeIndex, tr("Default"));
m_ui->comboBoxSeedingTimeMode->setItemText(DefaultModeIndex, tr("Default"));
m_ui->comboBoxInactiveSeedingTimeMode->setItemText(DefaultModeIndex, tr("Default"));
m_ui->comboBoxAction->setItemText(DefaultActionIndex
, (m_defaultShareLimitAction == BitTorrent::ShareLimitAction::Default)
? tr("Default")
: tr("Default (%1)", "Default (share limit action)").arg(shareLimitActionName(m_defaultShareLimitAction)));
}
else // TorrentOptions
{
m_ui->comboBoxRatioMode->setItemText(DefaultModeIndex, tr("From category"));
m_ui->comboBoxSeedingTimeMode->setItemText(DefaultModeIndex, tr("From category"));
m_ui->comboBoxInactiveSeedingTimeMode->setItemText(DefaultModeIndex, tr("From category"));
m_ui->comboBoxAction->setItemText(DefaultActionIndex
, (m_defaultShareLimitAction == BitTorrent::ShareLimitAction::Default)
? tr("From category")
: tr("From category (%1)", "From category (share limit action)").arg(shareLimitActionName(m_defaultShareLimitAction)));
}
}

View File

@@ -32,7 +32,7 @@
#include <QWidget>
#include "base/bittorrent/sharelimitaction.h"
#include "base/bittorrent/sharelimits.h"
namespace Ui
{
@@ -45,6 +45,12 @@ class TorrentShareLimitsWidget final : public QWidget
Q_DISABLE_COPY_MOVE(TorrentShareLimitsWidget)
public:
enum class UsedDefaults
{
Global,
Category
};
explicit TorrentShareLimitsWidget(QWidget *parent = nullptr);
~TorrentShareLimitsWidget() override;
@@ -53,7 +59,8 @@ public:
void setInactiveSeedingTimeLimit(int inactiveSeedingTimeLimit);
void setShareLimitAction(BitTorrent::ShareLimitAction action);
void setDefaultLimits(qreal ratioLimit, int seedingTimeLimit, int inactiveSeedingTimeLimit);
void setDefaults(UsedDefaults usedDefaults, qreal ratioLimit, int seedingTimeLimit
, int inactiveSeedingTimeLimit, BitTorrent::ShareLimitAction action);
std::optional<qreal> ratioLimit() const;
std::optional<int> seedingTimeLimit() const;
@@ -61,9 +68,10 @@ public:
std::optional<BitTorrent::ShareLimitAction> shareLimitAction() const;
private:
void refreshRatioLimitControls();
void refreshSeedingTimeLimitControls();
void refreshInactiveSeedingTimeLimitControls();
void onRatioLimitModeChanged(int currentIndex, int previousIndex);
void onSeedingTimeLimitModeChanged(int currentIndex, int previousIndex);
void onInactiveSeedingTimeLimitModeChanged(int currentIndex, int previousIndex);
void resetDefaultItemsText();
Ui::TorrentShareLimitsWidget *m_ui = nullptr;
@@ -74,4 +82,7 @@ private:
int m_defaultSeedingTimeLimit = -1;
int m_defaultInactiveSeedingTimeLimit = -1;
qreal m_defaultRatioLimit = -1;
BitTorrent::ShareLimitAction m_defaultShareLimitAction = BitTorrent::ShareLimitAction::Default;
UsedDefaults m_usedDefaults = UsedDefaults::Global;
};

View File

@@ -21,26 +21,7 @@
</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>
<widget class="QComboBox" name="comboBoxRatioMode"/>
</item>
<item row="0" column="2">
<widget class="QDoubleSpinBox" name="spinBoxRatioValue">
@@ -63,26 +44,7 @@
</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>
<widget class="QComboBox" name="comboBoxSeedingTimeMode"/>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="spinBoxSeedingTimeValue">
@@ -108,26 +70,7 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxInactiveSeedingTimeMode">
<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>
<widget class="QComboBox" name="comboBoxInactiveSeedingTimeMode"/>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="spinBoxInactiveSeedingTimeValue">
@@ -157,36 +100,7 @@
</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>
<widget class="QComboBox" name="comboBoxAction"/>
</item>
<item>
<spacer name="actionLayoutSpacer">

View File

@@ -392,7 +392,7 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons
case TR_RATIO:
return ratioString(torrent->realRatio());
case TR_RATIO_LIMIT:
return ratioString(torrent->maxRatio());
return ratioString(torrent->effectiveRatioLimit());
case TR_POPULARITY:
return ratioString(torrent->popularity());
case TR_CATEGORY:
@@ -509,7 +509,7 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co
case TR_COMPLETED:
return torrent->completedSize();
case TR_RATIO_LIMIT:
return torrent->maxRatio();
return torrent->effectiveRatioLimit();
case TR_SEEN_COMPLETE_DATE:
return torrent->lastSeenComplete();
case TR_LAST_ACTIVITY:

View File

@@ -163,9 +163,9 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
{KEY_TORRENT_AMOUNT_COMPLETED, torrent.completedSize()},
{KEY_TORRENT_CONNECTIONS_COUNT, torrent.connectionsCount()},
{KEY_TORRENT_CONNECTIONS_LIMIT, torrent.connectionsLimit()},
{KEY_TORRENT_MAX_RATIO, torrent.maxRatio()},
{KEY_TORRENT_MAX_SEEDING_TIME, torrent.maxSeedingTime()},
{KEY_TORRENT_MAX_INACTIVE_SEEDING_TIME, torrent.maxInactiveSeedingTime()},
{KEY_TORRENT_MAX_RATIO, torrent.effectiveRatioLimit()},
{KEY_TORRENT_MAX_SEEDING_TIME, torrent.effectiveSeedingTimeLimit()},
{KEY_TORRENT_MAX_INACTIVE_SEEDING_TIME, torrent.effectiveInactiveSeedingTimeLimit()},
{KEY_TORRENT_RATIO, adjustRatio(torrent.realRatio())},
{KEY_TORRENT_RATIO_LIMIT, torrent.ratioLimit()},
{KEY_TORRENT_POPULARITY, torrent.popularity()},

View File

@@ -1066,9 +1066,9 @@ void TorrentsController::addAction()
const QString torrentName = params()[u"rename"_s].trimmed();
const int upLimit = parseInt(params()[u"upLimit"_s]).value_or(-1);
const int dlLimit = parseInt(params()[u"dlLimit"_s]).value_or(-1);
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 double ratioLimit = parseDouble(params()[u"ratioLimit"_s]).value_or(BitTorrent::DEFAULT_RATIO_LIMIT);
const int seedingTimeLimit = parseInt(params()[u"seedingTimeLimit"_s]).value_or(BitTorrent::DEFAULT_SEEDING_TIME_LIMIT);
const int inactiveSeedingTimeLimit = parseInt(params()[u"inactiveSeedingTimeLimit"_s]).value_or(BitTorrent::DEFAULT_SEEDING_TIME_LIMIT);
const BitTorrent::ShareLimitAction shareLimitAction = Utils::String::toEnum(params()[u"shareLimitAction"_s], BitTorrent::ShareLimitAction::Default);
const std::optional<bool> autoTMM = parseBool(params()[u"autoTMM"_s]);
@@ -1897,7 +1897,7 @@ void TorrentsController::editCategoryAction()
categoryOptions.downloadPath = {useDownloadPath.value(), downloadPath};
}
if (!BitTorrent::Session::instance()->editCategory(category, categoryOptions))
if (!BitTorrent::Session::instance()->setCategoryOptions(category, categoryOptions))
throw APIError(APIErrorType::Conflict, tr("Unable to edit category"));
setResult(QString());