← All projects
Project  ·  June 2026

kivo

An IPTV launcher for Android TV, D-pad only with no touchscreen assumptions, with a curated set of live-TV sources baked in and resolved at play time.

FlutterAndroid TVIPTVDartMedia

kivo is an IPTV launcher for Android TV. It ships with a curated set of live-TV playlists baked in, so the user’s job is to browse, favourite, and watch, not manage URLs. Everything is driven by the D-pad: no pointer, no on-screen back button, no assumption of a touchscreen anywhere in the app.

Why I built this#

Most IPTV apps on Android TV are bring-your-own-playlist tools designed for a phone and awkwardly ported to a remote. I wanted a Netflix-style home screen (Live Now, Favourites, Recently Watched, top channel groups) that felt native to a TV, with sources already seeded and refreshed in the background.

How it works#

Kivo pulls from six different sources, each with a different shape:

  • Public M3U playlists that are directly playable
  • Scraped live-sports fixtures behind an iframe → XOR-decrypted player page → HLS/DRM’d DASH
  • An encrypted multi-category sports catalog, where each category becomes its own toggleable playlist
  • A bundled list resolved through a per-slug Flussonic token that rotates every play
  • A numbered channel range resolved from a player page for the real HLS host + expiry
  • A LAN-only Flussonic panel, silently skipped when unreachable

A channel reference is the stable string stored as a channel’s URL and the key for favourites/history. It’s either already playable, or a scheme-prefixed reference that a resolver turns into a playable URL at play time, because the underlying host, token, or DRM key is often short-lived.

Technical challenges#

Streams that die mid-watch#

Live streams fail in ways VOD never does: 404s, refused connections, stalls. The player auto-skips to the next channel on failure, with a “Skipped · X unavailable” toast, capped at one lap through the zap list so a dead playlist can’t loop forever. Before giving up, it does one silent re-resolve, since a mid-watch drop is often just a token expiring rather than a dead stream, and proactively refreshes tokens 60s before a resolved stream’s expiry.

Live-edge drift#

The player tracks how far behind live the stream has drifted (”12s behind live · Sync”) and offers a manual snap-to-live action, since HLS buffering on weak set-top hardware tends to creep.

Surviving weak hardware#

Built and tuned against 1GB-RAM Android TV boxes: bounded demuxer buffers, MediaCodec direct rendering, capped image cache, paginated DB reads, debounced UI invalidation. Per-user audio delay is also exposed in settings, since HDMI audio pipelines on cheap TVs/soundbars add latency the player has no way to detect on its own.

Stack#

  • Flutter/Dart for the UI and player
  • D-pad-first navigation — horizontal rows, vertical sections, no touch fallback
  • Per-source resolvers for token-based and scraped playlists
  • Local persistence for favourites, watch history, and per-source toggles

What this proves#

Kivo is a project about constraints: a remote instead of a mouse, live streams instead of stable VOD files, and hardware that’s actively hostile to smooth playback. Most of the interesting work is defensive, assuming every stream and every source will eventually misbehave and building around that.