Merge pull request #10895 from Chocobo1/tracker

Add dialog to mass edit torrent's tracker
This commit is contained in:
Mike Tzou 2019-07-12 10:59:50 +08:00 committed by GitHub
commit 24932f6cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 288 additions and 11 deletions

View File

@ -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());
}

View File

@ -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

View File

@ -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
)

View File

@ -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

View 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);
}

View 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;
};

View 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>

View File

@ -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();

View File

@ -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);