Skip to content

Import Apple Music playlists as tracklists - #129

Merged
jaasthisenna-jpg merged 1 commit into
mainfrom
claude/apple-music-import
Jul 21, 2026
Merged

jaasthisenna-jpg merged 1 commit into
mainfrom
claude/apple-music-import

Conversation

@sanylax2

Copy link
Copy Markdown
Collaborator

Adds a fourth library toolbar action: read the user's Apple Music playlists and import the ones they pick.

Apple Music audio is DRM-locked the same way Spotify's is, so this imports metadata only — each track carries a searchQuery and the existing pipeline re-sources the recording from YouTube. Same trade the Spotify importer already makes.

Why MediaPlayer and not MusicKit

MPMediaQuery gives us title + artist with only NSAppleMusicUsageDescription. MusicKit would additionally need the MusicKit App Service enabled on the App ID — a provisioning-profile change, and the TestFlight pipeline signs in the cloud, where a capability mismatch fails with "No profiles for 'com.sanylax.continuity'". The reader sits behind AppleMusicLibraryReading, so a MusicKit implementation can drop in later without touching callers.

What's here

  • ContinuityCore — AppleMusicTrack / AppleMusicPlaylistContents, plus title normalization that strips release-edition noise (Remastered 2009, - Deluxe Edition, [Explicit]) that YouTube titles don't repeat, while keeping qualifiers that name a genuinely different recording (feat., Live, Acoustic, remix credits). 17 new Linux-testable cases.
  • MetadataSourcedTrack — unifies the Spotify and Apple Music shapes so applySpotifySync generalizes into applyMetadataSync; both paths now share one sync implementation instead of a copy.
  • Domain — new PlaylistSource.appleMusic.
  • Ingest — AppleMusicLibraryReader (queries run off the main actor; MPMedia* objects never escape the closure) and PreparationQueue.importAppleMusicPlaylist.
  • App — AppleMusicImportView: permission prompt, multi-select playlist list, Settings deep-link when access is denied.

Playlists are source-backed by MPMediaPlaylist.persistentID, so sync re-reads the local library and works offline. A playlist deleted in Music leaves the local import untouched rather than wiping it, and re-importing updates in place instead of duplicating.

Verification

  • swift test in ContinuityCore: 211/211 pass (17 new).
  • Simulator build (iPhone 17 Pro, Xcode 26 beta): BUILD SUCCEEDED.
  • Device verification is yours — the permission prompt and real library reads can't be exercised on a simulator with an empty Music library.

🤖 Generated with Claude Code

Adds a fourth library toolbar action: read the user's Apple Music
playlists and import the ones they pick. Apple Music audio is DRM-locked
the same way Spotify's is, so this imports metadata only — each track
carries a searchQuery and the existing pipeline re-sources the recording
from YouTube.

MediaPlayer rather than MusicKit on purpose: MPMediaQuery gives us title
+ artist with only NSAppleMusicUsageDescription, while MusicKit would
need the App Service enabled on the App ID — a provisioning change that
breaks cloud-signed TestFlight builds. The reader sits behind
AppleMusicLibraryReading so a MusicKit implementation can replace it.

- ContinuityCore: AppleMusicTrack/AppleMusicPlaylistContents plus title
  normalization that strips release-edition noise ("Remastered 2009",
  "- Deluxe Edition") which YouTube titles don't repeat, while keeping
  the qualifiers that name a different recording (feat./Live/Remix).
- MetadataSourcedTrack unifies the Spotify and Apple Music shapes, so
  applySpotifySync generalizes to applyMetadataSync and both paths share
  one sync implementation.
- Playlists are source-backed by MPMediaPlaylist persistentID, so sync
  re-reads the local library and works offline; a playlist deleted in
  Music leaves the local import untouched rather than wiping it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jaasthisenna-jpg
jaasthisenna-jpg merged commit 6d2085d into main Jul 21, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants