video discover: fill rails to ~20 via concurrent deep-paging (no more 4-card rows)
A heavy library with hide-owned on drained the old 8-page sequential fill before a rail filled, leaving rows of 4-7 cards. Now the filtered-fill path pages up to 20 deep in concurrent waves of 5 (TTLCache + TMDB client are thread-safe), stopping as soon as it hits ~20 kept items or TMDB runs out — so digging deep costs ~4 page-latencies instead of 20. Refactored the per-page filter into consume(); trending + the no-filter path are unchanged in behaviour.
This commit is contained in:
parent
4f24ac2733
commit
09a1646a6a
1 changed files with 32 additions and 13 deletions
|
|
@ -14,6 +14,8 @@ video.db; isolated from the music API.
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import concurrent.futures
|
||||
|
||||
from flask import jsonify, request
|
||||
|
||||
from utils.logging_config import get_logger
|
||||
|
|
@ -312,13 +314,12 @@ def register_routes(bp):
|
|||
|
||||
try:
|
||||
items, seen = [], set()
|
||||
# When filtering (hide-owned or language), page DEEPER and drop items server-side
|
||||
# until the rail has ~enough to look full — instead of returning a half-empty rail.
|
||||
need_fill = hide_owned or bool(prefer_langs)
|
||||
target = 24 if need_fill else 0
|
||||
max_pages = 8 if need_fill else pages
|
||||
for offset in range(max_pages):
|
||||
batch = fetch(page + offset) or []
|
||||
|
||||
def consume(batch):
|
||||
"""Filter a page into `items` (dedup + hide-owned + language). Returns False
|
||||
once TMDB hands back an empty page (it ran out — stop paging)."""
|
||||
if not batch:
|
||||
return False
|
||||
for it in batch:
|
||||
dk = (it.get("kind"), it.get("tmdb_id"))
|
||||
if dk in seen:
|
||||
|
|
@ -331,12 +332,30 @@ def register_routes(bp):
|
|||
if ol and ol not in prefer_langs:
|
||||
continue # known foreign language not in your preference
|
||||
items.append(it)
|
||||
if key == "trending" or not batch:
|
||||
break # trending is a fixed list; empty batch = TMDB ran out
|
||||
if target and len(items) >= target:
|
||||
break # enough collected
|
||||
if not target and offset + 1 >= pages:
|
||||
break # no filtering: respect the requested page count
|
||||
return True
|
||||
|
||||
# When filtering (hide-owned or language), page DEEPER and drop items server-side
|
||||
# so a heavy library's rail still fills to ~target instead of showing 4 cards. We
|
||||
# fetch the extra pages in concurrent WAVES (TTLCache + the TMDB client are
|
||||
# thread-safe) so digging 20 pages deep costs ~4 page-latencies, not 20.
|
||||
need_fill = hide_owned or bool(prefer_langs)
|
||||
target = 20 if need_fill else 0
|
||||
if key == "trending":
|
||||
consume(fetch(page))
|
||||
elif not need_fill:
|
||||
for offset in range(pages): # no filtering: respect requested page count
|
||||
if not consume(fetch(page + offset)):
|
||||
break
|
||||
else:
|
||||
MAX_PAGES, WAVE = 20, 5
|
||||
offset, ran_out = 0, False
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=WAVE) as ex:
|
||||
while offset < MAX_PAGES and len(items) < target and not ran_out:
|
||||
batches = list(ex.map(fetch, [page + offset + i for i in range(WAVE)]))
|
||||
for batch in batches:
|
||||
if not consume(batch):
|
||||
ran_out = True # an empty page = TMDB has no more
|
||||
offset += WAVE
|
||||
return jsonify({"items": items, "page": page})
|
||||
except Exception:
|
||||
logger.exception("discover list failed (key=%s)", key)
|
||||
|
|
|
|||
Loading…
Reference in a new issue