fix(proxy): stable image-proxy URLs so expo-image actually caches thumbnails

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 <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-06-09 09:45:22 +02:00
parent 3e8a221981
commit abddd27856
2 changed files with 12 additions and 2 deletions

View file

@ -456,7 +456,9 @@ def _wrap_image_proxy(url: str, referer: str) -> str:
znać sekretu Referer backend wstawi sam. Long TTL (30d) bo thumby znać sekretu Referer backend wstawi sam. Long TTL (30d) bo thumby
stabilne, krótkie ttl by tylko niepotrzebnie zaśmiecało cache.""" stabilne, krótkie ttl by tylko niepotrzebnie zaśmiecało cache."""
from app.api.stream_proxy import make_token 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. # Path zachowuje rozszerzenie żeby HTTP Content-Type był rozpoznany.
import os as _os import os as _os
ext = _os.path.splitext(url.split("?")[0])[1].lstrip(".") or "jpg" ext = _os.path.splitext(url.split("?")[0])[1].lstrip(".") or "jpg"

View file

@ -162,6 +162,7 @@ def make_token(
refresh: str | None = None, refresh: str | None = None,
refresh_hoster: str | None = None, refresh_hoster: str | None = None,
impersonate: bool = False, impersonate: bool = False,
stable_bucket_sec: int | None = None,
) -> str: ) -> str:
"""Build proxy token. """Build proxy token.
@ -171,8 +172,15 @@ def make_token(
dispatch do dedicated re-extract logic. dispatch do dedicated re-extract logic.
`impersonate`: użyć curl_cffi chrome120 zamiast httpx (dla hosterów z JA3 bot `impersonate`: użyć curl_cffi chrome120 zamiast httpx (dla hosterów z JA3 bot
detection mxcontent, cloudflare-protected). 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: if refresh:
payload["rf"] = refresh payload["rf"] = refresh
if refresh_hoster: if refresh_hoster: