How francescograzioso/meld works
1. Meld is a multi-module Android music client built in Kotlin. The app’s core idea is split across two external ecosystems: Spotify provides identity, personalization, search, and library metadata; YouTube Music provides actual audio playback.
2. The main Android application lives in app/ and is organized as a Compose-based single-app shell with feature screens, ViewModels, a DI layer, and a set of background services/receivers. MainActivity and App bootstrap navigation and theme, while most user-facing logic is pushed into viewmodels/ and ui/screens/.
3. app/ is also the orchestration layer for local state. It uses Room (db/) for persistent music data, match caches, playlists, history, recognition history, and override records, plus DataStore utilities for preferences and account/configuration state. The many schema snapshots indicate explicit migration management is a first-class concern.
4. The Spotify boundary is isolated in the spotify/ module. It handles Spotify login, token handling, GraphQL/REST access, response models, and a Spotify-specific mapping layer. In the app, this data feeds home content, search, top tracks/artists, playlists, liked songs, and recommendation inputs.
5. The YouTube Music boundary is isolated in the innertube/ module. It contains the InnerTube client, request/response models, page parsers, and YouTube URL parsing helpers. This module is the app’s main gateway for browsing YouTube Music content and resolving playback streams.
6. Playback is centered around MusicService, MediaLibrarySessionCallback, and PlayerConnection. The playback stack uses an ExoPlayer-based service, queue abstractions, download/caching support, and audio processors for features like skip silence, equalization, and playback normalization. Sleep timer and sponsor-block style processing are part of the same playback domain.
7. A key architectural flow is Spotify-to-YouTube matching. Spotify track metadata is resolved to a playable YouTube Music item through SpotifyYouTubeMapper, cached locally, and optionally overridden manually by the user. The app’s recommendation engine uses Spotify taste data to build radio-like queues before playback resolution happens.
8. Lyrics are a separate integration layer, not just UI decoration. LyricsProviderRegistry coordinates multiple providers: Better Lyrics, LrcLib, KuGou, Paxsenix, and YouTube-based sources, with translation helpers and UI components layered on top. The standalone betterlyrics/ module exists as a parser/runtime dependency for time-synced lyric rendering.
9. Social and external integrations are modularized as well. kizzy/ implements Discord Rich Presence over the Discord gateway. lastfm/ provides Last.fm auth/scrobbling support. listen together classes handle peer synchronization with a protocol/client/server split. Cast support is flavor-dependent, with separate sources for Google Play Services-enabled builds and fallback variants.
10. The app has many Android entrypoints beyond the main UI: widgets, quick settings tiles, media/session callbacks, alarm receivers, recognition foreground services, and shortcut definitions. These are wired around the same core services so playback, recognition, and remote control all converge on the shared media/session state.
11. Recognition is its own pipeline: quick settings and widget entrypoints start a foreground recognition service, which generates audio signatures and returns track identity. The result is persisted in the local database for history and reuse.
12. The repo is intentionally split into build/runtime boundaries that mirror service risk and platform availability. gms, foss, and izzy source sets provide flavor-specific implementations for cast and related Google Play Services behavior, while app/src/main/assets contains token/cipher/PoToken tooling used in playback resolution and YouTube access.
13. In diagram terms, the central hub is app/: UI and user actions flow into ViewModels, then into local persistence and the Spotify/YouTube client modules, and finally into the playback service. Everything else—lyrics, scrobbling, Discord, recognition, widgets, cast, and listen-together—hangs off that same shared session/state core.
Main entry points: MusicService.kt Playback core · InnerTube.kt InnerTube · MusicDatabase.kt Room DB · LyricsProviderRegistry.kt Lyrics
Components 20
App shell
Main Android application, UI, state, and orchestration.
- App · Application bootstrap and theme/navigation host.
app/src/main/kotlin/com/metrolist/music/App.kt - Main UI · Primary activity that launches the Compose shell.
app/src/main/kotlin/com/metrolist/music/MainActivity.kt - Navigation · App navigation graph and screen wiring.
app/src/main/kotlin/com/metrolist/music/ui/component/AppNavigation.kt - Screens · Feature screens for home, library, search, settings, and player flows.
app/src/main/kotlin/com/metrolist/music/ui/screens - ViewModels · Screen and feature state holders coordinating UI actions and data.
app/src/main/kotlin/com/metrolist/music/viewmodels - Room DB · Local music, playlist, match, history, and recognition persistence with explicit migrations.
app/src/main/kotlin/com/metrolist/music/db/MusicDatabase.kt - DataStore · Local preferences and account/configuration state management.
app/src/main/kotlin/com/metrolist/music/utils/DataStore.kt - Playback core · ExoPlayer-backed service, queue, session, caching, timers, sponsor-block, and mapping flow.
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt - Track matcher · Resolves Spotify metadata into playable YouTube Music items with local cache and overrides.
app/src/main/kotlin/com/metrolist/music/playback/SpotifyYouTubeMapper.kt - Recommendations · Builds radio-like queues from Spotify profile and taste data.
app/src/main/kotlin/com/metrolist/music/playback/SpotifyRecommendationEngine.kt
Client modules
External service boundaries and shared runtime modules.
- Spotify · Spotify auth, API access, models, and mapping helpers.
spotify/src/main/kotlin/com/metrolist/spotify/Spotify.kt - InnerTube · YouTube Music browsing, parsing, and playback request/response client.
innertube/src/main/kotlin/com/metrolist/innertube/InnerTube.kt - BetterLyrics · Time-synced TTML lyric parsing runtime used by the lyrics stack.
betterlyrics/src/main/kotlin/com/metrolist/music/betterlyrics/BetterLyrics.kt
Integrations
Optional social, lyrics, recognition, and casting features.
- Lyrics · Coordinates lyric providers, translation, and synced lyric UI.
app/src/main/kotlin/com/metrolist/music/lyrics/LyricsProviderRegistry.kt - Recognition · Foreground track recognition service and signature generation.
app/src/main/kotlin/com/metrolist/music/recognition/MusicRecognitionService.kt - Listen Together · Peer synchronization client/server and session messaging.
app/src/main/kotlin/com/metrolist/music/listentogether/ListenTogetherManager.kt - Kizzy RPC · Discord gateway and rich presence implementation.
kizzy/src/main/kotlin/com/my/kizzy/rpc/KizzyRPC.kt - Last.fm · Last.fm authentication and scrobbling support.
lastfm/src/main/kotlin/com/metrolist/lastfm/LastFM.kt
Infrastructure
Build/runtime tooling and supporting assets.
- Cast flavors · Flavor-specific Cast and Google Play Services implementations.
app/src/gms/kotlin/com/metrolist/music/cast/CastManager.kt - Playback assets · Cipher, PoToken, and player-asset tooling used for YouTube access and playback resolution.
app/src/main/assets
Connections 25
- Main UI → App: bootstraps · Activity enters the Compose application shell.
- App → Navigation: hosts · Application sets up navigation and theme.
- Navigation → Screens: routes · Navigation selects feature screens.
- Screens → ViewModels: reads state · Screens observe and drive ViewModels.
- ViewModels → Room DB: persists · ViewModels read and write local music state.
- ViewModels → DataStore: stores prefs · ViewModels and app logic use preference state.
- Playback core → Room DB: uses cache · Playback consults local matches, queues, and history.
- Playback core → Track matcher: resolves tracks · Playback mapping turns Spotify items into playable YouTube media.
- Playback core → Recommendations: builds queues · Recommendation engine seeds radio-style playback queues.
- Track matcher → Spotify: reads metadata · Uses Spotify track, album, artist, and playlist data.
- Track matcher → InnerTube: finds media · Resolves YouTube Music candidates and streams.
- Recommendations → Spotify: uses taste · Consumes Spotify profile and recommendation inputs.
- Lyrics → BetterLyrics: parses synced · Uses parser/runtime support for synced lyrics rendering.
- Lyrics → InnerTube: youtube source · Can derive lyrics from YouTube content and subtitles.
- Lyrics → App: renders in UI · Lyrics registry feeds lyric screens and components.
- Recognition → Room DB: logs history · Recognition results are stored for reuse and history.
- Listen Together → Playback core: syncs session · Peer sync is anchored to the shared playback/session state.
- Kizzy RPC → Playback core: presence from player · Rich presence mirrors current playback state.
- Last.fm → Playback core: scrobbles · Scrobbling is driven by playback events.
- Cast flavors → Playback core: casts session · Flavor-specific cast handlers plug into the media session.
- Playback assets → InnerTube: supports access · Token and cipher tooling help YouTube access and stream resolution.
- Playback assets → Playback core: enables playback · Playback resolution depends on asset-backed tooling.
- Recognition → Screens: launches flows · Widget and quick settings entrypoints reach recognition screens.
- Spotify → Room DB: fills caches · Spotify-derived matches and library data are cached locally.
- InnerTube → Playback core: provides media · YouTube Music content and stream data feed playback.