Lyrics pipeline
The lyrics providers, the community database, voting, and AI translation.
Lyrics come from several independent sources behind one client, SimpMusicLyricsClient, in
the :lyricsService module.
Providers
| Provider | Constant | Fetched via |
|---|---|---|
| SimpMusic Lyrics | simpmusic | getLyrics(videoId) — the project's own database |
| YouTube Transcript | youtube | The InnerTube scraper in :kotlinYtmusicScraper |
| LRCLIB | lrclib | searchLrclibLyrics(...) |
| BetterLyrics | better_lyrics | searchBetterLyrics(...) |
The active provider is stored as lyricsProvider and defaults to SimpMusic Lyrics.
Spotify lyrics sit outside this list — they need a Spotify login and are toggled separately.
The client also reaches Apple Music artist endpoints (searchAMArtist, getAMArtist) for
artist metadata, with its own token manager.
Sync formats
Depending on the source, a track resolves to word-by-word, line-synced, or unsynced lyrics.
LrcTextParser handles LRC timing.
Community database
The client is not read-only. It can write back:
insertLyrics/insertTranslatedLyrics— contribute what you havevoteLyrics/voteTranslatedLyrics— upvote or downvote an entry
Contributions are opt-in behind Help SimpMusic lyrics build the lyrics database (off by default), with an optional contributor name and email.
AI translation
Translation is separate from fetching. The app calls the user's own provider through
:aiService:
| Setting | Values |
|---|---|
aiProvider | gemini (default), openai, custom_openai |
aiApiKey | User's key — required |
customModelId | Optional model override |
customOpenAIBaseUrl / customOpenAIHeaders | Custom endpoints only |
useAITranslation cannot be switched on without a key, and turns itself back off if the key
is removed — so the feature can never be enabled in a state where it would fail on every call.
Translated lyrics can also be fetched from the shared database (getTranslatedLyrics) rather
than generated, which avoids spending API quota on a translation someone already contributed.
