IanPlayer is a native Android music player I built from scratch using Kotlin and Jetpack Compose (Material 3). What started as a simple local music player evolved into a feature-rich application with YouTube Music streaming, synced lyrics, audio visualizer recording, card generators, and a monthly music recap — all running on-device with no server costs.
In this case study, I break down the architecture, key technical challenges, and design decisions behind IanPlayer.
Kotlin Jetpack Compose Material 3 Media3 ExoPlayer MediaSession Room DB Coil Palette API InnerTube API FFT Visualizer MediaProjection MediaCodec mp3agic Coroutines
IanPlayer automatically scans all local audio files via MediaStore (MP3, M4A, FLAC, WAV, OGG) and powers playback with Media3 ExoPlayer backed by a MediaSessionService for reliable background playback. The player supports shuffle, repeat modes (Off/All/One), a drag-to-reorder queue, crossfade between tracks, and automatic pre-fetching of the next track when 8 seconds remain.
Player state persistence ensures the queue survives app restarts — the user picks up exactly where they left off.
The most technically challenging feature. IanPlayer integrates with YouTube Music via the InnerTube API (the same API the official YouTube Music app uses). It handles PoToken/BotGuard attestation through a WebView-based cipher solution (ZemerCipher), with multi-client fallback (WEB → ANDROID → IOS → Invidious) if a stream fails.
Streamed songs are cached in a two-tier system (in-memory + Room DB) to minimize repeated network requests. The app always requests the highest available bitrate (up to 256k AAC/Opus). Users can also download streamed songs with proper ID3 metadata tagging (title, artist, album art) via mp3agic.
Lyrics are fetched from lrclib.net, supporting both synced LRC format (with auto-scroll and active-line highlight) and plain text lyrics. Users can select lyric lines to generate stylized quote-style cards rendered with Compose GraphicsLayer.
Beyond lyric cards, IanPlayer includes three more card generators:
A standout feature: IanPlayer can record a video of the audio visualizer with synced lyrics overlay. It uses the Android Visualizer API (FFT) for a 14-bar audio spectrum, combines it with animated lyrics via MediaProjection + AudioPlaybackCapture, and encodes the result as H.264 + AAC using MediaCodec + MediaMuxer.
The recording runs as a foreground service (WaveProjectionService) and saves to Pictures/IanPlayer/. A static image frame capture is also available.
A Spotify Wrapped-style summary generated entirely on-device each month. The recap shows total plays, total minutes listened, top 5 artists, and top 3 songs with auto-generated taste commentary based on listening patterns. A dismissible banner appears in the Songs tab when a new recap is ready.
The now-playing screen uses ambient color extraction via the Palette API — the background, controls, slider, and lyrics are automatically tinted to match the album art's dominant color. It supports dynamic color (Material You on Android 12+), manual light/dark mode toggle, edge-to-edge display, and an animated gradient background.
The mini-player supports three layouts: Default / Floating / Queue — cycle by swiping down. The app also has a fast scroller with alphabetical index, draggable scrollbar, and swipe-to-reveal actions on song rows.
IanPlayer includes voice search using SpeechRecognizer with Indonesian language support ("id-ID"), RMS level visualization during recording, and automatic 1-minute timeout.
The built-in auto-updater checks GitHub Releases on startup and handles in-app APK download + installation via FileProvider.
The app follows a clean architecture pattern with four main packages:
The ViewModel holds the entire playback state in a single state class. This keeps the UI reactive — every screen observes the same state source and updates automatically.
The full source code is available on GitHub. It's ~20,000+ lines of Kotlin spread across 40+ files, built over the course of several months.
GitHub Repository · Releases & APK
Back to all posts