Repository navigation
Conversation
loucass
force-pushed
the
fix/offline-first-media
branch
from
November 3, 2026 14:25
52b9120 to
d0e044e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Downloaded songs now behave truly offline-first: saved lyrics appear instantly, and downloaded songs keep their cover art on disk instead of relying on Coil's 24-hour cache.
The Problem
What I experienced: I download songs to listen offline. When opening a downloaded track with no internet, the lyrics and cover art took a long time to appear — sometimes they didn't show at all until a network request timed out. At first I thought the app simply wasn't downloading lyrics. After inspecting the code, I found the root cause.
Why it happened:
The Fix
1. Lyrics: Show saved first, refresh later
File:
SharedViewModel.getLyricsFromFormatshowSavedLyricsFirst(song, duration)which:lyricsCanvasRepository.getSavedLyrics(videoId)from the local DBLyricsProvider.OFFLINE(UI already displays "Offline" badge)saveToDatabaseflag onupdateLyricsgates both.2. Cover Art: Pin covers for downloaded songs
New files:
ArtworkStore(common interface) +NoOpArtworkStore(Desktop)AndroidArtworkStore(Android implementation,filesDir/artwork/)ArtworkFiles.kt— filename logic ({videoId}.jpgfor ytimg, SHA-256 of canonical URL otherwise)LocalArtworkInterceptor.kt— Coil interceptor, registered beforeNetworkFirstInterceptorBehaviour:
PREPARING/DOWNLOADING,observeDownloadedArtwork()launchessaveArtworkFor(videoId)off the collector (so conflated state flow doesn't drop transitions).MainActivity.onStartcallsensureDownloadedArtwork()to backfill covers for downloads that predate the feature and to finish in-progress ones.retainOnly(urls)keeps covers for both downloaded and downloading songs, then deletes orphaned files.deleteArtworkIfUnused(videoId, thumbnails)— builds a keep-set from all downloaded/downloading songs and only deletes if the file isn't shared (album art survives removing one track).retainOnly(emptyList())→ all pinned covers removed.NetworkFirstInterceptorwith the existing 24-hour rule.TurntableWidgetnow usescontext.imageLoader(singleton) so pinned covers resolve there too.Testing
./gradlew :composeApp:jvmTest— addsArtworkFilesTest(4 tests: ytimg naming, size-segment stripping, distinct images, blank URLs)./gradlew :androidApp:assembleDebug— debug APK buildsNotes
NoOpArtworkStore.Linked issue
Closes #2777
Closes #2602
Closes #2829
Checklist
i will download the debug apk and test it