Browse Source

Add ability to run external program on torrent added

PR #17646.
adaptive-webui-19844
Vladimir Golovnev 2 years ago committed by GitHub
parent
commit
4318de6dc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      src/app/application.cpp
  2. 5
      src/app/application.h
  3. 28
      src/base/preferences.cpp
  4. 14
      src/base/preferences.h
  5. 25
      src/gui/optionsdialog.cpp
  6. 37
      src/gui/optionsdialog.ui
  7. 20
      src/webui/api/appcontroller.cpp
  8. 27
      src/webui/www/private/views/preferences.html

27
src/app/application.cpp

@ -368,7 +368,7 @@ void Application::processMessage(const QString &message) @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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);

5
src/app/application.h

@ -136,7 +136,8 @@ public: @@ -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: @@ -155,7 +156,7 @@ private:
void initializeTranslation();
AddTorrentParams parseParams(const QStringList &params) const;
void processParams(const AddTorrentParams &params);
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

28
src/base/preferences.cpp

@ -867,22 +867,42 @@ void Preferences::setUILocked(const bool locked) @@ -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<QString>(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<QString>(u"AutoRun/program"_qs);
}
void Preferences::setAutoRunProgram(const QString &program)
void Preferences::setAutoRunOnTorrentFinishedProgram(const QString &program)
{
setValue(u"AutoRun/program"_qs, program);
}

14
src/base/preferences.h

@ -251,14 +251,20 @@ public: @@ -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;

25
src/gui/optionsdialog.cpp

@ -601,7 +601,15 @@ void OptionsDialog::loadDownloadsTabOptions() @@ -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() @@ -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() @@ -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 @@ -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

37
src/gui/optionsdialog.ui

@ -1395,7 +1395,13 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st @@ -1395,7 +1395,13 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
<item>
<widget class="QGroupBox" name="autoRunBox">
<property name="title">
<string>Run e&amp;xternal program on torrent completion</string>
<string>Run external program</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_19">
<item>
<widget class="QGroupBox" name="groupBoxRunOnAdded">
<property name="title">
<string>Run on torrent added</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -1403,9 +1409,30 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st @@ -1403,9 +1409,30 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_19">
<layout class="QVBoxLayout" name="verticalLayout_39">
<item>
<widget class="QLineEdit" name="lineEditRunOnAdded"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxRunOnFinished">
<property name="title">
<string>Run on torrent finished</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_36">
<item>
<widget class="QLineEdit" name="lineEditAutoRun"/>
<widget class="QLineEdit" name="lineEditRunOnFinished"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoRunConsole">
@ -3576,8 +3603,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string> @@ -3576,8 +3603,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
<tabstop>mailNotifUsername</tabstop>
<tabstop>mailNotifPassword</tabstop>
<tabstop>checkSmtpSSL</tabstop>
<tabstop>autoRunBox</tabstop>
<tabstop>lineEditAutoRun</tabstop>
<tabstop>lineEditRunOnAdded</tabstop>
<tabstop>lineEditRunOnFinished</tabstop>
<tabstop>scrollArea_3</tabstop>
<tabstop>randomButton</tabstop>
<tabstop>checkMaxConnections</tabstop>

20
src/webui/api/appcontroller.cpp

@ -157,9 +157,12 @@ void AppController::preferencesAction() @@ -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() @@ -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

27
src/webui/www/private/views/preferences.html

@ -200,10 +200,16 @@ @@ -200,10 +200,16 @@
<fieldset class="settings">
<legend>
<input type="checkbox" id="autorun_checkbox" onclick="qBittorrent.Preferences.updateAutoRun();" />
<label for="autorun_checkbox">QBT_TR(Run external program on torrent completion)QBT_TR[CONTEXT=OptionsDialog]</label>
QBT_TR(Run external program)QBT_TR[CONTEXT=OptionsDialog]
</legend>
<div class="formRow">
<input type="checkbox" id="autorunOnTorrentAddedCheckbox" onclick="qBittorrent.Preferences.updateAutoRunOnTorrentAdded();" />
<label for="autorunOnTorrentAddedCheckbox">QBT_TR(Run external program on torrent added)QBT_TR[CONTEXT=OptionsDialog]</label>
<input type="text" id="autorunOnTorrentAddedProgram" style="width: 400px;" />
</div>
<div class="formRow">
<input type="checkbox" id="autorun_checkbox" onclick="qBittorrent.Preferences.updateAutoRun();" />
<label for="autorun_checkbox">QBT_TR(Run external program on torrent finished)QBT_TR[CONTEXT=OptionsDialog]</label>
<input type="text" id="autorunProg_txt" style="width: 400px;" />
</div>
<div style="font-style: italic;">QBT_TR(Supported parameters (case sensitive):)QBT_TR[CONTEXT=OptionsDialog]
@ -1357,6 +1363,7 @@ @@ -1357,6 +1363,7 @@
updateMailNotification: updateMailNotification,
updateMailAuthSettings: updateMailAuthSettings,
updateAutoRun: updateAutoRun,
updateAutoRunOnTorrentAdded: updateAutoRunOnTorrentAdded,
generateRandomPort: generateRandomPort,
updateMaxConnecEnabled: updateMaxConnecEnabled,
updateMaxConnecPerTorrentEnabled: updateMaxConnecPerTorrentEnabled,
@ -1485,6 +1492,11 @@ @@ -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 @@ @@ -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 @@ @@ -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'));

Loading…
Cancel
Save