Direct googlevideo URLs are bound to the extractor's IP and expire, so the
browser fetching them from a different IP got intermittent 403s on playback.
Route playback through a same-origin /api/play proxy that fetches the stream
server-side (matching the extractor IP) with yt-dlp's own http_headers and
forwards Range headers for seeking; fall back to piping yt-dlp for SABR/itag-18
formats a plain GET can't fetch. Prefer adaptive streams over progressive in
the playback fallback order.
Server stamps a BUILD_TAG (stable per process, changes on restart/deploy)
into GET /api/version alongside the existing version string. Cache-Control
is set to no-store so the response is never cached by the SW or browser.
Client (WEB mode only) baselines the tag on first fetch after boot, then
rechecks every 5 minutes. On mismatch it calls the existing showUpdateBanner()
so the user sees the 'Update ready — Reload now' toast and can reload at will.
This mirrors the build-id polling pattern used across the BukidBountyApp
derivatives to avoid stale UI after deploys.