mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-11 07:18:08 +00:00
Added command line arguments for specifying options when adding torrents
Arguments include adding torrents as paused/started, skiping hash check, setting category, downloading in sequential order, downloading first and last pieces first, and skipping the 'add new torrent' dialog. Added TriStateBoolOption class for specifying options that don't have a default value when unused (e.g. add-paused). Also improved command line usage text to include more information, have better organization, and not exceed 80 columns in width. Also also added firstLastPiecePriority field to BitTorrent::AddTorrentData, and modified TorrentHandle so that if first/last piece priority should be on, it will be toggled on after the torrent's metadata has loaded.
This commit is contained in:
parent
172991e068
commit
eba41978b0
@ -407,15 +407,63 @@ void Application::processParams(const QStringList ¶ms)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
BitTorrent::AddTorrentParams torrentParams;
|
||||||
|
TriStateBool skipTorrentDialog;
|
||||||
|
|
||||||
foreach (QString param, params) {
|
foreach (QString param, params) {
|
||||||
param = param.trimmed();
|
param = param.trimmed();
|
||||||
|
|
||||||
|
// Process strings indicating options specified by the user.
|
||||||
|
|
||||||
|
if (param.startsWith(QLatin1String("@savePath="))) {
|
||||||
|
torrentParams.savePath = param.mid(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param.startsWith(QLatin1String("@addPaused="))) {
|
||||||
|
torrentParams.addPaused = param.mid(11).toInt() ? TriStateBool::True : TriStateBool::False;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param == QLatin1String("@skipChecking")) {
|
||||||
|
torrentParams.skipChecking = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param.startsWith(QLatin1String("@category="))) {
|
||||||
|
torrentParams.category = param.mid(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param == QLatin1String("@sequential")) {
|
||||||
|
torrentParams.sequential = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param == QLatin1String("@firstLastPiecePriority")) {
|
||||||
|
torrentParams.firstLastPiecePriority = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param.startsWith(QLatin1String("@skipDialog="))) {
|
||||||
|
skipTorrentDialog = param.mid(12).toInt() ? TriStateBool::True : TriStateBool::False;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_GUI
|
#ifndef DISABLE_GUI
|
||||||
if (AddNewTorrentDialog::isEnabled())
|
// There are two circumstances in which we want to show the torrent
|
||||||
AddNewTorrentDialog::show(param, m_window);
|
// dialog. One is when the application settings specify that it should
|
||||||
|
// be shown and skipTorrentDialog is undefined. The other is when
|
||||||
|
// skipTorrentDialog is false, meaning that the application setting
|
||||||
|
// should be overridden.
|
||||||
|
const bool showDialogForThisTorrent =
|
||||||
|
((AddNewTorrentDialog::isEnabled() && skipTorrentDialog == TriStateBool::Undefined)
|
||||||
|
|| skipTorrentDialog == TriStateBool::False);
|
||||||
|
if (showDialogForThisTorrent)
|
||||||
|
AddNewTorrentDialog::show(param, torrentParams, m_window);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
BitTorrent::Session::instance()->addTorrent(param);
|
BitTorrent::Session::instance()->addTorrent(param, torrentParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ int main(int argc, char *argv[])
|
|||||||
qDebug("qBittorrent is already running for this user.");
|
qDebug("qBittorrent is already running for this user.");
|
||||||
|
|
||||||
QThread::msleep(300);
|
QThread::msleep(300);
|
||||||
app->sendParams(params.torrents);
|
app->sendParams(params.paramList());
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -235,7 +235,7 @@ int main(int argc, char *argv[])
|
|||||||
signal(SIGSEGV, sigAbnormalHandler);
|
signal(SIGSEGV, sigAbnormalHandler);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return app->exec(params.torrents);
|
return app->exec(params.paramList());
|
||||||
}
|
}
|
||||||
catch (CommandLineParameterError &er) {
|
catch (CommandLineParameterError &er) {
|
||||||
displayBadArgMessage(er.messageForUser());
|
displayBadArgMessage(er.messageForUser());
|
||||||
|
@ -47,6 +47,10 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
const int USAGE_INDENTATION = 4;
|
||||||
|
const int USAGE_TEXT_COLUMN = 31;
|
||||||
|
const int WRAP_AT_COLUMN = 80;
|
||||||
|
|
||||||
// Base option class. Encapsulates name operations.
|
// Base option class. Encapsulates name operations.
|
||||||
class Option
|
class Option
|
||||||
{
|
{
|
||||||
@ -78,14 +82,15 @@ namespace
|
|||||||
+ QString(QLatin1String(m_name)).toUpper().replace(QLatin1Char('-'), QLatin1Char('_'));
|
+ QString(QLatin1String(m_name)).toUpper().replace(QLatin1Char('-'), QLatin1Char('_'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
static QString padUsageText(const QString &usage)
|
static QString padUsageText(const QString &usage)
|
||||||
{
|
{
|
||||||
const int TAB_WIDTH = 8;
|
QString res = QString(USAGE_INDENTATION, ' ') + usage;
|
||||||
QString res = QLatin1String("\t") + usage;
|
|
||||||
if (usage.size() < 2 * TAB_WIDTH)
|
if ((USAGE_TEXT_COLUMN - usage.length() - 4) > 0)
|
||||||
return res + QLatin1String("\t\t");
|
return res + QString(USAGE_TEXT_COLUMN - usage.length() - 4, ' ');
|
||||||
else
|
else
|
||||||
return res + QLatin1String("\t");
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -125,7 +130,7 @@ namespace
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const QString &s, const BoolOption &o)
|
bool operator==(const QString &s, const BoolOption &o)
|
||||||
{
|
{
|
||||||
return o == s;
|
return o == s;
|
||||||
}
|
}
|
||||||
@ -185,7 +190,7 @@ namespace
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const QString &s, const StringOption &o)
|
bool operator==(const QString &s, const StringOption &o)
|
||||||
{
|
{
|
||||||
return o == s;
|
return o == s;
|
||||||
}
|
}
|
||||||
@ -230,7 +235,69 @@ namespace
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const QString &s, const IntOption &o)
|
bool operator==(const QString &s, const IntOption &o)
|
||||||
|
{
|
||||||
|
return o == s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option that is explicitly set to true or false, and whose value is undefined when unspecified.
|
||||||
|
// May not have a shortcut.
|
||||||
|
class TriStateBoolOption: protected StringOption
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr TriStateBoolOption(const char *name)
|
||||||
|
: StringOption {name}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
using StringOption::operator==;
|
||||||
|
|
||||||
|
QString usage() const
|
||||||
|
{
|
||||||
|
return StringOption::usage(QLatin1String("true|false"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TriStateBool value(const QString &arg) const
|
||||||
|
{
|
||||||
|
QString val = StringOption::value(arg);
|
||||||
|
|
||||||
|
if (val.toUpper() == QLatin1String("TRUE") || val == QLatin1String("1")) {
|
||||||
|
return TriStateBool::True;
|
||||||
|
}
|
||||||
|
else if (val.toUpper() == QLatin1String("FALSE") || val == QLatin1String("0")) {
|
||||||
|
return TriStateBool::False;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'",
|
||||||
|
"e.g. Parameter '--add-paused' must follow syntax "
|
||||||
|
"'--add-paused=<true|false>'")
|
||||||
|
.arg(fullParameter())
|
||||||
|
.arg(QLatin1String("<true|false>")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TriStateBool value(const QProcessEnvironment &env) const
|
||||||
|
{
|
||||||
|
QString val = env.value(envVarName());
|
||||||
|
|
||||||
|
if (val.isEmpty()) {
|
||||||
|
return TriStateBool::Undefined;
|
||||||
|
}
|
||||||
|
else if (val.toUpper() == QLatin1String("TRUE") || val == QLatin1String("1")) {
|
||||||
|
return TriStateBool::True;
|
||||||
|
}
|
||||||
|
else if (val.toUpper() == QLatin1String("FALSE") || val == QLatin1String("0")) {
|
||||||
|
return TriStateBool::False;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qDebug() << QObject::tr("Expected %1 in environment variable '%2', but got '%3'")
|
||||||
|
.arg(QLatin1String("true|false")).arg(envVarName()).arg(val);
|
||||||
|
return TriStateBool::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const QString &s, const TriStateBoolOption &o)
|
||||||
{
|
{
|
||||||
return o == s;
|
return o == s;
|
||||||
}
|
}
|
||||||
@ -247,10 +314,22 @@ namespace
|
|||||||
constexpr const StringOption CONFIGURATION_OPTION = {"configuration"};
|
constexpr const StringOption CONFIGURATION_OPTION = {"configuration"};
|
||||||
constexpr const BoolOption PORTABLE_OPTION = {"portable"};
|
constexpr const BoolOption PORTABLE_OPTION = {"portable"};
|
||||||
constexpr const BoolOption RELATIVE_FASTRESUME = {"relative-fastresume"};
|
constexpr const BoolOption RELATIVE_FASTRESUME = {"relative-fastresume"};
|
||||||
|
constexpr const StringOption SAVE_PATH_OPTION = {"save-path"};
|
||||||
|
constexpr const TriStateBoolOption PAUSED_OPTION = {"add-paused"};
|
||||||
|
constexpr const BoolOption SKIP_HASH_CHECK_OPTION = {"skip-hash-check"};
|
||||||
|
constexpr const StringOption CATEGORY_OPTION = {"category"};
|
||||||
|
constexpr const BoolOption SEQUENTIAL_OPTION = {"sequential"};
|
||||||
|
constexpr const BoolOption FIRST_AND_LAST_OPTION = {"first-and-last"};
|
||||||
|
constexpr const TriStateBoolOption SKIP_DIALOG_OPTION = {"skip-dialog"};
|
||||||
}
|
}
|
||||||
|
|
||||||
QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &env)
|
QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &env)
|
||||||
: showHelp(false)
|
: showHelp(false)
|
||||||
|
, relativeFastresumePaths(RELATIVE_FASTRESUME.value(env))
|
||||||
|
, portableMode(PORTABLE_OPTION.value(env))
|
||||||
|
, skipChecking(SKIP_HASH_CHECK_OPTION.value(env))
|
||||||
|
, sequential(SEQUENTIAL_OPTION.value(env))
|
||||||
|
, firstLastPiecePriority(FIRST_AND_LAST_OPTION.value(env))
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
, showVersion(false)
|
, showVersion(false)
|
||||||
#endif
|
#endif
|
||||||
@ -260,13 +339,59 @@ QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &en
|
|||||||
, shouldDaemonize(DAEMON_OPTION.value(env))
|
, shouldDaemonize(DAEMON_OPTION.value(env))
|
||||||
#endif
|
#endif
|
||||||
, webUiPort(WEBUI_PORT_OPTION.value(env, -1))
|
, webUiPort(WEBUI_PORT_OPTION.value(env, -1))
|
||||||
|
, addPaused(PAUSED_OPTION.value(env))
|
||||||
|
, skipDialog(SKIP_DIALOG_OPTION.value(env))
|
||||||
, profileDir(PROFILE_OPTION.value(env))
|
, profileDir(PROFILE_OPTION.value(env))
|
||||||
, relativeFastresumePaths(RELATIVE_FASTRESUME.value(env))
|
|
||||||
, portableMode(PORTABLE_OPTION.value(env))
|
|
||||||
, configurationName(CONFIGURATION_OPTION.value(env))
|
, configurationName(CONFIGURATION_OPTION.value(env))
|
||||||
|
, savePath(SAVE_PATH_OPTION.value(env))
|
||||||
|
, category(CATEGORY_OPTION.value(env))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList QBtCommandLineParameters::paramList() const
|
||||||
|
{
|
||||||
|
QStringList result;
|
||||||
|
// Because we're passing a string list to the currently running
|
||||||
|
// qBittorrent process, we need some way of passing along the options
|
||||||
|
// the user has specified. Here we place special strings that are
|
||||||
|
// almost certainly not going to collide with a file path or URL
|
||||||
|
// specified by the user, and placing them at the beginning of the
|
||||||
|
// string listr so that they will be processed before the list of
|
||||||
|
// torrent paths or URLs.
|
||||||
|
|
||||||
|
if (!savePath.isEmpty())
|
||||||
|
result.append(QString("@savePath=%1").arg(savePath));
|
||||||
|
|
||||||
|
if (addPaused == TriStateBool::True) {
|
||||||
|
result.append(QLatin1String("@addPaused=1"));
|
||||||
|
}
|
||||||
|
else if (addPaused == TriStateBool::False) {
|
||||||
|
result.append(QLatin1String("@addPaused=0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipChecking)
|
||||||
|
result.append(QLatin1String("@skipChecking"));
|
||||||
|
|
||||||
|
if (!category.isEmpty())
|
||||||
|
result.append(QString("@category=%1").arg(category));
|
||||||
|
|
||||||
|
if (sequential)
|
||||||
|
result.append(QLatin1String("@sequential"));
|
||||||
|
|
||||||
|
if (firstLastPiecePriority)
|
||||||
|
result.append(QLatin1String("@firstLastPiecePriority"));
|
||||||
|
|
||||||
|
if (skipDialog == TriStateBool::True) {
|
||||||
|
result.append(QLatin1String("@skipDialog=1"));
|
||||||
|
}
|
||||||
|
else if (skipDialog == TriStateBool::False) {
|
||||||
|
result.append(QLatin1String("@skipDialog=0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
result += torrents;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QBtCommandLineParameters parseCommandLine(const QStringList &args)
|
QBtCommandLineParameters parseCommandLine(const QStringList &args)
|
||||||
{
|
{
|
||||||
QBtCommandLineParameters result {QProcessEnvironment::systemEnvironment()};
|
QBtCommandLineParameters result {QProcessEnvironment::systemEnvironment()};
|
||||||
@ -312,6 +437,27 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
|
|||||||
else if (arg == CONFIGURATION_OPTION) {
|
else if (arg == CONFIGURATION_OPTION) {
|
||||||
result.configurationName = CONFIGURATION_OPTION.value(arg);
|
result.configurationName = CONFIGURATION_OPTION.value(arg);
|
||||||
}
|
}
|
||||||
|
else if (arg == SAVE_PATH_OPTION) {
|
||||||
|
result.savePath = SAVE_PATH_OPTION.value(arg);
|
||||||
|
}
|
||||||
|
else if (arg == PAUSED_OPTION) {
|
||||||
|
result.addPaused = PAUSED_OPTION.value(arg);
|
||||||
|
}
|
||||||
|
else if (arg == SKIP_HASH_CHECK_OPTION) {
|
||||||
|
result.skipChecking = true;
|
||||||
|
}
|
||||||
|
else if (arg == CATEGORY_OPTION) {
|
||||||
|
result.category = CATEGORY_OPTION.value(arg);
|
||||||
|
}
|
||||||
|
else if (arg == SEQUENTIAL_OPTION) {
|
||||||
|
result.sequential = true;
|
||||||
|
}
|
||||||
|
else if (arg == FIRST_AND_LAST_OPTION) {
|
||||||
|
result.firstLastPiecePriority = true;
|
||||||
|
}
|
||||||
|
else if (arg == SKIP_DIALOG_OPTION) {
|
||||||
|
result.skipDialog = SKIP_DIALOG_OPTION.value(arg);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// Unknown argument
|
// Unknown argument
|
||||||
result.unknownParameter = arg;
|
result.unknownParameter = arg;
|
||||||
@ -343,43 +489,82 @@ const QString& CommandLineParameterError::messageForUser() const
|
|||||||
return m_messageForUser;
|
return m_messageForUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString wrapText(const QString &text, int initialIndentation = USAGE_TEXT_COLUMN, int wrapAtColumn = WRAP_AT_COLUMN)
|
||||||
|
{
|
||||||
|
QStringList words = text.split(' ');
|
||||||
|
QStringList lines = {words.first()};
|
||||||
|
int currentLineMaxLength = wrapAtColumn - initialIndentation;
|
||||||
|
|
||||||
|
foreach (const QString &word, words.mid(1)) {
|
||||||
|
if (lines.last().length() + word.length() + 1 < currentLineMaxLength) {
|
||||||
|
lines.last().append(" " + word);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lines.append(QString(initialIndentation, ' ') + word);
|
||||||
|
currentLineMaxLength = wrapAtColumn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
QString makeUsage(const QString &prgName)
|
QString makeUsage(const QString &prgName)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
QTextStream stream(&text, QIODevice::WriteOnly);
|
QTextStream stream(&text, QIODevice::WriteOnly);
|
||||||
|
QString indentation = QString(USAGE_INDENTATION, ' ');
|
||||||
|
|
||||||
stream << QObject::tr("Usage:") << '\n';
|
stream << QObject::tr("Usage:") << '\n';
|
||||||
#ifndef Q_OS_WIN
|
stream << indentation << prgName << QLatin1String(" [options] [(<filename> | <url>)...]") << '\n';
|
||||||
stream << '\t' << prgName << " [options] [(<filename> | <url>)...]" << '\n';
|
|
||||||
#endif
|
|
||||||
|
|
||||||
stream << QObject::tr("Options:") << '\n';
|
stream << QObject::tr("Options:") << '\n';
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
stream << SHOW_VERSION_OPTION.usage() << QObject::tr("Displays program version and exit") << '\n';
|
stream << SHOW_VERSION_OPTION.usage() << wrapText(QObject::tr("Displays program version and exit")) << '\n';
|
||||||
#endif
|
#endif
|
||||||
stream << SHOW_HELP_OPTION.usage() << QObject::tr("Displays this help message and exit") << '\n';
|
stream << SHOW_HELP_OPTION.usage() << wrapText(QObject::tr("Displays this help message and exit")) << '\n';
|
||||||
stream << WEBUI_PORT_OPTION.usage(QLatin1String("port"))
|
stream << WEBUI_PORT_OPTION.usage(QObject::tr("port"))
|
||||||
<< QObject::tr("Changes the Web UI port")
|
<< wrapText(QObject::tr("Changes the Web UI port"))
|
||||||
<< '\n';
|
<< '\n';
|
||||||
#ifndef DISABLE_GUI
|
#ifndef DISABLE_GUI
|
||||||
stream << NO_SPLASH_OPTION.usage() << QObject::tr("Disable splash screen") << '\n';
|
stream << NO_SPLASH_OPTION.usage() << wrapText(QObject::tr("Disable splash screen")) << '\n';
|
||||||
#else
|
#else
|
||||||
stream << DAEMON_OPTION.usage() << QObject::tr("Run in daemon-mode (background)") << '\n';
|
stream << DAEMON_OPTION.usage() << wrapText(QObject::tr("Run in daemon-mode (background)")) << '\n';
|
||||||
#endif
|
#endif
|
||||||
stream << PROFILE_OPTION.usage(QLatin1String("dir")) << QObject::tr("Store configuration files in <dir>") << '\n';
|
//: Use appropriate short form or abbreviation of "directory"
|
||||||
stream << CONFIGURATION_OPTION.usage(QLatin1String("name")) << QObject::tr("Store configuration files in directories qBittorrent_<name>") << '\n';
|
stream << PROFILE_OPTION.usage(QObject::tr("dir"))
|
||||||
stream << RELATIVE_FASTRESUME.usage() << QObject::tr("Hack into libtorrent fastresume files and make file paths relative to the profile directory") << '\n';
|
<< wrapText(QObject::tr("Store configuration files in <dir>")) << '\n';
|
||||||
stream << PORTABLE_OPTION.usage() << QObject::tr("Shortcut for --profile=<exe dir>/profile --relative-fastresume") << '\n';
|
stream << CONFIGURATION_OPTION.usage(QObject::tr("name"))
|
||||||
stream << "\tfiles or urls\t\t" << QObject::tr("Downloads the torrents passed by the user") << '\n'
|
<< wrapText(QObject::tr("Store configuration files in directories qBittorrent_<name>")) << '\n';
|
||||||
|
stream << RELATIVE_FASTRESUME.usage()
|
||||||
|
<< wrapText(QObject::tr("Hack into libtorrent fastresume files and make file paths relative "
|
||||||
|
"to the profile directory")) << '\n';
|
||||||
|
stream << PORTABLE_OPTION.usage()
|
||||||
|
<< wrapText(QObject::tr("Shortcut for --profile=<exe dir>/profile --relative-fastresume")) << '\n';
|
||||||
|
stream << Option::padUsageText(QObject::tr("files or urls"))
|
||||||
|
<< wrapText(QObject::tr("Downloads the torrents passed by the user")) << '\n'
|
||||||
<< '\n';
|
<< '\n';
|
||||||
|
|
||||||
stream << QObject::tr("Option values may be supplied via environment variables.") << '\n'
|
stream << wrapText(QObject::tr("Options when adding new torrents:"), 0) << '\n';
|
||||||
<< QObject::tr("For option named 'parameter-name', environment variable name is 'QBT_PARAMETER_NAME' (in upper case, '-' replaced with '_')") << '\n'
|
stream << SAVE_PATH_OPTION.usage(QObject::tr("path")) << wrapText(QObject::tr("Torrent save path")) << '\n';
|
||||||
<< QObject::tr("To pass flag values, set the variable to '1' or 'TRUE'.") << '\n'
|
stream << PAUSED_OPTION.usage() << wrapText(QObject::tr("Add torrents as started or paused")) << '\n';
|
||||||
<< QObject::tr("For example, to disable the splash screen: ")
|
stream << SKIP_HASH_CHECK_OPTION.usage() << wrapText(QObject::tr("Skip hash check")) << '\n';
|
||||||
<< "QBT_NO_SPLASH=1 " << prgName << '\n'
|
stream << CATEGORY_OPTION.usage(QObject::tr("name"))
|
||||||
<< '\n'
|
<< wrapText(QObject::tr("Assign torrents to category. If the category doesn't exist, it will be "
|
||||||
<< QObject::tr("Command line parameters take precedence over environment variables") << '\n';
|
"created.")) << '\n';
|
||||||
|
stream << SEQUENTIAL_OPTION.usage() << wrapText(QObject::tr("Download files in sequential order")) << '\n';
|
||||||
|
stream << FIRST_AND_LAST_OPTION.usage()
|
||||||
|
<< wrapText(QObject::tr("Download first and last pieces first")) << '\n';
|
||||||
|
stream << SKIP_DIALOG_OPTION.usage()
|
||||||
|
<< wrapText(QObject::tr("Specifies whether the \"Add New Torrent\" dialog opens when adding a "
|
||||||
|
"torrent.")) << '\n';
|
||||||
|
stream << '\n';
|
||||||
|
|
||||||
|
stream << wrapText(QObject::tr("Option values may be supplied via environment variables. For option named "
|
||||||
|
"'parameter-name', environment variable name is 'QBT_PARAMETER_NAME' (in upper "
|
||||||
|
"case, '-' replaced with '_'). To pass flag values, set the variable to '1' or "
|
||||||
|
"'TRUE'. For example, to disable the splash screen: "), 0) << "\n"
|
||||||
|
<< QLatin1String("QBT_NO_SPLASH=1 ") << prgName << '\n'
|
||||||
|
<< wrapText(QObject::tr("Command line parameters take precedence over environment variables"), 0) << '\n';
|
||||||
|
|
||||||
stream << flush;
|
stream << flush;
|
||||||
return text;
|
return text;
|
||||||
|
@ -38,11 +38,13 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "base/tristatebool.h"
|
||||||
|
|
||||||
class QProcessEnvironment;
|
class QProcessEnvironment;
|
||||||
|
|
||||||
struct QBtCommandLineParameters
|
struct QBtCommandLineParameters
|
||||||
{
|
{
|
||||||
bool showHelp;
|
bool showHelp, relativeFastresumePaths, portableMode, skipChecking, sequential, firstLastPiecePriority;
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
bool showVersion;
|
bool showVersion;
|
||||||
#endif
|
#endif
|
||||||
@ -52,14 +54,12 @@ struct QBtCommandLineParameters
|
|||||||
bool shouldDaemonize;
|
bool shouldDaemonize;
|
||||||
#endif
|
#endif
|
||||||
int webUiPort;
|
int webUiPort;
|
||||||
QString profileDir;
|
TriStateBool addPaused, skipDialog;
|
||||||
bool relativeFastresumePaths;
|
|
||||||
bool portableMode;
|
|
||||||
QString configurationName;
|
|
||||||
QStringList torrents;
|
QStringList torrents;
|
||||||
QString unknownParameter;
|
QString profileDir, configurationName, savePath, category, unknownParameter;
|
||||||
|
|
||||||
QBtCommandLineParameters(const QProcessEnvironment&);
|
QBtCommandLineParameters(const QProcessEnvironment&);
|
||||||
|
QStringList paramList() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommandLineParameterError: public std::runtime_error
|
class CommandLineParameterError: public std::runtime_error
|
||||||
|
@ -42,6 +42,7 @@ namespace BitTorrent
|
|||||||
QString savePath;
|
QString savePath;
|
||||||
bool disableTempPath = false; // e.g. for imported torrents
|
bool disableTempPath = false; // e.g. for imported torrents
|
||||||
bool sequential = false;
|
bool sequential = false;
|
||||||
|
bool firstLastPiecePriority = false;
|
||||||
TriStateBool addForced;
|
TriStateBool addForced;
|
||||||
TriStateBool addPaused;
|
TriStateBool addPaused;
|
||||||
QVector<int> filePriorities; // used if TorrentInfo is set
|
QVector<int> filePriorities; // used if TorrentInfo is set
|
||||||
|
@ -3666,6 +3666,8 @@ namespace
|
|||||||
magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
|
magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
|
||||||
torrentData.addPaused = fast.dict_find_int_value("qBt-paused");
|
torrentData.addPaused = fast.dict_find_int_value("qBt-paused");
|
||||||
torrentData.addForced = fast.dict_find_int_value("qBt-forced");
|
torrentData.addForced = fast.dict_find_int_value("qBt-forced");
|
||||||
|
torrentData.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority");
|
||||||
|
torrentData.sequential = fast.dict_find_int_value("qBt-sequential");
|
||||||
|
|
||||||
prio = fast.dict_find_int_value("qBt-queuePosition");
|
prio = fast.dict_find_int_value("qBt-queuePosition");
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ AddTorrentData::AddTorrentData(const AddTorrentParams ¶ms)
|
|||||||
, savePath(params.savePath)
|
, savePath(params.savePath)
|
||||||
, disableTempPath(params.disableTempPath)
|
, disableTempPath(params.disableTempPath)
|
||||||
, sequential(params.sequential)
|
, sequential(params.sequential)
|
||||||
|
, firstLastPiecePriority(params.firstLastPiecePriority)
|
||||||
, hasSeedStatus(params.skipChecking) // do not react on 'torrent_finished_alert' when skipping
|
, hasSeedStatus(params.skipChecking) // do not react on 'torrent_finished_alert' when skipping
|
||||||
, skipChecking(params.skipChecking)
|
, skipChecking(params.skipChecking)
|
||||||
, hasRootFolder(params.createSubfolder == TriStateBool::Undefined
|
, hasRootFolder(params.createSubfolder == TriStateBool::Undefined
|
||||||
@ -208,6 +209,7 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
|||||||
, m_tempPathDisabled(data.disableTempPath)
|
, m_tempPathDisabled(data.disableTempPath)
|
||||||
, m_hasMissingFiles(false)
|
, m_hasMissingFiles(false)
|
||||||
, m_hasRootFolder(data.hasRootFolder)
|
, m_hasRootFolder(data.hasRootFolder)
|
||||||
|
, m_needsToSetFirstLastPiecePriority(false)
|
||||||
, m_pauseAfterRecheck(false)
|
, m_pauseAfterRecheck(false)
|
||||||
, m_needSaveResumeData(false)
|
, m_needSaveResumeData(false)
|
||||||
{
|
{
|
||||||
@ -217,12 +219,22 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
|||||||
updateStatus();
|
updateStatus();
|
||||||
m_hash = InfoHash(m_nativeStatus.info_hash);
|
m_hash = InfoHash(m_nativeStatus.info_hash);
|
||||||
|
|
||||||
if (!data.resumed) {
|
// NB: the following two if statements are present because we don't want
|
||||||
|
// to set either sequential download or first/last piece priority to false
|
||||||
|
// if their respective flags in data are false when a torrent is being
|
||||||
|
// resumed. This is because, in that circumstance, this constructor is
|
||||||
|
// called with those flags set to false, even if the torrent was set to
|
||||||
|
// download sequentially or have first/last piece priority enabled when
|
||||||
|
// its resume data was saved. These two settings are restored later. But
|
||||||
|
// if we set them to false now, both will erroneously not be restored.
|
||||||
|
if (!data.resumed || data.sequential)
|
||||||
setSequentialDownload(data.sequential);
|
setSequentialDownload(data.sequential);
|
||||||
if (hasMetadata()) {
|
if (!data.resumed || data.firstLastPiecePriority)
|
||||||
if (filesCount() == 1)
|
setFirstLastPiecePriority(data.firstLastPiecePriority);
|
||||||
m_hasRootFolder = false;
|
|
||||||
}
|
if (!data.resumed && hasMetadata()) {
|
||||||
|
if (filesCount() == 1)
|
||||||
|
m_hasRootFolder = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,7 +741,8 @@ bool TorrentHandle::isSequentialDownload() const
|
|||||||
|
|
||||||
bool TorrentHandle::hasFirstLastPiecePriority() const
|
bool TorrentHandle::hasFirstLastPiecePriority() const
|
||||||
{
|
{
|
||||||
if (!hasMetadata()) return false;
|
if (!hasMetadata())
|
||||||
|
return m_needsToSetFirstLastPiecePriority;
|
||||||
|
|
||||||
// Get int first media file
|
// Get int first media file
|
||||||
std::vector<int> fp;
|
std::vector<int> fp;
|
||||||
@ -1229,7 +1242,10 @@ void TorrentHandle::toggleSequentialDownload()
|
|||||||
|
|
||||||
void TorrentHandle::setFirstLastPiecePriority(bool b)
|
void TorrentHandle::setFirstLastPiecePriority(bool b)
|
||||||
{
|
{
|
||||||
if (!hasMetadata()) return;
|
if (!hasMetadata()) {
|
||||||
|
m_needsToSetFirstLastPiecePriority = b;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> fp = m_nativeHandle.file_priorities();
|
std::vector<int> fp = m_nativeHandle.file_priorities();
|
||||||
std::vector<int> pp = m_nativeHandle.piece_priorities();
|
std::vector<int> pp = m_nativeHandle.piece_priorities();
|
||||||
@ -1508,6 +1524,11 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
|
|||||||
resumeData["qBt-magnetUri"] = toMagnetUri().toStdString();
|
resumeData["qBt-magnetUri"] = toMagnetUri().toStdString();
|
||||||
resumeData["qBt-paused"] = isPaused();
|
resumeData["qBt-paused"] = isPaused();
|
||||||
resumeData["qBt-forced"] = isForced();
|
resumeData["qBt-forced"] = isForced();
|
||||||
|
// Both firstLastPiecePriority and sequential need to be stored in the
|
||||||
|
// resume data if there is no metadata, otherwise they won't be
|
||||||
|
// restored if qBittorrent quits before the metadata are retrieved:
|
||||||
|
resumeData["qBt-firstLastPiecePriority"] = hasFirstLastPiecePriority();
|
||||||
|
resumeData["qBt-sequential"] = isSequentialDownload();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto savePath = resumeData.find_key("save_path")->string();
|
auto savePath = resumeData.find_key("save_path")->string();
|
||||||
@ -1634,6 +1655,13 @@ void TorrentHandle::handleMetadataReceivedAlert(libt::metadata_received_alert *p
|
|||||||
m_speedMonitor.reset();
|
m_speedMonitor.reset();
|
||||||
m_session->handleTorrentPaused(this);
|
m_session->handleTorrentPaused(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If first/last piece priority was specified when adding this torrent, we can set it
|
||||||
|
// now that we have metadata:
|
||||||
|
if (m_needsToSetFirstLastPiecePriority) {
|
||||||
|
setFirstLastPiecePriority(true);
|
||||||
|
m_needsToSetFirstLastPiecePriority = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTempPathChanged()
|
void TorrentHandle::handleTempPathChanged()
|
||||||
|
@ -96,6 +96,7 @@ namespace BitTorrent
|
|||||||
QString savePath;
|
QString savePath;
|
||||||
bool disableTempPath;
|
bool disableTempPath;
|
||||||
bool sequential;
|
bool sequential;
|
||||||
|
bool firstLastPiecePriority;
|
||||||
bool hasSeedStatus;
|
bool hasSeedStatus;
|
||||||
bool skipChecking;
|
bool skipChecking;
|
||||||
bool hasRootFolder;
|
bool hasRootFolder;
|
||||||
@ -429,6 +430,7 @@ namespace BitTorrent
|
|||||||
bool m_tempPathDisabled;
|
bool m_tempPathDisabled;
|
||||||
bool m_hasMissingFiles;
|
bool m_hasMissingFiles;
|
||||||
bool m_hasRootFolder;
|
bool m_hasRootFolder;
|
||||||
|
bool m_needsToSetFirstLastPiecePriority;
|
||||||
|
|
||||||
bool m_pauseAfterRecheck;
|
bool m_pauseAfterRecheck;
|
||||||
bool m_needSaveResumeData;
|
bool m_needSaveResumeData;
|
||||||
|
@ -76,14 +76,16 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::AddNewTorrentDialog)
|
, ui(new Ui::AddNewTorrentDialog)
|
||||||
, m_contentModel(0)
|
, m_contentModel(0)
|
||||||
, m_contentDelegate(0)
|
, m_contentDelegate(0)
|
||||||
, m_hasMetadata(false)
|
, m_hasMetadata(false)
|
||||||
, m_oldIndex(0)
|
, m_oldIndex(0)
|
||||||
|
, m_torrentParams(inParams)
|
||||||
{
|
{
|
||||||
|
// TODO: set dialog file properties using m_torrentParams.filePriorities
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
ui->lblMetaLoading->setVisible(false);
|
ui->lblMetaLoading->setVisible(false);
|
||||||
@ -91,7 +93,13 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
|||||||
|
|
||||||
auto session = BitTorrent::Session::instance();
|
auto session = BitTorrent::Session::instance();
|
||||||
|
|
||||||
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
|
if (m_torrentParams.addPaused == TriStateBool::True)
|
||||||
|
ui->startTorrentCheckBox->setChecked(false);
|
||||||
|
else if (m_torrentParams.addPaused == TriStateBool::False)
|
||||||
|
ui->startTorrentCheckBox->setChecked(true);
|
||||||
|
else
|
||||||
|
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
|
||||||
|
|
||||||
ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
|
ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
|
||||||
ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
|
ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
|
||||||
ui->comboTTM->blockSignals(false);
|
ui->comboTTM->blockSignals(false);
|
||||||
@ -99,8 +107,15 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
|||||||
connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int)));
|
connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int)));
|
||||||
connect(ui->browseButton, SIGNAL(clicked()), SLOT(browseButton_clicked()));
|
connect(ui->browseButton, SIGNAL(clicked()), SLOT(browseButton_clicked()));
|
||||||
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
|
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
|
||||||
ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder());
|
|
||||||
|
|
||||||
|
if (m_torrentParams.createSubfolder == TriStateBool::True)
|
||||||
|
ui->createSubfolderCheckBox->setChecked(true);
|
||||||
|
else if (m_torrentParams.createSubfolder == TriStateBool::False)
|
||||||
|
ui->createSubfolderCheckBox->setChecked(false);
|
||||||
|
else
|
||||||
|
ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder());
|
||||||
|
|
||||||
|
ui->skipCheckingCheckBox->setChecked(m_torrentParams.skipChecking);
|
||||||
ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never);
|
ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never);
|
||||||
|
|
||||||
// Load categories
|
// Load categories
|
||||||
@ -108,12 +123,14 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
|||||||
std::sort(categories.begin(), categories.end(), Utils::String::naturalCompareCaseInsensitive);
|
std::sort(categories.begin(), categories.end(), Utils::String::naturalCompareCaseInsensitive);
|
||||||
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
|
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
|
||||||
|
|
||||||
|
if (!m_torrentParams.category.isEmpty())
|
||||||
|
ui->categoryComboBox->addItem(m_torrentParams.category);
|
||||||
if (!defaultCategory.isEmpty())
|
if (!defaultCategory.isEmpty())
|
||||||
ui->categoryComboBox->addItem(defaultCategory);
|
ui->categoryComboBox->addItem(defaultCategory);
|
||||||
ui->categoryComboBox->addItem("");
|
ui->categoryComboBox->addItem("");
|
||||||
|
|
||||||
foreach (const QString &category, categories)
|
foreach (const QString &category, categories)
|
||||||
if (category != defaultCategory)
|
if (category != defaultCategory && category != m_torrentParams.category)
|
||||||
ui->categoryComboBox->addItem(category);
|
ui->categoryComboBox->addItem(category);
|
||||||
|
|
||||||
ui->categoryComboBox->model()->sort(0);
|
ui->categoryComboBox->model()->sort(0);
|
||||||
@ -179,9 +196,9 @@ void AddNewTorrentDialog::saveState()
|
|||||||
settings()->storeValue(KEY_EXPANDED, ui->adv_button->isChecked());
|
settings()->storeValue(KEY_EXPANDED, ui->adv_button->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
|
||||||
{
|
{
|
||||||
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent);
|
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(inParams, parent);
|
||||||
|
|
||||||
if (Utils::Misc::isUrl(source)) {
|
if (Utils::Misc::isUrl(source)) {
|
||||||
// Launch downloader
|
// Launch downloader
|
||||||
@ -205,6 +222,11 @@ void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
||||||
|
{
|
||||||
|
show(source, BitTorrent::AddTorrentParams(), parent);
|
||||||
|
}
|
||||||
|
|
||||||
bool AddNewTorrentDialog::loadTorrent(const QString &torrentPath)
|
bool AddNewTorrentDialog::loadTorrent(const QString &torrentPath)
|
||||||
{
|
{
|
||||||
if (torrentPath.startsWith("file://", Qt::CaseInsensitive))
|
if (torrentPath.startsWith("file://", Qt::CaseInsensitive))
|
||||||
@ -416,6 +438,18 @@ void AddNewTorrentDialog::categoryChanged(int index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddNewTorrentDialog::setSavePath(const QString &newPath)
|
||||||
|
{
|
||||||
|
int existingIndex = indexOfSavePath(newPath);
|
||||||
|
if (existingIndex < 0) {
|
||||||
|
// New path, prepend to combo box
|
||||||
|
ui->savePathComboBox->insertItem(0, Utils::Fs::toNativePath(newPath), newPath);
|
||||||
|
existingIndex = 0;
|
||||||
|
}
|
||||||
|
ui->savePathComboBox->setCurrentIndex(existingIndex);
|
||||||
|
onSavePathChanged(existingIndex);
|
||||||
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::browseButton_clicked()
|
void AddNewTorrentDialog::browseButton_clicked()
|
||||||
{
|
{
|
||||||
disconnect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onSavePathChanged(int)));
|
disconnect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onSavePathChanged(int)));
|
||||||
@ -430,17 +464,7 @@ void AddNewTorrentDialog::browseButton_clicked()
|
|||||||
newPath = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
|
newPath = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
|
||||||
|
|
||||||
if (!newPath.isEmpty()) {
|
if (!newPath.isEmpty()) {
|
||||||
const int existingIndex = indexOfSavePath(newPath);
|
setSavePath(newPath);
|
||||||
if (existingIndex >= 0) {
|
|
||||||
ui->savePathComboBox->setCurrentIndex(existingIndex);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// New path, prepend to combo box
|
|
||||||
ui->savePathComboBox->insertItem(0, Utils::Fs::toNativePath(newPath), newPath);
|
|
||||||
ui->savePathComboBox->setCurrentIndex(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSavePathChanged(0);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Restore index
|
// Restore index
|
||||||
@ -579,6 +603,9 @@ void AddNewTorrentDialog::populateSavePathComboBox()
|
|||||||
foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList())
|
foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList())
|
||||||
if (QDir(savePath) != defaultSaveDir)
|
if (QDir(savePath) != defaultSaveDir)
|
||||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
|
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
|
||||||
|
|
||||||
|
if (!m_torrentParams.savePath.isEmpty())
|
||||||
|
setSavePath(m_torrentParams.savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
||||||
@ -626,27 +653,25 @@ void AddNewTorrentDialog::accept()
|
|||||||
if (!m_hasMetadata)
|
if (!m_hasMetadata)
|
||||||
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&)));
|
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&)));
|
||||||
|
|
||||||
BitTorrent::AddTorrentParams params;
|
|
||||||
|
|
||||||
// TODO: Check if destination actually exists
|
// TODO: Check if destination actually exists
|
||||||
params.skipChecking = ui->skipCheckingCheckBox->isChecked();
|
m_torrentParams.skipChecking = ui->skipCheckingCheckBox->isChecked();
|
||||||
|
|
||||||
// Category
|
// Category
|
||||||
params.category = ui->categoryComboBox->currentText();
|
m_torrentParams.category = ui->categoryComboBox->currentText();
|
||||||
|
|
||||||
if (ui->defaultCategoryCheckbox->isChecked())
|
if (ui->defaultCategoryCheckbox->isChecked())
|
||||||
settings()->storeValue(KEY_DEFAULTCATEGORY, params.category);
|
settings()->storeValue(KEY_DEFAULTCATEGORY, m_torrentParams.category);
|
||||||
|
|
||||||
// Save file priorities
|
// Save file priorities
|
||||||
if (m_contentModel)
|
if (m_contentModel)
|
||||||
params.filePriorities = m_contentModel->model()->getFilePriorities();
|
m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities();
|
||||||
|
|
||||||
params.addPaused = TriStateBool(!ui->startTorrentCheckBox->isChecked());
|
m_torrentParams.addPaused = TriStateBool(!ui->startTorrentCheckBox->isChecked());
|
||||||
params.createSubfolder = TriStateBool(ui->createSubfolderCheckBox->isChecked());
|
m_torrentParams.createSubfolder = TriStateBool(ui->createSubfolderCheckBox->isChecked());
|
||||||
|
|
||||||
QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString();
|
QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString();
|
||||||
if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
||||||
params.savePath = savePath;
|
m_torrentParams.savePath = savePath;
|
||||||
saveSavePathHistory();
|
saveSavePathHistory();
|
||||||
if (ui->defaultSavePathCheckBox->isChecked())
|
if (ui->defaultSavePathCheckBox->isChecked())
|
||||||
BitTorrent::Session::instance()->setDefaultSavePath(savePath);
|
BitTorrent::Session::instance()->setDefaultSavePath(savePath);
|
||||||
@ -656,9 +681,9 @@ void AddNewTorrentDialog::accept()
|
|||||||
|
|
||||||
// Add torrent
|
// Add torrent
|
||||||
if (!m_hasMetadata)
|
if (!m_hasMetadata)
|
||||||
BitTorrent::Session::instance()->addTorrent(m_hash, params);
|
BitTorrent::Session::instance()->addTorrent(m_hash, m_torrentParams);
|
||||||
else
|
else
|
||||||
BitTorrent::Session::instance()->addTorrent(m_torrentInfo, params);
|
BitTorrent::Session::instance()->addTorrent(m_torrentInfo, m_torrentParams);
|
||||||
|
|
||||||
m_torrentGuard->markAsAddedToSession();
|
m_torrentGuard->markAsAddedToSession();
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "base/bittorrent/infohash.h"
|
#include "base/bittorrent/infohash.h"
|
||||||
#include "base/bittorrent/torrentinfo.h"
|
#include "base/bittorrent/torrentinfo.h"
|
||||||
|
#include "base/bittorrent/addtorrentparams.h"
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
{
|
{
|
||||||
@ -65,7 +66,8 @@ public:
|
|||||||
static bool isTopLevel();
|
static bool isTopLevel();
|
||||||
static void setTopLevel(bool value);
|
static void setTopLevel(bool value);
|
||||||
|
|
||||||
static void show(QString source, QWidget *parent = 0);
|
static void show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent);
|
||||||
|
static void show(QString source, QWidget *parent);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showAdvancedSettings(bool show);
|
void showAdvancedSettings(bool show);
|
||||||
@ -87,7 +89,7 @@ private slots:
|
|||||||
void reject() override;
|
void reject() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit AddNewTorrentDialog(QWidget *parent = 0);
|
explicit AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent);
|
||||||
bool loadTorrent(const QString &torrentPath);
|
bool loadTorrent(const QString &torrentPath);
|
||||||
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
|
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
|
||||||
void populateSavePathComboBox();
|
void populateSavePathComboBox();
|
||||||
@ -98,6 +100,7 @@ private:
|
|||||||
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
|
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
|
||||||
void setupTreeview();
|
void setupTreeview();
|
||||||
void setCommentText(const QString &str) const;
|
void setCommentText(const QString &str) const;
|
||||||
|
void setSavePath(const QString &newPath);
|
||||||
|
|
||||||
void showEvent(QShowEvent *event) override;
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
@ -112,6 +115,7 @@ private:
|
|||||||
QByteArray m_headerState;
|
QByteArray m_headerState;
|
||||||
int m_oldIndex;
|
int m_oldIndex;
|
||||||
QScopedPointer<TorrentFileGuard> m_torrentGuard;
|
QScopedPointer<TorrentFileGuard> m_torrentGuard;
|
||||||
|
BitTorrent::AddTorrentParams m_torrentParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ADDNEWTORRENTDIALOG_H
|
#endif // ADDNEWTORRENTDIALOG_H
|
||||||
|
@ -192,16 +192,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QCheckBox" name="startTorrentCheckBox_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Start torrent</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QCheckBox" name="createSubfolderCheckBox">
|
<widget class="QCheckBox" name="createSubfolderCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -343,7 +343,7 @@ void RSSWidget::downloadSelectedTorrents()
|
|||||||
|
|
||||||
if (!article->torrentUrl().isEmpty()) {
|
if (!article->torrentUrl().isEmpty()) {
|
||||||
if (AddNewTorrentDialog::isEnabled())
|
if (AddNewTorrentDialog::isEnabled())
|
||||||
AddNewTorrentDialog::show(article->torrentUrl());
|
AddNewTorrentDialog::show(article->torrentUrl(), window());
|
||||||
else
|
else
|
||||||
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
|
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user