mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-01 05:08:05 -06:00
Redesign "Incomplete folder" feature
Change "Incomplete/temp folder" term with "download folder". Allow to set "download folder" per torrent (in manual mode) and per category (in automatic mode).
This commit is contained in:
committed by
Vladimir Golovnev (glassez)
parent
b0e41abf5a
commit
1c0f8b4289
@@ -112,9 +112,9 @@ void AppController::preferencesAction()
|
||||
data["torrent_changed_tmm_enabled"] = !session->isDisableAutoTMMWhenCategoryChanged();
|
||||
data["save_path_changed_tmm_enabled"] = !session->isDisableAutoTMMWhenDefaultSavePathChanged();
|
||||
data["category_changed_tmm_enabled"] = !session->isDisableAutoTMMWhenCategorySavePathChanged();
|
||||
data["save_path"] = Utils::Fs::toNativePath(session->defaultSavePath());
|
||||
data["temp_path_enabled"] = session->isTempPathEnabled();
|
||||
data["temp_path"] = Utils::Fs::toNativePath(session->tempPath());
|
||||
data["save_path"] = Utils::Fs::toNativePath(session->savePath());
|
||||
data["temp_path_enabled"] = session->isDownloadPathEnabled();
|
||||
data["temp_path"] = Utils::Fs::toNativePath(session->downloadPath());
|
||||
data["export_dir"] = Utils::Fs::toNativePath(session->torrentExportDirectory());
|
||||
data["export_dir_fin"] = Utils::Fs::toNativePath(session->finishedTorrentExportDirectory());
|
||||
|
||||
@@ -399,11 +399,11 @@ void AppController::setPreferencesAction()
|
||||
if (hasKey("category_changed_tmm_enabled"))
|
||||
session->setDisableAutoTMMWhenCategorySavePathChanged(!it.value().toBool());
|
||||
if (hasKey("save_path"))
|
||||
session->setDefaultSavePath(it.value().toString());
|
||||
session->setSavePath(it.value().toString());
|
||||
if (hasKey("temp_path_enabled"))
|
||||
session->setTempPathEnabled(it.value().toBool());
|
||||
session->setDownloadPathEnabled(it.value().toBool());
|
||||
if (hasKey("temp_path"))
|
||||
session->setTempPath(it.value().toString());
|
||||
session->setDownloadPath(it.value().toString());
|
||||
if (hasKey("export_dir"))
|
||||
session->setTorrentExportDirectory(it.value().toString());
|
||||
if (hasKey("export_dir_fin"))
|
||||
@@ -866,7 +866,7 @@ void AppController::setPreferencesAction()
|
||||
|
||||
void AppController::defaultSavePathAction()
|
||||
{
|
||||
setResult(BitTorrent::Session::instance()->defaultSavePath());
|
||||
setResult(BitTorrent::Session::instance()->savePath());
|
||||
}
|
||||
|
||||
void AppController::networkInterfaceListAction()
|
||||
|
||||
@@ -33,6 +33,6 @@
|
||||
|
||||
void FreeDiskSpaceChecker::check()
|
||||
{
|
||||
const qint64 freeDiskSpace = Utils::Fs::freeDiskSpaceOnPath(BitTorrent::Session::instance()->defaultSavePath());
|
||||
const qint64 freeDiskSpace = Utils::Fs::freeDiskSpaceOnPath(BitTorrent::Session::instance()->savePath());
|
||||
emit checked(freeDiskSpace);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
|
||||
{KEY_TORRENT_SUPER_SEEDING, torrent.superSeeding()},
|
||||
{KEY_TORRENT_FORCE_START, torrent.isForced()},
|
||||
{KEY_TORRENT_SAVE_PATH, Utils::Fs::toNativePath(torrent.savePath())},
|
||||
{KEY_TORRENT_DOWNLOAD_PATH, Utils::Fs::toNativePath(torrent.downloadPath())},
|
||||
{KEY_TORRENT_CONTENT_PATH, Utils::Fs::toNativePath(torrent.contentPath())},
|
||||
{KEY_TORRENT_ADDED_ON, torrent.addedTime().toSecsSinceEpoch()},
|
||||
{KEY_TORRENT_COMPLETION_ON, torrent.completedTime().toSecsSinceEpoch()},
|
||||
|
||||
@@ -61,6 +61,7 @@ inline const char KEY_TORRENT_TAGS[] = "tags";
|
||||
inline const char KEY_TORRENT_SUPER_SEEDING[] = "super_seeding";
|
||||
inline const char KEY_TORRENT_FORCE_START[] = "force_start";
|
||||
inline const char KEY_TORRENT_SAVE_PATH[] = "save_path";
|
||||
inline const char KEY_TORRENT_DOWNLOAD_PATH[] = "download_path";
|
||||
inline const char KEY_TORRENT_CONTENT_PATH[] = "content_path";
|
||||
inline const char KEY_TORRENT_ADDED_ON[] = "added_on";
|
||||
inline const char KEY_TORRENT_COMPLETION_ON[] = "completion_on";
|
||||
|
||||
@@ -209,6 +209,7 @@ namespace
|
||||
case QMetaType::ULongLong:
|
||||
case QMetaType::UInt:
|
||||
case QMetaType::QDateTime:
|
||||
case QMetaType::Nullptr:
|
||||
if (prevData[key] != value)
|
||||
syncData[key] = value;
|
||||
break;
|
||||
@@ -426,6 +427,7 @@ SyncController::~SyncController()
|
||||
// - "uploaded_session": Amount of data uploaded since program open
|
||||
// - "amount_left": Amount of data left to download
|
||||
// - "save_path": Torrent save path
|
||||
// - "download_path": Torrent download path
|
||||
// - "completed": Amount of data completed
|
||||
// - "max_ratio": Upload max share ratio
|
||||
// - "max_seeding_time": Upload max seeding time
|
||||
@@ -496,15 +498,13 @@ void SyncController::maindataAction()
|
||||
data["torrents"] = torrents;
|
||||
|
||||
QVariantHash categories;
|
||||
const QStringMap categoriesList = session->categories();
|
||||
for (auto it = categoriesList.cbegin(); it != categoriesList.cend(); ++it)
|
||||
const QStringList categoriesList = session->categories();
|
||||
for (const auto &categoryName : categoriesList)
|
||||
{
|
||||
const QString &key = it.key();
|
||||
categories[key] = QVariantMap
|
||||
{
|
||||
{"name", key},
|
||||
{"savePath", it.value()}
|
||||
};
|
||||
const BitTorrent::CategoryOptions categoryOptions = session->categoryOptions(categoryName);
|
||||
QJsonObject category = categoryOptions.toJSON();
|
||||
category.insert(QLatin1String("name"), categoryName);
|
||||
categories[categoryName] = category.toVariantMap();
|
||||
}
|
||||
data["categories"] = categories;
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QUrl>
|
||||
|
||||
#include "base/bittorrent/categoryoptions.h"
|
||||
#include "base/bittorrent/common.h"
|
||||
#include "base/bittorrent/downloadpriority.h"
|
||||
#include "base/bittorrent/infohash.h"
|
||||
@@ -103,6 +104,7 @@ const char KEY_PROP_ADDITION_DATE[] = "addition_date";
|
||||
const char KEY_PROP_COMPLETION_DATE[] = "completion_date";
|
||||
const char KEY_PROP_CREATION_DATE[] = "creation_date";
|
||||
const char KEY_PROP_SAVE_PATH[] = "save_path";
|
||||
const char KEY_PROP_DOWNLOAD_PATH[] = "download_path";
|
||||
const char KEY_PROP_COMMENT[] = "comment";
|
||||
|
||||
// File keys
|
||||
@@ -372,6 +374,7 @@ void TorrentsController::infoAction()
|
||||
// - "completion_date": Torrent completion date
|
||||
// - "creation_date": Torrent creation date
|
||||
// - "save_path": Torrent save path
|
||||
// - "download_path": Torrent download path
|
||||
// - "comment": Torrent comment
|
||||
void TorrentsController::propertiesAction()
|
||||
{
|
||||
@@ -430,6 +433,7 @@ void TorrentsController::propertiesAction()
|
||||
dataDict[KEY_PROP_CREATION_DATE] = -1;
|
||||
}
|
||||
dataDict[KEY_PROP_SAVE_PATH] = Utils::Fs::toNativePath(torrent->savePath());
|
||||
dataDict[KEY_PROP_DOWNLOAD_PATH] = Utils::Fs::toNativePath(torrent->downloadPath());
|
||||
dataDict[KEY_PROP_COMMENT] = torrent->comment();
|
||||
|
||||
setResult(dataDict);
|
||||
@@ -643,6 +647,8 @@ void TorrentsController::addAction()
|
||||
const bool firstLastPiece = parseBool(params()["firstLastPiecePrio"]).value_or(false);
|
||||
const std::optional<bool> addPaused = parseBool(params()["paused"]);
|
||||
const QString savepath = params()["savepath"].trimmed();
|
||||
const QString downloadPath = params()["downloadPath"].trimmed();
|
||||
const std::optional<bool> useDownloadPath = parseBool(params()["useDownloadPath"]);
|
||||
const QString category = params()["category"];
|
||||
const QStringList tags = params()["tags"].split(',', Qt::SkipEmptyParts);
|
||||
const QString torrentName = params()["rename"].trimmed();
|
||||
@@ -682,6 +688,8 @@ void TorrentsController::addAction()
|
||||
addTorrentParams.addPaused = addPaused;
|
||||
addTorrentParams.contentLayout = contentLayout;
|
||||
addTorrentParams.savePath = savepath;
|
||||
addTorrentParams.downloadPath = downloadPath;
|
||||
addTorrentParams.useDownloadPath = useDownloadPath;
|
||||
addTorrentParams.category = category;
|
||||
addTorrentParams.tags.insert(tags.cbegin(), tags.cend());
|
||||
addTorrentParams.name = torrentName;
|
||||
@@ -1095,7 +1103,58 @@ void TorrentsController::setLocationAction()
|
||||
{
|
||||
LogMsg(tr("WebUI Set location: moving \"%1\", from \"%2\" to \"%3\"")
|
||||
.arg(torrent->name(), Utils::Fs::toNativePath(torrent->savePath()), Utils::Fs::toNativePath(newLocation)));
|
||||
torrent->move(Utils::Fs::expandPathAbs(newLocation));
|
||||
torrent->setAutoTMMEnabled(false);
|
||||
torrent->setSavePath(Utils::Fs::expandPathAbs(newLocation));
|
||||
});
|
||||
}
|
||||
|
||||
void TorrentsController::setSavePathAction()
|
||||
{
|
||||
requireParams({"id", "path"});
|
||||
|
||||
const QStringList ids {params()["id"].split('|')};
|
||||
const QString newPath {params()["path"]};
|
||||
|
||||
if (newPath.isEmpty())
|
||||
throw APIError(APIErrorType::BadParams, tr("Save path cannot be empty"));
|
||||
|
||||
// try to create the directory if it does not exist
|
||||
if (!QDir(newPath).mkpath("."))
|
||||
throw APIError(APIErrorType::Conflict, tr("Cannot create target directory"));
|
||||
|
||||
// check permissions
|
||||
if (!QFileInfo(newPath).isWritable())
|
||||
throw APIError(APIErrorType::AccessDenied, tr("Cannot write to directory"));
|
||||
|
||||
applyToTorrents(ids, [&newPath](BitTorrent::Torrent *const torrent)
|
||||
{
|
||||
if (!torrent->isAutoTMMEnabled())
|
||||
torrent->setSavePath(newPath);
|
||||
});
|
||||
}
|
||||
|
||||
void TorrentsController::setDownloadPathAction()
|
||||
{
|
||||
requireParams({"id", "path"});
|
||||
|
||||
const QStringList ids {params()["id"].split('|')};
|
||||
const QString newPath {params()["path"]};
|
||||
|
||||
if (!newPath.isEmpty())
|
||||
{
|
||||
// try to create the directory if it does not exist
|
||||
if (!QDir(newPath).mkpath("."))
|
||||
throw APIError(APIErrorType::Conflict, tr("Cannot create target directory"));
|
||||
|
||||
// check permissions
|
||||
if (!QFileInfo(newPath).isWritable())
|
||||
throw APIError(APIErrorType::AccessDenied, tr("Cannot write to directory"));
|
||||
}
|
||||
|
||||
applyToTorrents(ids, [&newPath](BitTorrent::Torrent *const torrent)
|
||||
{
|
||||
if (!torrent->isAutoTMMEnabled())
|
||||
torrent->setDownloadPath(newPath);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1164,16 +1223,24 @@ void TorrentsController::createCategoryAction()
|
||||
{
|
||||
requireParams({"category"});
|
||||
|
||||
const QString category {params()["category"]};
|
||||
const QString savePath {params()["savePath"]};
|
||||
|
||||
const QString category = params()["category"];
|
||||
if (category.isEmpty())
|
||||
throw APIError(APIErrorType::BadParams, tr("Category cannot be empty"));
|
||||
|
||||
if (!BitTorrent::Session::isValidCategoryName(category))
|
||||
throw APIError(APIErrorType::Conflict, tr("Incorrect category name"));
|
||||
|
||||
if (!BitTorrent::Session::instance()->addCategory(category, savePath))
|
||||
const QString savePath = params()["savePath"];
|
||||
const auto useDownloadPath = parseBool(params()["downloadPathEnabled"]);
|
||||
BitTorrent::CategoryOptions categoryOptions;
|
||||
categoryOptions.savePath = savePath;
|
||||
if (useDownloadPath.has_value())
|
||||
{
|
||||
const QString downloadPath = params()["downloadPath"];
|
||||
categoryOptions.downloadPath = {useDownloadPath.value(), downloadPath};
|
||||
}
|
||||
|
||||
if (!BitTorrent::Session::instance()->addCategory(category, categoryOptions))
|
||||
throw APIError(APIErrorType::Conflict, tr("Unable to create category"));
|
||||
}
|
||||
|
||||
@@ -1181,13 +1248,21 @@ void TorrentsController::editCategoryAction()
|
||||
{
|
||||
requireParams({"category", "savePath"});
|
||||
|
||||
const QString category {params()["category"]};
|
||||
const QString savePath {params()["savePath"]};
|
||||
|
||||
const QString category = params()["category"];
|
||||
if (category.isEmpty())
|
||||
throw APIError(APIErrorType::BadParams, tr("Category cannot be empty"));
|
||||
|
||||
if (!BitTorrent::Session::instance()->editCategory(category, savePath))
|
||||
const QString savePath = params()["savePath"];
|
||||
const auto useDownloadPath = parseBool(params()["downloadPathEnabled"]);
|
||||
BitTorrent::CategoryOptions categoryOptions;
|
||||
categoryOptions.savePath = savePath;
|
||||
if (useDownloadPath.has_value())
|
||||
{
|
||||
const QString downloadPath = params()["downloadPath"];
|
||||
categoryOptions.downloadPath = {useDownloadPath.value(), downloadPath};
|
||||
}
|
||||
|
||||
if (!BitTorrent::Session::instance()->editCategory(category, categoryOptions))
|
||||
throw APIError(APIErrorType::Conflict, tr("Unable to edit category"));
|
||||
}
|
||||
|
||||
@@ -1202,16 +1277,16 @@ void TorrentsController::removeCategoriesAction()
|
||||
|
||||
void TorrentsController::categoriesAction()
|
||||
{
|
||||
const auto session = BitTorrent::Session::instance();
|
||||
|
||||
QJsonObject categories;
|
||||
const QStringMap categoriesMap = BitTorrent::Session::instance()->categories();
|
||||
for (auto it = categoriesMap.cbegin(); it != categoriesMap.cend(); ++it)
|
||||
const QStringList categoriesList = session->categories();
|
||||
for (const auto &categoryName : categoriesList)
|
||||
{
|
||||
const auto &key = it.key();
|
||||
categories[key] = QJsonObject
|
||||
{
|
||||
{"name", key},
|
||||
{"savePath", it.value()}
|
||||
};
|
||||
const BitTorrent::CategoryOptions categoryOptions = session->categoryOptions(categoryName);
|
||||
QJsonObject category = categoryOptions.toJSON();
|
||||
category.insert(QLatin1String("name"), categoryName);
|
||||
categories[categoryName] = category;
|
||||
}
|
||||
|
||||
setResult(categories);
|
||||
|
||||
@@ -78,6 +78,8 @@ private slots:
|
||||
void topPrioAction();
|
||||
void bottomPrioAction();
|
||||
void setLocationAction();
|
||||
void setSavePathAction();
|
||||
void setDownloadPathAction();
|
||||
void setAutoManagementAction();
|
||||
void setSuperSeedingAction();
|
||||
void setForceStartAction();
|
||||
|
||||
Reference in New Issue
Block a user