Files
castarr/CONTEXT.md
benjamin 6c5fee849e Bootstrap Castarr from NodeCast prototype
Imported the native TV app (Kotlin, ExoPlayer, embedded remote server, QR
pairing) plus CONTEXT.md and ADRs 0001-0005. Rename, Compose for TV UI and
the Dispatcharr integration follow as tracked issues.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 00:09:00 +02:00

2.6 KiB

Castarr

Native Kotlin app for Google TV that lets every user of a Dispatcharr backend watch live IPTV comfortably on their own TV: full D-pad UI, login via OIDC Device Flow (Authentik), plus an optional phone Remote paired via QR code.

Language

TV-App (Castarr): The native Kotlin app running on Google TV; full TV UI, plays streams, serves the Remote. Avoid: receiver, player app, NodeCast (old name)

Device Flow: OIDC device authorization grant: TV shows QR/code, user confirms on the phone at Authentik, app receives Bearer tokens for the Backend API. Avoid: pairing (that word is reserved for the Remote)

Backend (Dispatcharr): The self-hosted stream manager owning sources, aggregation, failover, EPG and stream profiles; forked at be-nj with native OIDC. Avoid: server (ambiguous), nodecast (dropped, see ADR-0003)

Quelle (Source): A configured backend the TV-App reads channels from — primary type Dispatcharr fork (Bearer API), fallback type generic M3U+XMLTV without login (Threadfin, Tunarr, ErsatzTV).

Remote: The phone web UI served by the TV-App over HTTP; talks to the TV-App via WebSocket. Never talks to the Backend directly. Avoid: app (it is not an installed app), controller

Pairing: Trusting a Remote via the QR token (128-bit) or the rate-limited 4-digit code.

Channel: A playable live entry the Backend exposes via Xtream API or M3U. Avoid: station, sender (in code/docs)

Now/Next: The EPG scope of the Remote in phase 1: current + upcoming programme per Channel, no full guide timeline.

Relationships

  • The TV-App is a client of the Backend; the Remote only ever talks to the TV-App.
  • One User logs into one TV-App via Device Flow; favorites belong to the User on the Backend, not to the device.
  • A Remote controls exactly one TV-App; a TV-App accepts multiple paired Remotes.
  • Aggregation, failover and stream shaping happen in the Backend, not in the TV-App.

Example dialogue

Dev: "Does the Remote need Backend credentials?" Domain expert: "No — the user enters the Xtream credentials of a Quelle once via the Remote, the TV-App stores them and is the only one talking to the Backend."

Flagged ambiguities

  • "nativ" means: no Flutter/WebView wrapper — Kotlin app. It does not mean "no embedded web content" (the Remote is deliberately a web page).
  • "Passthrough" means the fork's raw stream profile (ffmpeg copy), selected per request via profile parameter — not a bypass of the Backend proxy.
  • Favorites are per User in the Dispatcharr fork (resolved; app-local and channel-group approaches were rejected).