MusicKit

RSS for tag

Let users play Apple Music and their local music library from your app using MusicKit.

MusicKit Documentation

Posts under MusicKit tag

206 Posts
Sort by:
Post not yet marked as solved
0 Replies
68 Views
Is it possible to play songs/playlists on another device on the same account of the user. Effectively, remote control. ex: I own a Mac Book and an iPad, my iPad is connected to speakers, I want to stop and start playing music on the iPad using my Mac Book, through APIs.
Posted
by Afshin9.
Last updated
.
Post not yet marked as solved
1 Replies
383 Views
I have MusicKit integrated into an Android app and it works fine for most users, but some users report that it seems to successfully authenticate but it doesn't play their music. Logs from their devices show errors like this during MediaPlayerController configuration: log D/SVAudioRendererNative: FootHillConfig::config() id: 0123456789abcde E/SVAudioRendererNative: KDSetAndroidID() ERROR status: 4294924646 I omitted the id value in the config log, but the number of characters is accurate - 15 in the logs from problem devices, while I've noticed that logs from test devices seem to have 16 character ids in this log entry. Throughout the time that MediaPlayerController is active (and should be playing music), this log is continually seen: log E/SVAudioRendererNative: SVFootHillPExchange::SVFootHillPExchange() ERROR 4294924645 retrieving SPC I haven't seen any other errors propagating to the Java level or being logged. What can I do to solve this issue for our users?
Posted Last updated
.
Post marked as solved
1 Replies
91 Views
Hi, I'm trying out the beta for music kit. In the current version of my app, my widget can show multiple albums. I preload the images of the album covers. In the beta's the url that is returned for the artwork starts with: "musickit://", which does not work with URLSession. How can I preload the data using the new url scheme? Current code:     func fetchArtworkFor (musicID: MusicItemID, url : URL?) async throws -> UIImage? {         guard let url = url else {             return nil         }         let urlRequest = URLRequest (url: url)         let data = try await URLSession.shared.data(for: urlRequest)         let image = UIImage(data: data.0)         return image     } // Some other function         for album in albumsToShow {             if let url = album.artwork?.url(width: context.family.imageHeight, height: context.family.imageHeight), let image = try? await fetchArtworkFor(musicID: album.id, url:url) {                 images[album] = image             }         }
Posted
by dongelen.
Last updated
.
Post not yet marked as solved
1 Replies
155 Views
Hi I am working on a music app where I can do some sound analysis, my end goal is to integrate Apple Music API in my app where users can search songs. When the song is played I want to show a type of soundwave/spectrogram. For sound visualization I have AVFoundation but the Music API returns only song ID which could be played using Apple MediaPlayer framework only. Is there any API for doing sound analysis or can I play the Apple music songs using AVFoundation.
Posted
by FJaffri.
Last updated
.
Post not yet marked as solved
7 Replies
216 Views
Hi there, tl;dr: What's the best way to get all tracks (with catalog IDs) from a playlist that has more than 100 tracks, using MusicLibraryRequest. I'm doing something dumb, not understanding something, and possibly both. I've got an existing, kinda okay function that uses the MusicDataRequest and the Apple Music API to fetch all tracks from a playlist, with pagination like this: func getTracksFromAppleMusicLibraryPlaylist(playlist: AppleMusicPlaylist) async throws -> [MusicKit.Track]? {     var tracksToReturn: [MusicKit.Track] = []     var libraryTracks: [AppleMusicLibraryTrack] = []     @Sendable     func fetchTracks(playlist: AppleMusicPlaylist, offset: Int) async -> AppleMusicPlaylistFetchResponse? {         do {             let playlistId = playlist.id             var playlistRequestURLComponents = URLComponents()             playlistRequestURLComponents.scheme = "https"             playlistRequestURLComponents.host = "api.music.apple.com"             playlistRequestURLComponents.path = "/v1/me/library/playlists/\(playlistId)/tracks"             playlistRequestURLComponents.queryItems = [                 URLQueryItem(name: "include", value: "catalog"),                 URLQueryItem(name: "limit", value: "100"),                 URLQueryItem(name: "offset", value: String(offset)),             ]             if let playlistRequestURL = playlistRequestURLComponents.url {                 let playlistRequest = MusicDataRequest(urlRequest: URLRequest(url: playlistRequestURL))                 let playlistResponse = try await playlistRequest.response()                 let decoder = JSONDecoder()                 // print("Get Tracks Dump")                 // print(String(data: playlistResponse.data, encoding: .utf8)!)                            let response = try decoder.decode(AppleMusicPlaylistFetchResponse.self, from: playlistResponse.data)                 return response             } else {                 print("Bad URL!")             }         } catch {             print(error)         }         return nil     }     Logger.log(.info, "Fetching inital tracks from \(playlist.attributes.name)")     if let response = await fetchTracks(playlist: playlist, offset: 0) {         if let items = response.data {             libraryTracks = items         }         if let totalItemCount = response.meta?.total {             Logger.log(.info, "There are \(totalItemCount) track(s) in \(playlist.attributes.name)")             if totalItemCount > 100 {                 let remainingItems = (totalItemCount - 100)                 let calls = remainingItems <= 100 ? 1 : (totalItemCount - 100) / 100                 Logger.log(.info, "Total items: \(totalItemCount)")                 Logger.log(.info, "Remaining items: \(remainingItems)")                 Logger.log(.info, "Calls: \(calls)")                 await withTaskGroup(of: [AppleMusicLibraryTrack]?.self) { group in                     for offset in stride(from: 100, to: calls * 100, by: 100) {                         Logger.log(.info, "Fetching additional tracks from \(playlist.attributes.name) with offset of \(offset)")                         group.addTask {                             if let response = await fetchTracks(playlist: playlist, offset: offset) {                                 if let items = response.data {                                     return items                                 }                             }                             return nil                         }                     }                     for await (fetchedTracks) in group {                         if let tracks = fetchedTracks {                             libraryTracks.append(contentsOf: tracks)                         }                     }                 }             }         }     } // props to @JoeKun for this bit of magic     Logger.log(.info, "Matching library playlist tracks with catalog tracks...")     for (i, track) in libraryTracks.enumerated() {         if let correspondingCatalogTrack = track.relationships?.catalog?.first {             tracksToReturn.append(correspondingCatalogTrack)             print("\(i) => \(track.id) corresponds to catalog track with ID: \(correspondingCatalogTrack.id).")         } else {             Logger.log(.warning, "\(i) => \(track.id) doesn't have any corresponding catalog track.")         }     }     if tracksToReturn.count == 0 {         return nil     }     return tracksToReturn } While not the most elegant, it gets the job done, and it's kinda quick due to the use of withTaskGroup .esp with playlists containing more than 100 songs/tracks. Regardless, I'm kinda stuck, trying to do something similar with the new MusicLibraryReqeust in iOS 16. The only way I can think of to get tracks from a playlist, using MusicLibraryRequest, having read the new docs, is like this: @available(iOS 16.0, *) func getAllTracksFromHugePlaylist(id: MusicItemID) async throws -> [MusicKit.Track]? {     do {         var request = MusicLibraryRequest<MusicKit.Playlist>()         request.filter(matching: \.id, equalTo: id)         let response = try await request.response()         if response.items.count > 0 {             if let tracks = try await response.items[0].with(.tracks, preferredSource: .catalog).tracks {                 Logger.log(.info, "Playlist track count: \(tracks.count)")                 return tracks.compactMap{$0}             }         }     } catch {         Logger.log(.error, "Could not: \(error)")     }     return nil } The problem with this is that .with seems to be capped at 100 songs/tracks, and I can't see any way to change that. Knowing that, I can't seem to tell MusicLibraryRequest that I want the tracks of the playlist with the initial request, where before I could use request.properties = .tracks, which I could then paginate if available. Any help setting me on the right course would be greatly appreciated.
Posted Last updated
.
Post not yet marked as solved
1 Replies
115 Views
Hi there! I have been trying to play the music videos we get from Apple Music API and have been unsuccessful. Here's my code: var video: MusicVideo var body: some View { VideoPlayer(player: AVPlayer(url: video.url!)) } I know the URL from the MusicVideo is not in a music format but just the URL to the video in the Apple Music catalog. How do I go about playing it without using something like MPMusicPlayerController.systemMusicPlayer.openToPlay(queueDescriptor) and provide an in-app experience (and not take the user to the Apple Music app)?
Posted
by snuff4.
Last updated
.
Post marked as solved
4 Replies
459 Views
Hi there! I am working on the genres screen and realised that I can directly use MusicCatalogResourceRequest for fetching genre with a particular ID: func getGenres() async {     do {       let genreID = MusicItemID("17")       let request = MusicCatalogResourceRequest<Genre>(matching: \.id, equalTo: genreID)       let genreResponse = try await request.response()       print(genreResponse.items)     } catch {       print(error)     }   } Apple Music also has an API to get the top charts genres. How would I do it without using MusicDataRequest, or is it the only way? My current approach: typealias Genres = MusicItemCollection<Genre> do { let countryCode = try await MusicDataRequest.currentCountryCode let genreURL = "https://api.music.apple.com/v1/catalog/\(countryCode)/genres" guard let url = URL(string: genreURL) else { throw URLError(.badURL) } let request = MusicDataRequest(urlRequest: URLRequest(url: url)) let response = try await request.response() let genre = try JSONDecoder().decode(Genres.self, from: response.data) print(genre) } catch { print(error) } Thank you!
Posted
by snuff4.
Last updated
.
Post marked as solved
3 Replies
119 Views
Hi there! I was experimenting with the MusicCatalogChartsRequest. I have one doubt, and I do not know if it is the intended behavior. If I have the kinds as [.cityTop] and the types as [Song.self], why does it print the city playlists and the top played playlists? Ideally, it should print an empty array, right? As I have only Song as a type? var request = MusicCatalogChartsRequest(kinds: [.cityTop], types: [Song.self]) request.limit = 1 let response = try await request.response() print(response.playlistCharts) The output is: [MusicCatalogChart<Playlist>(  id: "city-top:cityCharts",  kind: .cityTop,  title: "City Charts",  items: [   Playlist(    id: "pl.db537759ae3341eaa600bc5482209f7c",    name: "Top 25: Mumbai",    curatorName: "Apple Music",    isChart: true,    kind: "editorial",    lastModifiedDate: "2022-06-21",    url: "https://music.apple.com/in/playlist/top-25-mumbai/pl.db537759ae3341eaa600bc5482209f7c"   )  ],  hasNextBatch: true ), MusicCatalogChart<Playlist>(  id: "most-played:playlists",  kind: .mostPlayed,  title: "Top Playlists",  items: [   Playlist(    id: "pl.f4d106fed2bd41149aaacabb233eb5eb",    name: "Today’s Hits",    curatorName: "Apple Music Hits",    isChart: false,    kind: "editorial",    lastModifiedDate: "2022-06-21",    shortDescription: "Drake gets loose with “Sticky”.",    standardDescription: "Among the many surprises of Drake’s <i>Honestly, Nevermind</i>—not the least of which is the album’s very existence—is that it isn’t really a hip-hop album at all; he’s mainly singing. But “Sticky” is one of the few tracks where the project’s commitment to exploring dance music—courtesy here of production work from Australian artist RY X and Gordo (aka DJ Carnage)—meets actual rapping. Add Today’s Hits to your library to stay up on the biggest songs in pop, hip-hop, R&B and more.",    url: "https://music.apple.com/in/playlist/todays-hits/pl.f4d106fed2bd41149aaacabb233eb5eb"   )  ],  hasNextBatch: true )] Thank you!
Posted
by snuff4.
Last updated
.
Post not yet marked as solved
2 Replies
127 Views
Hi there, This is more of a "how-to," "am I doing this right?" question, as I've never done this before, and I couldn't find any definitive write up for how to do this, so I'm asking here. With the release of iOS16 beta, I've been implementing some new MusicKit features in an iOS app I'm working on that was initially built for iOS 15. Setup: dev machine: masOS Monterey 12.4 test device 1: iOS 15.4 test device 2: iOS 16 beta 2 Xcode versions: 14.0 beta 2 (14A5229c) 13.4.1 (13F100) The original app was written, using Xcode 13 and has an iOS Development Target of 15.0 Steps: create new branch off main called beta16 open Xcode beta2 and switch to new branch set the iOS Development Target for the project to 15.0 make code changes in the new branch, using ifavailable to handle both iOS 16 and fallback version code. Results: When I test the new code using Xcode 14 beta 2 on an iOS 16 device, things work as expected. When I test the new code using Xcode 14 beta on an iOS 15 device, the app builds and then crashes immediately upon open with: dyld[38909]: Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs   Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp   Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs   Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp   Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit When coding, I followed all of Xcodes prompting that says when a potentially unsupported new feature is being used. When I look to where .includeTopResults is being used, I can see that it was not wrapped with ifavailable: var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])     request.includeTopResults = true let response = try await request.response() If I comment out the line with .includeTopResults, the app runs on the iOS 15 device w/o issue. If I wrap it in ifavailable, like this, it crashes as before: var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self]) if #available(iOS 16, *) {     request.includeTopResults = true } let response = try await request.response() If I check the docs here, I think I'm using .includeTopResults correctly. Question: My main question here is if I'm correctly developing the app toward the goal of supporting new iOS 16 features, while also supporting devices using iOS 15, via fallback. Ultimately, I plan to merge the beta16 branch into a branch from which I'll deploy the app. The app crashing when using .includeTopResults has me hesitant because I don't know if that's a bug or if I'm the bug. Usually, it's the latter. It seems like the steps outlined above are the correct way to develop toward supporting upcoming features and "legacy iOS versions", but I'm not sure. Any clarity on this would be most appreciated. Thanks!
Posted Last updated
.
Post marked as solved
2 Replies
108 Views
Hi , I have a usecase where I need to add multiple songs to apple music playlists. I am using MPMediaplaylist.addItem(withProductID: ) function to add a single song to the playlist. Is there a way to convert the song to MPMediaItem so that I can use MPMediaplaylist.add([MPMediaItem]) to add multiple songs to the playlist? Regards
Posted
by Nitishbll.
Last updated
.
Post not yet marked as solved
6 Replies
409 Views
I'm trying to stream an array of Apple music songs that are not tied to a single playlist. I have all the id's of these songs and I can play them individually if I use "setQueue" such as this:    await musicKit.value.setQueue({   songs: ["1616228595", "1564530724"],     autoplay: true,     }); After the first song finishes playing it just stops altogether. How can I have the next song in the array play? I'm able to use:   await musicKit.value.skipToNextItem();   await musicKit.value.skipToPreviousItem(); And that works fine to toggle between the songs in the array, but I haven't found anything that shows an example of how this would be done with an array of songs such as I have. What do I need to add in order to get this playing songs back to back in from the song array?
Posted
by gonzosan.
Last updated
.
Post not yet marked as solved
0 Replies
107 Views
Hello, I'm new to the Swift MusicKit API and am starting with the implementation in iOS 16. I'm getting stuck on an issue where there is no background or text color associated with the Artwork object. Is this something you have to make an additional property request for, and if so, how do you do that? var catalogSearch = MusicCatalogResourceRequest<Album>(matching: \.id, equalTo: item.id) let catalogResponse = try await request.response() guard let firstItem = catalogResponse.items.first else { return } In this example, firstItem.artwork only contains the url and what look like incorrect max width/height values. here's a printout of firstItem.artwork Optional(Artwork(   urlFormat: "musicKit://artwork/library/5F37858D-F46B-4F12-BA67-40FA8DD63D87/{w}x{h}?at=item&fat=&id=7718670444435992305&lid=5F37858D-F46B-4F12-BA67-40FA8DD63D87&mt=music&aat=Music122/v4/37/25/f5/3725f515-249f-7b91-77bb-f479cd48201c/22UMGIM32254.rgb.jpg", maximumWidth: 0, maximumHeight: 0 ))
Posted Last updated
.
Post marked as solved
2 Replies
211 Views
I am making a media player for Apple iOS and wanted it to be able to pull my music library using an API. The closest thing I found to this is this: https://developer.apple.com/musickit/ However, I don't know if it will allow users to play their music purchased by apple. Does anyone know how to do this so the user logs into their apple account through my app and then has complete access to their movies, tv shows, and music? Any answers are really appreciated I did my best to find the answer to this and know its annoying to ask these questions when google or apple has it documented somewhere.
Posted
by Xylapple.
Last updated
.
Post marked as solved
4 Replies
629 Views
Is there any sign of an update to MusicKit JS? The 1.x version still seems to be the only one available despite updates to the iOS and MacOS SDKs. The 1.x version has been fairly unreliable for me and I've paused updates to Apple Music support in my app in hopes that a better version is coming soon.
Posted
by farleyja.
Last updated
.
Post not yet marked as solved
1 Replies
173 Views
I have my music kit instance setup with a few songs:   await musicKitInstance.setQueue({     songs: ["726416473", "1099848811"],     startPlaying: true,   }); Previously I was having issues with tracks playing back to back, but with these tracks I don't have this issue. I wanted this queue to continue looping. I then thought to add:   await musicKitInstance.setQueue({     songs: ["726416473", "1099848811"],     startPlaying: true, repeatMode:1   }); and that does loop, but it only loops the last song. I also changed it to 2 and it does the same thing. I looked through the docs, but they don't really explain this from what I saw. If there's some documentation that clearly explains the various options I can use for the music kit instance I'd like to see it.
Posted
by gonzosan.
Last updated
.
Post not yet marked as solved
2 Replies
939 Views
We're using  https://developer.apple.com/documentation/musickitjs to authorize Apple music, on Desktop it opens a new window to authorize to apple. But It's NOT working on mobile In-App Browser (both iOS &amp; Android), probably because on mobile messenger, it's not possible to allow the opening of multiple windows. Are we missing something here? Any workaround for it? Has anyone done that?
Posted
by baltech.
Last updated
.
Post marked as solved
1 Replies
137 Views
Hi there! I was using the Apple Music app and stumbled upon Categories. For example, if you search for Apple Music Party, the first result is a Category that shows a list of playlists. How do I access these using MusicKit? Is Categories Music exclusive only or available to third-party developers?
Posted
by snuff4.
Last updated
.