Browse Source

Add options to adjust behavior of merging trackers to existing torrent

PR #19278.
Closes #19251.
adaptive-webui-19844
Vladimir Golovnev 1 year ago committed by GitHub
parent
commit
4ef9a6444a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/base/bittorrent/session.h
  2. 32
      src/base/bittorrent/sessionimpl.cpp
  3. 3
      src/base/bittorrent/sessionimpl.h
  4. 13
      src/base/preferences.cpp
  5. 2
      src/base/preferences.h
  6. 30
      src/gui/addnewtorrentdialog.cpp
  7. 7
      src/gui/optionsdialog.cpp
  8. 35
      src/gui/optionsdialog.ui
  9. 3
      src/webui/api/appcontroller.cpp

2
src/base/bittorrent/session.h

@ -419,6 +419,8 @@ namespace BitTorrent
virtual void setBannedIPs(const QStringList &newList) = 0; virtual void setBannedIPs(const QStringList &newList) = 0;
virtual ResumeDataStorageType resumeDataStorageType() const = 0; virtual ResumeDataStorageType resumeDataStorageType() const = 0;
virtual void setResumeDataStorageType(ResumeDataStorageType type) = 0; virtual void setResumeDataStorageType(ResumeDataStorageType type) = 0;
virtual bool isMergeTrackersEnabled() const = 0;
virtual void setMergeTrackersEnabled(bool enabled) = 0;
virtual bool isRestored() const = 0; virtual bool isRestored() const = 0;

32
src/base/bittorrent/sessionimpl.cpp

@ -523,6 +523,7 @@ SessionImpl::SessionImpl(QObject *parent)
, m_excludedFileNames(BITTORRENT_SESSION_KEY(u"ExcludedFileNames"_s)) , m_excludedFileNames(BITTORRENT_SESSION_KEY(u"ExcludedFileNames"_s))
, m_bannedIPs(u"State/BannedIPs"_s, QStringList(), Algorithm::sorted<QStringList>) , m_bannedIPs(u"State/BannedIPs"_s, QStringList(), Algorithm::sorted<QStringList>)
, m_resumeDataStorageType(BITTORRENT_SESSION_KEY(u"ResumeDataStorageType"_s), ResumeDataStorageType::Legacy) , m_resumeDataStorageType(BITTORRENT_SESSION_KEY(u"ResumeDataStorageType"_s), ResumeDataStorageType::Legacy)
, m_isMergeTrackersEnabled(BITTORRENT_KEY(u"MergeTrackersEnabled"_s), false)
, m_isI2PEnabled {BITTORRENT_SESSION_KEY(u"I2P/Enabled"_s), false} , m_isI2PEnabled {BITTORRENT_SESSION_KEY(u"I2P/Enabled"_s), false}
, m_I2PAddress {BITTORRENT_SESSION_KEY(u"I2P/Address"_s), u"127.0.0.1"_s} , m_I2PAddress {BITTORRENT_SESSION_KEY(u"I2P/Address"_s), u"127.0.0.1"_s}
, m_I2PPort {BITTORRENT_SESSION_KEY(u"I2P/Port"_s), 7656} , m_I2PPort {BITTORRENT_SESSION_KEY(u"I2P/Port"_s), 7656}
@ -2677,10 +2678,31 @@ bool SessionImpl::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &so
if (Torrent *torrent = findTorrent(infoHash); torrent) if (Torrent *torrent = findTorrent(infoHash); torrent)
{ {
// a duplicate torrent is being added
if (torrent->isPrivate())
return false;
if (hasMetadata) if (hasMetadata)
{ {
// Trying to set metadata to existing torrent in case if it has none // Trying to set metadata to existing torrent in case if it has none
torrent->setMetadata(std::get<TorrentInfo>(source)); torrent->setMetadata(std::get<TorrentInfo>(source));
const TorrentInfo &torrentInfo = std::get<TorrentInfo>(source);
if (torrentInfo.isPrivate())
return false;
// merge trackers and web seeds
torrent->addTrackers(torrentInfo.trackers());
torrent->addUrlSeeds(torrentInfo.urlSeeds());
}
else
{
const MagnetUri &magnetUri = std::get<MagnetUri>(source);
// merge trackers and web seeds
torrent->addTrackers(magnetUri.trackers());
torrent->addUrlSeeds(magnetUri.urlSeeds());
} }
return false; return false;
@ -3904,6 +3926,16 @@ void SessionImpl::setResumeDataStorageType(const ResumeDataStorageType type)
m_resumeDataStorageType = type; m_resumeDataStorageType = type;
} }
bool SessionImpl::isMergeTrackersEnabled() const
{
return m_isMergeTrackersEnabled;
}
void SessionImpl::setMergeTrackersEnabled(const bool enabled)
{
m_isMergeTrackersEnabled = enabled;
}
QStringList SessionImpl::bannedIPs() const QStringList SessionImpl::bannedIPs() const
{ {
return m_bannedIPs; return m_bannedIPs;

3
src/base/bittorrent/sessionimpl.h

@ -398,6 +398,8 @@ namespace BitTorrent
void setBannedIPs(const QStringList &newList) override; void setBannedIPs(const QStringList &newList) override;
ResumeDataStorageType resumeDataStorageType() const override; ResumeDataStorageType resumeDataStorageType() const override;
void setResumeDataStorageType(ResumeDataStorageType type) override; void setResumeDataStorageType(ResumeDataStorageType type) override;
bool isMergeTrackersEnabled() const override;
void setMergeTrackersEnabled(bool enabled) override;
bool isRestored() const override; bool isRestored() const override;
@ -704,6 +706,7 @@ namespace BitTorrent
CachedSettingValue<QStringList> m_excludedFileNames; CachedSettingValue<QStringList> m_excludedFileNames;
CachedSettingValue<QStringList> m_bannedIPs; CachedSettingValue<QStringList> m_bannedIPs;
CachedSettingValue<ResumeDataStorageType> m_resumeDataStorageType; CachedSettingValue<ResumeDataStorageType> m_resumeDataStorageType;
CachedSettingValue<bool> m_isMergeTrackersEnabled;
CachedSettingValue<bool> m_isI2PEnabled; CachedSettingValue<bool> m_isI2PEnabled;
CachedSettingValue<QString> m_I2PAddress; CachedSettingValue<QString> m_I2PAddress;
CachedSettingValue<int> m_I2PPort; CachedSettingValue<int> m_I2PPort;

13
src/base/preferences.cpp

@ -1508,6 +1508,19 @@ void Preferences::setConfirmPauseAndResumeAll(const bool enabled)
setValue(u"GUI/ConfirmActions/PauseAndResumeAllTorrents"_s, enabled); setValue(u"GUI/ConfirmActions/PauseAndResumeAllTorrents"_s, enabled);
} }
bool Preferences::confirmMergeTrackers() const
{
return value(u"GUI/ConfirmActions/MergeTrackers"_s, true);
}
void Preferences::setConfirmMergeTrackers(const bool enabled)
{
if (enabled == confirmMergeTrackers())
return;
setValue(u"GUI/ConfirmActions/MergeTrackers"_s, enabled);
}
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
TrayIcon::Style Preferences::trayIconStyle() const TrayIcon::Style Preferences::trayIconStyle() const
{ {

2
src/base/preferences.h

@ -317,6 +317,8 @@ public:
void setConfirmRemoveAllTags(bool enabled); void setConfirmRemoveAllTags(bool enabled);
bool confirmPauseAndResumeAll() const; bool confirmPauseAndResumeAll() const;
void setConfirmPauseAndResumeAll(bool enabled); void setConfirmPauseAndResumeAll(bool enabled);
bool confirmMergeTrackers() const;
void setConfirmMergeTrackers(bool enabled);
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
bool systemTrayEnabled() const; bool systemTrayEnabled() const;
void setSystemTrayEnabled(bool enabled); void setSystemTrayEnabled(bool enabled);

30
src/gui/addnewtorrentdialog.cpp

@ -539,9 +539,10 @@ bool AddNewTorrentDialog::loadTorrentImpl()
const BitTorrent::InfoHash infoHash = m_torrentInfo.infoHash(); const BitTorrent::InfoHash infoHash = m_torrentInfo.infoHash();
// Prevent showing the dialog if download is already present // Prevent showing the dialog if download is already present
if (BitTorrent::Session::instance()->isKnownTorrent(infoHash)) const auto *btSession = BitTorrent::Session::instance();
if (btSession->isKnownTorrent(infoHash))
{ {
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(infoHash); BitTorrent::Torrent *const torrent = btSession->findTorrent(infoHash);
if (torrent) if (torrent)
{ {
// Trying to set metadata to existing torrent in case if it has none // Trying to set metadata to existing torrent in case if it has none
@ -552,11 +553,17 @@ bool AddNewTorrentDialog::loadTorrentImpl()
RaisedMessageBox::warning(this, tr("Torrent is already present"), tr("Torrent '%1' is already in the transfer list. Trackers cannot be merged because it is a private torrent.").arg(torrent->name()), QMessageBox::Ok); RaisedMessageBox::warning(this, tr("Torrent is already present"), tr("Torrent '%1' is already in the transfer list. Trackers cannot be merged because it is a private torrent.").arg(torrent->name()), QMessageBox::Ok);
} }
else else
{
bool mergeTrackers = btSession->isMergeTrackersEnabled();
if (Preferences::instance()->confirmMergeTrackers())
{ {
const QMessageBox::StandardButton btn = RaisedMessageBox::question(this, tr("Torrent is already present") const QMessageBox::StandardButton btn = RaisedMessageBox::question(this, tr("Torrent is already present")
, tr("Torrent '%1' is already in the transfer list. Do you want to merge trackers from new source?").arg(torrent->name()) , tr("Torrent '%1' is already in the transfer list. Do you want to merge trackers from new source?").arg(torrent->name())
, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes); , (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes);
if (btn == QMessageBox::Yes) mergeTrackers = (btn == QMessageBox::Yes);
}
if (mergeTrackers)
{ {
torrent->addTrackers(m_torrentInfo.trackers()); torrent->addTrackers(m_torrentInfo.trackers());
torrent->addUrlSeeds(m_torrentInfo.urlSeeds()); torrent->addUrlSeeds(m_torrentInfo.urlSeeds());
@ -592,9 +599,10 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
const BitTorrent::InfoHash infoHash = magnetUri.infoHash(); const BitTorrent::InfoHash infoHash = magnetUri.infoHash();
// Prevent showing the dialog if download is already present // Prevent showing the dialog if download is already present
if (BitTorrent::Session::instance()->isKnownTorrent(infoHash)) auto *btSession = BitTorrent::Session::instance();
if (btSession->isKnownTorrent(infoHash))
{ {
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(infoHash); BitTorrent::Torrent *const torrent = btSession->findTorrent(infoHash);
if (torrent) if (torrent)
{ {
if (torrent->isPrivate()) if (torrent->isPrivate())
@ -602,11 +610,17 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
RaisedMessageBox::warning(this, tr("Torrent is already present"), tr("Torrent '%1' is already in the transfer list. Trackers haven't been merged because it is a private torrent.").arg(torrent->name()), QMessageBox::Ok); RaisedMessageBox::warning(this, tr("Torrent is already present"), tr("Torrent '%1' is already in the transfer list. Trackers haven't been merged because it is a private torrent.").arg(torrent->name()), QMessageBox::Ok);
} }
else else
{
bool mergeTrackers = btSession->isMergeTrackersEnabled();
if (Preferences::instance()->confirmMergeTrackers())
{ {
const QMessageBox::StandardButton btn = RaisedMessageBox::question(this, tr("Torrent is already present") const QMessageBox::StandardButton btn = RaisedMessageBox::question(this, tr("Torrent is already present")
, tr("Torrent '%1' is already in the transfer list. Do you want to merge trackers from new source?").arg(torrent->name()) , tr("Torrent '%1' is already in the transfer list. Do you want to merge trackers from new source?").arg(torrent->name())
, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes); , (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes);
if (btn == QMessageBox::Yes) mergeTrackers = (btn == QMessageBox::Yes);
}
if (mergeTrackers)
{ {
torrent->addTrackers(magnetUri.trackers()); torrent->addTrackers(magnetUri.trackers());
torrent->addUrlSeeds(magnetUri.urlSeeds()); torrent->addUrlSeeds(magnetUri.urlSeeds());
@ -621,7 +635,7 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
return false; return false;
} }
connect(BitTorrent::Session::instance(), &BitTorrent::Session::metadataDownloaded, this, &AddNewTorrentDialog::updateMetadata); connect(btSession, &BitTorrent::Session::metadataDownloaded, this, &AddNewTorrentDialog::updateMetadata);
// Set dialog title // Set dialog title
const QString torrentName = magnetUri.name(); const QString torrentName = magnetUri.name();
@ -630,7 +644,7 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
updateDiskSpaceLabel(); updateDiskSpaceLabel();
TMMChanged(m_ui->comboTTM->currentIndex()); TMMChanged(m_ui->comboTTM->currentIndex());
BitTorrent::Session::instance()->downloadMetadata(magnetUri); btSession->downloadMetadata(magnetUri);
setMetadataProgressIndicator(true, tr("Retrieving metadata...")); setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
m_ui->labelInfohash1Data->setText(magnetUri.infoHash().v1().isValid() ? magnetUri.infoHash().v1().toString() : tr("N/A")); m_ui->labelInfohash1Data->setText(magnetUri.infoHash().v1().isValid() ? magnetUri.infoHash().v1().toString() : tr("N/A"));
m_ui->labelInfohash2Data->setText(magnetUri.infoHash().v2().isValid() ? magnetUri.infoHash().v2().toString() : tr("N/A")); m_ui->labelInfohash2Data->setText(magnetUri.infoHash().v2().isValid() ? magnetUri.infoHash().v2().toString() : tr("N/A"));

7
src/gui/optionsdialog.cpp

@ -504,6 +504,9 @@ void OptionsDialog::loadDownloadsTabOptions()
m_ui->stopConditionLabel->setEnabled(!m_ui->checkStartPaused->isChecked()); m_ui->stopConditionLabel->setEnabled(!m_ui->checkStartPaused->isChecked());
m_ui->stopConditionComboBox->setEnabled(!m_ui->checkStartPaused->isChecked()); m_ui->stopConditionComboBox->setEnabled(!m_ui->checkStartPaused->isChecked());
m_ui->checkMergeTrackers->setChecked(session->isMergeTrackersEnabled());
m_ui->checkConfirmMergeTrackers->setChecked(pref->confirmMergeTrackers());
const TorrentFileGuard::AutoDeleteMode autoDeleteMode = TorrentFileGuard::autoDeleteMode(); const TorrentFileGuard::AutoDeleteMode autoDeleteMode = TorrentFileGuard::autoDeleteMode();
m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never); m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never);
m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always); m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always);
@ -619,6 +622,8 @@ void OptionsDialog::loadDownloadsTabOptions()
m_ui->stopConditionComboBox->setEnabled(!checked); m_ui->stopConditionComboBox->setEnabled(!checked);
}); });
connect(m_ui->stopConditionComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); connect(m_ui->stopConditionComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkMergeTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkConfirmMergeTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->deleteCancelledTorrentBox, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->deleteCancelledTorrentBox, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
@ -684,6 +689,8 @@ void OptionsDialog::saveDownloadsTabOptions() const
TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never
: !m_ui->deleteCancelledTorrentBox->isChecked() ? TorrentFileGuard::IfAdded : !m_ui->deleteCancelledTorrentBox->isChecked() ? TorrentFileGuard::IfAdded
: TorrentFileGuard::Always); : TorrentFileGuard::Always);
session->setMergeTrackersEnabled(m_ui->checkMergeTrackers->isChecked());
pref->setConfirmMergeTrackers(m_ui->checkConfirmMergeTrackers->isChecked());
session->setPreallocationEnabled(preAllocateAllFiles()); session->setPreallocationEnabled(preAllocateAllFiles());
session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked()); session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked());

35
src/gui/optionsdialog.ui

@ -950,6 +950,41 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QGroupBox" name="duplicateTorrentGroup">
<property name="title">
<string>When duplicate torrent is being added</string>
</property>
<layout class="QVBoxLayout" name="deleteTorrentBoxLayout">
<item>
<widget class="QCheckBox" name="checkMergeTrackers">
<property name="toolTip">
<string>Whether trackers should be merged to existing torrent</string>
</property>
<property name="text">
<string>Merge trackers to existing torrent</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkConfirmMergeTrackers">
<property name="toolTip">
<string>Shows a confirmation dialog upon merging trackers to existing torrent</string>
</property>
<property name="text">
<string>Confirm merging trackers</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="deleteTorrentBox"> <widget class="QGroupBox" name="deleteTorrentBox">
<property name="toolTip"> <property name="toolTip">

3
src/webui/api/appcontroller.cpp

@ -126,6 +126,7 @@ void AppController::preferencesAction()
data[u"add_to_top_of_queue"_s] = session->isAddTorrentToQueueTop(); data[u"add_to_top_of_queue"_s] = session->isAddTorrentToQueueTop();
data[u"start_paused_enabled"_s] = session->isAddTorrentPaused(); data[u"start_paused_enabled"_s] = session->isAddTorrentPaused();
data[u"torrent_stop_condition"_s] = Utils::String::fromEnum(session->torrentStopCondition()); data[u"torrent_stop_condition"_s] = Utils::String::fromEnum(session->torrentStopCondition());
data[u"merge_trackers"_s] = session->isMergeTrackersEnabled();
data[u"auto_delete_mode"_s] = static_cast<int>(TorrentFileGuard::autoDeleteMode()); data[u"auto_delete_mode"_s] = static_cast<int>(TorrentFileGuard::autoDeleteMode());
data[u"preallocate_all"_s] = session->isPreallocationEnabled(); data[u"preallocate_all"_s] = session->isPreallocationEnabled();
data[u"incomplete_files_ext"_s] = session->isAppendExtensionEnabled(); data[u"incomplete_files_ext"_s] = session->isAppendExtensionEnabled();
@ -477,6 +478,8 @@ void AppController::setPreferencesAction()
session->setAddTorrentPaused(it.value().toBool()); session->setAddTorrentPaused(it.value().toBool());
if (hasKey(u"torrent_stop_condition"_s)) if (hasKey(u"torrent_stop_condition"_s))
session->setTorrentStopCondition(Utils::String::toEnum(it.value().toString(), BitTorrent::Torrent::StopCondition::None)); session->setTorrentStopCondition(Utils::String::toEnum(it.value().toString(), BitTorrent::Torrent::StopCondition::None));
if (hasKey(u"merge_trackers"_s))
session->setMergeTrackersEnabled(it.value().toBool());
if (hasKey(u"auto_delete_mode"_s)) if (hasKey(u"auto_delete_mode"_s))
TorrentFileGuard::setAutoDeleteMode(static_cast<TorrentFileGuard::AutoDeleteMode>(it.value().toInt())); TorrentFileGuard::setAutoDeleteMode(static_cast<TorrentFileGuard::AutoDeleteMode>(it.value().toInt()));

Loading…
Cancel
Save