tv-web
Smart-TV IPTV player (SolidJS) for Samsung Tizen and LG webOS — spatial navigation, EPG, QR device activation, playing M3U/Xtream/XMLTV sources.
Overview
tv-web is a clean-room SolidJS rebuild of a commercial smart-TV app
architecture, targeting Samsung Tizen 6.0 / LG webOS 6 (2021, Chromium
76/79). It ships as a static SPA served by Caddy at
https://tv.albertonline.org and as the target of thin packaged Tizen
(.wgt) / webOS (.ipk) shells.
The app provides spatial navigation (D-pad friendly), EPG, QR device
activation (RFC 8628), and plays IPTV sources (M3U/Xtream playlists,
XMLTV EPG) via the monorepo's Effect RPC backend on apps/web.
Stack
- SolidJS +
@solidjs/router(hash routing — packaged-app safe) - Vite (
build.target: ["chrome76", "es2019"]), CSS Modules + CSS custom-property tokens - Effect service layer via
@repo/api/client(UI stays plain Solid signals /createResource; Effect never leaks onto the render path) - shaka-player behind the
src/services/playback/shaka.tsseam - Vitest (node unit + chromium component projects)
Develop
pnpm -F tv-web dev # http://localhost:3006Dev proxies /api to apps/web on :3001 (see vite.config.ts), so
auth cookies + /api/rpc work same-origin — run pnpm dev:web
alongside. Set VITE_API_BASE to point the RPC client at another origin
(packaged builds).
Build & deploy
pnpm -F tv-web build # static SPA → dist/
pnpm -F tv-web check:es # ES-syntax gate for the 2021 TV fleet floor
pnpm -F tv-web check:size # initial bundle ≤ 300 kB gz budget
pnpm -F tv-web build && cp -r apps/tv-web/dist/. /var/www/tv-web/
# live deploy (Caddy static root)The production build uses VITE_API_BASE=https://www.albertonline.org
so all API calls (device auth + RPC) go cross-origin to the web app.
CORS is allowlisted on both /api/rpc and /api/auth/* for
https://tv.albertonline.org.
Sign-in flow
Device-flow sign-in (RFC 8628) against better-auth's
deviceAuthorization plugin: /activation shows a user code + QR
(rendered with uqr), polls /api/auth/device/token until approval on
another device, then stores the returned session token. The shell gates
every route on that token (signed out → /activation).
Structure
src/main.tsx boot: polyfills → render
src/app.tsx hash router + shell
src/core/ platform detection, focus system, theme
src/features/ home, watch, activation, settings, profiles,
epg, search, discover
src/services/ rpc.ts, session.ts, device-auth.ts, playback/shaka.tsSee the root README for monorepo-wide commands.