diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index 644af158b..f3b62c1c9 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -282,6 +282,7 @@ namespace BitTorrent virtual int maxInactiveSeedingTime() const = 0; virtual qreal realRatio() const = 0; virtual qreal popularity() const = 0; + virtual qreal importance() const = 0; virtual int uploadPayloadRate() const = 0; virtual int downloadPayloadRate() const = 0; virtual qlonglong totalPayloadUpload() const = 0; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index c3a7c0f2b..a1ecb010b 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1572,6 +1572,25 @@ qreal TorrentImpl::popularity() const return (activeMonths > 0) ? (realRatio() / activeMonths) : 0; } +qreal TorrentImpl::importance() const +{ + // Popularity divided by seed count is a much better measure of how important you are as a seed for a torrent than popularity alone + const qreal pop = popularity(); + const int seeds = totalSeedsCount(); + + if (seeds > 0) + { + return pop / seeds; + } + + if (pop > 0) + { + return Torrent::MAX_RATIO; + } + + return 0.0; +} + void TorrentImpl::setName(const QString &name) { if (m_name != name) diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 2c1f9af77..e99554f2d 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -209,6 +209,7 @@ namespace BitTorrent int maxInactiveSeedingTime() const override; qreal realRatio() const override; qreal popularity() const override; + qreal importance() const override; int uploadPayloadRate() const override; int downloadPayloadRate() const override; qlonglong totalPayloadUpload() const override; diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index d86f5a074..a2128fa68 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -227,6 +227,7 @@ void PropertiesWidget::clear() m_ui->labelReannounceInVal->clear(); m_ui->labelShareRatioVal->clear(); m_ui->labelPopularityVal->clear(); + m_ui->labelImportanceVal->clear(); m_ui->listWebSeeds->clear(); m_ui->labelETAVal->clear(); m_ui->labelSeedsVal->clear(); @@ -446,6 +447,9 @@ void PropertiesWidget::loadDynamicData() const qreal popularity = m_torrent->popularity(); m_ui->labelPopularityVal->setText(popularity >= BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(popularity, 2)); + const qreal importance = m_torrent->importance(); + m_ui->labelImportanceVal->setText(importance >= BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(importance, 2)); + m_ui->labelSeedsVal->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)") .arg(QString::number(m_torrent->seedsCount()) , QString::number(m_torrent->totalSeedsCount()))); diff --git a/src/gui/properties/propertieswidget.ui b/src/gui/properties/propertieswidget.ui index dd21f6fef..574d256f0 100644 --- a/src/gui/properties/propertieswidget.ui +++ b/src/gui/properties/propertieswidget.ui @@ -633,6 +633,41 @@ + + + + + 0 + 0 + + + + Popularity / Total Seeds, shows how important the specific seeder is. + + + Importance: + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + 0 + 0 + + + + Popularity / Total Seeds, shows how important the specific seeder is. + + + Qt::TextFormat::PlainText + + + diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 0298db047..d3ed311fe 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -168,6 +168,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed"); case TR_RATIO: return tr("Ratio", "Share ratio"); case TR_POPULARITY: return tr("Popularity"); + case TR_IMPORTANCE: return tr("Importance"); case TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left"); case TR_CATEGORY: return tr("Category"); case TR_TAGS: return tr("Tags"); @@ -202,6 +203,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation switch (section) { case TR_POPULARITY: return tr("Ratio / Time Active (in months), indicates how popular the torrent is"); + case TR_IMPORTANCE: return tr("Popularity / Total Seeds, shows how important the specific seeder is."); default: return {}; } } @@ -227,6 +229,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_RATIO_LIMIT: case TR_RATIO: case TR_POPULARITY: + case TR_IMPORTANCE: case TR_QUEUE_POSITION: case TR_LAST_ACTIVITY: case TR_AVAILABILITY: @@ -395,6 +398,8 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons return ratioString(torrent->maxRatio()); case TR_POPULARITY: return ratioString(torrent->popularity()); + case TR_IMPORTANCE: + return ratioString(torrent->importance()); case TR_CATEGORY: return torrent->category(); case TR_TAGS: @@ -476,6 +481,8 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co return torrent->realRatio(); case TR_POPULARITY: return torrent->popularity(); + case TR_IMPORTANCE: + return torrent->importance(); case TR_CATEGORY: return torrent->category(); case TR_TAGS: @@ -588,6 +595,7 @@ QVariant TransferListModel::data(const QModelIndex &index, const int role) const case TR_RATIO_LIMIT: case TR_RATIO: case TR_POPULARITY: + case TR_IMPORTANCE: case TR_QUEUE_POSITION: case TR_LAST_ACTIVITY: case TR_AVAILABILITY: diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h index 306beee0b..d3f744244 100644 --- a/src/gui/transferlistmodel.h +++ b/src/gui/transferlistmodel.h @@ -63,6 +63,7 @@ public: TR_ETA, TR_RATIO, TR_POPULARITY, + TR_IMPORTANCE, TR_CATEGORY, TR_TAGS, TR_ADD_DATE, diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 782aead74..2ed0e8eaf 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -210,6 +210,9 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r case TransferListModel::TR_POPULARITY: return customCompare(leftValue.toReal(), rightValue.toReal()); + case TransferListModel::TR_IMPORTANCE: + return customCompare(leftValue.toReal(), rightValue.toReal()); + case TransferListModel::TR_STATUS: return threeWayCompare(leftValue.toInt(), rightValue.toInt()); diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 6fb71bfaa..d3f8c3a25 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -187,6 +187,7 @@ TransferListWidget::TransferListWidget(IGUIApplication *app, QWidget *parent) setColumnHidden(TransferListModel::TR_COMPLETED, true); setColumnHidden(TransferListModel::TR_RATIO_LIMIT, true); setColumnHidden(TransferListModel::TR_POPULARITY, true); + setColumnHidden(TransferListModel::TR_IMPORTANCE, true); setColumnHidden(TransferListModel::TR_SEEN_COMPLETE_DATE, true); setColumnHidden(TransferListModel::TR_LAST_ACTIVITY, true); setColumnHidden(TransferListModel::TR_TOTAL_SIZE, true); diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index 94c83a934..4f67ad5d4 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -169,6 +169,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent) {KEY_TORRENT_RATIO, adjustRatio(torrent.realRatio())}, {KEY_TORRENT_RATIO_LIMIT, torrent.ratioLimit()}, {KEY_TORRENT_POPULARITY, torrent.popularity()}, + {KEY_TORRENT_IMPORTANCE, adjustRatio(torrent.importance())}, {KEY_TORRENT_SEEDING_TIME_LIMIT, torrent.seedingTimeLimit()}, {KEY_TORRENT_INACTIVE_SEEDING_TIME_LIMIT, torrent.inactiveSeedingTimeLimit()}, {KEY_TORRENT_LAST_SEEN_COMPLETE_TIME, Utils::DateTime::toSecsSinceEpoch(torrent.lastSeenComplete())}, diff --git a/src/webui/api/serialize/serialize_torrent.h b/src/webui/api/serialize/serialize_torrent.h index 438960e7f..2b34c6fda 100644 --- a/src/webui/api/serialize/serialize_torrent.h +++ b/src/webui/api/serialize/serialize_torrent.h @@ -55,6 +55,7 @@ inline const QString KEY_TORRENT_LEECHS = u"num_leechs"_s; inline const QString KEY_TORRENT_NUM_INCOMPLETE = u"num_incomplete"_s; inline const QString KEY_TORRENT_RATIO = u"ratio"_s; inline const QString KEY_TORRENT_POPULARITY = u"popularity"_s; +inline const QString KEY_TORRENT_IMPORTANCE = u"importance"_s; inline const QString KEY_TORRENT_ETA = u"eta"_s; inline const QString KEY_TORRENT_STATE = u"state"_s; inline const QString KEY_TORRENT_SEQUENTIAL_DOWNLOAD = u"seq_dl"_s; diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 9e9a4ebf6..662e823c3 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -102,6 +102,7 @@ const QString KEY_PROP_PEERS = u"peers"_s; const QString KEY_PROP_PEERS_TOTAL = u"peers_total"_s; const QString KEY_PROP_RATIO = u"share_ratio"_s; const QString KEY_PROP_POPULARITY = u"popularity"_s; +const QString KEY_PROP_IMPORTANCE = u"importance"_s; const QString KEY_PROP_REANNOUNCE = u"reannounce"_s; const QString KEY_PROP_TOTAL_SIZE = u"total_size"_s; const QString KEY_PROP_PIECES_NUM = u"pieces_num"_s; @@ -637,6 +638,7 @@ void TorrentsController::infoAction() // - "peers_total": Torrent total number of peers // - "share_ratio": Torrent share ratio // - "popularity": Torrent popularity +// - "importance": Torrent importance // - "reannounce": Torrent next reannounce time // - "total_size": Torrent total size // - "pieces_num": Torrent pieces count @@ -672,6 +674,7 @@ void TorrentsController::propertiesAction() const int uploadLimit = torrent->uploadLimit(); const qreal ratio = torrent->realRatio(); const qreal popularity = torrent->popularity(); + const qreal importance = torrent->importance(); const bool hasMetadata = torrent->hasMetadata(); const bool isPrivate = torrent->isPrivate(); @@ -703,6 +706,7 @@ void TorrentsController::propertiesAction() {KEY_PROP_PEERS_TOTAL, torrent->totalLeechersCount()}, {KEY_PROP_RATIO, ((ratio >= BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)}, {KEY_PROP_POPULARITY, ((popularity >= BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)}, + {KEY_PROP_IMPORTANCE, ((importance >= BitTorrent::Torrent::MAX_RATIO) ? -1 : importance)}, {KEY_PROP_REANNOUNCE, torrent->nextAnnounce()}, {KEY_PROP_TOTAL_SIZE, torrent->totalSize()}, {KEY_PROP_PIECES_NUM, torrent->piecesCount()}, diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 032a79a1e..dbdf8a0c8 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1116,6 +1116,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("eta", "", "QBT_TR(ETA)QBT_TR[CONTEXT=TransferListModel]", 100, true); this.newColumn("ratio", "", "QBT_TR(Ratio)QBT_TR[CONTEXT=TransferListModel]", 100, true); this.newColumn("popularity", "", "QBT_TR(Popularity)QBT_TR[CONTEXT=TransferListModel]", 100, true); + this.newColumn("importance", "", "QBT_TR(Importance)QBT_TR[CONTEXT=TransferListModel]", 100, true); this.newColumn("category", "", "QBT_TR(Category)QBT_TR[CONTEXT=TransferListModel]", 100, true); this.newColumn("tags", "", "QBT_TR(Tags)QBT_TR[CONTEXT=TransferListModel]", 100, true); this.newColumn("added_on", "", "QBT_TR(Added On)QBT_TR[CONTEXT=TransferListModel]", 100, true); @@ -1419,6 +1420,14 @@ window.qBittorrent.DynamicTable ??= (() => { td.title = popularity; }; + // importance + this.columns["importance"].updateId = function(td, row) { + const value = this.getRowValue(row); + const importance = (value === -1) ? "∞" : window.qBittorrent.Misc.toFixedPointString(value, 2); + td.textContent = importance; + td.title = importance; + }; + // added on this.columns["added_on"].updateTd = function(td, row) { const date = new Date(this.getRowValue(row) * 1000).toLocaleString(); diff --git a/src/webui/www/private/scripts/prop-general.js b/src/webui/www/private/scripts/prop-general.js index fce3c84a6..5bf45f8be 100644 --- a/src/webui/www/private/scripts/prop-general.js +++ b/src/webui/www/private/scripts/prop-general.js @@ -58,6 +58,7 @@ window.qBittorrent.PropGeneral ??= (() => { document.getElementById("peers").textContent = ""; document.getElementById("share_ratio").textContent = ""; document.getElementById("popularity").textContent = ""; + document.getElementById("importance").textContent = ""; document.getElementById("reannounce").textContent = ""; document.getElementById("last_seen").textContent = ""; document.getElementById("total_size").textContent = ""; @@ -174,6 +175,8 @@ window.qBittorrent.PropGeneral ??= (() => { document.getElementById("popularity").textContent = data.popularity.toFixed(2); + document.getElementById("importance").textContent = (data.importance === -1) ? "∞" : data.importance.toFixed(2); + document.getElementById("reannounce").textContent = window.qBittorrent.Misc.friendlyDuration(data.reannounce); const lastSeen = (data.last_seen >= 0) diff --git a/src/webui/www/private/views/properties.html b/src/webui/www/private/views/properties.html index fbcaa1d53..e4b30f3a7 100644 --- a/src/webui/www/private/views/properties.html +++ b/src/webui/www/private/views/properties.html @@ -52,6 +52,9 @@ QBT_TR(Popularity:)QBT_TR[CONTEXT=PropertiesWidget] + + QBT_TR(Importance:)QBT_TR[CONTEXT=PropertiesWidget] +