Optional: prefetch lyrics for every track on the currently-playing album#193
Open
koto9x wants to merge 14 commits into
Open
Optional: prefetch lyrics for every track on the currently-playing album#193koto9x wants to merge 14 commits into
koto9x wants to merge 14 commits into
Conversation
Required usage description string for MusicKit authorization on macOS.
TDD: 3 TTML fixtures (synced/plain/malformed) + failing tests first, then XMLDocument-based parser with HH:MM:SS.mmm timecode parsing. All 3 TTMLParserTests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ns [], span fixture) - TTMLParserError now Equatable; malformed test asserts .invalidXML specifically - Empty TTML (no <p>) returns [] instead of throwing .missingBody (caller-chain falls through naturally); removed unused .missingBody case - New ttml-synced-spans.ttml fixture mirrors Apple's word-level <span> children with ttm:agent attributes; new test verifies stringValue assembles line text correctly with no XML leakage (no parser changes needed — XMLElement.stringValue concatenates child text nodes + Apple's inter-span whitespace) - Renamed local startMS -> startTimeMS; documented ms-vs-seconds convention - Expanded parseTimecode switch cases to multi-line - XCTUnwrap in fixture helper (no more force-unwraps) - Doc comment: "static block" -> "unsynced block" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lightweight CoreData migration. Adds optional appleMusicID (String?) to SongObject so fetched lyrics can be keyed by Apple Music catalog ID (Adam ID) in addition to the existing Spotify trackID. This enables cross-player cache reuse and catalog-ID-based lookup for the AM provider. New fields: appleMusicID (optional String)
- Pin koto9x/mediaremote-adapter to 6825821 (feat/expose-adam-ids branch)
which adds contentItemIdentifier + albumiTunesStoreAdamIdentifier to
TrackInfo.Payload, plus the missing CFSTR definitions that fix the linker.
- Add lastObservedCatalogID / lastObservedAlbumCatalogID vars to
AppleMusicPlayer, populated from the MediaRemote payload in ViewModel's
onTrackInfoReceived callback.
- Fix MediaController() call site: bundleIdentifier param was removed in
adapter commit b8ce5d1 ("remove broken bundle ID filtering").
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nd cache Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ext) A sheet attached to a MenuBarExtra label view is a silent no-op on macOS — the label has no NSWindow host. Route the auth trigger through an openWindow(id:) call to a dedicated Window scene, matching the existing onboarding/search/update window pattern. The auth trigger + denied alert are pulled into an AppleMusicAuthModifier to keep the MenuBarExtra label's modifier chain (and thereby the @SceneBuilder body) inside SwiftUI's type-check budget. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional albumID: String? to SongObject (lightweight migration). Used by AppleMusicPrefetcher to group cached lyrics by album and avoid re-fetching tracks already warmed for the current album. Depends on: schema v2 (appleMusicID, from Apple Music PR)
On every Apple Music track change (when authorized + albumID known), fire-and-forget warmAlbum enumerates album tracks via MusicKit catalog API, diffs against CoreData, and prefetches lyrics for uncached tracks with a bounded TaskGroup (cap=4). All failures are silent; demand-fetch on next play recovers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gating - UserDefaultStorage: add prefetchAlbumLyrics: Bool (@AppStorage, default false) - MenubarWindowView: show 'Prefetch album lyrics in background' Toggle when Apple Music is the active player; hidden otherwise - ViewModel: gate warmAlbum trigger on userDefaultStorage.prefetchAlbumLyrics; also write song.albumID when demand-fetching succeeds (mirrors prefetcher behavior) - AppleMusicPrefetcher: drop sourceProvider/userPicked writes (those fields live in the separate sticky-picks PR; this PR's schema only adds albumID)
koto9x
added a commit
to koto9x/LyricFever
that referenced
this pull request
Jul 4, 2026
Upstream PRs: - A: koto9x:upstream-pr-a-applemusic → aviwad#191 Title: Add Apple Music as a first-class lyric source via MusicKit Commits: TTMLParser, AppleMusicAuthManager, AppleMusicAuthView, schema v2 (appleMusicID only), catalog ID capture (Task 6), AppleMusicLyricProvider, ViewModel chain reorder, auth sheet trigger + Window scene fix - B: koto9x:upstream-pr-b-sticky-picks → aviwad#192 Title: Make SearchWindow manual picks sticky + add 'Reset lyrics' menu item Commits: schema v2 (userPicked+sourceProvider only), ViewModel sticky read path, SearchWindow apply, resetLyricsForCurrentTrack + menubar button - C: koto9x:upstream-pr-c-album-prefetch → aviwad#193 Title: Optional: prefetch lyrics for every track on the currently-playing album Commits: schema v3 (albumID), AppleMusicPrefetcher.warmAlbum, prefetchAlbumLyrics toggle (DEFAULT OFF), ViewModel gating Adapter dependency: ejbills/mediaremote-adapter#4 (koto9x/mediaremote-adapter feat/expose-adam-ids temporarily pinned in PR-A pbxproj until upstream merges). Stays in fork (not upstreamed): Lyrics9x provider, 3-tier romanization+translation, Plexamp player + smart routing, MediaRemote adapter callback fork-specific bits, Tailscale ATS exception, warmQueueWindow, sandbox fix for Plexamp, Kotopia Inc team/bundle ID. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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
When Apple Music is active and the user enables a new opt-in setting, LyricFever silently pre-fetches lyrics for every other track on the currently-playing album. The next time you skip a track or the album auto-advances, lyrics load instantly — no spinner.
Default: OFF. Existing users see no change in behavior unless they explicitly enable the setting.
What's included
AppleMusicPrefetcher(actor) —warmAlbum(albumID:)enumerates album tracks via MusicKit catalog API, diffs against CoreData to avoid re-fetching already-cached tracks, and fetches lyrics in a boundedTaskGroup(cap = 4 concurrent requests). All failures are silent; demand-fetch on next play recovers gracefully.SongObjectschema v3 — adds optionalalbumID: String?via lightweight Core Data migration. Used to group cached entries by album for the diff check.UserDefaultsviaObservableUserDefault;falseby default.warmAlbumfire-and-forget task is guarded byuserDefaultStorage.prefetchAlbumLyrics; the demand-fetch path also now writessong.albumID.Dependencies
If you're reviewing/merging these in order: land PR-A first, then this one.
What's NOT included
warmQueueWindow(Music.app queue enumeration) — that remains in the fork as a best-effort mechanism that doesn't yet have a reliable Apple Music queue API surface; it is NOT upstreamed in any of these three PRs.Test plan
AppleMusicPrefetcher.warmAlbum: N new tracks for album <ID>Note on schema versioning
PR-A adds schema v2 (
appleMusicID). This PR adds schema v3 (albumID). If both are merged, Xcode's automatic lightweight migration handles the two-step upgrade transparently for existing users.