mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-12-21 08:09:35 +08:00
Merge pull request #10895 from Chocobo1/tracker
Add dialog to mass edit torrent's tracker
This commit is contained in:
commit
24932f6cb6
@ -154,5 +154,11 @@ const lt::announce_entry &TrackerEntry::nativeEntry() const
|
||||
|
||||
bool BitTorrent::operator==(const TrackerEntry &left, const TrackerEntry &right)
|
||||
{
|
||||
return (QUrl(left.url()) == QUrl(right.url()));
|
||||
return ((left.tier() == right.tier())
|
||||
&& QUrl(left.url()) == QUrl(right.url()));
|
||||
}
|
||||
|
||||
uint BitTorrent::qHash(const TrackerEntry &key, const uint seed)
|
||||
{
|
||||
return (::qHash(key.url(), seed) ^ key.tier());
|
||||
}
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
#include <libtorrent/announce_entry.hpp>
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
class QString;
|
||||
|
||||
namespace BitTorrent
|
||||
@ -70,6 +72,7 @@ namespace BitTorrent
|
||||
};
|
||||
|
||||
bool operator==(const TrackerEntry &left, const TrackerEntry &right);
|
||||
uint qHash(const TrackerEntry &key, uint seed);
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_TRACKERENTRY_H
|
||||
|
@ -52,6 +52,7 @@ torrentcontentmodelfolder.h
|
||||
torrentcontentmodelitem.h
|
||||
torrentcontenttreeview.h
|
||||
torrentcreatordialog.h
|
||||
trackerentriesdialog.h
|
||||
transferlistdelegate.h
|
||||
transferlistfilterswidget.h
|
||||
transferlistmodel.h
|
||||
@ -98,6 +99,7 @@ torrentcontentmodelfolder.cpp
|
||||
torrentcontentmodelitem.cpp
|
||||
torrentcontenttreeview.cpp
|
||||
torrentcreatordialog.cpp
|
||||
trackerentriesdialog.cpp
|
||||
transferlistdelegate.cpp
|
||||
transferlistfilterswidget.cpp
|
||||
transferlistmodel.cpp
|
||||
@ -125,6 +127,7 @@ speedlimitdialog.ui
|
||||
statsdialog.ui
|
||||
torrentcategorydialog.ui
|
||||
torrentcreatordialog.ui
|
||||
trackerentriesdialog.ui
|
||||
updownratiodialog.ui
|
||||
)
|
||||
|
||||
|
@ -57,6 +57,7 @@ HEADERS += \
|
||||
$$PWD/torrentcontentmodelitem.h \
|
||||
$$PWD/torrentcontenttreeview.h \
|
||||
$$PWD/torrentcreatordialog.h \
|
||||
$$PWD/trackerentriesdialog.h \
|
||||
$$PWD/transferlistdelegate.h \
|
||||
$$PWD/transferlistfilterswidget.h \
|
||||
$$PWD/transferlistmodel.h \
|
||||
@ -114,6 +115,7 @@ SOURCES += \
|
||||
$$PWD/torrentcontentmodelitem.cpp \
|
||||
$$PWD/torrentcontenttreeview.cpp \
|
||||
$$PWD/torrentcreatordialog.cpp \
|
||||
$$PWD/trackerentriesdialog.cpp \
|
||||
$$PWD/transferlistdelegate.cpp \
|
||||
$$PWD/transferlistfilterswidget.cpp \
|
||||
$$PWD/transferlistmodel.cpp \
|
||||
@ -157,6 +159,7 @@ FORMS += \
|
||||
$$PWD/statsdialog.ui \
|
||||
$$PWD/torrentcategorydialog.ui \
|
||||
$$PWD/torrentcreatordialog.ui \
|
||||
$$PWD/trackerentriesdialog.ui \
|
||||
$$PWD/updownratiodialog.ui
|
||||
|
||||
RESOURCES += $$PWD/about.qrc
|
||||
|
112
src/gui/trackerentriesdialog.cpp
Normal file
112
src/gui/trackerentriesdialog.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2019 Mike Tzou (Chocobo1)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "trackerentriesdialog.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QHash>
|
||||
|
||||
#include "base/bittorrent/trackerentry.h"
|
||||
#include "ui_trackerentriesdialog.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define SETTINGS_KEY(name) "TrackerEntriesDialog/" name
|
||||
|
||||
TrackerEntriesDialog::TrackerEntriesDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::TrackerEntriesDialog)
|
||||
, m_storeDialogSize(SETTINGS_KEY("Dimension"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
TrackerEntriesDialog::~TrackerEntriesDialog()
|
||||
{
|
||||
saveSettings();
|
||||
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void TrackerEntriesDialog::setTrackers(const QVector<BitTorrent::TrackerEntry> &trackers)
|
||||
{
|
||||
int maxTier = -1;
|
||||
QHash<int, QString> tiers; // <tier, tracker URLs>
|
||||
|
||||
for (const BitTorrent::TrackerEntry &entry : trackers) {
|
||||
tiers[entry.tier()] += (entry.url() + '\n');
|
||||
maxTier = std::max(maxTier, entry.tier());
|
||||
}
|
||||
|
||||
QString text = tiers.value(0);
|
||||
|
||||
for (int i = 1; i <= maxTier; ++i)
|
||||
text += ('\n' + tiers.value(i));
|
||||
|
||||
m_ui->plainTextEdit->setPlainText(text);
|
||||
}
|
||||
|
||||
QVector<BitTorrent::TrackerEntry> TrackerEntriesDialog::trackers() const
|
||||
{
|
||||
const QString plainText = m_ui->plainTextEdit->toPlainText();
|
||||
const QVector<QStringRef> lines = plainText.splitRef('\n');
|
||||
|
||||
QVector<BitTorrent::TrackerEntry> entries;
|
||||
entries.reserve(lines.size());
|
||||
|
||||
int tier = 0;
|
||||
for (QStringRef line : lines) {
|
||||
line = line.trimmed();
|
||||
|
||||
if (line.isEmpty()) {
|
||||
++tier;
|
||||
continue;
|
||||
}
|
||||
|
||||
BitTorrent::TrackerEntry entry {line.toString()};
|
||||
entry.setTier(tier);
|
||||
entries.append(entry);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
void TrackerEntriesDialog::saveSettings()
|
||||
{
|
||||
m_storeDialogSize = size();
|
||||
}
|
||||
|
||||
void TrackerEntriesDialog::loadSettings()
|
||||
{
|
||||
Utils::Gui::resize(this, m_storeDialogSize);
|
||||
}
|
64
src/gui/trackerentriesdialog.h
Normal file
64
src/gui/trackerentriesdialog.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2019 Mike Tzou (Chocobo1)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QVector>
|
||||
|
||||
#include "base/settingvalue.h"
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TrackerEntry;
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TrackerEntriesDialog;
|
||||
}
|
||||
|
||||
class TrackerEntriesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(TrackerEntriesDialog)
|
||||
|
||||
public:
|
||||
explicit TrackerEntriesDialog(QWidget *parent);
|
||||
~TrackerEntriesDialog() override;
|
||||
|
||||
void setTrackers(const QVector<BitTorrent::TrackerEntry> &trackers);
|
||||
QVector<BitTorrent::TrackerEntry> trackers() const;
|
||||
|
||||
private:
|
||||
void saveSettings();
|
||||
void loadSettings();
|
||||
|
||||
Ui::TrackerEntriesDialog *m_ui;
|
||||
CachedSettingValue<QSize> m_storeDialogSize;
|
||||
};
|
43
src/gui/trackerentriesdialog.ui
Normal file
43
src/gui/trackerentriesdialog.ui
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TrackerEntriesDialog</class>
|
||||
<widget class="QDialog" name="TrackerEntriesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>506</width>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit trackers</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>One tracker URL per line.
|
||||
|
||||
- You can split the trackers into groups by inserting blank lines.
|
||||
- All trackers within the same group will belong to the same tier.
|
||||
- The group on top will be tier 0, the next group tier 1 and so on.
|
||||
- Below will show the common subset of trackers of the selected torrents.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -28,6 +28,8 @@
|
||||
|
||||
#include "transferlistwidget.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDebug>
|
||||
#include <QFileDialog>
|
||||
@ -36,6 +38,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QSet>
|
||||
#include <QShortcut>
|
||||
#include <QStylePainter>
|
||||
#include <QTableView>
|
||||
@ -44,6 +47,7 @@
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/bittorrent/trackerentry.h"
|
||||
#include "base/global.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/preferences.h"
|
||||
@ -59,6 +63,7 @@
|
||||
#include "previewselectdialog.h"
|
||||
#include "speedlimitdialog.h"
|
||||
#include "torrentcategorydialog.h"
|
||||
#include "trackerentriesdialog.h"
|
||||
#include "transferlistdelegate.h"
|
||||
#include "transferlistmodel.h"
|
||||
#include "transferlistsortmodel.h"
|
||||
@ -73,7 +78,7 @@ namespace
|
||||
{
|
||||
using ToggleFn = std::function<void (Qt::CheckState)>;
|
||||
|
||||
QStringList extractHashes(const QList<BitTorrent::TorrentHandle *> &torrents)
|
||||
QStringList extractHashes(const QVector<BitTorrent::TorrentHandle *> &torrents)
|
||||
{
|
||||
QStringList hashes;
|
||||
for (BitTorrent::TorrentHandle *const torrent : torrents)
|
||||
@ -395,9 +400,9 @@ void TransferListWidget::torrentDoubleClicked()
|
||||
}
|
||||
}
|
||||
|
||||
QList<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() const
|
||||
QVector<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() const
|
||||
{
|
||||
QList<BitTorrent::TorrentHandle *> torrents;
|
||||
QVector<BitTorrent::TorrentHandle *> torrents;
|
||||
for (const QModelIndex &index : asConst(selectionModel()->selectedRows()))
|
||||
torrents << m_listModel->torrentHandle(mapToSource(index));
|
||||
|
||||
@ -406,7 +411,7 @@ QList<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() con
|
||||
|
||||
void TransferListWidget::setSelectedTorrentsLocation()
|
||||
{
|
||||
const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
if (torrents.isEmpty()) return;
|
||||
|
||||
const QString oldLocation = torrents[0]->savePath();
|
||||
@ -489,7 +494,7 @@ void TransferListWidget::deleteSelectedTorrents(bool deleteLocalFiles)
|
||||
{
|
||||
if (m_mainWindow->currentTabWidget() != this) return;
|
||||
|
||||
const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
if (torrents.empty()) return;
|
||||
|
||||
if (Preferences::instance()->confirmTorrentDeletion()
|
||||
@ -503,7 +508,7 @@ void TransferListWidget::deleteVisibleTorrents()
|
||||
{
|
||||
if (m_sortFilterModel->rowCount() <= 0) return;
|
||||
|
||||
QList<BitTorrent::TorrentHandle *> torrents;
|
||||
QVector<BitTorrent::TorrentHandle *> torrents;
|
||||
for (int i = 0; i < m_sortFilterModel->rowCount(); ++i)
|
||||
torrents << m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0)));
|
||||
|
||||
@ -617,7 +622,7 @@ void TransferListWidget::previewSelectedTorrents()
|
||||
|
||||
void TransferListWidget::setDlLimitSelectedTorrents()
|
||||
{
|
||||
QList<BitTorrent::TorrentHandle *> torrentsList;
|
||||
QVector<BitTorrent::TorrentHandle *> torrentsList;
|
||||
for (BitTorrent::TorrentHandle *const torrent : asConst(getSelectedTorrents())) {
|
||||
if (torrent->isSeed())
|
||||
continue;
|
||||
@ -647,7 +652,7 @@ void TransferListWidget::setDlLimitSelectedTorrents()
|
||||
|
||||
void TransferListWidget::setUpLimitSelectedTorrents()
|
||||
{
|
||||
QList<BitTorrent::TorrentHandle *> torrentsList = getSelectedTorrents();
|
||||
QVector<BitTorrent::TorrentHandle *> torrentsList = getSelectedTorrents();
|
||||
if (torrentsList.empty()) return;
|
||||
|
||||
int oldLimit = torrentsList.first()->uploadLimit();
|
||||
@ -672,7 +677,7 @@ void TransferListWidget::setUpLimitSelectedTorrents()
|
||||
|
||||
void TransferListWidget::setMaxRatioSelectedTorrents()
|
||||
{
|
||||
const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
if (torrents.isEmpty()) return;
|
||||
|
||||
qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio();
|
||||
@ -807,6 +812,39 @@ void TransferListWidget::askAddTagsForSelection()
|
||||
addSelectionTag(tag);
|
||||
}
|
||||
|
||||
void TransferListWidget::editTorrentTrackers()
|
||||
{
|
||||
const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
|
||||
QVector<BitTorrent::TrackerEntry> commonTrackers;
|
||||
|
||||
if (!torrents.empty()) {
|
||||
commonTrackers = torrents[0]->trackers();
|
||||
|
||||
for (const BitTorrent::TorrentHandle *torrent : torrents) {
|
||||
QSet<BitTorrent::TrackerEntry> trackerSet;
|
||||
|
||||
for (const BitTorrent::TrackerEntry &entry : asConst(torrent->trackers()))
|
||||
trackerSet.insert(entry);
|
||||
|
||||
commonTrackers.erase(std::remove_if(commonTrackers.begin(), commonTrackers.end()
|
||||
, [&trackerSet](const BitTorrent::TrackerEntry &entry) { return !trackerSet.contains(entry); })
|
||||
, commonTrackers.end());
|
||||
}
|
||||
}
|
||||
|
||||
auto trackerDialog = new TrackerEntriesDialog(this);
|
||||
trackerDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
trackerDialog->setTrackers(commonTrackers);
|
||||
|
||||
connect(trackerDialog, &QDialog::accepted, this, [torrents, trackerDialog]()
|
||||
{
|
||||
for (BitTorrent::TorrentHandle *torrent : torrents)
|
||||
torrent->replaceTrackers(trackerDialog->trackers());
|
||||
});
|
||||
|
||||
trackerDialog->open();
|
||||
}
|
||||
|
||||
void TransferListWidget::confirmRemoveAllTagsForSelection()
|
||||
{
|
||||
QMessageBox::StandardButton response = QMessageBox::question(
|
||||
@ -951,6 +989,8 @@ void TransferListWidget::displayListMenu(const QPoint &)
|
||||
actionAutoTMM->setCheckable(true);
|
||||
actionAutoTMM->setToolTip(tr("Automatic mode means that various torrent properties(eg save path) will be decided by the associated category"));
|
||||
connect(actionAutoTMM, &QAction::triggered, this, &TransferListWidget::setSelectedAutoTMMEnabled);
|
||||
QAction *actionEditTracker = new QAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Edit trackers..."), listMenu);
|
||||
connect(actionEditTracker, &QAction::triggered, this, &TransferListWidget::editTorrentTrackers);
|
||||
// End of actions
|
||||
|
||||
// Enable/disable pause/start action given the DL state
|
||||
@ -1046,6 +1086,7 @@ void TransferListWidget::displayListMenu(const QPoint &)
|
||||
listMenu->addAction(actionSetTorrentPath);
|
||||
if (selectedIndexes.size() == 1)
|
||||
listMenu->addAction(actionRename);
|
||||
listMenu->addAction(actionEditTracker);
|
||||
|
||||
// Category Menu
|
||||
QStringList categories = BitTorrent::Session::instance()->categories().keys();
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <QTreeView>
|
||||
#include <QVector>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
@ -99,7 +100,7 @@ protected:
|
||||
QModelIndex mapToSource(const QModelIndex &index) const;
|
||||
QModelIndex mapFromSource(const QModelIndex &index) const;
|
||||
bool loadSettings();
|
||||
QList<BitTorrent::TorrentHandle *> getSelectedTorrents() const;
|
||||
QVector<BitTorrent::TorrentHandle *> getSelectedTorrents() const;
|
||||
|
||||
protected slots:
|
||||
void torrentDoubleClicked();
|
||||
@ -118,6 +119,7 @@ signals:
|
||||
private:
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
void askAddTagsForSelection();
|
||||
void editTorrentTrackers();
|
||||
void confirmRemoveAllTagsForSelection();
|
||||
QStringList askTagsForSelection(const QString &dialogTitle);
|
||||
void applyToSelectedTorrents(const std::function<void (BitTorrent::TorrentHandle *const)> &fn);
|
||||
|
Loading…
Reference in New Issue
Block a user