discover · compare · collections · requirements · contribute · feed · watching · stats · help with your tokens
raulshma/jellyplay · source
Snapshot 0 · 2026-11-04T12:47:28Z · Kotlin · GPL-3.0
Content fingerprint
1428b38116f50d7e609e2e5b0f788f605a5de15841802908704780619f5a1f07GitHub description at capture
Jellyfin client for Android, Android TV & Fire TV. Native Kotlin/Jetpack Compose app with ExoPlayer, mpv & VLC playback, synced-lyrics music, offline downloads, SyncPlay, IPTV, and Jellyseerr/Overseerr requests. Open-source self-hosted media player.
README at capture
<div align="center">
# JellyPlay
</div>
<p align="center">
<img src="media-resources/app_logo.svg" width="150" alt="JellyPlay app logo" />
</p>
<p align="center">
<img alt="API 28+" src="https://img.shields.io/badge/Api%2028%2B-50f270?logo=android&logoColor=black&style=for-the-badge" />
<img alt="Kotlin" src="https://img.shields.io/badge/Kotlin-7F52FF?logo=kotlin&logoColor=white&style=for-the-badge" />
<img alt="Jetpack Compose" src="https://img.shields.io/badge/Jetpack%20Compose-4285F4?logo=jetpackcompose&logoColor=white&style=for-the-badge" />
<img alt="Material 3" src="https://custom-icon-badges.demolab.com/badge/material%20you-lightblue?style=for-the-badge&logoColor=333&logo=material-you" />
<img alt="Media3" src="https://img.shields.io/badge/Media3-FF6F00?style=for-the-badge&logo=android&logoColor=white" />
<img alt="License GPL-3.0" src="https://img.shields.io/github/license/raulshma/jellyplay?style=for-the-badge&color=blue" />
<img alt="Status - Beta" src="https://img.shields.io/badge/Status-Beta-orange?style=for-the-badge" />
</p>
<p align="center">
<sub>Native Jellyfin client for Android, Android TV, Fire TV & Windows desktop · Material 3 Expressive · ExoPlayer, libmpv & LibVLC · Self-hosted, no tracking</sub>
</p>
<div align="center">
### Modern, open-source Jellyfin client for Android, Android TV, Fire TV & Windows desktop
**JellyPlay** is a native, high-performance **Jellyfin client** — built from scratch in **Kotlin** and **Jetpack Compose** with **Material 3 Expressive**. No web wrapper, no Cordova, no embedded browser.
One app for every screen: **phones, tablets, foldables, Android TV, and Amazon Fire TV**. Stream movies and shows, play music with synced lyrics, read comics and ebooks, request content via **Jellyseerr/Overseerr**, manage your **Radarr/Sonarr** queues, download for offline, and run your server from a built-in **admin dashboard** — with three switchable video engines (**ExoPlayer, libmpv, LibVLC**), in-app **self-update** via GitHub Releases, no accounts, and no tracking.
**Also growing beyond Android:** the codebase is now Kotlin Multiplatform — an early **Windows desktop** build (Compose Multiplatform + libmpv) runs browsing, search, details, home, settings, music with real audio playback (full effect stack: equalizer, bass boost, night mode, ReplayGain, …), in-player video with working keyboard media keys, the video effect stack (brightness/contrast/saturation/hue/sharpen/blur/rotate), **render profiles with Anime4K upscaling**, frame capture to `~/Pictures/JellyPlay`, live subtitle cues, the full metadata editor, and the in-app book reader (CBZ/CBR/PDF/EPUB — read-aloud excepted); sign-in uses the shared auth flow (Quick Connect, remembered users, server-address alternates). The KMP migration itself is complete (docs/kmp-migration-plan.md). Player polish, and macOS/Linux (build-from-source, untested), are still landing — treat the desktop build as a preview, not a release; the auto-update client and release checklist have landed, signing and per-OS passes remain.
If you self-host Jellyfin and want a truly native, beautiful, capable client — or a **Plex/Kodi alternative** — give JellyPlay a try.
[Highlights](#highlights) • [Why JellyPlay?](#why-jellyplay) • [Features](#features) • [Tech Stack](#tech-stack) • [Requirements](#requirements) • [Building](#building) • [Local Development](#local-development) • [Permissions](#permissions) • [Project Structure](#project-structure) • [Docs](./docs) • [Website](https://raulshma.github.io/jellyplay/)
</div>
## Highlights
| | |
| :------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🎬 **Multi-engine video player** | Switch between **ExoPlayer (Media3)**, **libmpv**, and **LibVLC** per device — HDR, refresh rate/resolution matching, **render profiles** (Anime4K shader packs, tone mapping, quality), trickplay seeking, A/B repeat with seek-bar region visualization, multi-range buffered seek bar, gestures, Chromecast, floating Picture-in-Picture, and live transcode-reason surfacing. |
| 💬 **Full subtitle system** | **ASS/SSA** & **VTT** parsing, external subtitle loading & download, full styling, delay offset, **live sync preview** with cue stack & ±30 s offset slider, **multi-provider search** (Jellyfin, Wyzie, OpenSubtitles), **per-series role memory**, and consistent track labels & badges across engines. |
| 📱 **Native on every screen** | Phone, tablet, foldable, **Android TV**, and **Fire TV** with D-pad navigation, a Leanback launcher, and adaptive Material 3 layouts — plus an early **Windows desktop** build from the same Kotlin Multiplatform codebase. |
| 🎵 **Rich audio player** | Synced lyrics via LRCLIB, 10-band equalizer, Night Mode & Dialogue Boost, ambient visualizer, mood playlists, and gapless playback. |
| 📚 **In-app book reader** | Read comics (CBZ/CBR), PDFs, and EPUBs with bookmarks, highlights & notes, in-book search, EPUB typography, read-aloud with sleep timer, and server-synced reading position. |
| ⬇️ **Offline downloads & sync** | WorkManager-backed downloads with HTTP Range resumption, multi-connection acceleration, bundled subtitles & trickplay tiles, dedicated offline library, and durable watch-progress sync outbox. |
| 📡 **Seerr + Arr integration** | Discover and request via **Jellyseerr/Overseerr**, manage **Radarr/Sonarr** queues, and track an upcoming-releases calendar — all in-app. |
| 👯 **SyncPlay & Play On** | Real-time watch parties with speed/skip-to-sync correction and in-player chat, plus cast-to and control other Jellyfin sessions. |
| 🛠️ **Server admin dashboard** | System health, active sessions, scheduled tasks, server logs, user stats, and stale-media cleanup — without leaving the app. |
| 📺 **Live TV & DVR** | Browse live channels, an Electronic Program Guide, **delivery-method selection** (Auto / Direct Stream / Transcode), and manage DVR recordings. |
| 🎨 **Fully customizable** | 8 themes (Standard, Synthwave, Soothing, Monochrome, Vivid, Aurora, Sakura, Vector Pop), OLED mode, **390+ settings**, 4 home-screen widgets, and a 10-step onboarding wizard. |
<table align="center" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0;">
<tr>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/home.webp" width="180" alt="Home screen" style="display: block;" /></td>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/library.webp" width="180" alt="Library screen" style="display: block;" /></td>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/search.webp" width="180" alt="Search screen" style="display: block;" /></td>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/settings.webp" width="180" alt="Settings screen" style="display: block;" /></td>
</tr>
<tr>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/audio_home.webp" width="180" alt="Audio home screen" style="display: block;" /></td>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/audio_player.webp" width="180" alt="Audio player screen" style="display: block;" /></td>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/media_detail.webp" width="180" alt="Media detail screen" style="display: block;" /></td>
<td align="center" style="padding: 1px;"><img src="media-resources/screenshots/media_detail_2.webp" width="180" alt="Secondary media detail screen" style="display: block;" /></td>
</tr>
<tr>
<td colspan="4" align="center" style="padding: 1px;"><img src="media-resources/screenshots/video_player.webp" width="760" alt="Landscape video player screen" style="display: block;" /></td>
</tr>
</table>
---
> [!NOTE]
> **JellyPlay is currently in Active Beta.**
> The application is under active development. While the core features (such as playback, multi-server support, and offline downloads) are functional and stable, you may encounter occasional visual bugs or edge-case issues. We highly appreciate any bug reports, feedback, and contributions!
## Why JellyPlay?
JellyPlay is built for people who self-host a [Jellyfin](https://jellyfin.org/)
media server and want a **truly native**, **beautiful**, and **capable** client
on every screen — phone, tablet, foldable, Android TV, and Amazon Fire TV.
- **Native, not a web wrapper.** Written from scratch in **Kotlin** and
[Jetpack Compose](https://developer.android.com/jetpack/compose), with
[Compose for TV](https://developer.android.com/tv/compose) on the big
screen. No Cordova, no embedded browser, no compromises.
- **Three video engines.** Pick **[ExoPlayer / Media3](https://developer.android.com/media/media3)**,
**[libmpv](https://github.com/mpv-player/mpv)**, or **[LibVLC](https://www.videolan.org/vlc/)**
per device — each has its own strengths for codec support, post-processing,
and ASS/SSA subtitle rendering.
- **One app, every form factor.** Adaptive layouts across phones, tablets,
foldables, and Android TV with a dedicated Leanback launcher. Edge-to-edge
immersive mode, predictive back gesture, and Material 3 dynamic theming
from your artwork.
- **Self-hosted first.** No accounts, no telemetry, no cloud dependency.
Multi-server, multi-user support with Quick Connect and token-based auth.
Automatic **server address failover** across primary/alternate URLs keeps you
connected whether you're on LAN or remote.
- **Extensive offline & watch-progress sync.** Take your library anywhere with
WorkManager-backed background downloads, multi-connection byte-range
acceleration, HTTP Range resumption, and bundled subtitles, trickplay preview
tiles, and intro/outro skip markers. A durable **playback outbox** records
progress and watched states offline, automatically syncing back to your server
with latest-wins reconciliation on reconnect. **Selective freshness resync**
refreshes changed metadata or artwork without re-downloading media files.
- **Beyond streaming.** **SyncPlay** watch parties, **Jellyseerr / Overseerr**
requests with **Radarr/Sonarr queue management**, an **upcoming releases
calendar**, a full **metadata editor**, an in-app **server admin dashboard**,
**Play On** casting to other Jellyfin sessions, synchronized lyrics via LRCLIB,
10-band equalizer with night mode, and a weekly **newsletter digest** of your
library activity.
<details>
<summary><strong>Comparison with Official Jellyfin Clients</strong></summary>
| Capability | Official Jellyfin Clients (`jellyfin-android` / `jellyfin-androidtv`) | JellyPlay |
| :------------------------------ | :-------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- |
| **Native UI Architecture** | ❌ Cordova WebView (Mobile) / Leanback (TV) | ✅ **100% Jetpack Compose** (Unified across all devices) |
| **Playback Engines** | ❌ ExoPlayer only | ✅ **3 switchable engines** (Media3 / ExoPlayer, libmpv, LibVLC) |
| **Complex Subtitles (ASS/SSA)** | ❌ Server transcoding required | ✅ **Client-side styled rendering** via libmpv (Direct Play) |
| **Adaptive Form Factors** | ❌ Split across 2 separate apps | ✅ **Single unified adaptive app** (Phone, Tablet, TV, Foldable) |
| **Material You & Theming** | ❌ Web / static themes only | ✅ **Material 3 Expressive** with dynamic artwork palette (8 themes + OLED) |
| **Offline Downloads** | ⚠️ Basic browser save (Mobile only, no TV, no background queue) | ✅ **WorkManager Engine** (HTTP Range, multi-connection, bundled subtitles & trickplay) |
| **Watch-Progress Sync** | ❌ No offline progress tracking or sync | ✅ **Durable Outbox** (Captures progress offline; auto-reconciles on reconnect) |
| **Freshness Resync** | ❌ Full re-download required | ✅ **Selective SHA-256 hash diff** (Refreshes metadata/artwork/subs with zero media download) |
| **SyncPlay (Watch Parties)** | ⚠️ Web-based SyncPlay only (limited on TV) | ✅ **Native multi-screen sync** (Real-time speed/skip sync, in-player chat, Mobile + TV) |
| **Rich Music Player & DSP** | ❌ Basic web audio playback | ✅ **Full audio DSP suite** (10-band EQ, LRCLIB lyrics, ReplayGain, visualizer) |
| **Seerr & \*Arr Integration** | ❌ Not supported | ✅ **Jellyseerr / Overseerr** with Sonarr/Radarr queues & release calendar |
| **Server Administration** | ⚠️ Web UI (Mobile only, not on TV) | ✅ **Native dashboard** (Mobile, Tablet, and TV with D-pad navigation) |
| **Metadata Editor** | ⚠️ Web UI (Mobile only, not on TV) | ✅ **Native editor** for titles, posters, and tags (Mobile, Tablet, TV) |
| **Connection Failover** | ❌ Single server URL (manual switching) | ✅ **Automatic LAN/WAN address failover** without session loss |
</details>
> If you're looking for a Kodi alternative, a Plex alternative, or a
> self-hosted media player for Android & Android TV — give JellyPlay a try.
## Features
Click any section to expand. The full feature list is preserved — collapsed only to keep this page scannable.
<details>
<summary><strong>Video player & subtitles</strong></summary>
**Video player**
- **Three built-in engines**: ExoPlayer (Media3), libmpv, and LibVLC, on an engine-agnostic core
- **Force direct play** profile with automatic transcode fallback
- **Transcode-reason surfacing** — the Stats-for-Nerds overlay, playback error dialogs, and the Live TV banner explain _why_ the server is transcoding, with localized reasons and remedy hints
- **Server-side audio/subtitle switching** on transcode (no restart needed)
- **FFmpeg software decoder** fallback for unsupported codecs
- Video filter controls: Adjust brightness, contrast, saturation, and sharpness in-player (libmpv & LibVLC)
- Enhanced Video Stats Overlay presenting real-time stream bitrate, frame rate, and dropped frames
- External player launching (MX Player, VLC, etc.)
- Direct play, direct stream, and transcoding support with quality/transcoding picker
- Resume playback and progress reporting
- Audio and subtitle track selection with language matching and reset functionality — selections preserved across transcodes and engine reloads
- Per-item playback preferences
- Playback speed control (0.25x–4x) with current speed display and estimated end time
- **Hold speed** — press and hold to temporarily increase playback speed
- Gesture controls for seek, brightness, and volume
- Chapter and episode navigation
- HDR badge indicator
- Picture-in-Picture via a dedicated player activity that floats over the browse UI — transport remote actions, auto-enter on home, aspect-ratio handling, and auto-exit
- Mini player overlay
- Trickplay thumbnail seeking (Jellyfin trickplay sprite sheets) with offline caching support
- **Refresh rate & resolution matching** — 3 modes (Off / Frame Rate Only / Frame Rate + Resolution) with judder-free cadence matching (24→60/120, etc.) and ±0.5 Hz tolerance
- Cross-episode audio/subtitle **track memory** with role-aware scoring and remembered container codec (re-matches when track labels churn), plus **track-selection presets & language rules** — ordered rules with language preferences and title patterns under _Settings → Language → Track Selection_
- **Rendering sheet (render profiles)** — pick a shader pack (**Anime4K** modes A/B/C on desktop, user shaders supported), HDR→SDR tone mapping, and render quality in-player; apply for this session only or save as a per-item / per-series override
- **Multi-range buffered seek bar** — the seek bar visualizes every buffered range (not just the contiguous band), and a stalled-at-end detector completes the item cleanly when the stream freezes near the finish
- **A/B repeat** — loop any segment of the video, visualized as a highlighted seek-bar region with repeat badges
- **Video byte cache** — direct-play/direct-stream segments are cached to disk so backward seeks don't re-fetch
- **Screenshot capture** — save the current frame via PixelCopy
- **Subtitle AV-sync measurement** — press-and-hold to measure and correct audio/video/subtitle sync offset
- **Subtitle sync preview** — live bidirectional preview with a cue stack of the played range and an offset slider (±30 s); malformed-track detection gates cue accumulation until a valid track is active
- Per-item subtitle delay persistence
- Free-form `mpv.conf` option parsing for power users
- Adaptive bitrate streaming
- Intro skip and next episode auto-play with segment auto-skip (intro/outro/recap)
- **Play On** — cast to and control other Jellyfin sessions, with a full-screen companion transport screen
- Chromecast support via Google Cast SDK
- Media session integration for lock screen and notifications
- Sleep timer with configurable duration
- Aspect ratio selection
- Hardware/software decoder selection
- Audio delay adjustment (ms)
- Screen orientation toggle
- Player lock screen overlay to prevent accidental touches
- **Companion Dashboard** — view lyrics and transport controls alongside video playback
- Tap-to-translate subtitle feature
**Subtitle system**
- External subtitle loading and download
- ASS/SSA and VTT subtitle format parsing with enhanced cue handling
- Subtitle styling (font size, color, background, edge type, position) with persistence
- Subtitle delay offset control
- Preferred subtitle language selection
- **Per-series subtitle role preferences** — remember language + forced/SDH role across episodes, with tiered fallback matching (exact → relax SDH → language only), plus an explicit per-series subtitles-off choice
- **Consistent track labels everywhere** — unified label formatting & role badges (Forced / Default / SDH) across all engines and the Jellyfin server path, with marker detection from titles
- **Per-subtitle download status & retry** — independent download state per remote subtitle (downloading / ready / delayed / failed) with inline retry, "Use" action, and live track-list refresh
- **Multi-provider subtitle search** — search across **Jellyfin**, **Wyzie**, and **OpenSubtitles** (OpenSubtitles uses secure username/password account login; configure providers under _Integrations → Subtitle Providers_), with provenance badges and per-provider download dispatch
- **Subtitle sync preview** — bidirectional live preview with a cue stack of the played range and an offset slider (±30 s) so you can dial in delay before committing; malformed-track detection gates cue accumulation until a valid track is active
- **Provider subtitle upload** — persist externally-fetched subtitles back to the Jellyfin server via upload, so they're available across devices
- **Provider subtitles work offline** — a streaming subtitle store persists downloaded provider subtitles and re-attaches them during offline playback
- **Zoom-safe captions** — screen-pinned subtitles that stay put during pinch/crop zoom (ExoPlayer reparents its native subtitle views; mpv emits a live cue via `sub-text` rendered as a Compose overlay)
- Community rating indicator for search results and subtitle download sheet
</details>
<details>
<summary><strong>Audio player & music discovery</strong></summary>
**Audio player**
- Music browsing for artists, albums, tracks, genres, and playlists
- Queue management with drag-to-reorder
- Shuffle and repeat modes
- Playback speed control
- Waveform-style seek bar
- Real-time FFT audio visualizer
- Synced and unsynced lyrics via LRCLIB API
- 10-band equalizer with presets
- Night Mode (loudness enhancement with configurable strength)
- Dialogue Boost (vocal frequency equalization with configurable strength)
- Audio normalization (ReplayGain), channel mix modes, dynamics compression, and dialogue de-noise
- Virtualizer (3D audio) and Reverb effect presets
- Gapless playback and crossfade between tracks
- Ambient Mode with animated color blobs derived from album art
- Sleep timer with configurable duration
- **Playback focus** — music and book read-aloud never talk over each other; the interrupted side stays paused for manual resume
- **Volume memory** — remember one volume level each for video, music, and audiobooks (master toggle; desktop mpv and the audio players)
**Music discovery**
- Smart playlists with criteria-based filtering (genre, artist, year, rating, play count, tags)
- Mood playlists with 10 presets (Happy Vibes, Chill Out, Energetic, Deep Focus, Workout, Melancholy, Romantic, Party Time, Sleep, Late Night Drive)
- Recently played, frequent artists, and recommended albums
</details>
<details>
<summary><strong>Library, browsing & discovery</strong></summary>
- Home sections: Continue Watching, Next Up, Recently Added, Latest, Favorites, and Surprise Me shuffle
- **Persistent home-section cache** with stale-while-revalidate — instant home screen, background refresh, and full invalidation on pull-to-refresh
- **Hide top header on scroll** toggle for a more immersive browse
- Episode cards show a series badge in the footer with resolved series posters
- Library browsing with pagination and folder filtering
- **Library filter chips & sheet** — filter by genre, year, tags, video/audio format, and more via quick chips and a full filter sheet, with a custom year-range filter and reset confirmation flow
- **Compound sort** — sort by multiple criteria (e.g. title + year) with ascending/descending per key
- **Section mode & grouping** — group the library by first letter, genre, studio, or other keys
- **Adjustable poster size & masonry view** — pick poster size and a masonry layout for dense browsing
- **Quick actions** — long-press any poster for play, mark watched/unwatched, favorite, download, add-to-playlist, delete (offline items), and details, with undo support
- Media detail pages with cast, crew, metadata, related items, **TMDB reviews**, and a **special features/extras** row
- **Chapter navigation** — chapter markers on the seek bar plus a chapter list sheet with timestamps
- **Collection management** — add titles to an existing collection or create-and-add from the detail screen
- **Audio instant mix** — build a shuffled queue around any track or album
- **Start a watch party** from any detail screen; the last-viewed season tab is remembered per series
- **Unified remote & offline detail screens** — offline items show probed local stream info as quality/audio badges
- **Pull-to-refresh** on the detail screen triggers full cache invalidation
- Person detail pages with filmography browsing, plus a dedicated **cast & crew screen**
- **Advanced series delete sheet** with multi-select episode management
- Collection/box set browsing
- Global Jellyfin search across movies, shows, music, albums, and more
- **Seerr & offline side rows** — search results also surface Seerr discover hits and downloaded items alongside the library grid, with independent error/retry handling
- Search filters for genre, year, and media type; voice search support
- Search history persisted per-user with per-item deletion, bulk clear, and hide option
- **Add-to-Playlist picker, Watch Later, and playlist creation** from the detail screen — add movies, episodes, and series to existing playlists or create new ones, with a pinned Watch Later row
- **Compact episode list preference & vertical layout toggle** for series detail
- **Photo albums & viewer**: album browsing, full-screen zoom/pan, swipe navigation, EXIF metadata
- **Watch Progress Heatmap** — GitHub-style year-in-review calendar of watch activity, filter by media type, streak tracking, tap any day for session details, share as PNG (requires Jellyfin Playback Reporting plugin)
</details>
<details>
<summary><strong>Book reader</strong></summary>
- Read comics (**CBZ/CBR**), **PDF**, and **EPUB** books in-app, straight from the detail screen (**Read** / **Continue**) — on Android, Android TV, and desktop
- **Bookmarks** — save any position (page or exact EPUB spot) with per-book counts on the detail screen
- **Highlights & notes** — select EPUB text to highlight in four colors (or underline), attach notes, and export everything to Markdown or JSON
- **In-book search** — full-text EPUB search with jump-to-hit; PDF outline (table of contents) with page jumps
- **EPUB typography** — light/sepia/dark themes, type size, font family, line height, margins, justification, and continuous-scroll mode; theme and type size settable per book
- **Paged zoom & fit** — pinch-zoom with pan, double-tap toggle, and fit modes; zoomed PDF pages re-raster sharply (up to 3×)
- **Read aloud (Android)** — system TTS with paragraph highlighting, auto chapter advance, sentence-level skip, and adjustable speed/pitch
- **Sleep timer & auto-scroll** — stop read-aloud/auto-scroll after 5–60 minutes or at chapter end
- **Chapter tick rail** — opt-in side ticks showing the current chapter in the table of contents; tap to jump, press-drag to scrub
- **Book-aware detail screen** — cover hero, format badge, reading-progress card, chapter **Contents** row that deep-links into the reader, and "Mark as finished"
- **Resume that survives devices** — position syncs to the server encoded exactly like jellyfin-web (page ticks for paged books, percent ticks for EPUB), with exact local CFI resume per install on EPUBs
- **Offline reading** — downloaded books open with no network; offline positions sync back on reconnect
- Works on **Jellyfin 10.x and 12.x** servers (12.x probes page counts and comic series metadata; older servers render a flat list)
See [Book reader](./docs/book-reader.md) for the full guide.
</details>
<details>
<summary><strong>Seerr, Radarr/Sonarr & calendar</strong></summary>
**Seerr integration**
- Jellyseerr and Overseerr connection support
- Discover trending, popular, and upcoming content
- Request content via Radarr/Sonarr directly from the app
- **Full request management screen** with:
- Filter by request status (Pending, Approved, Declined, Processing, etc.)
- Filter by media type (All, Movies, TV)
- Sort by Recent or Modified, with ascending/descending toggle
- "My Requests Only" filter for admins
- Paginated request list with prev/next navigation
- **Admin actions**: Approve, Decline, Retry, Delete requests (with confirmation timer)
- **Remove from Radarr/Sonarr** action for processed requests
- **Request Detail Bottom Sheet** — full metadata: poster, title, status badge, overview, request ID, TMDB ID, requester, date, quality profile, root folder, seasons, and download status
- Per-request TMDB metadata enrichment (title, poster, year, overview)
- **Anime-aware TV requests** — TMDB keyword detection auto-selects your Sonarr anime quality profile, root folder, and tags
- Seerr detail pages for unavailable media
- Region configuration for streaming and discover content
- **Radarr/Sonarr connection testing** with server discovery and force-import flows
**Arr queue management**
- Browse and manage **Radarr** and **Sonarr** queues directly in the app
- Delete and re-download flow via the \*arr file-delete API
- Per-series management screen (replaces per-episode redownload dialogs)
- Queue status, progress, and quality tracking
**Calendar**
- **Upcoming releases calendar** for movies and shows from your Radarr/Sonarr libraries
- Month view with release badges and filtering by media type
- Tap any date to see what's premiering
</details>
<details>
<summary><strong>Downloads & offline</strong></summary>
- Video downloads via WorkManager with progress tracking
- Series downloads with episode selection (seasons pre-fetched when opening the sheet)
- Queued, paused, resumed, and retried downloads with HTTP Range resumption
- **Auto-retry budget** (3 attempts) with pause-reason tracking — network interruptions auto-resume; user-paused downloads stay paused
- **Notification actions** — pause, resume, or cancel transfers straight from the progress notification
- Offline playback for completed downloads
- Offline Library browser organized by series
- Offline Series view for downloaded episode browsing
- **Download details sheet** — full on-disk file inventory with sizes and a storage breakdown
- **Freshness check & selective resync** — per-axis sync baselines (metadata, artwork, subtitles, trickplay, segments) with granular force-resync options
- **Offline state sync** — favorite changes made offline sync back via an outbox with fan-out
- Foreground notification with speed and ETA
</details>
<details>
<summary><strong>SyncPlay, Play On & Live TV</strong></summary>
**SyncPlay (watch parties)**
- Create and join synchronized watch groups
- Start a **watch party from any detail screen** — group creation, join, and queue seeding in one tap
- Real-time playback sync with speed-to-sync and skip-to-sync correction
- Server time synchronization for precise coordination
- Player opens app-wide automatically when a joined group starts playing
- In-player group chat
- Group settings for repeat and shuffle modes
**Play On / casting**
- Cast to and control other Jellyfin sessions from the player
- Chromecast support via Google Cast SDK
- Media session integration for lock screen and notifications
**Live TV & DVR**
- Live TV channel browsing with current program info
- Electronic Program Guide (EPG) with program timeline
- **Delivery method selection** — choose Auto, Direct Stream, or Transcode per channel, with a live play-method badge (DIRECT/TRANSCODE) and on-error delivery-method fallback
- Direct Stream support for HTSP/HLS tuners (raw MPEG-TS passthrough)
- DVR recording management
</details>
<details>
<summary><strong>Server admin, metadata editor & remote control</strong></summary>
**Admin dashboard**
- Accessible directly via settings menu for server administrators
- Real-time system health monitor showing server status, CPU/Memory load, OS details, and server controls (restart/shutdown)
- Active User Sessions: View all active devices connected to the server, view session details, and end sessions remotely
- Library stats row: Direct overview of item counts across movies, series, episodes, albums, songs, and books
- Scheduled Tasks manager: Monitor, trigger, and cancel scheduled tasks on the Jellyfin server with **live realtime tracking** (~1 s updates)
- Server Logs viewer: Browse, view, and download active server logs with severity indicators, recent activity timelines, and a **live activity-log stream** with automatic polling fallback
- Running tasks card tracking background operations with live progress updates
- User Statistics: Per-user playback history and statistics with charts
- Stale Media Scanner: Detect unwatched/stale media with background scan worker
- Watched Media Cleanup: Bulk cleanup of watched media with audit history log
**Plugin management**
- View installed server plugins with version and status info
- Enable/disable plugins remotely
- Plugin configuration viewer
- **Markdown-rendered changelogs** on the plugin detail screen
**Metadata & media editor**
- Directly accessible from the media detail screen for authorized/admin users
- Comprehensive metadata editing (title, original title, tagline, overview, premiere/release dates, sorting titles, and custom ratings)
- Rich artwork manager: Upload, update, or remove Primary, Backdrop, Banner, Logo, Art, Disc, and Thumb images
- Subtitle editor: View embedded subtitle tracks, upload external subtitle files, and delete unwanted external tracks
**Remote control**
- WebSocket-based remote control from Jellyfin server
- Receive Play, Pause, Seek, and general commands remotely
- **General-command ladder** — navigate the app remotely (GoBack, move focus, select, open context menu) and request display content, which is idle-gated and requires explicit user consent
- Media browser service integration for third-party controller apps
- Active player management and remote playback reporting
</details>
<details>
<summary><strong>JellyPlay companion server plugin</strong></summary>
JellyPlay works great against a plain Jellyfin server — but install the companion **[JellyPlay server plugin](https://github.com/raulshma/jellyfin-plugin-jellyplay)** and a set of JellyPlay-exclusive features light up. The app probes the server for the plugin's capabilities endpoint at sign-in; every feature below degrades gracefully when the plugin is absent.
**Install** (Jellyfin 12.x / .NET 10 hosts): Jellyfin Dashboard → Plugins → Repositories → add
```
https://raw.githubusercontent.com/raulshma/jellyfin-plugin-jellyplay/main/manifest.json
```
then install **JellyPlay** from the catalog and restart.
What it unlocks:
- **Settings & profile sync** — opt-in per-user sync of preferences, search history, hidden-content (continue-watching) filters, book bookmarks/annotations and home layout across your devices: last-write-wins with server-side conflict previews (keep mine / take theirs), deletions that roam both ways, per-namespace selective sync with pending counts, restore points and export/import — live via SSE with background flushes and a silent push nudge when no live connection exists
- **Admin defaults** — tri-state (unset / suggested / forced) client defaults pushed to users from the plugin dashboard, with config backup/restore
- **Events & messages** — new-media events, admin broadcasts and a rich inbox message system over per-user SSE streams
- **Seerr bridge** — server-brokered Seerr single sign-on (password + Quick Connect) with a full catch-all API proxy, so no per-user Seerr tokens live on devices
- **Newsletter** — the weekly server digest gets a real SMTP backend
- **Ratings** — MDBList aggregates, TMDB episode/season ratings, and IMDb charts with server-held API keys and caching
- **Custom & seasonal home rows** — Letterboxd / IMDb / MDBList lists and seasonal keyword rows resolved against your library
- **Anime markers** — filler / recap / canon badges (AnimeFillerList + Tenrai) with MAL↔AniList mapping
- **Recommendations** — server-scored similar items (genres / tags / people / studios / franchise)
- **User data & transcode insights** — one-response personal ratings plus book-reader bookmark/notes sync, admin transcode dashboard data and per-user download progress
Client-side architecture, sync semantics and the wire contract are documented in the [plugin guide](./docs/jellyplay-plugin.md).
</details>
<details>
<summary><strong>Platform, theming, widgets & accessibility</strong></summary>
- Multi-server Jellyfin support with auto-discovery
- Token-based and Quick Connect authentication
- **Client certificates (mTLS)** — import a PKCS#12 bundle or PEM cert/key pair (plus an optional server CA) under _Settings → Server Management_ for servers that require mutual TLS; presented automatically, fail-closed when enabled but missing
- **Server address failover** — register primary and alternate addresses (Settings → Server Management); connectivity probes pick a reachable one, failover triggers only on connection failures, and the primary is preferred again once healthy
- Multi-user support with per-server user switching and a home-screen **user switcher** chip for multi-user servers
- **Realtime user-data sync** — home rows and open detail screens refresh live from server WebSocket pushes
- Material 3 UI with dynamic theming from artwork
- Expressive animations and spring-based motion specifications
- **Material 3 Expressive navigation bar style** option
- Shared element transitions between screens (incl. season layout switching and offline artwork)
- Performance Mode (disables animations for low-end devices)
- Predictive back gesture support
- Edge-to-edge immersive layouts
- Adaptive layouts for phone, tablet, foldable, and TV
- Android TV support with D-pad navigation and Leanback launcher
- Android TV screensaver (Daydream) with configurable slideshow and Ken Burns effect
- PIN lock and biometric authentication (fingerprint/face) with auto-lock timer
- Kids Mode with content filtering
- **8 theme variants**: Standard (Material 3 dynamic), Synthwave (neon/retro), Soothing (GitHub-dark-inspired), Monochrome (black-and-white), Vivid (bold two-tone pop), Aurora (night-sky gradient, dark-only), Sakura (soft pastels), and Vector Pop (flat poster look with thick outlines)
- 9 accent color swatches (Dynamic, Brand, Sapphire Blue, Emerald Green, Amethyst Purple, Rose Pink, Coral Orange, Amber Gold, Crimson Red)
- 3 contrast levels (Default, Medium, High) with full light/dark variants
- OLED mode for AMOLED displays
- **Home screen widgets** with configurable sources:
- **Now Playing** — album art, transport controls (play/pause, next/prev, rewind/forward), and a 7-zone seek bar
- **Continue Watching** — list of in-progress media items
- **Library Recommendations** — poster grid with selectable source (Similar to Recent, Latest, Favorites, Surprise Me)
- **Seerr Recommendations** — poster grid with selectable source (Trending, Popular Movies/TV, Upcoming Movies/TV)
- Quick settings tile launcher
- App shortcuts:
- **Static**: Continue Watching, Search, Play Music, Downloads, Surprise Me, Settings
- **Dynamic**: Continue Listening — auto-updates with the currently playing track and album art
- BlurHash image placeholders for smooth loading
- Localized in 9 languages (English, Deutsch, Español, Français, Italiano, Português, 日本語, 한국어, 中文)
- Deep link support via `jellyplay://` and `https://raulshma.github.io/jellyplay/` URI schemes
- `jellyplay://media/{id}`, `jellyplay://newsletter/{section}`, `jellyplay://seerr/{tmdbId}/{type}`
- HTTPS equivalents under `https://raulshma.github.io/jellyplay/...`
- Widgets, notifications, and shortcuts all use deep links for navigation
- **Onboarding Wizard** — 10-step first-run setup (appearance, performance, home layout, player, audio, subtitles, security, Seerr), re-accessible anytime from Settings
- **Newsletter digest** — weekly server library-activity digest (Recently Added, Continue Watching, Next Up, Fresh Picks, Activity Digest, Library Stats) with Home banner, pull-to-refresh, and configurable schedule
- **Settings search** — find any setting instantly by name
- **New media notifications** — real-time per-library notifications when new content is added, with quiet hours, seen-media tracking, grouped notifications, and notification actions (configurable check interval, per-library channels, 30-day seen pruning, Open-detail / Mark-as-seen actions)
- **In-app self-update** — check, download, and install new releases directly from GitHub Releases (auto-check toggle + manual check in Settings → About; dismissed versions are suppressed for 24h; APK downloads survive restarts with cancel/re-download support and an opt-in auto-download of new releases). Every update URL is **fail-closed against a compiled-in GitHub owner/repo allow-list** before a download or browse starts
- **Desktop idle screen** _(desktop)_ — a configurable "Ready to play" ambient overlay after inactivity, respecting the screensaver-consent setting
- **Navigation customization** — global overflow menu on the navigation bar with active-download count badges, plus a tablet navigation-rail toggle
- **Settings deep-linking** — search from the home bar jumps straight into the matching settings screen with entry highlighting
- **Privacy & Data hub** — confirm-gated clearing of caches, image cache, and search history, plus sign-out and factory reset in one place
- **Factory reset** — reset all settings to defaults or per-category (15 categories), with a changed-count diff preview and a coverage guard keeping the reset list in sync
- **Home ambient backdrop** — blurred hero artwork / drifting palette blobs behind the home screen (auto-disabled in Performance Mode)
- **Accessibility** — blue light filter with strength control, reduce motion toggle, haptic feedback intensity, and font scaling
</details>
<details>
<summary><strong>Settings — 390+ options across 19 top-level sections</strong></summary>
- **Player**: engine selection, decoder mode, audio passthrough, orientation, seek duration, gesture toggles, autoplay, controls timeout, preload buffer, force direct play, refresh rate/resolution matching, A/B repeat, AV-sync
- **Audio**: default speed, gapless playback, crossfade, night mode, dialogue boost, equalizer, audio normalization, channel mix, dynamics compression, dialogue de-noise, virtualizer, reverb, volume memory, output device _(desktop)_
- **Language**: app language, preferred audio & subtitle languages, **track-selection presets & language rules**, subtitle tester
- **Subtitles**: language, style, trickplay, intro/outro skip (manual and auto), tap-to-translate, per-series role preferences
- **SyncPlay**: progress reporting, auto-join, sync correction parameters
- **Downloads**: connections preference, max cache size (with unlimited/0 option support)
- **Storage**: offline media management, cache size, download location
- **Visual**: dynamic theming, theme variant (Standard/Synthwave/Soothing/Monochrome/Vivid/Aurora/Sakura/Vector Pop), accent color, contrast level, OLED mode, streaming quality, performance mode, home backdrop
- **Navigation**: overflow menu visibility, tablet navigation-rail toggle, hide header on scroll
- **Account**: switch user, sign out / sign out from server, **server management** (primary & alternate addresses, failover, client certificates)
- **Activity & insights**: favorites, watch-progress heatmap, Radarr/Sonarr activity queue, upcoming releases, Seerr requests
- **Security**: PIN lock, biometric lock, auto-lock timer
- **Privacy & Data**: clear cache/image cache/search history, sign out, factory reset
- **Kids**: mode toggle, max content rating
- **Screensaver**: interval, Ken Burns effect, transition style, image categories, title overlay
- **Newsletter**: enable/disable, delivery day, notification badge
- **Notifications**: new media notifications, quiet hours, per-library channels
- **System**: admin dashboard entry, setup wizard, and the **desktop idle screen** (ambient "Ready to play" overlay)
- **Live TV/DVR**: channel sources, EPG refresh, recording defaults
- **Widget**: per-widget source configuration, refresh interval
- **Accessibility**: color blind modes, blue light filter, reduce motion, haptic intensity, font scaling
- **Experimental**: feature flags for in-development capabilities
- **Seerr**: server URL, API key, feature toggles, regions
- **Arr (Radarr/Sonarr)**: server URLs, API keys, connection testing, queue management
- **Calendar**: enabled libraries, media-type filters
- **About**: auto-generated open-source licenses (AboutLibraries), in-app update checker (auto-check toggle + manual check)
- **Backup & Reset**: export/import settings, per-category or full factory reset
- **Onboarding**: re-run setup wizard anytime
- **Settings search**: find any setting instantly by name
</details>
---
<a name="tech-stack"></a>
<details>
<summary><strong>Tech Stack</strong></summary>
| Category | Technologies |
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
| Language | Kotlin 2.3.21, Java 17 |
| UI | Jetpack Compose (BOM 2026.06.01), Material 3, Material 3 Expressive |
| Build | AGP 9.4.1, Gradle, KSP2 |
| TV | Android TV Material, Leanback |
| Navigation | Navigation 3 |
| DI | Koin 4.2.2 (Kotlin Multiplatform) |
| Multiplatform | Compose Multiplatform 1.11.1 (shared core/features), libmpv via JNA (desktop) |
| Storage | Room 3.0.3 (androidx.room3), DataStore Preferences, AndroidX Security-Crypto |
| Background | WorkManager, Coroutines, StateFlow |
| Video Players | Media3/ExoPlayer 1.10.1, libmpv, LibVLC |
| Subtitles | libass (ExoPlayer ASS/SSA), ASS/SSA & VTT parsing |
| Book Reader | PDFBox 3.0.5 (desktop) / pdfbox-android 2.0.27.0, junrar 8.1.1 (CBR), vendored epub.js 0.3.93 + JSZip 3.10.1 |
| Audio Effects | Android Equalizer, LoudnessEnhancer, Virtualizer, Reverb |
| Media Session | Media3 Session, Media3 Cast |
| Casting | Google Play Services Cast, DLNA/UPnP |
| Networking | OkHttp 5.4.0, Jellyfin SDK 1.8.12, kotlinx.serialization 1.11.0 |
| Images | Coil 3.4.0 (3.5.0 on Android, with BlurHash), Palette (color extraction) |
| Typography | Google Fonts (Compose integration) |
| Markdown | multiplatform-markdown-renderer (release notes, plugin changelogs) |
| Pagination | Paging 3 |
| Text Recognition | ML Kit |
| Biometrics | AndroidX Biometric |
| Testing | JUnit 4, MockK, Espresso, Compose UI Test, Robolectric, UIAutomator, OkHttp MockWebServer, Room Testing |
| Code Quality | Kover (coverage), R8 Full Mode, KSP2, CodeQL |
| Performance | Baseline Profiles (Macro Benchmark, phone & TV generators) |
</details>
---
## Requirements
- Android 9.0 (API 28) or later
- JDK 17
- Android Studio with Android SDK (compileSdk 37)
- A Jellyfin server (10.x or 12.x) for authentication and playback
- Optional: the [JellyPlay companion server plugin](https://github.com/raulshma/jellyfin-plugin-jellyplay) (Jellyfin 12.x / .NET 10 hosts) — unlocks settings sync, Seerr SSO, the newsletter backend, ratings, custom home rows and more; everything degrades gracefully without it
---
<a name="building"></a>
<details>
<summary><strong>Building</strong></summary>
<details>
<summary><strong>Prerequisites</strong></summary>
- Android Studio or Gradle CLI
- JDK 17
</details>
### Build Commands
```bash
# Debug builds (phone and TV)
./gradlew assemblePhoneDebug
./gradlew assembleTvDebug
# Release builds
./gradlew assemblePhoneRelease
./gradlew assembleTvRelease
# Desktop (JVM; Windows tested, macOS/Linux build-from-source and untested)
./gradlew :apps:desktop:run
```
The project uses product flavors — `phone` (standard mobile) and `tv` (Android TV with Leanback launcher). Release builds ship `arm64-v8a` and universal APKs; debug builds additionally produce `x86_64` and `x86` APKs for emulators and legacy Android TV system images.
<details>
<summary><strong>Desktop playback: bundled libmpv (Windows)</strong></summary>
Desktop video/audio playback goes through **libmpv** loaded via JNA. On
**Windows nothing is required from the user**: the build fetches a pinned,
sha256-verified `libmpv-2.dll` (LGPL build from the
[mpv-winbuild](https://github.com/zhongfly/mpv-winbuild) project) into the
gitignored `tools/mpv/` directory — the `fetchBundledLibmpv` task in
`apps/desktop/build.gradle.kts` — and ships it inside the installed app
image, so both `gradlew :apps:desktop:run` and the packaged MSI resolve it
automatically. The fetch needs a 7-Zip binary on the machine (the dev
package ships as `.7z`; standard on Windows dev boxes and CI runners); a
manually dropped `tools/mpv/libmpv-2.dll` always wins over the fetch, and
`-Pjellyplay.mpvDevUrl=…` pins a different archive.
On **Linux/macOS** (build-from-source, untested) the app still loads the
system `libmpv.so` / `libmpv.dylib` through JNA's normal search path. The
`MPV_LIBRARY` environment variable pointing at an absolute path overrides
everything on every OS, and a load failure now surfaces as a playback-error
dialog instead of a silent black screen.
</details>
</details>
---
<a name="local-development"></a>
<details>
<summary><strong>Local Development</strong></summary>
### Setup
1. Install the [Requirements](#requirements): JDK 17, Android Studio with SDK 37 (compileSdk), and a Jellyfin server (10.x or 12.x) to develop against.
2. Clone the repo and open it in Android Studio — Gradle sync pulls the wrapper, KMP toolchains, and the bundled libmpv fetch (see below).
3. Point the app at a local server (e.g. `http://<LAN-IP>:8096`) during onboarding, or use the seeded Docker server from `tools/e2e/bootstrap-jellyfin.sh`.
> The repo is Kotlin Multiplatform: day-to-day feature work happens in `shared/` (commonMain + platform `androidMain`/`jvmMain` actuals). `app/` is the only Android-only module.
### Run each target
| Target | Command | Notes |
| :-------------- | :--------------------------------- | :------------------------------------------------------------------------------------------ |
| Android phone | `./gradlew :app:installPhoneDebug` | Needs a device/emulator connected via adb, or run the `app` config from Android Studio |
| Android TV | `./gradlew :app:installTvDebug` | Same, on a TV device/emulator |
| Windows desktop | `./gradlew :apps:desktop:run` | First run fetches a pinned `libmpv-2.dll` — needs 7-Zip on PATH (see [Building](#building)) |
### Tests & verification
```bash
# JVM tests for a shared KMP module
./gradlew :shared:core:data:jvmTest
# Android unit tests (flavor-aware)
./gradlew :app:testPhoneDebugUnitTest
# Desktop unit tests (includes the Koin-registration guard)
./gradlew :apps:desktop:test
# Coverage report (opt-in flag required)
./gradlew koverHtmlReport -PenableCoverage
```
### Local E2E & verification lanes
`tools/e2e/` ships the driver scripts used by the project's verification passes:
- `bootstrap-jellyfin.sh` — spins up a local Jellyfin in Docker at `http://localhost:8096` (user `harness` / `harness-e2e-pass`) seeded with generated test media; requires Docker and ffmpeg.
- Desktop lanes: `desktop-session-pass.sh`, `msi-boot-pass.sh`, `desktop-native-dialog-pass.sh`, `desktop-native-dialog-flows-pass.sh`.
- Physical-device lanes (adb + UiAutomator): `device-locale-pass.sh`, `device-pip-pass.sh`.
### Tips
- Desktop playback without the auto-fetch: drop a `libmpv-2.dll` into `tools/mpv/`, or point `MPV_LIBRARY` at an absolute path to override on any OS.
- Prefer the shared tree over `app/` for new features — `app/` is Android glue (deep links, widgets, Cast, PiP host).
- After touching Koin module registration, `:apps:desktop:test` catches missing registrations that only fail at runtime otherwise.
</details>
---
<details>
<summary><strong>CI/CD</strong></summary>
A GitHub Actions workflow (`.github/workflows/release.yml`) automates release builds:
- Triggered on push to `v[0-9]+*` or `release/**` branches
- Auto-calculates version from branch name with git tag-based patch incrementing
- Builds signed release APKs for both phone and TV flavors
- Publishes APKs to GitHub Releases with auto-generated release notes
Two more workflows run alongside it:
- `.github/workflows/codeql.yml` — CodeQL security analysis on pushes/PRs to `main`, plus a weekly scheduled scan
- `.github/workflows/deploy-pages.yml` — publishes the landing page to GitHub Pages on pushes to `release-web`
A fourth workflow keeps the Kotlin Multiplatform tree honest:
- `.github/workflows/kmp-build.yml` — on pushes to `main`/`master`/`kmp-alpha` and every PR, compiles all configured targets of the `shared/` tree (JVM + Android) on Ubuntu, Windows, and macOS, runs the full `jvmTest` suite per shared module, and runs `:apps:desktop:test` (home of the Koin-registration guard)
</details>
---
<a name="permissions"></a>
<details>
<summary><strong>Permissions</strong></summary>
| Permission | Purpose |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `INTERNET` | Jellyfin API access and media playback |
| `ACCESS_NETWORK_STATE` | Network connectivity monitoring |
| `ACCESS_WIFI_STATE` | WiFi state for server discovery and streaming |
| `ACCESS_LOCAL_NETWORK` | Android 17+ (API 37) runtime permission for LAN server discovery and direct local-network connections |
| `CHANGE_WIFI_MULTICAST_STATE` | Jellyfin server auto-discovery |
| `WAKE_LOCK` | Keeps CPU/Wi-Fi awake during backgrounded streaming playback |
| `FOREGROUND_SERVICE` | Foreground service for playback and downloads |
| `FOREGROUND_SERVICE_MEDIA_PLAYBACK` | Media playback foreground service type |
| `FOREGROUND_SERVICE_DATA_SYNC` | Download worker foreground service type |
| `POST_NOTIFICATIONS` | Playback, download, and widget notifications |
| `MODIFY_AUDIO_SETTINGS` | Audio effects (equalizer, loudness, virtualizer) |
| `RECORD_AUDIO` | Required by the real-time audio visualizer |
| `USE_BIOMETRIC` | Biometric authentication (fingerprint/face) |
| `REQUEST_INSTALL_PACKAGES` | In-app self-update from GitHub Releases |
| `SYSTEM_ALERT_WINDOW` | Overlay media-controller card |
| `WRITE_EPG_INPUT` | Publishes Watch Next / EPG rows on Android TV |
</details>
---
<a name="project-structure"></a>
<details>
<summary><strong>Project Structure</strong></summary>
The codebase is Kotlin Multiplatform: features and core live in the `shared/` KMP tree (commonMain + platform actuals). The legacy Android-only core modules were folded in at the 2026-09-12 cutover — their Android halves are now `androidMain` source sets of the shared core modules — leaving `app/` the only Android-only Gradle module, beside the desktop shell.
```
apps/
desktop/ Windows desktop shell (Compose Multiplatform; libmpv engine via JNA) — preview
app/ Android application module (deep links, widgets, Cast, PiP host activity, shortcuts, TV)
shared/
core/
concurrency/ Coroutine utilities (map-concurrent, task bundling, cancellation-safe runCatching)
model/ Pure Kotlin data models (111 model files)
designsystem/ Theming (8 variants), colors, shapes, typography, motion
datastore/ DataStore preferences (390+ settings), encrypted credentials, OS keyring seam
database/ Room KMP database (20 DAOs), v57 migration chain
network/ Jellyfin API clients, Radarr/Sonarr (Arr) clients, Seerr client, TMDB, LRCLIB, Wyzie/OpenSubtitles, GitHub Releases, server discovery, address failover
data/ Repositories, playback managers, audio effects, SyncPlay, downloads; Android-only machinery (workers, receivers, media session, Cast, notifications) lives in its androidMain
ui/ Shared UI components, adaptive layouts, TV focus, animations, navigation; Android shims (biometric, WebView trailer, TV bits) in its androidMain
player-contract/ Engine-agnostic MediaEngine contract + engine-shared machinery
feature/
auth/ Server selection and authentication
onboarding/ First-run setup wizard (10-step preferences)
home/ Home screen, Kids home, newsletter banner, discover sections, and the offline home (downloaded content shelf + gate)
library/ Library browsing and media collections (auto-filters to downloads while offline)
photos/ Photo albums and full-screen photo viewer with brightness/contrast/saturation adjustments and export
search/ Search experience with history
details/ Media detail, person detail, collection detail, Seerr detail
player-video/ Video playback UI, multi-engine support, SyncPlay integration, Play On
player-audio/ Audio playback UI, lyrics, equalizer, ambient mode
player-live/ Live TV playback UI, delivery-method selection, play-method badge, error recovery
player-book/ Book reader (CBZ/CBR/PDF/EPUB — typography, bookmarks, highlights & notes, in-book search, TTS read-aloud, sleep timer, chapter tick rail)
downloads/ Download management, offline library, and offline playback
settings/ Settings, server/user management, Seerr & Arr configuration, settings search, import preview
music/ Music browsing, smart/mood playlists, artist/album details
livetv/ Live TV channels, EPG guide, and DVR
syncplay/ SyncPlay group management and watch party UI
editor/ Metadata, artwork, and subtitle editor for media items
admin/ Admin dashboard for server status, active devices, logs, tasks, user stats
newsletter/ Weekly server digest with library activity, curated picks, and stats
insights/ Watch progress heatmap with streak tracking and share-as-image
requests/ Jellyseerr/Overseerr request management with filter/sort/admin actions
arrqueue/ Radarr/Sonarr queue management, delete & re-download flow
calendar/ Upcoming releases calendar from Radarr/Sonarr libraries
shortcuts/ App shortcuts (static + dynamic, e.g. Continue Listening)
subtitle-tester/ Subtitle parser & styling test harness (dev/diagnostic tool, Android-only)
shell/ Shell-graph aggregator (appSections nav graph + ShellHostHooks shared by the Android and desktop shells)
baselineprofile/ Baseline profile generator for phone startup optimization
tools/ Dev/CI drivers: e2e/ (bootstrap-jellyfin; desktop-session / msi-boot / native-dialog passes — desktop lane scripts; device-locale / device-pip passes — physical-phone adb+uiautomator lanes), perf/ (desktop-baseline.sh), and the gitignored mpv/ drop-in dir for libmpv-2.dll (wired into :apps:desktop:test, see Building)
website/ Landing page (GitHub Pages)
docs/ Documentation guides
```
</details>
---
<details>
<summary><strong>Documentation</strong></summary>
Looking for setup, integration, or troubleshooting guides?
- [Setup guide](./docs/setup.md) — install JellyPlay on any device
- [Android TV & Fire TV setup](./docs/android-tv-setup.md) — sideload & install on the big screen
- [Jellyseerr/Seerr/Overseerr integration](./docs/jellyseerr-integration.md) — request movies & shows from inside the app
- [SyncPlay watch parties](./docs/syncplay-guide.md) — synchronized group playback
- [Offline downloads](./docs/offline-downloads.md) — download media for travel
- [Music player & synced lyrics](./docs/lyrics-music-player.md) — get the most out of your library
- [Book reader](./docs/book-reader.md) — read comics, PDFs, and EPUBs in-app
- [Player engines comparison](./docs/player-engines.md) — ExoPlayer vs libmpv vs LibVLC
- [Playback progress sync](./docs/playback-progress-sync.md) — how watch progress is reported and synced
- [Companion server plugin](./docs/jellyplay-plugin.md) — the JellyPlay server plugin: what it adds, install, and how the client integrates
</details>
---
<details>
<summary><strong>See Also</strong></summary>
Other open-source projects in the Jellyfin ecosystem:
- [jellyfin-plugin-jellyplay](https://github.com/raulshma/jellyfin-plugin-jellyplay) — the JellyPlay companion server plugin (settings sync, events, Seerr bridge, ratings, custom rows & more)
- [jellyfin/jellyfin](https://github.com/jellyfin/jellyfin) — the free software media system
- [jellyfin/jellyfin-android](https://github.com/jellyfin/jellyfin-android) — the official Android client (web wrapper)
- [jellyfin/jellyfin-androidtv](https://github.com/jellyfin/jellyfin-androidtv) — the official Android TV client
- [jarnedemeulemeester/findroid](https://github.com/jarnedemeulemeester/findroid) — third-party native Android client
- [damontecres/Wholphin](https://github.com/damontecres/Wholphin) — OSS Android TV client
- [MakD/AFinity](https://github.com/MakD/AFinity) — modern Compose + LibMPV client
- [streamyfin/streamyfin](https://github.com/streamyfin/streamyfin) — cross-platform Expo client
- [fallensword/awesome-jellyfin](https://github.com/awesome-jellyfin/awesome-jellyfin) — curated list of Jellyfin plugins, themes & clients
</details>
---
<details>
<summary><strong>At a Glance</strong></summary>
| Metric | Value |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Gradle modules | 37 (app + 9 shared core + 25 shared feature + desktop shell + baseline profile) |
| Feature modules | 25 (KMP, under `shared/feature/`) |
| Configurable settings | 390+ |
| Data models | 111 |
| API clients | 20+ |
| Room DAOs | 20 |
| Supported languages | 9 (English, Deutsch, Español, Français, Italiano, Português, 日本語, 한국어, 中文) |
| External integrations | Jellyfin, Jellyseerr/Overseerr, Radarr, Sonarr, LRCLIB, TMDB, Wyzie, OpenSubtitles, GitHub Releases (self-update), Google Cast |
| Min SDK | 28 (Android 9.0) |
| Target/Compile SDK | 37 |
</details>
---
## Contributing
We welcome contributions of all sizes — bug reports, feature requests, code,
translations, and documentation.
## Sponsor
If JellyPlay is useful to you, consider sponsoring development:
<iframe src="https://github.com/sponsors/raulshma/button" title="Sponsor raulshma" height="32" width="114" style="border: 0; border-radius: 6px;"></iframe>
## License
This project is licensed under the **GNU General Public License v3.0** — see
the [`LICENSE`](LICENSE) file for details.
By contributing to JellyPlay, you agree that your contributions will be
licensed under the same GPL-3.0 license.
## Star History
<a href="https://star-history.com/#raulshma/jellyplay&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=raulshma/jellyplay&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=raulshma/jellyplay&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=raulshma/jellyplay&type=Date" />
</picture>
</a>