From abddd278567e476c954c495fe0a3d9d46840186f Mon Sep 17 00:00:00 2001 From: jtrzupek Date: Tue, 9 Jun 2026 09:45:22 +0200 Subject: [PATCH] fix(proxy): stable image-proxy URLs so expo-image actually caches thumbnails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make_token embedded the current timestamp in the expiry, so every /scenes fetch produced a DIFFERENT proxied URL for the same thumbnail → expo-image (keyed by URI) cache-missed and re-downloaded every list load / app launch. Add stable_bucket_sec: quantize the expiry base to a window so the URL is identical across requests. _wrap_image_proxy uses a 7-day bucket → thumbnails disk-cache for a week instead of re-fetching constantly. Answers "czy miniatury są cache'owane" — now yes. Co-Authored-By: Claude Opus 4.8 --- app/api/scenes.py | 4 +++- app/api/stream_proxy.py | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/api/scenes.py b/app/api/scenes.py index 67670f5..45da51d 100644 --- a/app/api/scenes.py +++ b/app/api/scenes.py @@ -456,7 +456,9 @@ def _wrap_image_proxy(url: str, referer: str) -> str: znać sekretu Referer — backend wstawi sam. Long TTL (30d) bo thumby są stabilne, krótkie ttl by tylko niepotrzebnie zaśmiecało cache.""" from app.api.stream_proxy import make_token - token = make_token(url, referer, ttl_sec=30 * 24 * 3600) + # stable_bucket_sec=7d → proxied URL identyczny przez tydzień → expo-image + # disk-cache hit zamiast re-download miniatur przy każdym fetchu listy / starcie apki. + token = make_token(url, referer, ttl_sec=30 * 24 * 3600, stable_bucket_sec=7 * 24 * 3600) # Path zachowuje rozszerzenie żeby HTTP Content-Type był rozpoznany. import os as _os ext = _os.path.splitext(url.split("?")[0])[1].lstrip(".") or "jpg" diff --git a/app/api/stream_proxy.py b/app/api/stream_proxy.py index 28b4519..5c56279 100644 --- a/app/api/stream_proxy.py +++ b/app/api/stream_proxy.py @@ -162,6 +162,7 @@ def make_token( refresh: str | None = None, refresh_hoster: str | None = None, impersonate: bool = False, + stable_bucket_sec: int | None = None, ) -> str: """Build proxy token. @@ -171,8 +172,15 @@ def make_token( dispatch do dedicated re-extract logic. `impersonate`: użyć curl_cffi chrome120 zamiast httpx (dla hosterów z JA3 bot detection — mxcontent, cloudflare-protected). + `stable_bucket_sec`: kwantyzuje czas bazowy expiry do okna N sekund, więc token + (→ proxied URL) jest IDENTYCZNY dla wszystkich requestów w oknie. Bez tego `e` + zawiera bieżący timestamp → URL inny przy każdym fetchu listy → expo-image cache + miss → re-download miniatur za każdym razem. Dla thumbów (stabilne) dajemy 7d bucket + → URL stały przez tydzień → disk-cache hit. exp = bucket_start + ttl (zawsze > now). """ - payload: dict = {"u": url, "r": referer or "", "e": int(time.time()) + ttl_sec} + now = int(time.time()) + base = (now // stable_bucket_sec) * stable_bucket_sec if stable_bucket_sec else now + payload: dict = {"u": url, "r": referer or "", "e": base + ttl_sec} if refresh: payload["rf"] = refresh if refresh_hoster: