From 4318de6dc5ff8cccad81515e9a6b682c66ad3679 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sun, 4 Sep 2022 07:51:50 +0300 Subject: [PATCH] Add ability to run external program on torrent added PR #17646. --- src/app/application.cpp | 27 +++++++---- src/app/application.h | 5 ++- src/base/preferences.cpp | 28 ++++++++++-- src/base/preferences.h | 14 ++++-- src/gui/optionsdialog.cpp | 25 ++++++----- src/gui/optionsdialog.ui | 47 +++++++++++++++----- src/webui/api/appcontroller.cpp | 20 ++++++--- src/webui/www/private/views/preferences.html | 27 +++++++++-- 8 files changed, 144 insertions(+), 49 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index 4e69fd236..587f30a47 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -368,7 +368,7 @@ void Application::processMessage(const QString &message) m_paramsQueue.append(params); } -void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const +void Application::runExternalProgram(const QString &programTemplate, const BitTorrent::Torrent *torrent) const { // Cannot give users shell environment by default, as doing so could // enable command injection via torrent name and other arguments @@ -437,7 +437,7 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const // The processing sequenece is different for Windows and other OS, this is intentional #if defined(Q_OS_WIN) - const QString program = replaceVariables(Preferences::instance()->getAutoRunProgram().trimmed()); + const QString program = replaceVariables(programTemplate); const std::wstring programWStr = program.toStdWString(); // Need to split arguments manually because QProcess::startDetached(QString) @@ -481,8 +481,7 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const }); proc.startDetached(); #else // Q_OS_WIN - const QString program = Preferences::instance()->getAutoRunProgram().trimmed(); - QStringList args = Utils::String::splitCommand(program); + QStringList args = Utils::String::splitCommand(programTemplate); if (args.isEmpty()) return; @@ -497,7 +496,7 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const } // show intended command in log - LogMsg(logMsg.arg(torrent->name(), replaceVariables(program))); + LogMsg(logMsg.arg(torrent->name(), replaceVariables(programTemplate))); const QString command = args.takeFirst(); QProcess::startDetached(command, args); @@ -523,13 +522,22 @@ void Application::sendNotificationEmail(const BitTorrent::Torrent *torrent) content); } -void Application::torrentFinished(BitTorrent::Torrent *const torrent) +void Application::torrentAdded(const BitTorrent::Torrent *torrent) const { - Preferences *const pref = Preferences::instance(); + const Preferences *pref = Preferences::instance(); + + // AutoRun program + if (pref->isAutoRunOnTorrentAddedEnabled()) + runExternalProgram(pref->getAutoRunOnTorrentAddedProgram().trimmed(), torrent); +} + +void Application::torrentFinished(const BitTorrent::Torrent *torrent) +{ + const Preferences *pref = Preferences::instance(); // AutoRun program - if (pref->isAutoRunEnabled()) - runExternalProgram(torrent); + if (pref->isAutoRunOnTorrentFinishedEnabled()) + runExternalProgram(pref->getAutoRunOnTorrentFinishedProgram().trimmed(), torrent); // Mail notification if (pref->isMailNotificationEnabled()) @@ -731,6 +739,7 @@ try #endif connect(BitTorrent::Session::instance(), &BitTorrent::Session::restored, this, [this]() { + connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentAdded, this, &Application::torrentAdded); connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished); connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection); diff --git a/src/app/application.h b/src/app/application.h index 364f28916..d8801face 100644 --- a/src/app/application.h +++ b/src/app/application.h @@ -136,7 +136,8 @@ public: private slots: void processMessage(const QString &message); - void torrentFinished(BitTorrent::Torrent *const torrent); + void torrentAdded(const BitTorrent::Torrent *torrent) const; + void torrentFinished(const BitTorrent::Torrent *torrent); void allTorrentsFinished(); void cleanup(); @@ -155,7 +156,7 @@ private: void initializeTranslation(); AddTorrentParams parseParams(const QStringList ¶ms) const; void processParams(const AddTorrentParams ¶ms); - void runExternalProgram(const BitTorrent::Torrent *torrent) const; + void runExternalProgram(const QString &programTemplate, const BitTorrent::Torrent *torrent) const; void sendNotificationEmail(const BitTorrent::Torrent *torrent); #ifdef QBT_USES_LIBTORRENT2 diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 9ad689b6b..7742ac281 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -867,22 +867,42 @@ void Preferences::setUILocked(const bool locked) setValue(u"Locking/locked"_qs, locked); } -bool Preferences::isAutoRunEnabled() const +bool Preferences::isAutoRunOnTorrentAddedEnabled() const +{ + return value(u"AutoRun/OnTorrentAdded/Enabled"_qs, false); +} + +void Preferences::setAutoRunOnTorrentAddedEnabled(const bool enabled) +{ + setValue(u"AutoRun/OnTorrentAdded/Enabled"_qs, enabled); +} + +QString Preferences::getAutoRunOnTorrentAddedProgram() const +{ + return value(u"AutoRun/OnTorrentAdded/Program"_qs); +} + +void Preferences::setAutoRunOnTorrentAddedProgram(const QString &program) +{ + setValue(u"AutoRun/OnTorrentAdded/Program"_qs, program); +} + +bool Preferences::isAutoRunOnTorrentFinishedEnabled() const { return value(u"AutoRun/enabled"_qs, false); } -void Preferences::setAutoRunEnabled(const bool enabled) +void Preferences::setAutoRunOnTorrentFinishedEnabled(const bool enabled) { setValue(u"AutoRun/enabled"_qs, enabled); } -QString Preferences::getAutoRunProgram() const +QString Preferences::getAutoRunOnTorrentFinishedProgram() const { return value(u"AutoRun/program"_qs); } -void Preferences::setAutoRunProgram(const QString &program) +void Preferences::setAutoRunOnTorrentFinishedProgram(const QString &program) { setValue(u"AutoRun/program"_qs, program); } diff --git a/src/base/preferences.h b/src/base/preferences.h index c9b9ffed3..0915cf5d1 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -251,14 +251,20 @@ public: void setUILockPassword(const QByteArray &password); bool isUILocked() const; void setUILocked(bool locked); - bool isAutoRunEnabled() const; - void setAutoRunEnabled(bool enabled); - QString getAutoRunProgram() const; - void setAutoRunProgram(const QString &program); + + bool isAutoRunOnTorrentAddedEnabled() const; + void setAutoRunOnTorrentAddedEnabled(const bool enabled); + QString getAutoRunOnTorrentAddedProgram() const; + void setAutoRunOnTorrentAddedProgram(const QString &program); + bool isAutoRunOnTorrentFinishedEnabled() const; + void setAutoRunOnTorrentFinishedEnabled(bool enabled); + QString getAutoRunOnTorrentFinishedProgram() const; + void setAutoRunOnTorrentFinishedProgram(const QString &program); #if defined(Q_OS_WIN) bool isAutoRunConsoleEnabled() const; void setAutoRunConsoleEnabled(bool enabled); #endif + bool shutdownWhenDownloadsComplete() const; void setShutdownWhenDownloadsComplete(bool shutdown); bool suspendWhenDownloadsComplete() const; diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 013dc6a90..b6dbfd8bb 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -601,7 +601,15 @@ void OptionsDialog::loadDownloadsTabOptions() m_ui->mailNotifUsername->setText(pref->getMailNotificationSMTPUsername()); m_ui->mailNotifPassword->setText(pref->getMailNotificationSMTPPassword()); - m_ui->autoRunBox->setChecked(pref->isAutoRunEnabled()); + m_ui->groupBoxRunOnAdded->setChecked(pref->isAutoRunOnTorrentAddedEnabled()); + m_ui->groupBoxRunOnFinished->setChecked(pref->isAutoRunOnTorrentFinishedEnabled()); + m_ui->lineEditRunOnAdded->setText(pref->getAutoRunOnTorrentAddedProgram()); + m_ui->lineEditRunOnFinished->setText(pref->getAutoRunOnTorrentFinishedProgram()); +#if defined(Q_OS_WIN) + m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled()); +#else + m_ui->autoRunConsole->hide(); +#endif const auto autoRunStr = u"%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n %11\n %12\n %13\n%14"_qs .arg(tr("Supported parameters (case sensitive):") , tr("%N: Torrent name") @@ -618,12 +626,6 @@ void OptionsDialog::loadDownloadsTabOptions() , tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)") , tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")")); m_ui->labelAutoRunParam->setText(autoRunStr); - m_ui->lineEditAutoRun->setText(pref->getAutoRunProgram()); -#if defined(Q_OS_WIN) - m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled()); -#else - m_ui->autoRunConsole->hide(); -#endif connect(m_ui->checkAdditionDialog, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkAdditionDialogFront, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); @@ -674,7 +676,8 @@ void OptionsDialog::loadDownloadsTabOptions() connect(m_ui->mailNotifPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->autoRunBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->lineEditAutoRun, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->lineEditRunOnAdded, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->lineEditRunOnFinished, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton); } @@ -726,8 +729,10 @@ void OptionsDialog::saveDownloadsTabOptions() const pref->setMailNotificationSMTPUsername(m_ui->mailNotifUsername->text()); pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text()); - pref->setAutoRunEnabled(m_ui->autoRunBox->isChecked()); - pref->setAutoRunProgram(m_ui->lineEditAutoRun->text().trimmed()); + pref->setAutoRunOnTorrentAddedEnabled(m_ui->groupBoxRunOnAdded->isChecked()); + pref->setAutoRunOnTorrentAddedProgram(m_ui->lineEditRunOnAdded->text().trimmed()); + pref->setAutoRunOnTorrentFinishedEnabled(m_ui->groupBoxRunOnFinished->isChecked()); + pref->setAutoRunOnTorrentFinishedProgram(m_ui->lineEditRunOnFinished->text().trimmed()); #if defined(Q_OS_WIN) pref->setAutoRunConsoleEnabled(m_ui->autoRunConsole->isChecked()); #endif diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index 4136ad5e6..35b7664a5 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -1395,17 +1395,44 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'. - Run e&xternal program on torrent completion - - - true - - - false + Run external program - + + + Run on torrent added + + + true + + + false + + + + + + + + + + + + Run on torrent finished + + + true + + + false + + + + + + + @@ -3576,8 +3603,8 @@ Use ';' to split multiple entries. Can use wildcard '*'. mailNotifUsername mailNotifPassword checkSmtpSSL - autoRunBox - lineEditAutoRun + lineEditRunOnAdded + lineEditRunOnFinished scrollArea_3 randomButton checkMaxConnections diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index f678831d5..a535c964b 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -157,9 +157,12 @@ void AppController::preferencesAction() data[u"mail_notification_auth_enabled"_qs] = pref->getMailNotificationSMTPAuth(); data[u"mail_notification_username"_qs] = pref->getMailNotificationSMTPUsername(); data[u"mail_notification_password"_qs] = pref->getMailNotificationSMTPPassword(); - // Run an external program on torrent completion - data[u"autorun_enabled"_qs] = pref->isAutoRunEnabled(); - data[u"autorun_program"_qs] = pref->getAutoRunProgram(); + // Run an external program on torrent added + data[u"autorun_on_torrent_added_enabled"_qs] = pref->isAutoRunOnTorrentAddedEnabled(); + data[u"autorun_on_torrent_added_program"_qs] = pref->getAutoRunOnTorrentAddedProgram(); + // Run an external program on torrent finished + data[u"autorun_enabled"_qs] = pref->isAutoRunOnTorrentFinishedEnabled(); + data[u"autorun_program"_qs] = pref->getAutoRunOnTorrentFinishedProgram(); // Connection // Listening Port @@ -510,11 +513,16 @@ void AppController::setPreferencesAction() pref->setMailNotificationSMTPUsername(it.value().toString()); if (hasKey(u"mail_notification_password"_qs)) pref->setMailNotificationSMTPPassword(it.value().toString()); - // Run an external program on torrent completion + // Run an external program on torrent added + if (hasKey(u"autorun_on_torrent_added_enabled"_qs)) + pref->setAutoRunOnTorrentAddedEnabled(it.value().toBool()); + if (hasKey(u"autorun_on_torrent_added_program"_qs)) + pref->setAutoRunOnTorrentAddedProgram(it.value().toString()); + // Run an external program on torrent finished if (hasKey(u"autorun_enabled"_qs)) - pref->setAutoRunEnabled(it.value().toBool()); + pref->setAutoRunOnTorrentFinishedEnabled(it.value().toBool()); if (hasKey(u"autorun_program"_qs)) - pref->setAutoRunProgram(it.value().toString()); + pref->setAutoRunOnTorrentFinishedProgram(it.value().toString()); // Connection // Listening Port diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index fe35cbbe3..4f3939849 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -200,10 +200,16 @@
- - + QBT_TR(Run external program)QBT_TR[CONTEXT=OptionsDialog]
+ + + +
+
+ +
QBT_TR(Supported parameters (case sensitive):)QBT_TR[CONTEXT=OptionsDialog] @@ -1357,6 +1363,7 @@ updateMailNotification: updateMailNotification, updateMailAuthSettings: updateMailAuthSettings, updateAutoRun: updateAutoRun, + updateAutoRunOnTorrentAdded: updateAutoRunOnTorrentAdded, generateRandomPort: generateRandomPort, updateMaxConnecEnabled: updateMaxConnecEnabled, updateMaxConnecPerTorrentEnabled: updateMaxConnecPerTorrentEnabled, @@ -1485,6 +1492,11 @@ $('mail_password_text').setProperty('disabled', !isMailAuthEnabled); }; + const updateAutoRunOnTorrentAdded = function() { + const isAutoRunOnTorrentAddedEnabled = $('autorunOnTorrentAddedCheckbox').getProperty('checked'); + $('autorunOnTorrentAddedProgram').setProperty('disabled', !isAutoRunOnTorrentAddedEnabled); + }; + const updateAutoRun = function() { const isAutoRunEnabled = $('autorun_checkbox').getProperty('checked'); $('autorunProg_txt').setProperty('disabled', !isAutoRunEnabled); @@ -1788,7 +1800,11 @@ updateMailNotification(); updateMailAuthSettings(); - // Run an external program on torrent completion + // Run an external program on torrent added + $('autorunOnTorrentAddedCheckbox').setProperty('checked', pref.autorun_on_torrent_added_enabled); + $('autorunOnTorrentAddedProgram').setProperty('value', pref.autorun_on_torrent_added_program); + updateAutoRunOnTorrentAdded(); + // Run an external program on torrent finished $('autorun_checkbox').setProperty('checked', pref.autorun_enabled); $('autorunProg_txt').setProperty('value', pref.autorun_program); updateAutoRun(); @@ -2112,7 +2128,10 @@ settings.set('mail_notification_username', $('mail_username_text').getProperty('value')); settings.set('mail_notification_password', $('mail_password_text').getProperty('value')); - // Run an external program on torrent completion + // Run an external program on torrent added + settings.set('autorun_on_torrent_added_enabled', $('autorunOnTorrentAddedCheckbox').getProperty('checked')); + settings.set('autorun_on_torrent_added_program', $('autorunOnTorrentAddedProgram').getProperty('value')); + // Run an external program on torrent finished settings.set('autorun_enabled', $('autorun_checkbox').getProperty('checked')); settings.set('autorun_program', $('autorunProg_txt').getProperty('value'));