Control server security and robustness:
- Socket read timeout, handshake deadline and a client cap so an idle or
hostile connection can no longer pin threads forever (#1)
- Per-address rate limiting that counts every failed hello, Origin
checking on the upgrade, and a separate revocable session token for
code-authenticated clients so the guessable path no longer yields the
QR credential (#2)
- Credentials excluded from cloud backup and device transfer, constant
time comparisons, and a pairing reset in the settings (#3)
- Playlist fetches restricted to http(s), capped at 24 MB and bounded by
an overall transfer deadline (#4)
- Port conflicts and MediaSession id collisions no longer crash the app;
the remote degrades to unavailable with a plain-language note (#11)
Player:
- Seeking no longer collapses to position 0 when the duration is unknown
(#5)
- Pause acts on playWhenReady, so pausing during a stall works and
playback cannot resume in the background after leaving the app (#6)
- Playback failures stay on screen with a retry action instead of
silently dropping back to the list (#7)
- Reconnects are spaced 1s/3s/8s and re-entering the channel just closed
waits out a short grace period, which is what the provider needs to
release the previous session (#12)
Channel list and remote:
- Leaving playback returns to the channel the viewer came from (#13)
- The remote only rebuilds its list when the data changed, never
overwrites a focused input and carries indices instead of scanning (#8)
- Pairing retry reconnects properly, resets its backoff and validates the
code before spending an attempt (#9)
- M3U parsing keeps commas in names, strips a BOM and rejects payloads
that are not playlists, covered by unit tests under tests/ (#10)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Overlay shows current programme (title, time range, EPG progress) and
what's next; resurfaces briefly on programme change, hides after 5s.
- Audio tracks: listed from the stream, switchable via D-pad left/right
on live streams (seek keeps left/right on seekable media), via chips
in the overlay and from the phone remote (set_audio message).
- Main UI font switches to Inter; Space Grotesk stays for the wordmark.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Compose for TV scaffold: D-pad app shell (Live/Einstellungen), channel list
with focus handling, fullscreen player with auto-hiding overlay; zapping via
channel/D-pad keys (closes#2)
- Generic source end-to-end: M3U + XMLTV configurable on the TV, Now/Next with
progress in the list, channel cache (closes#3)
- OIDC device-flow login: server URL is the only input, issuer/client id come
from the fork's status endpoint; QR + user code screen, silent refresh,
logout (closes#4)
- Dispatcharr source via Bearer API: channels, groups, EPG grid; switchable
against the generic source (closes#5)
- Per-user favorites: star via long-press, favorites filter, backend-synced
(closes#6)
- Stream profile selection (Standard/Passthrough/audiofix/720p from the
backend profile list), applied per stream URL (closes#7)
- Phone remote: Now/Next lines, favorites star + filter over the WebSocket
protocol (closes#8)
Device verification pending (TV currently in use).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Package/applicationId com.nodecast.tv -> dev.castarr.tv, all branding in app
and remote page renamed, remote localStorage key changed. Foojay toolchain
resolver + jvmToolchain(17) so hosts with only a JRE can build.
Closes#1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>