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
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
from flask import jsonify, request
|
from flask import jsonify, request
|
||||||
|
|
||||||
from utils.logging_config import get_logger
|
from utils.logging_config import get_logger
|
||||||
|
|
@ -312,13 +314,12 @@ def register_routes(bp):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
items, seen = [], set()
|
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.
|
def consume(batch):
|
||||||
need_fill = hide_owned or bool(prefer_langs)
|
"""Filter a page into `items` (dedup + hide-owned + language). Returns False
|
||||||
target = 24 if need_fill else 0
|
once TMDB hands back an empty page (it ran out — stop paging)."""
|
||||||
max_pages = 8 if need_fill else pages
|
if not batch:
|
||||||
for offset in range(max_pages):
|
return False
|
||||||
batch = fetch(page + offset) or []
|
|
||||||
for it in batch:
|
for it in batch:
|
||||||
dk = (it.get("kind"), it.get("tmdb_id"))
|
dk = (it.get("kind"), it.get("tmdb_id"))
|
||||||
if dk in seen:
|
if dk in seen:
|
||||||
|
|
@ -331,12 +332,30 @@ def register_routes(bp):
|
||||||
if ol and ol not in prefer_langs:
|
if ol and ol not in prefer_langs:
|
||||||
continue # known foreign language not in your preference
|
continue # known foreign language not in your preference
|
||||||
items.append(it)
|
items.append(it)
|
||||||
if key == "trending" or not batch:
|
return True
|
||||||
break # trending is a fixed list; empty batch = TMDB ran out
|
|
||||||
if target and len(items) >= target:
|
# When filtering (hide-owned or language), page DEEPER and drop items server-side
|
||||||
break # enough collected
|
# so a heavy library's rail still fills to ~target instead of showing 4 cards. We
|
||||||
if not target and offset + 1 >= pages:
|
# fetch the extra pages in concurrent WAVES (TTLCache + the TMDB client are
|
||||||
break # no filtering: respect the requested page count
|
# 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})
|
return jsonify({"items": items, "page": page})
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("discover list failed (key=%s)", key)
|
logger.exception("discover list failed (key=%s)", key)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue