Skip to content

Commit d96ba49

Browse files
committed
Add options for email notifications on add/finish
Introduce `mail_notification_on_add` and `mail_notification_on_end` options for email notifications. Update GUI and WebUI to allow users to configure these settings. Extend WebAPI endpoints (`app/preferences` and `app/setPreferences`) to support the new options. Update backend logic to respect these preferences and enhance the UI with checkboxes and tooltips for better usability.
1 parent f4acdce commit d96ba49

10 files changed

Lines changed: 150 additions & 10 deletions

File tree

WebAPI_Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# WebAPI Changelog
22

33
## 2.16.0
4+
* [#24289](https://github.com/qbittorrent/qBittorrent/pull/24289)
5+
* `app/preferences` endpoint includes `mail_notification_on_add` option
6+
* `app/preferences` endpoint includes `mail_notification_on_end` option
7+
* `app/setPreferences` endpoint allows to set `mail_notification_on_add` option
8+
* `app/setPreferences` endpoint allows to set `mail_notification_on_end` option
49
* [#24210](https://github.com/qbittorrent/qBittorrent/pull/24210)
510
* `torrentcreator/status` endpoint now returns `timeAdded`, `timeStarted`, and `timeFinished` as Unix timestamps
611
* [#24158](https://github.com/qbittorrent/qBittorrent/pull/24158)

src/app/application.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,25 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo
733733
#endif
734734
}
735735

736-
void Application::sendNotificationEmail(const BitTorrent::Torrent *torrent)
736+
void Application::sendNotificationEmailAdded(const BitTorrent::Torrent *torrent)
737+
{
738+
// Prepare mail content
739+
const QString content = tr("Torrent name: %1").arg(torrent->name()) + u'\n'
740+
+ tr("Torrent size: %1").arg(Utils::Misc::friendlyUnit(torrent->wantedSize())) + u'\n'
741+
+ tr("Save path: %1").arg(torrent->savePath().toString()) + u"\n\n"
742+
+ tr("The torrent has been added.") + u"\n\n\n"
743+
+ tr("Thank you for using qBittorrent.") + u'\n';
744+
745+
// Send the notification email
746+
const Preferences* pref = Preferences::instance();
747+
auto* smtp = new Net::Smtp(this);
748+
smtp->sendMail(pref->getMailNotificationSender(),
749+
pref->getMailNotificationEmail(),
750+
tr("Torrent \"%1\" has been added").arg(torrent->name()),
751+
content);
752+
}
753+
754+
void Application::sendNotificationEmailFinished(const BitTorrent::Torrent *torrent)
737755
{
738756
// Prepare mail content
739757
const QString content = tr("Torrent name: %1").arg(torrent->name()) + u'\n'
@@ -770,13 +788,20 @@ void Application::sendTestEmail() const
770788
}
771789
}
772790

773-
void Application::torrentAdded(const BitTorrent::Torrent *torrent) const
791+
void Application::torrentAdded(const BitTorrent::Torrent *torrent)
774792
{
775793
const Preferences *pref = Preferences::instance();
776794

777795
// AutoRun program
778796
if (pref->isAutoRunOnTorrentAddedEnabled())
779797
runExternalProgram(pref->getAutoRunOnTorrentAddedProgram().trimmed(), torrent);
798+
799+
// Mail notification
800+
if (pref->isMailNotificationEnabled() && pref->isMailNotificationOnAdd())
801+
{
802+
LogMsg(tr("Torrent: %1, sending added mail notification").arg(torrent->name()));
803+
sendNotificationEmailAdded(torrent);
804+
}
780805
}
781806

782807
void Application::torrentFinished(const BitTorrent::Torrent *torrent)
@@ -788,10 +813,10 @@ void Application::torrentFinished(const BitTorrent::Torrent *torrent)
788813
runExternalProgram(pref->getAutoRunOnTorrentFinishedProgram().trimmed(), torrent);
789814

790815
// Mail notification
791-
if (pref->isMailNotificationEnabled())
816+
if (pref->isMailNotificationEnabled() && pref->isMailNotificationOnEnd())
792817
{
793-
LogMsg(tr("Torrent: %1, sending mail notification").arg(torrent->name()));
794-
sendNotificationEmail(torrent);
818+
LogMsg(tr("Torrent: %1, sending finished mail notification").arg(torrent->name()));
819+
sendNotificationEmailFinished(torrent);
795820
}
796821

797822
#ifndef DISABLE_GUI

src/app/application.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class Application final : public BaseApplication, public BaseIApplication
149149

150150
private slots:
151151
void processMessage(const QString &message);
152-
void torrentAdded(const BitTorrent::Torrent *torrent) const;
152+
void torrentAdded(const BitTorrent::Torrent *torrent);
153153
void torrentFinished(const BitTorrent::Torrent *torrent);
154154
void allTorrentsFinished();
155155
void cleanup();
@@ -167,7 +167,8 @@ private slots:
167167
void initializeTranslation();
168168
void processParams(const QBtCommandLineParameters &params);
169169
void runExternalProgram(const QString &programTemplate, const BitTorrent::Torrent *torrent) const;
170-
void sendNotificationEmail(const BitTorrent::Torrent *torrent);
170+
void sendNotificationEmailAdded(const BitTorrent::Torrent *torrent);
171+
void sendNotificationEmailFinished(const BitTorrent::Torrent *torrent);
171172

172173
#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
173174
void applyMemoryWorkingSetLimit() const;

src/base/preferences.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,32 @@ void Preferences::setMailNotificationEnabled(const bool enabled)
542542
setValue(u"Preferences/MailNotification/enabled"_s, enabled);
543543
}
544544

545+
bool Preferences::isMailNotificationOnAdd() const
546+
{
547+
return value(u"Preferences/MailNotification/SendOnAdd"_s, false);
548+
}
549+
550+
void Preferences::setMailNotificationOnAdd(const bool enabled)
551+
{
552+
if (enabled == isMailNotificationOnAdd())
553+
return;
554+
555+
setValue(u"Preferences/MailNotification/SendOnAdd"_s, enabled);
556+
}
557+
558+
bool Preferences::isMailNotificationOnEnd() const
559+
{
560+
return value(u"Preferences/MailNotification/SendOnEnd"_s, true);
561+
}
562+
563+
void Preferences::setMailNotificationOnEnd(const bool enabled)
564+
{
565+
if (enabled == isMailNotificationOnEnd())
566+
return;
567+
568+
setValue(u"Preferences/MailNotification/SendOnEnd"_s, enabled);
569+
}
570+
545571
QString Preferences::getMailNotificationSender() const
546572
{
547573
return value<QString>(u"Preferences/MailNotification/sender"_s);

src/base/preferences.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ class Preferences final : public QObject
137137
void setScanDirsLastPath(const Path &path);
138138
bool isMailNotificationEnabled() const;
139139
void setMailNotificationEnabled(bool enabled);
140+
bool isMailNotificationOnAdd() const;
141+
void setMailNotificationOnAdd(bool enabled);
142+
bool isMailNotificationOnEnd() const;
143+
void setMailNotificationOnEnd(bool enabled);
140144
QString getMailNotificationSender() const;
141145
void setMailNotificationSender(const QString &mail);
142146
QString getMailNotificationEmail() const;

src/gui/optionsdialog.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,11 @@ void OptionsDialog::loadDownloadsTabOptions()
666666
m_ui->textExcludedFileNames->setPlainText(session->excludedFileNames().join(u'\n'));
667667

668668
m_ui->groupMailNotification->setChecked(pref->isMailNotificationEnabled());
669+
m_ui->checkMailOnAdd->setChecked(pref->isMailNotificationOnAdd());
670+
m_ui->checkMailOnAdd->setToolTip(tr("Send email notification when a torrent is added."));
671+
m_ui->checkMailOnEnd->setChecked(pref->isMailNotificationOnEnd());
672+
m_ui->checkMailOnEnd->setToolTip(tr("Send email notification when a torrent has finished downloading."));
673+
updateMailWhenToSendStates();
669674
m_ui->senderEmailTxt->setText(pref->getMailNotificationSender());
670675
m_ui->senderEmailTxt->setToolTip(tr("Provide the sending email address."));
671676
m_ui->lineEditDestEmail->setText(pref->getMailNotificationEmail());
@@ -784,6 +789,10 @@ void OptionsDialog::loadDownloadsTabOptions()
784789
connect(m_ui->removeWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
785790

786791
connect(m_ui->groupMailNotification, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
792+
connect(m_ui->checkMailOnAdd, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
793+
connect(m_ui->checkMailOnAdd, &QAbstractButton::toggled, this, &ThisType::updateMailWhenToSendStates);
794+
connect(m_ui->checkMailOnEnd, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
795+
connect(m_ui->checkMailOnEnd, &QAbstractButton::toggled, this, &ThisType::updateMailWhenToSendStates);
787796
connect(m_ui->senderEmailTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
788797
connect(m_ui->lineEditDestEmail, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
789798
connect(m_ui->lineEditSMTPServer, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
@@ -850,6 +859,8 @@ void OptionsDialog::saveDownloadsTabOptions() const
850859
session->setExcludedFileNames(m_ui->textExcludedFileNames->toPlainText().split(u'\n', Qt::SkipEmptyParts));
851860

852861
pref->setMailNotificationEnabled(m_ui->groupMailNotification->isChecked());
862+
pref->setMailNotificationOnAdd(m_ui->checkMailOnAdd->isChecked());
863+
pref->setMailNotificationOnEnd(m_ui->checkMailOnEnd->isChecked());
853864
pref->setMailNotificationSender(m_ui->senderEmailTxt->text());
854865
pref->setMailNotificationEmail(m_ui->lineEditDestEmail->text());
855866
pref->setMailNotificationSMTP(m_ui->lineEditSMTPServer->text());
@@ -1910,6 +1921,16 @@ void OptionsDialog::changeSMTPEncryptionPortInfoLabel()
19101921
m_ui->labelSMTPEncryptionPortInfo->setText(tr("Default port: %1").arg(QString::number(port)));
19111922
}
19121923

1924+
void OptionsDialog::updateMailWhenToSendStates()
1925+
{
1926+
const bool isMailNotificationOnAddChecked = m_ui->checkMailOnAdd->isChecked();
1927+
const bool isMailNotificationOnEndChecked = m_ui->checkMailOnEnd->isChecked();
1928+
if (!isMailNotificationOnAddChecked && !isMailNotificationOnEndChecked)
1929+
return;
1930+
m_ui->checkMailOnAdd->setEnabled(isMailNotificationOnEndChecked);
1931+
m_ui->checkMailOnEnd->setEnabled(isMailNotificationOnAddChecked);
1932+
}
1933+
19131934
bool OptionsDialog::isSplashScreenDisabled() const
19141935
{
19151936
return !m_ui->checkShowSplash->isChecked();

src/gui/optionsdialog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public slots:
8585
private slots:
8686
void adjustProxyOptions();
8787
void changeSMTPEncryptionPortInfoLabel();
88+
void updateMailWhenToSendStates();
8889
void on_buttonBox_accepted();
8990
void on_buttonBox_rejected();
9091
void enableApplyButton();

src/gui/optionsdialog.ui

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1593,7 +1593,7 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
15931593
<item>
15941594
<widget class="QGroupBox" name="groupMailNotification">
15951595
<property name="title">
1596-
<string>Email notification &amp;upon download completion</string>
1596+
<string>Email notification</string>
15971597
</property>
15981598
<property name="checkable">
15991599
<bool>true</bool>
@@ -1602,6 +1602,29 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
16021602
<bool>false</bool>
16031603
</property>
16041604
<layout class="QVBoxLayout" name="verticalLayout_171">
1605+
<item>
1606+
<widget class="QGroupBox" name="groupMailNotificationWhen">
1607+
<property name="title">
1608+
<string>Send when</string>
1609+
</property>
1610+
<layout class="QVBoxLayout" name="groupMailNotificationWhenLayout">
1611+
<item>
1612+
<widget class="QCheckBox" name="checkMailOnAdd">
1613+
<property name="text">
1614+
<string>Torrent Added</string>
1615+
</property>
1616+
</widget>
1617+
</item>
1618+
<item>
1619+
<widget class="QCheckBox" name="checkMailOnEnd">
1620+
<property name="text">
1621+
<string>Torrent Finished</string>
1622+
</property>
1623+
</widget>
1624+
</item>
1625+
</layout>
1626+
</widget>
1627+
</item>
16051628
<item>
16061629
<layout class="QGridLayout" name="gridLayout_9">
16071630
<item row="0" column="0">

src/webui/api/appcontroller.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ void AppController::preferencesAction()
216216

217217
// Email notification upon download completion
218218
data[u"mail_notification_enabled"_s] = pref->isMailNotificationEnabled();
219+
data[u"mail_notification_on_add"_s] = pref->isMailNotificationOnAdd();
220+
data[u"mail_notification_on_end"_s] = pref->isMailNotificationOnEnd();
219221
data[u"mail_notification_sender"_s] = pref->getMailNotificationSender();
220222
data[u"mail_notification_email"_s] = pref->getMailNotificationEmail();
221223
data[u"mail_notification_smtp"_s] = pref->getMailNotificationSMTP();
@@ -680,6 +682,10 @@ void AppController::setPreferencesAction()
680682
// Email notification upon download completion
681683
if (hasKey(u"mail_notification_enabled"_s))
682684
pref->setMailNotificationEnabled(it.value().toBool());
685+
if (hasKey(u"mail_notification_on_add"_s))
686+
pref->setMailNotificationOnAdd(it.value().toBool());
687+
if (hasKey(u"mail_notification_on_end"_s))
688+
pref->setMailNotificationOnEnd(it.value().toBool());
683689
if (hasKey(u"mail_notification_sender"_s))
684690
pref->setMailNotificationSender(it.value().toString());
685691
if (hasKey(u"mail_notification_email"_s))

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,19 @@
326326
<fieldset class="settings">
327327
<legend>
328328
<input type="checkbox" id="mail_notification_checkbox" onclick="qBittorrent.Preferences.updateMailNotification();">
329-
<label for="mail_notification_checkbox">QBT_TR(Email notification upon download completion)QBT_TR[CONTEXT=OptionsDialog]</label>
329+
<label for="mail_notification_checkbox">QBT_TR(Email notification)QBT_TR[CONTEXT=OptionsDialog]</label>
330330
</legend>
331+
<fieldset class="settings">
332+
<legend>QBT_TR(Send when)QBT_TR[CONTEXT=OptionsDialog]</legend>
333+
<div class="formRow">
334+
<input type="checkbox" id="mailNotificationOnAddCheckbox" title="QBT_TR(Send email notification when a torrent is added.)QBT_TR[CONTEXT=OptionsDialog]" onclick="qBittorrent.Preferences.updateMailWhenToSend();">
335+
<label id="mailNotificationOnAddLabel" for="mailNotificationOnAddCheckbox">QBT_TR(Torrent Added)QBT_TR[CONTEXT=OptionsDialog]</label>
336+
</div>
337+
<div class="formRow">
338+
<input type="checkbox" id="mailNotificationOnEndCheckbox" title="QBT_TR(Send email notification when a torrent has finished downloading.)QBT_TR[CONTEXT=OptionsDialog]" onclick="qBittorrent.Preferences.updateMailWhenToSend();">
339+
<label id="mailNotificationOnEndLabel" for="mailNotificationOnEndCheckbox">QBT_TR(Torrent Finished)QBT_TR[CONTEXT=OptionsDialog]</label>
340+
</div>
341+
</fieldset>
331342
<table>
332343
<tbody>
333344
<tr>
@@ -1866,6 +1877,7 @@
18661877
updateExcludedFileNamesEnabled: updateExcludedFileNamesEnabled,
18671878
changeWatchFolderSelect: changeWatchFolderSelect,
18681879
updateMailNotification: updateMailNotification,
1880+
updateMailWhenToSend: updateMailWhenToSend,
18691881
updateMailAuthSettings: updateMailAuthSettings,
18701882
sendTestEmail: sendTestEmail,
18711883
updateAutoRun: updateAutoRun,
@@ -2029,19 +2041,31 @@
20292041

20302042
const updateMailNotification = () => {
20312043
const isMailNotificationEnabled = document.getElementById("mail_notification_checkbox").checked;
2044+
document.getElementById("mailNotificationOnAddCheckbox").disabled = !isMailNotificationEnabled;
2045+
document.getElementById("mailNotificationOnEndCheckbox").disabled = !isMailNotificationEnabled;
20322046
document.getElementById("src_email_txt").disabled = !isMailNotificationEnabled;
20332047
document.getElementById("dest_email_txt").disabled = !isMailNotificationEnabled;
20342048
document.getElementById("smtp_server_txt").disabled = !isMailNotificationEnabled;
20352049
document.getElementById("mailNotificationEncryptionCombobox").disabled = !isMailNotificationEnabled;
20362050
document.getElementById("mail_auth_checkbox").disabled = !isMailNotificationEnabled;
20372051
document.getElementById("mail_test_button").disabled = !isMailNotificationEnabled;
2038-
2052+
if (isMailNotificationEnabled)
2053+
updateMailWhenToSend();
20392054
if (!isMailNotificationEnabled) {
20402055
document.getElementById("mail_auth_checkbox").checked = !isMailNotificationEnabled;
20412056
updateMailAuthSettings();
20422057
}
20432058
};
20442059

2060+
const updateMailWhenToSend = () => {
2061+
const isMailNotificationOnAddChecked = document.getElementById("mailNotificationOnAddCheckbox").checked;
2062+
const isMailNotificationOnEndChecked = document.getElementById("mailNotificationOnEndCheckbox").checked;
2063+
if (!isMailNotificationOnAddChecked && !isMailNotificationOnEndChecked)
2064+
return;
2065+
document.getElementById("mailNotificationOnAddCheckbox").disabled = !isMailNotificationOnEndChecked;
2066+
document.getElementById("mailNotificationOnEndCheckbox").disabled = !isMailNotificationOnAddChecked;
2067+
};
2068+
20452069
const updateMailAuthSettings = () => {
20462070
const isMailAuthEnabled = document.getElementById("mail_auth_checkbox").checked;
20472071
document.getElementById("mail_username_text").disabled = !isMailAuthEnabled;
@@ -2466,6 +2490,8 @@
24662490

24672491
// Email notification upon download completion
24682492
document.getElementById("mail_notification_checkbox").checked = pref.mail_notification_enabled;
2493+
document.getElementById("mailNotificationOnAddCheckbox").checked = pref.mail_notification_on_add;
2494+
document.getElementById("mailNotificationOnEndCheckbox").checked = pref.mail_notification_on_end;
24692495
document.getElementById("src_email_txt").value = pref.mail_notification_sender;
24702496
document.getElementById("dest_email_txt").value = pref.mail_notification_email;
24712497
document.getElementById("smtp_server_txt").value = pref.mail_notification_smtp;
@@ -2868,6 +2894,8 @@
28682894

28692895
// Email notification upon download completion
28702896
settings["mail_notification_enabled"] = document.getElementById("mail_notification_checkbox").checked;
2897+
settings["mail_notification_on_add"] = document.getElementById("mailNotificationOnAddCheckbox").checked;
2898+
settings["mail_notification_on_end"] = document.getElementById("mailNotificationOnEndCheckbox").checked;
28712899
settings["mail_notification_sender"] = document.getElementById("src_email_txt").value;
28722900
settings["mail_notification_email"] = document.getElementById("dest_email_txt").value;
28732901
settings["mail_notification_smtp"] = document.getElementById("smtp_server_txt").value;

0 commit comments

Comments
 (0)