From 37f227ae743b4b98bc2f78a7473a6486400cb44f Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Fri, 25 Jun 2021 20:44:23 +0300 Subject: [PATCH] Provide v1 and v2 infohashes in UI (#15097) --- src/app/application.cpp | 6 ++ src/base/bittorrent/infohash.cpp | 18 +++++ src/base/bittorrent/infohash.h | 2 + src/gui/addnewtorrentdialog.cpp | 6 +- src/gui/addnewtorrentdialog.ui | 72 ++++++++++-------- src/gui/optionsdialog.cpp | 6 +- src/gui/properties/propertieswidget.cpp | 9 ++- src/gui/properties/propertieswidget.ui | 74 +++++++++++++------ src/gui/transferlistwidget.cpp | 53 +++++++++++-- src/gui/transferlistwidget.h | 26 ++++--- src/webui/api/serialize/serialize_torrent.cpp | 5 +- src/webui/api/serialize/serialize_torrent.h | 3 + src/webui/api/torrentscontroller.cpp | 2 + src/webui/www/private/index.html | 4 +- src/webui/www/private/scripts/client.js | 8 +- src/webui/www/private/scripts/dynamicTable.js | 2 +- src/webui/www/private/scripts/mocha-init.js | 34 ++++++++- src/webui/www/private/scripts/prop-files.js | 4 +- src/webui/www/private/scripts/prop-general.js | 23 ++++-- src/webui/www/private/scripts/prop-peers.js | 6 +- .../www/private/scripts/prop-trackers.js | 2 +- .../www/private/scripts/prop-webseeds.js | 2 +- src/webui/www/private/views/preferences.html | 4 +- src/webui/www/private/views/properties.html | 8 +- 24 files changed, 279 insertions(+), 100 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index 6e001baa4af..d89a5171922 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -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': diff --git a/src/base/bittorrent/infohash.cpp b/src/base/bittorrent/infohash.cpp index 7651136820c..6fef481487e 100644 --- a/src/base/bittorrent/infohash.cpp +++ b/src/base/bittorrent/infohash.cpp @@ -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) diff --git a/src/base/bittorrent/infohash.h b/src/base/bittorrent/infohash.h index e161dbd1de6..c06844c231d 100644 --- a/src/base/bittorrent/infohash.h +++ b/src/base/bittorrent/infohash.h @@ -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; diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 0cc29346cad..63af9c6be20 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -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) 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; diff --git a/src/gui/addnewtorrentdialog.ui b/src/gui/addnewtorrentdialog.ui index 7c2a20e6c45..64321122a11 100644 --- a/src/gui/addnewtorrentdialog.ui +++ b/src/gui/addnewtorrentdialog.ui @@ -249,10 +249,10 @@ Torrent information - - + + - Date: + Info hash v1: @@ -262,24 +262,7 @@ - - - - Size: - - - - - - - Qt::PlainText - - - Qt::TextSelectableByMouse - - - - + background-color: rgba(0, 0, 0, 0); @@ -295,7 +278,7 @@ 0 0 - 333 + 317 69 @@ -335,20 +318,51 @@ - - + + + + Comment: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + - Hash: + Size: + + + + + + + Qt::PlainText + + + Qt::TextSelectableByMouse + + + + + + + Date: - + - Comment: + Info hash v2 - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 4ed42877fb1..3b989cb25b0 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -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) , 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); diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index 90f1ea7f335..27070bc6bc0 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -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) // 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()) { diff --git a/src/gui/properties/propertieswidget.ui b/src/gui/properties/propertieswidget.ui index 8ca6b278db3..63dee3bc41f 100644 --- a/src/gui/properties/propertieswidget.ui +++ b/src/gui/properties/propertieswidget.ui @@ -11,6 +11,9 @@ + + 0 + 0 @@ -23,9 +26,6 @@ 0 - - 0 - @@ -788,7 +788,7 @@ - + 0 @@ -796,15 +796,31 @@ - Torrent Hash: + Info Hash v1: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + 0 + 0 + + + + Info Hash v2: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 0 @@ -819,7 +835,7 @@ - + @@ -835,8 +851,24 @@ - - + + + + + 0 + 0 + + + + Comment: + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + 0 @@ -846,31 +878,31 @@ Qt::PlainText - - true - Qt::TextSelectableByMouse - - + + - + 0 0 - - Comment: + + Qt::PlainText - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + true + + + Qt::TextSelectableByMouse - + diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index fed58259737..d3300f85224 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -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 &) 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 &) 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 &) 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 &) 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()); } diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index dc5a888bdfd..ef1400e3bf5 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -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: 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: void previewFile(const QString &filePath); void renameSelectedTorrent(); -protected: - QModelIndex mapToSource(const QModelIndex &index) const; - QModelIndex mapFromSource(const QModelIndex &index) const; - bool loadSettings(); - QVector getSelectedTorrents() const; +signals: + void currentTorrentChanged(BitTorrent::Torrent *const torrent); -protected slots: +private slots: void torrentDoubleClicked(); void displayListMenu(const QPoint &); void currentChanged(const QModelIndex ¤t, const QModelIndex&) override; @@ -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 getSelectedTorrents() const; void askAddTagsForSelection(); void editTorrentTrackers(); void confirmRemoveAllTagsForSelection(); diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index c6f138c6af3..3ca112d36e5 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -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()}, diff --git a/src/webui/api/serialize/serialize_torrent.h b/src/webui/api/serialize/serialize_torrent.h index eab6aca90e6..b4eb79d9fc3 100644 --- a/src/webui/api/serialize/serialize_torrent.h +++ b/src/webui/api/serialize/serialize_torrent.h @@ -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"; diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index adbcd8e1bdd..bb5ed148f34 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -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(torrent->eta()); diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index aa01441e5f7..ce4a6269413 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -166,8 +166,10 @@

qBittorrent Web User Interface QBT_TR(Copy)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(Copy)QBT_TR[CONTEXT=TransferListWidget] diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index 4a58f0021fa..c6c7bf038ea 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -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 ""; } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 31bcf62e3fb..98e220f18c5 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1383,7 +1383,7 @@ window.qBittorrent.DynamicTable = (function() { tr.addClass("torrentsTableContextMenuTarget"); }, - getCurrentTorrentHash: function() { + getCurrentTorrentID: function() { return this.getSelectedRowId(); }, diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index e6b093f720a..20398041418 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -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() { 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() { 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() { return magnets.join("\n"); }; - copyHashFN = function() { + copyIdFN = function() { return torrentsTable.selectedRowsIds().join("\n"); }; diff --git a/src/webui/www/private/scripts/prop-files.js b/src/webui/www/private/scripts/prop-files.js index 87577b09658..9b8d67ec9fa 100644 --- a/src/webui/www/private/scripts/prop-files.js +++ b/src/webui/www/private/scripts/prop-files.js @@ -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() { 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; diff --git a/src/webui/www/private/scripts/prop-general.js b/src/webui/www/private/scripts/prop-general.js index e6a8ed8df42..2c77cfab253 100644 --- a/src/webui/www/private/scripts/prop-general.js +++ b/src/webui/www/private/scripts/prop-general.js @@ -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() { // 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() { 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))); diff --git a/src/webui/www/private/scripts/prop-peers.js b/src/webui/www/private/scripts/prop-peers.js index e6f2c9555b6..46ac08e2f5c 100644 --- a/src/webui/www/private/scripts/prop-peers.js +++ b/src/webui/www/private/scripts/prop-peers.js @@ -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() { 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() { noCache: true, method: 'post', data: { - hash: torrentsTable.getCurrentTorrentHash(), + hash: torrentsTable.getCurrentTorrentID(), peers: selectedPeers.join('|') } }).send(); diff --git a/src/webui/www/private/scripts/prop-trackers.js b/src/webui/www/private/scripts/prop-trackers.js index 94847e11cfe..985449c0484 100644 --- a/src/webui/www/private/scripts/prop-trackers.js +++ b/src/webui/www/private/scripts/prop-trackers.js @@ -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); diff --git a/src/webui/www/private/scripts/prop-webseeds.js b/src/webui/www/private/scripts/prop-webseeds.js index 0910a705d25..a5668593380 100644 --- a/src/webui/www/private/scripts/prop-webseeds.js +++ b/src/webui/www/private/scripts/prop-webseeds.js @@ -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); diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 319cd08a670..56dadeb2435 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -209,7 +209,9 @@
  • QBT_TR(%C: Number of files)QBT_TR[CONTEXT=OptionsDialog]
  • QBT_TR(%Z: Torrent size (bytes))QBT_TR[CONTEXT=OptionsDialog]
  • QBT_TR(%T: Current tracker)QBT_TR[CONTEXT=OptionsDialog]
  • -
  • QBT_TR(%I: Info hash)QBT_TR[CONTEXT=OptionsDialog]
  • +
  • QBT_TR(%I: Info hash v1)QBT_TR[CONTEXT=OptionsDialog]
  • +
  • QBT_TR(%J: Info hash v2)QBT_TR[CONTEXT=OptionsDialog]
  • +
  • QBT_TR(%K: Torrent ID)QBT_TR[CONTEXT=OptionsDialog]
  • QBT_TR(Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., "%N"))QBT_TR[CONTEXT=OptionsDialog] diff --git a/src/webui/www/private/views/properties.html b/src/webui/www/private/views/properties.html index 771a26b3aa7..cc0b5a56007 100644 --- a/src/webui/www/private/views/properties.html +++ b/src/webui/www/private/views/properties.html @@ -64,8 +64,12 @@ - QBT_TR(Torrent Hash:)QBT_TR[CONTEXT=PropertiesWidget] - + QBT_TR(Info Hash v1:)QBT_TR[CONTEXT=PropertiesWidget] + + + + QBT_TR(Info Hash v2:)QBT_TR[CONTEXT=PropertiesWidget] + QBT_TR(Save Path:)QBT_TR[CONTEXT=PropertiesWidget]