Atoll: Add MusicKit animated artwork fetching for Apple Music

Uses MusicKit MusicCatalogSearchRequest to find the current track, then
fetches editorialVideo.motionTallVideo3x4 HLS URL via MusicDataRequest.
The animated artwork URL is pre-fetched on track change and cached per
song for instant availability.

Adds NSAppleMusicUsageDescription to Info.plist for MusicKit
authorization.

Signed-off-by: Jis G Jacob <studiokeys@blissroms.org>
This commit is contained in:
Jis G Jacob 2026-04-16 16:23:10 +05:30 • committed by delli
commit 3afa968236
3 changed files with 154 additions and 49 deletions

View file

@ -1451,61 +1451,15 @@ class MusicManager: ObservableObject {
let artist = artistName
Task {
let url = await fetchAnimatedArtworkURL(title: title, artist: artist)
let url = await AnimatedArtworkManager.shared.fetchAnimatedArtworkURL(
title: title, artist: artist
)
await MainActor.run {
self.videoArtworkURL = url
}
}
}
private func fetchAnimatedArtworkURL(title: String, artist: String) async -> URL? {
guard !title.isEmpty, !artist.isEmpty else { return nil }
let query = "\(title) \(artist)"
guard let encoded = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let searchURL = URL(string: "https://itunes.apple.com/search?term=\(encoded)&media=music&entity=musicVideo&limit=5")
else { return nil }
do {
let (data, _) = try await URLSession.shared.data(from: searchURL)
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let results = json["results"] as? [[String: Any]],
let first = results.first,
let previewURLString = first["previewUrl"] as? String,
let previewURL = URL(string: previewURLString)
else { return nil }
return previewURL
} catch {
return nil
}
}
func fetchHighResArtworkURL() async -> URL? {
let title = songTitle
let artist = artistName
guard !title.isEmpty, !artist.isEmpty else { return nil }
let query = "\(title) \(artist)"
guard let encoded = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let searchURL = URL(string: "https://itunes.apple.com/search?term=\(encoded)&media=music&entity=song&limit=5")
else { return nil }
do {
let (data, _) = try await URLSession.shared.data(from: searchURL)
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let results = json["results"] as? [[String: Any]],
let first = results.first,
let artworkURLString = first["artworkUrl100"] as? String
else { return nil }
let highRes = artworkURLString.replacingOccurrences(of: "100x100", with: "3000x3000")
return URL(string: highRes)
} catch {
return nil
}
}
func toggleLyrics() {
// Toggle the UI state first so the views can react immediately.
showLyrics.toggle()