Code reference · Core
:core:model
The domain vocabulary. Plain Kotlin, no Android dependency at all.
dev.quiblo.core.model
Every other module speaks in these types. They carry no framework annotations, no
persistence concerns and no formatting — a Channel is what a channel
is, not how it is stored or drawn.
This is the module that makes the layering pay: because nothing here imports Android, a television frontend, a desktop frontend or a test can all use it unchanged.
data classChannel
One playable item — a live channel, a film, or a series container.
The most-used type in our codebase, and the one whose kind matters most. A
SERIES channel is a container: its streamUrl is not an episode and
must never be handed to the player. Episodes come from the panel per series and are never
rows in the channel table.
id | Database row id. Reassigned by every refresh — never store it. |
|---|---|
stableKey | The provider's own identity. What survives a refresh, and what favourites and resume points are keyed by. |
kind | LIVE, VOD or SERIES. Decides how the item may be played. |
providerStreamId | The panel's id, used to request a guide or details. For a series this is the series id, not a stream id. |
groupTitle | The provider's category name. Also the key an override is stored against. |
sortIndex | Preserves the provider's ordering, which is the channel numbering a viewer knows. |
enumMediaKind
LIVE, VOD, SERIES. The distinction that decides almost every branch.
Worth stating plainly: an M3U playlist has no way to express this, so the
M3U parser assigns LIVE to everything. Films and series require Xtream.
data classProfile
Who is watching. Owns favourites and resume positions, and nothing else.
Player settings, hidden categories, the metadata key and the sources themselves stay app-wide: they describe the television and the account behind it rather than the person on the sofa, and a household that had to configure its playlist twice would rightly call that a bug.
There is no password and no PIN. This answers "whose favourites are these", not "who is allowed to watch what" — the second is a different feature with different requirements.
isGuest | The throwaway one. Its data is deleted when the session ends, and again at startup, because a killed process never tidies up after itself. |
|---|---|
NONE_ID | The id used while nobody has chosen. Matches no row — ids start at 1 — so reads return nothing and writes land nowhere, and no screen needs a special case. |
data classCategory
A grouping of items, derived by grouping channels rather than stored.
title | The provider's own name. The stable identity, and what an override is keyed by. |
|---|---|
displayTitle | The local rename if there is one, otherwise the provider name. |
isHidden | Filtered out of browsing. Nothing is deleted. |
UNGROUPED_TITLE | The bucket for entries with no group. Not localised — it is a storage key, and the UI substitutes a translated label. |
data classProgramme
One guide entry. Times are UTC milliseconds.
Source-agnostic by design. Only Xtream supplies programme data in v1, but nothing about this type is Xtream-specific, so adding XMLTV later needs no schema migration.
Panels report a local formatted string alongside a Unix timestamp and only the timestamp is trustworthy; conversion to the device's zone happens at render time.
data classSource
A configured playlist or account. Carries no credentials.
Note what is absent: no username, no password, no token. Those live encrypted in
:core:datastore and never reach the database, so an export or a debug dump
cannot leak them.
data classSeriesDetails / Season / Episode
A series' seasons and their episodes, fetched per series and held for a session.
An Episode is identified by its streamUrl, because there is
nothing else stable to identify it by — episodes are never stored as rows. That is why the
player takes an episode's URL explicitly, and why history denormalises the episode's title
rather than joining to a channel.
data classVodDetails
A film's plot, cover, release date and genre, as the panel describes it.
data classTitleMetadata
What the optional metadata service knows about a title.
rating | The score shown on poster tiles. |
|---|---|
authorLabel | Whether `author` is a director or a creator — which follows from the kind. |
isPartial | True when only the search step ran, giving a score and artwork but no cast or plot. Lets a tile be satisfied by one request and a detail screen upgrade the same row. |
data classHistoryEntry
Something started and not finished, for the continue-watching row.
A series appears once, at the episode last watched — six tiles for six episodes of one
programme is a list of one thing. That collapsing happens in
WatchHistoryRepository, so both apps agree about it.
data classPlayerSettings
Skip interval, buffer mode, bitrate cap and the next-episode delay, as one object.
enumSeekInterval / BufferMode / MaxBitrateCap / AspectRatioMode / AutoNextDelay
The player settings, as closed sets rather than free numbers.
They live in :core:model rather than :core:media deliberately, so
the settings store and the settings screen can name them without either depending on the
media layer.
AutoNextDelay carries OFF as one of its values rather than sitting
behind a separate switch: "do not do this" and "do it after ten seconds" are the same question
asked once. Off still offers the next episode; what stops is the counting.
data classAppearance / ThemeMode
Theme choice and dynamic colour. Phone only — the television is always dark.
enumSourceKind
M3U or XTREAM. Selects which MediaSource implementation handles a source.