Orientation
Scope and principles
What we decided once and stopped relitigating, and the rules the code is held to.
# Why we fix scope early
A media player is a project with no natural edge. There is always one more format, one more protocol, one more screen. We settled the expensive decisions early — the licence, the language, the toolkit, the player, the minimum Android version, which protocols and formats we support, where data lives, how we ship — and wrote them down.
The more useful half turned out to be the list of things we are not building. It answers most design questions before they are asked, and it is why the architecture looks the way it does.
# The decisions
| Area | Decision |
|---|---|
| Licence | GPLv3 |
| Language | Kotlin |
| UI | Jetpack Compose, Material 3 |
| Player | AndroidX Media3 / ExoPlayer |
| Platforms | Android phones, and Android TV / Google TV |
| minSdk | 30 (Android 11) |
| Sources | M3U/M3U8 (remote URL and local file), Xtream Codes API |
| Guide | Xtream only. M3U playlists carry no schedule. |
| Formats | HLS, DASH, raw MPEG-TS, progressive MP4/MKV. No DRM. |
| Content types | Live TV, films, series |
| Storage | Local only (Room), with manual export and import to a file |
| Distribution | GitHub Releases (APK) |
| Network | Direct client-to-provider. No proxy, no relay, no intermediary. |
Two of those deserve their reasoning. No DRM: M3U and Xtream providers
overwhelmingly serve unencrypted streams, so DRM is substantial engineering work serving a
near-empty use case here. Phones before television: identical data layer, far
faster iteration, and none of the D-pad focus cost — the television inherits every
:core:* module unchanged.
# The architectural invariants
Six rules that hold at every commit. A change that breaks one is a design regression regardless of whether the tests pass.
- No UI code in
:core:*. No Compose import, no AndroidContextbeyond what Room and DataStore require. We check this at build time, not in review. - The source layer is abstracted.
MediaSourceis an interface; M3U and Xtream are implementations. Adding a protocol means adding one implementation and changing zero feature modules. - The guide is source-agnostic. Only Xtream supplies programme data today, but the storage and query layer accepts programmes from any provider, so adding XMLTV later needs no schema migration.
- Playback is behind an interface. Feature code never touches ExoPlayer;
it talks to a
PlayerController. That is the seam where DRM would slot in. - The app never phones home. No telemetry and no server of ours; the one unprompted request is a check for a newer release, which sends nothing and can be switched off.
- Credentials never leave the device.
Rules 1 and 2 are why our television frontend cost a presentation layer instead of a second application. Rules 5 and 6 are the privacy posture, written as engineering rules so we can test them rather than merely intend them.
# What we mean by finished
A user installs the APK, adds either an M3U URL or Xtream credentials, browses categorised live, film and series content, marks favourites, plays a stream full-screen, and exports their configuration to a file — all offline-tolerant, with no account and no network call to any host they did not enter themselves.
This must hold on a phone and on a television, with the television driven by a remote alone.
Everything in Acceptance exists to make that testable rather than a matter of opinion.