Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed empty popular torrents page #8152

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 58 additions & 62 deletions src/tribler/core/database/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class MetadataStore:
Storage of metadata for channels and torrents.
"""

def __init__( # noqa: PLR0913
def __init__(
self,
db_filename: str,
private_key: PrivateKey,
Expand Down Expand Up @@ -530,7 +530,7 @@ def search_keyword(self, query: str, origin_id: int | None = None) -> Query:
return left_join(g for g in self.TorrentMetadata if g.rowid in fts_ids)

@db_session
def get_entries_query( # noqa: C901, PLR0912, PLR0913
def get_entries_query( # noqa: C901, PLR0913
self,
metadata_type: int | None = None,
channel_pk: bytes | None = None,
Expand All @@ -557,26 +557,25 @@ def get_entries_query( # noqa: C901, PLR0912, PLR0913

if txt_filter:
pony_query = self.search_keyword(txt_filter, origin_id=origin_id)
else:
pony_query = left_join(g for g in self.TorrentMetadata)

infohash_set = infohash_set or ({infohash} if infohash else None)
if popular:
elif popular:
if metadata_type != REGULAR_TORRENT:
msg = "With `popular=True`, only `metadata_type=REGULAR_TORRENT` is allowed"
raise TypeError(msg)

t = time() - POPULAR_TORRENTS_FRESHNESS_PERIOD
health_list = list(
select(
health for health in self.TorrentState
return select(
g for g in self.TorrentMetadata
for health in self.TorrentState
if health.has_data == 1 # The condition had to be written this way for the partial index to work
and health.last_check >= t and (health.seeders > 0 or health.leechers > 0)
and g.health == health
).order_by(
lambda health: (desc(health.seeders), desc(health.leechers), desc(health.last_check))
)[:POPULAR_TORRENTS_COUNT]
)
pony_query = pony_query.where(lambda g: g.health in health_list)
lambda g: (desc(g.health.seeders), desc(g.health.leechers), desc(g.health.last_check))
).limit(POPULAR_TORRENTS_COUNT)
else:
pony_query = left_join(g for g in self.TorrentMetadata)

infohash_set = infohash_set or ({infohash} if infohash else None)

if max_rowid is not None:
pony_query = pony_query.where(lambda g: g.rowid <= max_rowid)
Expand Down Expand Up @@ -624,54 +623,51 @@ def get_entries_query( # noqa: C901, PLR0912, PLR0913
sort_expression = raw_sql(f"g.{sort_by} COLLATE NOCASE" + (" DESC" if sort_desc else ""))
pony_query = pony_query.sort_by(sort_expression)

if sort_by is None:
if txt_filter:
"""
The following call of `sort_by` produces an ORDER BY expression that looks like this:

ORDER BY
case when "g"."metadata_type" = $CHANNEL_TORRENT then 1
when "g"."metadata_type" = $COLLECTION_NODE then 2
else 3 end,

search_rank(
$QUERY_STRING,
g.title,
torrentstate.seeders,
torrentstate.leechers,
$CURRENT_TIME - strftime('%s', g.torrent_date)
) DESC,

"torrentstate"."last_check" DESC,

So, the channel torrents and channel folders are always on top if they are not filtered out.
Then regular torrents are selected in order of their relevance according to a search_rank() result.
If two torrents have the same search rank, they are ordered by the last time they were checked.

The search_rank() function is called directly from the SQLite query, but is implemented in Python,
it is actually the torrent_rank() function from core/utilities/search_utils.py, wrapped with
keep_exception() to return possible exception from SQLite to Python.

The search_rank() function receives the following arguments:
- the current query string (like "Big Buck Bunny");
- the title of the current torrent;
- the number of seeders;
- the number of leechers;
- the number of seconds since the torrent's creation time.
"""

pony_query = pony_query.sort_by(
f"""
(1 if g.metadata_type == {CHANNEL_TORRENT} else 2 if g.metadata_type == {COLLECTION_NODE} else 3),
raw_sql('''search_rank(
$txt_filter, g.title, torrentstate.seeders, torrentstate.leechers,
$int(time()) - strftime('%s', g.torrent_date)
) DESC'''),
desc(g.health.last_check) # just to trigger the TorrentState table inclusion into the left join
"""
)
elif popular:
pony_query = pony_query.sort_by('(desc(g.health.seeders), desc(g.health.leechers))')
if sort_by is None and txt_filter:
"""
The following call of `sort_by` produces an ORDER BY expression that looks like this:

ORDER BY
case when "g"."metadata_type" = $CHANNEL_TORRENT then 1
when "g"."metadata_type" = $COLLECTION_NODE then 2
else 3 end,

search_rank(
$QUERY_STRING,
g.title,
torrentstate.seeders,
torrentstate.leechers,
$CURRENT_TIME - strftime('%s', g.torrent_date)
) DESC,

"torrentstate"."last_check" DESC,

So, the channel torrents and channel folders are always on top if they are not filtered out.
Then regular torrents are selected in order of their relevance according to a search_rank() result.
If two torrents have the same search rank, they are ordered by the last time they were checked.

The search_rank() function is called directly from the SQLite query, but is implemented in Python,
it is actually the torrent_rank() function from core/utilities/search_utils.py, wrapped with
keep_exception() to return possible exception from SQLite to Python.

The search_rank() function receives the following arguments:
- the current query string (like "Big Buck Bunny");
- the title of the current torrent;
- the number of seeders;
- the number of leechers;
- the number of seconds since the torrent's creation time.
"""

pony_query = pony_query.sort_by(
f"""
(1 if g.metadata_type == {CHANNEL_TORRENT} else 2 if g.metadata_type == {COLLECTION_NODE} else 3),
raw_sql('''search_rank(
$txt_filter, g.title, torrentstate.seeders, torrentstate.leechers,
$int(time()) - strftime('%s', g.torrent_date)
) DESC'''),
desc(g.health.last_check) # just to trigger the TorrentState table inclusion into the left join
"""
)
Comment on lines +626 to +670
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ruff wanted me to change the if condition, nothing else changed.


return pony_query

Expand Down