Files
castarr/CONTEXT.md
be-nj a11b5a68c0 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

71 lines
2.6 KiB
Markdown

# 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).