Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,9 @@ void Application::torrentFinished(const BitTorrent::Torrent *torrent)
const Preferences *pref = Preferences::instance();

// AutoRun program
if (pref->isAutoRunOnTorrentFinishedEnabled())
if (!torrent->runOnFinishedProgram().isEmpty())
runExternalProgram(torrent->runOnFinishedProgram().trimmed(), torrent);
else if (pref->isAutoRunOnTorrentFinishedEnabled())
runExternalProgram(pref->getAutoRunOnTorrentFinishedProgram().trimmed(), torrent);

// Mail notification
Expand Down
2 changes: 2 additions & 0 deletions src/base/bittorrent/bencoderesumedatastorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
return nonstd::make_unexpected(tr("Cannot parse resume data: invalid format"));

LoadTorrentParams torrentParams;
torrentParams.runOnFinishedProgram = fromLTString(resumeDataRoot.dict_find_string_value("qBt-runOnFinishedProgram"));
torrentParams.category = fromLTString(resumeDataRoot.dict_find_string_value("qBt-category"));
torrentParams.name = fromLTString(resumeDataRoot.dict_find_string_value("qBt-name"));
torrentParams.comment = fromLTString(resumeDataRoot.dict_find_string_value("qBt-comment"));
Expand Down Expand Up @@ -435,6 +436,7 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
data["qBt-inactiveSeedingTimeLimit"] = resumeData.inactiveSeedingTimeLimit;
data["qBt-shareLimitAction"] = Utils::String::fromEnum(resumeData.shareLimitAction).toStdString();

data["qBt-runOnFinishedProgram"] = resumeData.runOnFinishedProgram.toStdString();
data["qBt-category"] = resumeData.category.toStdString();
data["qBt-tags"] = setToEntryList(resumeData.tags);
data["qBt-name"] = resumeData.name.toStdString();
Expand Down
5 changes: 5 additions & 0 deletions src/base/bittorrent/dbresumedatastorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ namespace
const Column DB_COLUMN_TORRENT_ID = makeColumn(u"torrent_id"_s);
const Column DB_COLUMN_QUEUE_POSITION = makeColumn(u"queue_position"_s);
const Column DB_COLUMN_NAME = makeColumn(u"name"_s);
const Column DB_COLUMN_RUN_ON_FINISHED_PROGRAM = makeColumn(u"run_on_finished_program"_s);
const Column DB_COLUMN_CATEGORY = makeColumn(u"category"_s);
const Column DB_COLUMN_TAGS = makeColumn(u"tags"_s);
const Column DB_COLUMN_COMMENT = makeColumn(u"comment"_s);
Expand Down Expand Up @@ -460,6 +461,7 @@ void BitTorrent::DBResumeDataStorage::createDB() const
makeColumnDefinition(DB_COLUMN_TORRENT_ID, u"BLOB NOT NULL UNIQUE"_s),
makeColumnDefinition(DB_COLUMN_QUEUE_POSITION, u"INTEGER NOT NULL DEFAULT -1"_s),
makeColumnDefinition(DB_COLUMN_NAME, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_RUN_ON_FINISHED_PROGRAM, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_CATEGORY, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_TAGS, u"TEXT"_s),
makeColumnDefinition(DB_COLUMN_COMMENT, u"TEXT"_s),
Expand Down Expand Up @@ -623,6 +625,7 @@ LoadResumeDataResult DBResumeDataStorage::parseQueryResultRow(const QSqlQuery &q
{
LoadTorrentParams resumeData;
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
resumeData.runOnFinishedProgram = query.value(DB_COLUMN_RUN_ON_FINISHED_PROGRAM.name).toString();
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
resumeData.comment = query.value(DB_COLUMN_COMMENT.name).toString();
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
Expand Down Expand Up @@ -838,6 +841,7 @@ StoreJob::StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData)
QList<Column> columns {
DB_COLUMN_TORRENT_ID,
DB_COLUMN_NAME,
DB_COLUMN_RUN_ON_FINISHED_PROGRAM,
DB_COLUMN_CATEGORY,
DB_COLUMN_TAGS,
DB_COLUMN_COMMENT,
Expand Down Expand Up @@ -903,6 +907,7 @@ StoreJob::StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData)

query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, m_torrentID.toString());
query.bindValue(DB_COLUMN_NAME.placeholder, m_resumeData.name);
query.bindValue(DB_COLUMN_RUN_ON_FINISHED_PROGRAM.placeholder, m_resumeData.runOnFinishedProgram);
query.bindValue(DB_COLUMN_CATEGORY.placeholder, m_resumeData.category);
query.bindValue(DB_COLUMN_TAGS.placeholder, (m_resumeData.tags.isEmpty()
? QString() : Utils::String::joinIntoString(m_resumeData.tags, u","_s)));
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/loadtorrentparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ namespace BitTorrent

bool addToQueueTop = false; // only for new torrents

QString runOnFinishedProgram;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ namespace BitTorrent
void torrentMetadataReceived(Torrent *torrent);
void torrentStopped(Torrent *torrent);
void torrentStarted(Torrent *torrent);
void torrentRunOnFinishedProgramChanged(Torrent *torrent);
void torrentSavePathChanged(Torrent *torrent);
void torrentSavingModeChanged(Torrent *torrent);
void torrentsLoaded(const QList<Torrent *> &torrents);
Expand Down
4 changes: 4 additions & 0 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5245,6 +5245,10 @@ void SessionImpl::handleTorrentSavePathChanged(TorrentImpl *const torrent)
emit torrentSavePathChanged(torrent);
}

void SessionImpl::handleTorrentRunOnFinishedProgramChanged(TorrentImpl *const torrent) {
emit torrentRunOnFinishedProgramChanged(torrent);
}

void SessionImpl::handleTorrentCategoryChanged(TorrentImpl *const torrent, const QString &oldCategory)
{
emit torrentCategoryChanged(torrent, oldCategory);
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ namespace BitTorrent
void handleTorrentShareLimitChanged(TorrentImpl *torrent);
void handleTorrentNameChanged(TorrentImpl *torrent);
void handleTorrentSavePathChanged(TorrentImpl *torrent);
void handleTorrentRunOnFinishedProgramChanged(TorrentImpl *torrent);
void handleTorrentCategoryChanged(TorrentImpl *torrent, const QString &oldCategory);
void handleTorrentTagAdded(TorrentImpl *torrent, const Tag &tag);
void handleTorrentTagRemoved(TorrentImpl *torrent, const Tag &tag);
Expand Down
2 changes: 2 additions & 0 deletions src/base/bittorrent/torrent.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ namespace BitTorrent
virtual void setDownloadPath(const Path &downloadPath) = 0;
virtual Path rootPath() const = 0;
virtual Path contentPath() const = 0;
virtual QString runOnFinishedProgram() const = 0;
virtual void setRunOnFinishedProgram(const QString &program) = 0;
virtual QString category() const = 0;
virtual bool belongsToCategory(const QString &category) const = 0;
virtual bool setCategory(const QString &category) = 0;
Expand Down
14 changes: 14 additions & 0 deletions src/base/bittorrent/torrentimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ TorrentImpl::TorrentImpl(SessionImpl *session, const lt::torrent_handle &nativeH
, m_name(params.name)
, m_savePath(params.savePath)
, m_downloadPath(params.downloadPath)
, m_runOnFinishedProgram(params.runOnFinishedProgram)
, m_category(params.category)
, m_tags(params.tags)
, m_ratioLimit(params.ratioLimit)
Expand Down Expand Up @@ -2256,6 +2257,7 @@ void TorrentImpl::prepareResumeData(lt::add_torrent_params params)
.stopped = m_isStopped,
.stopCondition = m_stopCondition,
.addToQueueTop = false,
.runOnFinishedProgram = m_runOnFinishedProgram,
.ratioLimit = m_ratioLimit,
.seedingTimeLimit = m_seedingTimeLimit,
.inactiveSeedingTimeLimit = m_inactiveSeedingTimeLimit,
Expand Down Expand Up @@ -2621,6 +2623,18 @@ void TorrentImpl::updateProgress()
}
}

QString TorrentImpl::runOnFinishedProgram() const {
return m_runOnFinishedProgram;
}

void TorrentImpl::setRunOnFinishedProgram(const QString &program) {
if (m_runOnFinishedProgram != program) {
m_runOnFinishedProgram = program;
deferredRequestResumeData();
m_session->handleTorrentRunOnFinishedProgramChanged(this);
}
}

void TorrentImpl::setRatioLimit(qreal limit)
{
if (limit < USE_GLOBAL_RATIO)
Expand Down
3 changes: 3 additions & 0 deletions src/base/bittorrent/torrentimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ namespace BitTorrent
Path actualStorageLocation() const override;
Path rootPath() const override;
Path contentPath() const override;
QString runOnFinishedProgram() const override;
void setRunOnFinishedProgram(const QString &program) override;
QString category() const override;
bool belongsToCategory(const QString &category) const override;
bool setCategory(const QString &category) override;
Expand Down Expand Up @@ -358,6 +360,7 @@ namespace BitTorrent
QString m_name;
Path m_savePath;
Path m_downloadPath;
QString m_runOnFinishedProgram;
QString m_category;
TagSet m_tags;
qreal m_ratioLimit = 0;
Expand Down
46 changes: 46 additions & 0 deletions src/gui/torrentoptionsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QList<BitTorre
m_ui->downloadPath->setDialogCaption(tr("Choose save path"));

const auto *session = BitTorrent::Session::instance();
bool allSameRunOnFinishedProgram = true;
bool allSameUpLimit = true;
bool allSameDownLimit = true;
bool allSameRatio = true;
Expand All @@ -96,6 +97,7 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QList<BitTorre
const bool isFirstTorrentAutoTMMEnabled = torrents[0]->isAutoTMMEnabled();
const Path firstTorrentSavePath = torrents[0]->savePath();
const Path firstTorrentDownloadPath = torrents[0]->downloadPath();
const QString firstRunOnFinishedProgram = torrents[0]->runOnFinishedProgram();
const QString firstTorrentCategory = torrents[0]->category();

const int firstTorrentUpLimit = std::max(0, torrents[0]->uploadLimit());
Expand Down Expand Up @@ -132,6 +134,11 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QList<BitTorre
if (torrent->downloadPath() != firstTorrentDownloadPath)
allSameDownloadPath = false;
}
if (allSameRunOnFinishedProgram)
{
if (torrent->runOnFinishedProgram() != firstRunOnFinishedProgram)
allSameRunOnFinishedProgram = false;
}
if (m_allSameCategory)
{
if (torrent->category() != firstTorrentCategory)
Expand Down Expand Up @@ -217,6 +224,27 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QList<BitTorre
m_ui->checkUseDownloadPath->setCheckState(Qt::PartiallyChecked);
}

if (allSameRunOnFinishedProgram)
{
m_ui->runOnFinishedProgram->setText(firstRunOnFinishedProgram);
const bool active = !firstRunOnFinishedProgram.isEmpty();
m_ui->runOnFinishedEnabled->setChecked(active);
m_ui->runOnFinishedProgram->setEnabled(active);
}
else
{
m_ui->runOnFinishedEnabled->setCheckState(Qt::PartiallyChecked);
m_ui->runOnFinishedProgram->setEnabled(false);
}

QAction *runOnFinishedWarning = new QAction(this);
m_ui->runOnFinishedProgram->addAction(runOnFinishedWarning, QLineEdit::TrailingPosition);
runOnFinishedWarning->setIcon(style()->standardIcon(QStyle::SP_MessageBoxInformation));
runOnFinishedWarning->setToolTip(tr("This overrides the global setting"));

connect(m_ui->runOnFinishedEnabled, &QCheckBox::clicked,
this, &TorrentOptionsDialog::handleRunOnFinishedEnabledChanged);

if (!m_allSameCategory)
{
m_ui->comboCategory->addItem(m_currentCategoriesString);
Expand Down Expand Up @@ -345,6 +373,8 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QList<BitTorre
{
.savePath = m_ui->savePath->selectedPath(),
.downloadPath = m_ui->downloadPath->selectedPath(),
.runOnFinishedEnabled = m_ui->runOnFinishedEnabled->checkState(),
.runOnFinishedProgram = m_ui->runOnFinishedProgram->text(),
.category = m_ui->comboCategory->currentText(),
.ratio = m_ui->torrentShareLimitsWidget->ratioLimit(),
.seedingTime = m_ui->torrentShareLimitsWidget->seedingTimeLimit(),
Expand Down Expand Up @@ -417,6 +447,16 @@ void TorrentOptionsDialog::accept()
}
}

if(m_ui->runOnFinishedEnabled->checkState() == Qt::Checked)
{
const QString runOnFinishedProgram = m_ui->runOnFinishedProgram->text();
torrent->setRunOnFinishedProgram(runOnFinishedProgram);
}
else
{
torrent->setRunOnFinishedProgram(QString());
}

const QString category = m_ui->comboCategory->currentText();
// index 0 is always the current category
if ((m_initialValues.category != category) || (m_ui->comboCategory->currentIndex() != 0))
Expand Down Expand Up @@ -542,6 +582,12 @@ void TorrentOptionsDialog::handleTMMChanged()
}
}

void TorrentOptionsDialog::handleRunOnFinishedEnabledChanged()
{
const bool isChecked = m_ui->runOnFinishedEnabled->checkState() == Qt::Checked;
m_ui->runOnFinishedProgram->setEnabled(isChecked);
}

void TorrentOptionsDialog::handleUseDownloadPathChanged()
{
const bool isChecked = m_ui->checkUseDownloadPath->checkState() == Qt::Checked;
Expand Down
3 changes: 3 additions & 0 deletions src/gui/torrentoptionsdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public slots:
private slots:
void handleCategoryChanged(int index);
void handleTMMChanged();
void handleRunOnFinishedEnabledChanged();
void handleUseDownloadPathChanged();

void handleUpSpeedLimitChanged();
Expand All @@ -84,6 +85,8 @@ private slots:
{
Path savePath;
Path downloadPath;
Qt::CheckState runOnFinishedEnabled;
QString runOnFinishedProgram;
QString category;
std::optional<qreal> ratio;
std::optional<int> seedingTime;
Expand Down
14 changes: 14 additions & 0 deletions src/gui/torrentoptionsdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="runOnFinishedEnabled">
<property name="text">
<string>Run external program when finished</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="runOnFinishedProgram"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
Expand Down