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:
Vladimir Golovnev (Glassez)
2021-05-20 10:36:44 +03:00
committed by Vladimir Golovnev (glassez)
parent b0e41abf5a
commit 1c0f8b4289
48 changed files with 1457 additions and 599 deletions

View File

@@ -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()

View File

@@ -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);
}

View File

@@ -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()},

View File

@@ -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";

View File

@@ -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;

View File

@@ -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);

View File

@@ -78,6 +78,8 @@ private slots:
void topPrioAction();
void bottomPrioAction();
void setLocationAction();
void setSavePathAction();
void setDownloadPathAction();
void setAutoManagementAction();
void setSuperSeedingAction();
void setForceStartAction();