Browse Source

Provide v1 and v2 infohashes in UI (#15097)

adaptive-webui-19844
Vladimir Golovnev 3 years ago committed by GitHub
parent
commit
37f227ae74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      src/app/application.cpp
  2. 18
      src/base/bittorrent/infohash.cpp
  3. 2
      src/base/bittorrent/infohash.h
  4. 6
      src/gui/addnewtorrentdialog.cpp
  5. 72
      src/gui/addnewtorrentdialog.ui
  6. 6
      src/gui/optionsdialog.cpp
  7. 9
      src/gui/properties/propertieswidget.cpp
  8. 74
      src/gui/properties/propertieswidget.ui
  9. 53
      src/gui/transferlistwidget.cpp
  10. 26
      src/gui/transferlistwidget.h
  11. 5
      src/webui/api/serialize/serialize_torrent.cpp
  12. 3
      src/webui/api/serialize/serialize_torrent.h
  13. 2
      src/webui/api/torrentscontroller.cpp
  14. 4
      src/webui/www/private/index.html
  15. 8
      src/webui/www/private/scripts/client.js
  16. 2
      src/webui/www/private/scripts/dynamicTable.js
  17. 34
      src/webui/www/private/scripts/mocha-init.js
  18. 4
      src/webui/www/private/scripts/prop-files.js
  19. 23
      src/webui/www/private/scripts/prop-general.js
  20. 6
      src/webui/www/private/scripts/prop-peers.js
  21. 2
      src/webui/www/private/scripts/prop-trackers.js
  22. 2
      src/webui/www/private/scripts/prop-webseeds.js
  23. 4
      src/webui/www/private/views/preferences.html
  24. 8
      src/webui/www/private/views/properties.html

6
src/app/application.cpp

@ -353,6 +353,12 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const @@ -353,6 +353,12 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
program.replace(i, 2, torrent->tags().join(QLatin1String(",")));
break;
case u'I':
program.replace(i, 2, (torrent->infoHash().v1().isValid() ? torrent->infoHash().v1().toString() : QLatin1String("-")));
break;
case u'J':
program.replace(i, 2, (torrent->infoHash().v2().isValid() ? torrent->infoHash().v2().toString() : QLatin1String("-")));
break;
case u'K':
program.replace(i, 2, torrent->id().toString());
break;
case u'L':

18
src/base/bittorrent/infohash.cpp

@ -41,6 +41,24 @@ bool BitTorrent::InfoHash::isValid() const @@ -41,6 +41,24 @@ bool BitTorrent::InfoHash::isValid() const
return m_valid;
}
SHA1Hash BitTorrent::InfoHash::v1() const
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
return (m_nativeHash.has_v1() ? SHA1Hash(m_nativeHash.v1) : SHA1Hash());
#else
return {m_nativeHash};
#endif
}
SHA256Hash BitTorrent::InfoHash::v2() const
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
return (m_nativeHash.has_v2() ? SHA256Hash(m_nativeHash.v2) : SHA256Hash());
#else
return {};
#endif
}
BitTorrent::TorrentID BitTorrent::InfoHash::toTorrentID() const
{
#if (LIBTORRENT_VERSION_NUM >= 20000)

2
src/base/bittorrent/infohash.h

@ -69,6 +69,8 @@ namespace BitTorrent @@ -69,6 +69,8 @@ namespace BitTorrent
InfoHash(const WrappedType &nativeHash);
bool isValid() const;
SHA1Hash v1() const;
SHA256Hash v2() const;
TorrentID toTorrentID() const;
operator WrappedType() const;

6
src/gui/addnewtorrentdialog.cpp

@ -296,7 +296,8 @@ bool AddNewTorrentDialog::loadTorrentImpl() @@ -296,7 +296,8 @@ bool AddNewTorrentDialog::loadTorrentImpl()
return false;
}
m_ui->labelHashData->setText(torrentID.toString());
m_ui->labelInfohash1Data->setText(m_torrentInfo.infoHash().v1().isValid() ? m_torrentInfo.infoHash().v1().toString() : tr("N/A"));
m_ui->labelInfohash2Data->setText(m_torrentInfo.infoHash().v2().isValid() ? m_torrentInfo.infoHash().v2().toString() : tr("N/A"));
setupTreeview();
TMMChanged(m_ui->comboTTM->currentIndex());
return true;
@ -348,7 +349,8 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri) @@ -348,7 +349,8 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
BitTorrent::Session::instance()->downloadMetadata(magnetUri);
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
m_ui->labelHashData->setText(torrentID.toString());
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_magnetURI = magnetUri;
return true;

72
src/gui/addnewtorrentdialog.ui

@ -249,10 +249,10 @@ @@ -249,10 +249,10 @@
<string>Torrent information</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QLabel" name="labelDate">
<item row="2" column="0">
<widget class="QLabel" name="labelInfohash1">
<property name="text">
<string>Date:</string>
<string>Info hash v1:</string>
</property>
</widget>
</item>
@ -262,24 +262,7 @@ @@ -262,24 +262,7 @@
<item row="1" column="1">
<widget class="QLabel" name="labelDateData"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelSize">
<property name="text">
<string>Size:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labelHashData">
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QScrollArea" name="scrollArea">
<property name="styleSheet">
<string notr="true">background-color: rgba(0, 0, 0, 0);</string>
@ -295,7 +278,7 @@ @@ -295,7 +278,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>333</width>
<width>317</width>
<height>69</height>
</rect>
</property>
@ -335,20 +318,51 @@ @@ -335,20 +318,51 @@
</widget>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelHash">
<item row="4" column="0">
<widget class="QLabel" name="labelComment">
<property name="text">
<string>Comment:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelSize">
<property name="text">
<string>Hash:</string>
<string>Size:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labelInfohash1Data">
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelDate">
<property name="text">
<string>Date:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelComment">
<widget class="QLabel" name="labelInfohash2">
<property name="text">
<string>Comment:</string>
<string>Info hash v2</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="labelInfohash2Data">
<property name="text">
<string/>
</property>
</widget>
</item>

6
src/gui/optionsdialog.cpp

@ -388,7 +388,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) @@ -388,7 +388,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
connect(m_ui->lineEditAutoRun, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
const QString autoRunStr = QString("%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n %11\n%12")
const QString autoRunStr = QString("%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n %11\n %12\n %13\n%14")
.arg(tr("Supported parameters (case sensitive):")
, tr("%N: Torrent name")
, tr("%L: Category")
@ -399,7 +399,9 @@ OptionsDialog::OptionsDialog(QWidget *parent) @@ -399,7 +399,9 @@ OptionsDialog::OptionsDialog(QWidget *parent)
, tr("%C: Number of files")
, tr("%Z: Torrent size (bytes)"))
.arg(tr("%T: Current tracker")
, tr("%I: Info hash")
, tr("%I: Info hash v1 (or '-' if unavailable)")
, tr("%J: Info hash v2 (or '-' if unavailable)")
, tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)")
, tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")"));
m_ui->labelAutoRunParam->setText(autoRunStr);

9
src/gui/properties/propertieswidget.cpp

@ -232,7 +232,8 @@ void PropertiesWidget::clear() @@ -232,7 +232,8 @@ void PropertiesWidget::clear()
m_ui->labelSavePathVal->clear();
m_ui->labelCreatedOnVal->clear();
m_ui->labelTotalPiecesVal->clear();
m_ui->labelHashVal->clear();
m_ui->labelInfohash1Val->clear();
m_ui->labelInfohash2Val->clear();
m_ui->labelCommentVal->clear();
m_ui->labelProgressVal->clear();
m_ui->labelAverageAvailabilityVal->clear();
@ -312,9 +313,9 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::Torrent *const torrent) @@ -312,9 +313,9 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::Torrent *const torrent)
// Save path
updateSavePath(m_torrent);
// Info hash (Truncated info hash (torrent ID) with libtorrent2)
// TODO: Update label for this property to express its meaning more clearly (or change it to display real info hash(es))
m_ui->labelHashVal->setText(m_torrent->id().toString());
// Info hashes
m_ui->labelInfohash1Val->setText(m_torrent->infoHash().v1().isValid() ? m_torrent->infoHash().v1().toString() : tr("N/A"));
m_ui->labelInfohash2Val->setText(m_torrent->infoHash().v2().isValid() ? m_torrent->infoHash().v2().toString() : tr("N/A"));
m_propListModel->model()->clear();
if (m_torrent->hasMetadata())
{

74
src/gui/properties/propertieswidget.ui

@ -11,6 +11,9 @@ @@ -11,6 +11,9 @@
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -23,9 +26,6 @@ @@ -23,9 +26,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedProperties">
<property name="currentIndex">
@ -788,7 +788,7 @@ @@ -788,7 +788,7 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelHash">
<widget class="QLabel" name="labelInfohash1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -796,15 +796,31 @@ @@ -796,15 +796,31 @@
</sizepolicy>
</property>
<property name="text">
<string>Torrent Hash:</string>
<string>Info Hash v1:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1" colspan="5">
<widget class="QLabel" name="labelHashVal">
<item row="3" column="0">
<widget class="QLabel" name="labelInfohash2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Info Hash v2:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1" colspan="5">
<widget class="QLabel" name="labelInfohash2Val">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -819,7 +835,7 @@ @@ -819,7 +835,7 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="labelSavePath">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
@ -835,8 +851,24 @@ @@ -835,8 +851,24 @@
</property>
</widget>
</item>
<item row="3" column="1" colspan="5">
<widget class="QLabel" name="labelSavePathVal">
<item row="5" column="0">
<widget class="QLabel" name="labelComment">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Comment:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
</property>
</widget>
</item>
<item row="2" column="1" colspan="5">
<widget class="QLabel" name="labelInfohash1Val">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -846,31 +878,31 @@ @@ -846,31 +878,31 @@
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelComment">
<item row="4" column="1" colspan="5">
<widget class="QLabel" name="labelSavePathVal">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Comment:</string>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="1" colspan="5">
<item row="5" column="1" colspan="5">
<widget class="QLabel" name="labelCommentVal">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">

53
src/gui/transferlistwidget.cpp

@ -487,7 +487,33 @@ void TransferListWidget::copySelectedNames() const @@ -487,7 +487,33 @@ void TransferListWidget::copySelectedNames() const
qApp->clipboard()->setText(torrentNames.join('\n'));
}
void TransferListWidget::copySelectedHashes() const
void TransferListWidget::copySelectedInfohashes(const CopyInfohashPolicy policy) const
{
const auto selectedTorrents = getSelectedTorrents();
QStringList infoHashes;
infoHashes.reserve(selectedTorrents.size());
switch (policy)
{
case CopyInfohashPolicy::Version1:
for (const BitTorrent::Torrent *torrent : selectedTorrents)
{
if (const auto infoHash = torrent->infoHash().v1(); infoHash.isValid())
infoHashes << infoHash.toString();
}
break;
case CopyInfohashPolicy::Version2:
for (const BitTorrent::Torrent *torrent : selectedTorrents)
{
if (const auto infoHash = torrent->infoHash().v2(); infoHash.isValid())
infoHashes << infoHash.toString();
}
break;
}
qApp->clipboard()->setText(infoHashes.join('\n'));
}
void TransferListWidget::copySelectedIDs() const
{
QStringList torrentIDs;
for (BitTorrent::Torrent *const torrent : asConst(getSelectedTorrents()))
@ -827,10 +853,14 @@ void TransferListWidget::displayListMenu(const QPoint &) @@ -827,10 +853,14 @@ void TransferListWidget::displayListMenu(const QPoint &)
connect(actionForceReannounce, &QAction::triggered, this, &TransferListWidget::reannounceSelectedTorrents);
auto *actionCopyMagnetLink = new QAction(UIThemeManager::instance()->getIcon("kt-magnet"), tr("Magnet link"), listMenu);
connect(actionCopyMagnetLink, &QAction::triggered, this, &TransferListWidget::copySelectedMagnetURIs);
auto *actionCopyID = new QAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Torrent ID"), listMenu);
connect(actionCopyID, &QAction::triggered, this, &TransferListWidget::copySelectedIDs);
auto *actionCopyName = new QAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Name"), listMenu);
connect(actionCopyName, &QAction::triggered, this, &TransferListWidget::copySelectedNames);
auto *actionCopyHash = new QAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Hash"), listMenu);
connect(actionCopyHash, &QAction::triggered, this, &TransferListWidget::copySelectedHashes);
auto *actionCopyHash1 = new QAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Info hash v1"), listMenu);
connect(actionCopyHash1, &QAction::triggered, this, [this]() { copySelectedInfohashes(CopyInfohashPolicy::Version1); });
auto *actionCopyHash2 = new QAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Info hash v2"), listMenu);
connect(actionCopyHash2, &QAction::triggered, this, [this]() { copySelectedInfohashes(CopyInfohashPolicy::Version2); });
auto *actionSuperSeedingMode = new TriStateAction(tr("Super seeding mode"), listMenu);
connect(actionSuperSeedingMode, &QAction::triggered, this, &TransferListWidget::setSelectedTorrentsSuperSeeding);
auto *actionRename = new QAction(UIThemeManager::instance()->getIcon("edit-rename"), tr("Rename..."), listMenu);
@ -860,6 +890,7 @@ void TransferListWidget::displayListMenu(const QPoint &) @@ -860,6 +890,7 @@ void TransferListWidget::displayListMenu(const QPoint &)
bool first = true;
TagSet tagsInAny;
TagSet tagsInAll;
bool hasInfohashV1 = false, hasInfohashV2 = false;
for (const QModelIndex &index : selectedIndexes)
{
@ -939,12 +970,18 @@ void TransferListWidget::displayListMenu(const QPoint &) @@ -939,12 +970,18 @@ void TransferListWidget::displayListMenu(const QPoint &)
if (torrent->hasMetadata())
needsPreview = true;
if (!hasInfohashV1 && torrent->infoHash().v1().isValid())
hasInfohashV1 = true;
if (!hasInfohashV2 && torrent->infoHash().v2().isValid())
hasInfohashV2 = true;
first = false;
if (oneHasMetadata && oneNotSeed && !allSameSequentialDownloadMode
&& !allSamePrioFirstlast && !allSameSuperSeeding && !allSameCategory
&& needsStart && needsForce && needsPause && needsPreview && !allSameAutoTMM)
{
&& needsStart && needsForce && needsPause && needsPreview && !allSameAutoTMM
&& hasInfohashV1 && hasInfohashV2)
{
break;
}
}
@ -1084,8 +1121,12 @@ void TransferListWidget::displayListMenu(const QPoint &) @@ -1084,8 +1121,12 @@ void TransferListWidget::displayListMenu(const QPoint &)
QMenu *copySubMenu = listMenu->addMenu(
UIThemeManager::instance()->getIcon("edit-copy"), tr("Copy"));
copySubMenu->addAction(actionCopyName);
copySubMenu->addAction(actionCopyHash);
copySubMenu->addAction(actionCopyHash1);
actionCopyHash1->setEnabled(hasInfohashV1);
copySubMenu->addAction(actionCopyHash2);
actionCopyHash2->setEnabled(hasInfohashV2);
copySubMenu->addAction(actionCopyMagnetLink);
copySubMenu->addAction(actionCopyID);
listMenu->popup(QCursor::pos());
}

26
src/gui/transferlistwidget.h

@ -42,9 +42,16 @@ namespace BitTorrent @@ -42,9 +42,16 @@ namespace BitTorrent
class TorrentID;
}
enum class CopyInfohashPolicy
{
Version1,
Version2
};
class TransferListWidget final : public QTreeView
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TransferListWidget)
public:
TransferListWidget(QWidget *parent, MainWindow *mainWindow);
@ -74,7 +81,8 @@ public slots: @@ -74,7 +81,8 @@ public slots:
void bottomQueuePosSelectedTorrents();
void copySelectedMagnetURIs() const;
void copySelectedNames() const;
void copySelectedHashes() const;
void copySelectedInfohashes(CopyInfohashPolicy policy) const;
void copySelectedIDs() const;
void openSelectedTorrentsFolder() const;
void recheckSelectedTorrents();
void reannounceSelectedTorrents();
@ -91,13 +99,10 @@ public slots: @@ -91,13 +99,10 @@ public slots:
void previewFile(const QString &filePath);
void renameSelectedTorrent();
protected:
QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndex mapFromSource(const QModelIndex &index) const;
bool loadSettings();
QVector<BitTorrent::Torrent *> getSelectedTorrents() const;
signals:
void currentTorrentChanged(BitTorrent::Torrent *const torrent);
protected slots:
private slots:
void torrentDoubleClicked();
void displayListMenu(const QPoint &);
void currentChanged(const QModelIndex &current, const QModelIndex&) override;
@ -108,11 +113,12 @@ protected slots: @@ -108,11 +113,12 @@ protected slots:
void askNewCategoryForSelection();
void saveSettings();
signals:
void currentTorrentChanged(BitTorrent::Torrent *const torrent);
private:
void wheelEvent(QWheelEvent *event) override;
QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndex mapFromSource(const QModelIndex &index) const;
bool loadSettings();
QVector<BitTorrent::Torrent *> getSelectedTorrents() const;
void askAddTagsForSelection();
void editTorrentTrackers();
void confirmRemoveAllTagsForSelection();

5
src/webui/api/serialize/serialize_torrent.cpp

@ -96,8 +96,9 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent) @@ -96,8 +96,9 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
};
return {
// TODO: Add fields for real SHA1 and SHA256 hashes
{KEY_TORRENT_ID, QString(torrent.id().toString())},
{KEY_TORRENT_ID, torrent.id().toString()},
{KEY_TORRENT_INFOHASHV1, torrent.infoHash().v1().toString()},
{KEY_TORRENT_INFOHASHV2, torrent.infoHash().v2().toString()},
{KEY_TORRENT_NAME, torrent.name()},
{KEY_TORRENT_MAGNET_URI, torrent.createMagnetURI()},
{KEY_TORRENT_SIZE, torrent.wantedSize()},

3
src/webui/api/serialize/serialize_torrent.h

@ -36,7 +36,10 @@ namespace BitTorrent @@ -36,7 +36,10 @@ namespace BitTorrent
}
// Torrent keys
// TODO: Rename it to `id`.
inline const char KEY_TORRENT_ID[] = "hash";
inline const char KEY_TORRENT_INFOHASHV1[] = "infohash_v1";
inline const char KEY_TORRENT_INFOHASHV2[] = "infohash_v2";
inline const char KEY_TORRENT_NAME[] = "name";
inline const char KEY_TORRENT_MAGNET_URI[] = "magnet_uri";
inline const char KEY_TORRENT_SIZE[] = "size";

2
src/webui/api/torrentscontroller.cpp

@ -382,6 +382,8 @@ void TorrentsController::propertiesAction() @@ -382,6 +382,8 @@ void TorrentsController::propertiesAction()
QJsonObject dataDict;
dataDict[KEY_TORRENT_INFOHASHV1] = torrent->infoHash().v1().toString();
dataDict[KEY_TORRENT_INFOHASHV2] = torrent->infoHash().v2().toString();
dataDict[KEY_PROP_TIME_ELAPSED] = torrent->activeTime();
dataDict[KEY_PROP_SEEDING_TIME] = torrent->seedingTime();
dataDict[KEY_PROP_ETA] = static_cast<double>(torrent->eta());

4
src/webui/www/private/index.html

@ -166,8 +166,10 @@ @@ -166,8 +166,10 @@
<a href="#" class="arrow-right"><img src="icons/edit-copy.svg" alt="QBT_TR(Copy)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Copy)QBT_TR[CONTEXT=TransferListWidget]</a>
<ul>
<li><a href="#" id="copyName" class="copyToClipboard"><img src="icons/edit-copy.svg" alt="QBT_TR(Name)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Name)QBT_TR[CONTEXT=TransferListWidget]</a></li>
<li><a href="#" id="copyHash" class="copyToClipboard"><img src="icons/edit-copy.svg" alt="QBT_TR(Hash)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Hash)QBT_TR[CONTEXT=TransferListWidget]</a></li>
<li><a href="#" id="copyInfohash1" class="copyToClipboard"><img src="icons/edit-copy.svg" alt="QBT_TR(Info hash v1)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Info hash v1)QBT_TR[CONTEXT=TransferListWidget]</a></li>
<li><a href="#" id="copyInfohash2" class="copyToClipboard"><img src="icons/edit-copy.svg" alt="QBT_TR(Info hash v2)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Info hash v2)QBT_TR[CONTEXT=TransferListWidget]</a></li>
<li><a href="#" id="copyMagnetLink" class="copyToClipboard"><img src="icons/kt-magnet.svg" alt="QBT_TR(Magnet link)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Magnet link)QBT_TR[CONTEXT=TransferListWidget]</a></li>
<li><a href="#" id="copyID" class="copyToClipboard"><img src="icons/edit-copy.svg" alt="QBT_TR(Torrent ID)QBT_TR[CONTEXT=TransferListWidget]" /> QBT_TR(Torrent ID)QBT_TR[CONTEXT=TransferListWidget]</a></li>
</ul>
</li>
</ul>

8
src/webui/www/private/scripts/client.js

@ -1201,10 +1201,14 @@ function setupCopyEventHandler() { @@ -1201,10 +1201,14 @@ function setupCopyEventHandler() {
switch (trigger.id) {
case "copyName":
return copyNameFN();
case "copyInfohash1":
return copyInfohashFN(1);
case "copyInfohash2":
return copyInfohashFN(2);
case "copyMagnetLink":
return copyMagnetLinkFN();
case "copyHash":
return copyHashFN();
case "copyID":
return copyIdFN();
default:
return "";
}

2
src/webui/www/private/scripts/dynamicTable.js

@ -1383,7 +1383,7 @@ window.qBittorrent.DynamicTable = (function() { @@ -1383,7 +1383,7 @@ window.qBittorrent.DynamicTable = (function() {
tr.addClass("torrentsTableContextMenuTarget");
},
getCurrentTorrentHash: function() {
getCurrentTorrentID: function() {
return this.getSelectedRowId();
},

34
src/webui/www/private/scripts/mocha-init.js

@ -84,8 +84,9 @@ let resumeTorrentsByTrackerFN = function() {}; @@ -84,8 +84,9 @@ let resumeTorrentsByTrackerFN = function() {};
let pauseTorrentsByTrackerFN = function() {};
let deleteTorrentsByTrackerFN = function() {};
let copyNameFN = function() {};
let copyInfohashFN = function(policy) {};
let copyMagnetLinkFN = function() {};
let copyHashFN = function() {};
let copyIdFN = function() {};
let setQueuePositionFN = function() {};
const initializeWindows = function() {
@ -905,7 +906,7 @@ const initializeWindows = function() { @@ -905,7 +906,7 @@ const initializeWindows = function() {
copyNameFN = function() {
const selectedRows = torrentsTable.selectedRowsIds();
const names = [];
if (selectedRows.length) {
if (selectedRows.length > 0) {
const rows = torrentsTable.getFilteredAndSortedRows();
for (let i = 0; i < selectedRows.length; ++i) {
const hash = selectedRows[i];
@ -915,10 +916,35 @@ const initializeWindows = function() { @@ -915,10 +916,35 @@ const initializeWindows = function() {
return names.join("\n");
};
copyInfohashFN = function(policy) {
const selectedRows = torrentsTable.selectedRowsIds();
const infohashes = [];
if (selectedRows.length > 0) {
const rows = torrentsTable.getFilteredAndSortedRows();
switch (policy) {
case 1:
for (const id of selectedRows) {
const infohash = rows[id].full_data.infohash_v1;
if (infohash !== "")
infohashes.push(infohash);
}
break;
case 2:
for (const id of selectedRows) {
const infohash = rows[id].full_data.infohash_v2;
if (infohash !== "")
infohashes.push(infohash);
}
break;
}
}
return infohashes.join("\n");
};
copyMagnetLinkFN = function() {
const selectedRows = torrentsTable.selectedRowsIds();
const magnets = [];
if (selectedRows.length) {
if (selectedRows.length > 0) {
const rows = torrentsTable.getFilteredAndSortedRows();
for (let i = 0; i < selectedRows.length; ++i) {
const hash = selectedRows[i];
@ -928,7 +954,7 @@ const initializeWindows = function() { @@ -928,7 +954,7 @@ const initializeWindows = function() {
return magnets.join("\n");
};
copyHashFN = function() {
copyIdFN = function() {
return torrentsTable.selectedRowsIds().join("\n");
};

4
src/webui/www/private/scripts/prop-files.js

@ -343,7 +343,7 @@ window.qBittorrent.PropFiles = (function() { @@ -343,7 +343,7 @@ window.qBittorrent.PropFiles = (function() {
// Tab changed, don't do anything
return;
}
const new_hash = torrentsTable.getCurrentTorrentHash();
const new_hash = torrentsTable.getCurrentTorrentID();
if (new_hash === "") {
torrentFilesTable.clear();
clearTimeout(loadTorrentFilesDataTimer);
@ -527,7 +527,7 @@ window.qBittorrent.PropFiles = (function() { @@ -527,7 +527,7 @@ window.qBittorrent.PropFiles = (function() {
menu: 'torrentFilesMenu',
actions: {
Rename: function(element, ref) {
const hash = torrentsTable.getCurrentTorrentHash();
const hash = torrentsTable.getCurrentTorrentID();
if (!hash) return;
const rowId = torrentFilesTable.selectedRowsIds()[0];
if (rowId === undefined) return;

23
src/webui/www/private/scripts/prop-general.js

@ -61,7 +61,8 @@ window.qBittorrent.PropGeneral = (function() { @@ -61,7 +61,8 @@ window.qBittorrent.PropGeneral = (function() {
$('addition_date').set('html', '');
$('completion_date').set('html', '');
$('creation_date').set('html', '');
$('torrent_hash').set('html', '');
$('torrent_hash_v1').set('html', '');
$('torrent_hash_v2').set('html', '');
$('save_path').set('html', '');
$('comment').set('html', '');
};
@ -73,16 +74,14 @@ window.qBittorrent.PropGeneral = (function() { @@ -73,16 +74,14 @@ window.qBittorrent.PropGeneral = (function() {
// Tab changed, don't do anything
return;
}
const current_hash = torrentsTable.getCurrentTorrentHash();
if (current_hash === "") {
const current_id = torrentsTable.getCurrentTorrentID();
if (current_id === "") {
clearData();
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(5000);
return;
}
// Display hash
$('torrent_hash').set('html', current_hash);
const url = new URI('api/v2/torrents/properties?hash=' + current_hash);
const url = new URI('api/v2/torrents/properties?hash=' + current_id);
new Request.JSON({
url: url,
noCache: true,
@ -191,6 +190,18 @@ window.qBittorrent.PropGeneral = (function() { @@ -191,6 +190,18 @@ window.qBittorrent.PropGeneral = (function() {
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('creation_date').set('html', temp);
if (data.infohash_v1 === "")
temp = "QBT_TR(N/A)QBT_TR[CONTEXT=PropertiesWidget]";
else
temp = data.infohash_v1;
$('torrent_hash_v1').set('html', temp);
if (data.infohash_v2 === "")
temp = "QBT_TR(N/A)QBT_TR[CONTEXT=PropertiesWidget]";
else
temp = data.infohash_v2;
$('torrent_hash_v2').set('html', temp);
$('save_path').set('html', data.save_path);
$('comment').set('html', window.qBittorrent.Misc.parseHtmlLinks(window.qBittorrent.Misc.escapeHtml(data.comment)));

6
src/webui/www/private/scripts/prop-peers.js

@ -51,7 +51,7 @@ window.qBittorrent.PropPeers = (function() { @@ -51,7 +51,7 @@ window.qBittorrent.PropPeers = (function() {
torrentPeersTable.clear();
return;
}
const current_hash = torrentsTable.getCurrentTorrentHash();
const current_hash = torrentsTable.getCurrentTorrentID();
if (current_hash === "") {
syncTorrentPeersLastResponseId = 0;
torrentPeersTable.clear();
@ -118,7 +118,7 @@ window.qBittorrent.PropPeers = (function() { @@ -118,7 +118,7 @@ window.qBittorrent.PropPeers = (function() {
menu: 'torrentPeersMenu',
actions: {
addPeer: function(element, ref) {
const hash = torrentsTable.getCurrentTorrentHash();
const hash = torrentsTable.getCurrentTorrentID();
if (!hash)
return;
@ -147,7 +147,7 @@ window.qBittorrent.PropPeers = (function() { @@ -147,7 +147,7 @@ window.qBittorrent.PropPeers = (function() {
noCache: true,
method: 'post',
data: {
hash: torrentsTable.getCurrentTorrentHash(),
hash: torrentsTable.getCurrentTorrentID(),
peers: selectedPeers.join('|')
}
}).send();

2
src/webui/www/private/scripts/prop-trackers.js

@ -50,7 +50,7 @@ window.qBittorrent.PropTrackers = (function() { @@ -50,7 +50,7 @@ window.qBittorrent.PropTrackers = (function() {
// Tab changed, don't do anything
return;
}
const new_hash = torrentsTable.getCurrentTorrentHash();
const new_hash = torrentsTable.getCurrentTorrentID();
if (new_hash === "") {
torrentTrackersTable.clear();
clearTimeout(loadTrackersDataTimer);

2
src/webui/www/private/scripts/prop-webseeds.js

@ -100,7 +100,7 @@ window.qBittorrent.PropWebseeds = (function() { @@ -100,7 +100,7 @@ window.qBittorrent.PropWebseeds = (function() {
// Tab changed, don't do anything
return;
}
const new_hash = torrentsTable.getCurrentTorrentHash();
const new_hash = torrentsTable.getCurrentTorrentID();
if (new_hash === "") {
wsTable.removeAllRows();
clearTimeout(loadWebSeedsDataTimer);

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

@ -209,7 +209,9 @@ @@ -209,7 +209,9 @@
<li>QBT_TR(%C: Number of files)QBT_TR[CONTEXT=OptionsDialog]</li>
<li>QBT_TR(%Z: Torrent size (bytes))QBT_TR[CONTEXT=OptionsDialog]</li>
<li>QBT_TR(%T: Current tracker)QBT_TR[CONTEXT=OptionsDialog]</li>
<li>QBT_TR(%I: Info hash)QBT_TR[CONTEXT=OptionsDialog]</li>
<li>QBT_TR(%I: Info hash v1)QBT_TR[CONTEXT=OptionsDialog]</li>
<li>QBT_TR(%J: Info hash v2)QBT_TR[CONTEXT=OptionsDialog]</li>
<li>QBT_TR(%K: Torrent ID)QBT_TR[CONTEXT=OptionsDialog]</li>
</ul>
QBT_TR(Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., "%N"))QBT_TR[CONTEXT=OptionsDialog]
</div>

8
src/webui/www/private/views/properties.html

@ -64,8 +64,12 @@ @@ -64,8 +64,12 @@
<td id="creation_date"></td>
</tr>
<tr>
<td class="generalLabel">QBT_TR(Torrent Hash:)QBT_TR[CONTEXT=PropertiesWidget]</td>
<td colspan="5" id="torrent_hash"></td>
<td class="generalLabel">QBT_TR(Info Hash v1:)QBT_TR[CONTEXT=PropertiesWidget]</td>
<td colspan="5" id="torrent_hash_v1"></td>
</tr>
<tr>
<td class="generalLabel">QBT_TR(Info Hash v2:)QBT_TR[CONTEXT=PropertiesWidget]</td>
<td colspan="5" id="torrent_hash_v2"></td>
</tr>
<tr>
<td class="generalLabel">QBT_TR(Save Path:)QBT_TR[CONTEXT=PropertiesWidget]</td>

Loading…
Cancel
Save