Add the Popularity metric

PR #20180.
This commit is contained in:
Aliaksei Urbanski 2024-04-01 21:23:08 +03:00 committed by GitHub
parent 8e6515be2c
commit f37d0c486c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 93 additions and 0 deletions

View file

@ -282,6 +282,7 @@ namespace BitTorrent
virtual int maxSeedingTime() const = 0;
virtual int maxInactiveSeedingTime() const = 0;
virtual qreal realRatio() const = 0;
virtual qreal popularity() const = 0;
virtual int uploadPayloadRate() const = 0;
virtual int downloadPayloadRate() const = 0;
virtual qlonglong totalPayloadUpload() const = 0;

View file

@ -1545,6 +1545,15 @@ qlonglong TorrentImpl::nextAnnounce() const
return lt::total_seconds(m_nativeStatus.next_announce);
}
qreal TorrentImpl::popularity() const
{
// in order to produce floating-point numbers using `std::chrono::duration_cast`,
// we should use `qreal` as `Rep` to define the `months` duration
using months = std::chrono::duration<qreal, std::chrono::months::period>;
const auto activeMonths = std::chrono::duration_cast<months>(m_nativeStatus.active_duration).count();
return (activeMonths > 0) ? (realRatio() / activeMonths) : 0;
}
void TorrentImpl::setName(const QString &name)
{
if (m_name != name)

View file

@ -210,6 +210,7 @@ namespace BitTorrent
int maxSeedingTime() const override;
int maxInactiveSeedingTime() const override;
qreal realRatio() const override;
qreal popularity() const override;
int uploadPayloadRate() const override;
int downloadPayloadRate() const override;
qlonglong totalPayloadUpload() const override;

View file

@ -220,6 +220,7 @@ void PropertiesWidget::clear()
m_ui->labelConnectionsVal->clear();
m_ui->labelReannounceInVal->clear();
m_ui->labelShareRatioVal->clear();
m_ui->labelPopularityVal->clear();
m_ui->listWebSeeds->clear();
m_ui->labelETAVal->clear();
m_ui->labelSeedsVal->clear();
@ -407,6 +408,9 @@ void PropertiesWidget::loadDynamicData()
const qreal ratio = m_torrent->realRatio();
m_ui->labelShareRatioVal->setText(ratio > BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(ratio, 2));
const qreal popularity = m_torrent->popularity();
m_ui->labelPopularityVal->setText(popularity > BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(popularity, 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())));

View file

@ -295,6 +295,25 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelPopularity">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Ratio / Time Active (in months), indicates how popular the torrent is</string>
</property>
<property name="text">
<string>Popularity:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="labelConnectionsVal">
<property name="sizePolicy">
@ -495,6 +514,22 @@
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="labelPopularityVal">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Ratio / Time Active (in months), indicates how popular the torrent is</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="labelUploaded">
<property name="sizePolicy">

View file

@ -167,6 +167,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation
case TR_DLSPEED: return tr("Down Speed", "i.e: Download speed");
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_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left");
case TR_CATEGORY: return tr("Category");
case TR_TAGS: return tr("Tags");
@ -195,6 +196,14 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation
default: return {};
}
}
else if (role == Qt::ToolTipRole)
{
switch (section)
{
case TR_POPULARITY: return tr("Ratio / Time Active (in months), indicates how popular the torrent is");
default: return {};
}
}
else if (role == Qt::TextAlignmentRole)
{
switch (section)
@ -216,6 +225,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation
case TR_DLLIMIT:
case TR_RATIO_LIMIT:
case TR_RATIO:
case TR_POPULARITY:
case TR_QUEUE_POSITION:
case TR_LAST_ACTIVITY:
case TR_AVAILABILITY:
@ -373,6 +383,8 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons
return ratioString(torrent->realRatio());
case TR_RATIO_LIMIT:
return ratioString(torrent->maxRatio());
case TR_POPULARITY:
return ratioString(torrent->popularity());
case TR_CATEGORY:
return torrent->category();
case TR_TAGS:
@ -450,6 +462,8 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co
return torrent->eta();
case TR_RATIO:
return torrent->realRatio();
case TR_POPULARITY:
return torrent->popularity();
case TR_CATEGORY:
return torrent->category();
case TR_TAGS:
@ -559,6 +573,7 @@ QVariant TransferListModel::data(const QModelIndex &index, const int role) const
case TR_DLLIMIT:
case TR_RATIO_LIMIT:
case TR_RATIO:
case TR_POPULARITY:
case TR_QUEUE_POSITION:
case TR_LAST_ACTIVITY:
case TR_AVAILABILITY:

View file

@ -62,6 +62,7 @@ public:
TR_UPSPEED,
TR_ETA,
TR_RATIO,
TR_POPULARITY,
TR_CATEGORY,
TR_TAGS,
TR_ADD_DATE,

View file

@ -196,6 +196,7 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r
case TransferListModel::TR_PROGRESS:
case TransferListModel::TR_RATIO:
case TransferListModel::TR_RATIO_LIMIT:
case TransferListModel::TR_POPULARITY:
return customCompare(leftValue.toReal(), rightValue.toReal());
case TransferListModel::TR_STATUS:

View file

@ -178,6 +178,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *mainWindow)
setColumnHidden(TransferListModel::TR_INFOHASH_V2, true);
setColumnHidden(TransferListModel::TR_COMPLETED, true);
setColumnHidden(TransferListModel::TR_RATIO_LIMIT, true);
setColumnHidden(TransferListModel::TR_POPULARITY, true);
setColumnHidden(TransferListModel::TR_SEEN_COMPLETE_DATE, true);
setColumnHidden(TransferListModel::TR_LAST_ACTIVITY, true);
setColumnHidden(TransferListModel::TR_TOTAL_SIZE, true);
@ -696,6 +697,7 @@ void TransferListWidget::displayColumnHeaderMenu()
continue;
const auto columnName = m_listModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
const QVariant columnToolTip = m_listModel->headerData(i, Qt::Horizontal, Qt::ToolTipRole);
QAction *action = menu->addAction(columnName, this, [this, i](const bool checked)
{
if (!checked && (visibleColumnsCount() <= 1))
@ -710,6 +712,8 @@ void TransferListWidget::displayColumnHeaderMenu()
});
action->setCheckable(true);
action->setChecked(!isColumnHidden(i));
if (!columnToolTip.isNull())
action->setToolTip(columnToolTip.toString());
}
menu->addSeparator();

View file

@ -152,6 +152,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
{KEY_TORRENT_MAX_INACTIVE_SEEDING_TIME, torrent.maxInactiveSeedingTime()},
{KEY_TORRENT_RATIO, adjustRatio(torrent.realRatio())},
{KEY_TORRENT_RATIO_LIMIT, torrent.ratioLimit()},
{KEY_TORRENT_POPULARITY, torrent.popularity()},
{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())},

View file

@ -54,6 +54,7 @@ inline const QString KEY_TORRENT_NUM_COMPLETE = u"num_complete"_s;
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_ETA = u"eta"_s;
inline const QString KEY_TORRENT_STATE = u"state"_s;
inline const QString KEY_TORRENT_SEQUENTIAL_DOWNLOAD = u"seq_dl"_s;

View file

@ -97,6 +97,7 @@ const QString KEY_PROP_SEEDS_TOTAL = u"seeds_total"_s;
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_REANNOUNCE = u"reannounce"_s;
const QString KEY_PROP_TOTAL_SIZE = u"total_size"_s;
const QString KEY_PROP_PIECES_NUM = u"pieces_num"_s;
@ -398,6 +399,7 @@ void TorrentsController::infoAction()
// - "peers": Torrent connected peers
// - "peers_total": Torrent total number of peers
// - "share_ratio": Torrent share ratio
// - "popularity": Torrent popularity
// - "reannounce": Torrent next reannounce time
// - "total_size": Torrent total size
// - "pieces_num": Torrent pieces count
@ -432,6 +434,7 @@ void TorrentsController::propertiesAction()
const int downloadLimit = torrent->downloadLimit();
const int uploadLimit = torrent->uploadLimit();
const qreal ratio = torrent->realRatio();
const qreal popularity = torrent->popularity();
const QJsonObject ret
{
@ -460,6 +463,7 @@ void TorrentsController::propertiesAction()
{KEY_PROP_PEERS, torrent->leechsCount()},
{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_REANNOUNCE, torrent->nextAnnounce()},
{KEY_PROP_TOTAL_SIZE, torrent->totalSize()},
{KEY_PROP_PIECES_NUM, torrent->piecesCount()},

View file

@ -926,6 +926,7 @@ window.qBittorrent.DynamicTable = (function() {
this.newColumn('upspeed', '', 'QBT_TR(Up Speed)QBT_TR[CONTEXT=TransferListModel]', 100, true);
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('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);
@ -1228,6 +1229,14 @@ window.qBittorrent.DynamicTable = (function() {
td.set('title', string);
};
// popularity
this.columns['popularity'].updateTd = function(td, row) {
const value = this.getRowValue(row);
const popularity = (value === -1) ? '∞' : window.qBittorrent.Misc.toFixedPointString(value, 2);
td.set('text', popularity);
td.set('title', popularity);
};
// added on
this.columns['added_on'].updateTd = function(td, row) {
const date = new Date(this.getRowValue(row) * 1000).toLocaleString();

View file

@ -58,6 +58,7 @@ window.qBittorrent.PropGeneral = (function() {
$('seeds').set('html', '');
$('peers').set('html', '');
$('share_ratio').set('html', '');
$('popularity').set('html', '');
$('reannounce').set('html', '');
$('last_seen').set('html', '');
$('total_size').set('html', '');
@ -160,6 +161,8 @@ window.qBittorrent.PropGeneral = (function() {
$('share_ratio').set('html', data.share_ratio.toFixed(2));
$('popularity').set('html', data.popularity.toFixed(2));
$('reannounce').set('html', window.qBittorrent.Misc.friendlyDuration(data.reannounce));
const lastSeen = (data.last_seen >= 0)

View file

@ -49,6 +49,10 @@
<td class="generalLabel">QBT_TR(Last Seen Complete:)QBT_TR[CONTEXT=PropertiesWidget]</td>
<td id="last_seen"></td>
</tr>
<tr>
<td class="generalLabel" title="QBT_TR(Ratio / Time Active (in months), indicates how popular the torrent is)QBT_TR[CONTEXT=PropertiesWidget]">QBT_TR(Popularity:)QBT_TR[CONTEXT=PropertiesWidget]</td>
<td id="popularity" title="QBT_TR(Ratio / Time Active (in months), indicates how popular the torrent is)QBT_TR[CONTEXT=PropertiesWidget]"></td>
</tr>
</table>
</fieldset>
<fieldset>