LyricsData.kt
63 lines · 2.3 KB
Changed in: 0.5.0
| 1 | package dev.stave.lyrics |
| 2 | |
| 3 | import kotlinx.serialization.Serializable |
| 4 | import kotlin.time.Duration |
| 5 | import kotlin.time.Duration.Companion.milliseconds |
| 6 | |
| 7 | /** |
| 8 | * Raw response shape from `https://lrclib.net/api/get`. LRCLIB is generous about which |
| 9 | * fields it returns — plain-text-only tracks get `syncedLyrics = null`, instrumentals |
| 10 | * get `instrumental = true` with both lyrics fields null, tracks it has no record of |
| 11 | * return a 404 which we surface as [LyricsResult.NotFound]. |
| 12 | */ |
| 13 | @Serializable |
| 14 | data class LrclibResponse( |
| 15 | val id: Long? = null, |
| 16 | val trackName: String? = null, |
| 17 | val artistName: String? = null, |
| 18 | val albumName: String? = null, |
| 19 | val duration: Double? = null, |
| 20 | val instrumental: Boolean = false, |
| 21 | val plainLyrics: String? = null, |
| 22 | val syncedLyrics: String? = null, |
| 23 | ) |
| 24 | |
| 25 | /** |
| 26 | * One LRC line = timestamp + text. Timestamp is the start of the line; the line's end |
| 27 | * is the next line's start (or the track's duration for the last one). |
| 28 | */ |
| 29 | data class LrcLine(val start: Duration, val text: String) { |
| 30 | companion object { |
| 31 | fun at(millis: Long, text: String) = LrcLine(millis.milliseconds, text) |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | /** |
| 36 | * Everything the lyrics UI needs for one track. Synced lyrics give us line-level |
| 37 | * highlighting during playback; plain lyrics are shown as a static block. Both may |
| 38 | * be present; if only plain is present we show that. |
| 39 | */ |
| 40 | sealed interface LyricsResult { |
| 41 | /** Still fetching from LRCLIB (or from the on-disk cache). */ |
| 42 | data object Loading : LyricsResult |
| 43 | |
| 44 | /** Track exists in LRCLIB and has lyrics. [synced] is non-empty when the track has |
| 45 | * timestamped lyrics; [plain] is the plain-text version (may also be non-null). */ |
| 46 | data class Loaded( |
| 47 | val synced: List<LrcLine>, |
| 48 | val plain: String?, |
| 49 | ) : LyricsResult |
| 50 | |
| 51 | /** LRCLIB knows this track but the rightsholder marked it instrumental. */ |
| 52 | data object Instrumental : LyricsResult |
| 53 | |
| 54 | /** LRCLIB has no record of this track. */ |
| 55 | data object NotFound : LyricsResult |
| 56 | |
| 57 | /** External calls are disabled in privacy settings. UI surfaces this with a |
| 58 | * pointer to the setting rather than pretending we searched and found nothing. */ |
| 59 | data object PrivacyDisabled : LyricsResult |
| 60 | |
| 61 | /** Network / parse / anything else went sideways. */ |
| 62 | data class Error(val message: String) : LyricsResult |
| 63 | } |


