SAUTV WEB 1.0.0
2026-10-13

RUN THE BUNDLED EDITION
Install Node.js 22 or newer. Extract the entire web ZIP into one folder.
Windows: run Start-SAUTV.cmd. Other systems: run node start.mjs in that folder.
Open http://127.0.0.1:4173/ in a current browser. Keep the server running while
watching. Ctrl+C stops it. This is a local browser application, not a published
public website. No provider account or channels are bundled.

BUILD FROM SOURCE
npm ci
npm run build
npm start
The build uses pinned hls.js and esbuild versions. Runtime files have no CDN
dependency and the bundled Node server needs no npm packages after building.
Run npm test for the local backend and updater regression suite. After building,
run npm run test:browser and npm run test:ota-browser for isolated Chromium
fixtures. The complete gate is node --test --test-concurrency=1 tests/*.test.mjs.
Browser tests require
Playwright, Chrome and the local video fixture; SAUTV_PLAYWRIGHT, SAUTV_CHROME
and SAUTV_TEST_MEDIA can select their paths. Both suites use local fixtures and
do not contact a provider. Provider verification is a separate, serialized run.
The regression suite covers 28 backend, 35 updater, 16 browser and 7 OTA browser
tests. SAUTV_TEST_BUNDLE and SAUTV_BROWSER_EVIDENCE select an isolated candidate
bundle and browser evidence directory; SAUTV_OTA_EVIDENCE selects updater evidence.
Earlier first-candidate real
live/movie/episode decoded-frame checks, pause/resume, a bounded browser download
and a 206 byte-range sample also passed. See VALIDATION.txt for exact coverage,
environment and limits. These samples do not certify every provider title/codec.

AUTOMATIC UPDATES
Use Start-SAUTV.cmd / node start.mjs to enable the local updater. The launcher
checks at startup, and browser startup also requests a bounded check. Settings
has Check for updates. Offline, unavailable or invalid feeds leave the app usable.
The production feed is:
https://sautv-downloads.mss.sa/sautv-update.json

Only the signed stable release envelope is trusted: RSA 3072 / RS256, key ID
sautv-ota-2026-a. A newer internal build must pass the persisted sequence floor,
exact ZIP size and SHA256 checks, safe extraction, and bundled identity checks.
The visible version is 1.0.0. Build 15 uses the R2 download host exclusively.
Artifact URLs must match the signed version/build and fixed platform filename;
redirects cannot change the canonical path or origin. RSA trust is unchanged.
Builds 11–14 pin the old distribution URLs and need one manual upgrade: stop the
gateway, extract the complete build15 bundle into the same folder, then restart.
Keep the same local port/browser origin to retain favorites, history and settings.
Provider sign-in is in-memory and is requested again after a manual restart.
Original signed build14 artifacts are unchanged. No GitHub migration bridge is used.
Partial transfers restart safely. Updates never use provider request headers.

The stable bootstrap keeps .sautv-updates beside start.mjs, outside individual
release folders. It retains the active and previous signed archives, cleans only
its own obsolete staging names, and recovers the previous build if the new one
cannot start. Keep the whole extracted folder writable and together. If the
updater folder cannot be used, the bundled application still opens.

The listening address and in-memory sessions stay alive during a local update.
Playback (including manual pauses), open dialogs, typed sign-in details and
active requests/downloads defer the safe handoff. Browser preferences, favorites,
history and current browsing view are retained. New assets revalidate together.
The next server launch loads the verified updated launcher and gateway as well.
No account credentials are saved in updater state.

The actual byte percentage is displayed during download. A visible update lasts
at least 1500 ms plus a 600 ms settle period; reduced motion uses still states.
Updated successfully appears only after the expected new build is running and
the new browser bundle confirms its identity. It stays readable for at least
3500 ms after its animation finishes while the page is visible and focused, then
dismisses automatically. Losing focus restarts the full readable interval.
A durable installation/build acknowledgment prevents repeat notices in
new tabs or on a later server restart. Fresh installs do not show update success.

Hosted operation is controlled by the server operator. Browser version checks
refresh assets at an idle boundary after an operator deploys a new gateway.
Remote browsers cannot start an installer or choose a feed, URL, key or path.
Running node server.mjs directly also uses this operator-managed behavior.

For a future release, set SAUTV_BUILD_NUMBER and SAUTV_VERSION only when running
npm run build. These are build-time inputs; identity.json and executable/browser
bundles embed the result. Runtime environment variables cannot fake the build.
Package the resulting dist contents under one SAUTV-Web/ directory in the ZIP.

WHAT IS IMPLEMENTED
English LIVE/MOVIES/TVSHOWS/Settings; phone bottom tabs and desktop/TV side rail;
categories, search, movie/series details, episode selection, per-account local
favorites/recent/progress, HTML video/HLS playback and browser-managed downloads.
SAUTV brand v2 assets and reduced motion. Display Name is local presentation.
Reconnection retries the active failed or stale library once at a safe browsing
boundary. Filters and catalog focus are retained. Buffered or paused video stays
untouched; an actual playback failure offers Retry with the saved position.
Closing details or a connecting player cancels its pending browser API request.
Shared gateway catalog/detail requests may finish to populate the session cache.
The server handles Xtream login/library, Cloudflare encrypted DNS, VLC-compatible
headers with bounded 403 profile negotiation, safe same-origin media/artwork
proxying, HLS child playlist/key/segment URI rewriting and byte-range relay.
Server address and protocol follow the native sign-in policy: supplied protocol
first, HTTPS for a bare address, one alternate on eligible transport failure.
No protocol fallback on rejected accounts/HTTP refusal/DNS/malformed JSON.
Normal TLS certificate validation stays enabled.

SESSION AND STORAGE
Provider credentials remain in the server process memory after login; they are
not persisted by this edition. The browser gets an HttpOnly SameSite cookie
and opaque encrypted resource references, not provider URLs or passwords.
Sessions expire after 12 hours without a request and are lost on server restart.
Signing out aborts that session's upstream requests. Resource links expire.
Favorites/recent/progress/preferences are stored by the interface locally and
scoped to the account; there is no cross-device synchronization or subscription.
Avoid sharing the browser profile if its viewing history should stay private.

BOUNDARIES
- Browser codecs differ from LibVLC and Android. LIVE requires provider HLS
  (m3u8); raw continuous MPEG-TS, unsupported MKV/codecs/DRM and transcoding are
  not implemented. Unsupported streams should show an actionable message.
- Downloads are handled by the browser. There is no native durable background
  queue, bulk series downloader or guaranteed resume after browser/server exit.
  Browser Range requests are relayed to the provider when available.
  Known HLS playlist titles explain the native-app download requirement instead
  of offering an unsupported browser download link.
- HLS resources stay behind the local gateway. EXT-X-DEFINE variables and DRM
  protocols are unsupported. The gateway intentionally blocks HTTPS-to-HTTP
  media redirects; use the provider's correct HTTP connection if required.
- Provider API and active request limits still apply. Multiple browser transfers
  may use multiple provider connections; close playback before large downloads.
- This web gateway uses public IPv4 destinations. Private/LAN/loopback,
  link-local, metadata, multicast and IPv6-only providers are not supported.
  Redirect destinations and DNS answers are checked before connecting.
- The library cache is session memory only. Failed refresh can retain its last
  good data while this server process remains alive. The web edition does not
  promise offline installation/PWA background playback or durable offline media.
- Bundling confirms source compilation. See the accompanying validation report
  for the tested browser, local fixture results and any provider limitations.

HOSTING CONFIGURATION
Default bind is 127.0.0.1, port 4173. SAUTV_PORT changes the port.
Remote hosting requires ALL of:
  SAUTV_HOST=0.0.0.0
  SAUTV_ORIGIN=https://your-private-web-host.example
  SAUTV_PROVIDER_ORIGINS=https://your-provider.example,http://your-provider.example
Use exact permitted origins, including required custom ports. Put the service
behind your HTTPS reverse proxy with an owner-controlled access gate and forward
its original Host. No public hosting, DNS, firewall or cloud setup was performed.
The static files alone cannot reproduce the gateway's provider headers, DNS,
session and stream behavior; R2 static hosting alone is not sufficient.

TECHNICAL REFERENCES
https://github.com/video-dev/hls.js
https://hlsjs.video-dev.org/api-docs/
https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-json/
https://nodejs.org/api/http.html

Attribution: hls.js is Apache-2.0; its license is included under public/vendor.
Existing SAUTV fonts/assets retain their original project attribution.
