albertonline.org docs
Apps

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.ts seam
  • Vitest (node unit + chromium component projects)

Develop

pnpm -F tv-web dev        # http://localhost:3006

Dev 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.ts

See the root README for monorepo-wide commands.

On this page