Meet MusicKit for Swift

RSS for tag

Discuss the WWDC21 session Meet MusicKit for Swift.

View Session

Posts under wwdc21-10294 tag

47 Posts
Sort by:
Post marked as solved
1 Replies
336 Views
In my app I'm trying to play an Apple Music video using VideoPlayer(player: AVPlayer(url: video.url!)) where "video" is a MusicVideo instance but all I get is a blank player. video.title and video.artistName work fine I've tried using fileURLWithPath and string also, which work with hosted videos no problem (apologies for the poor use of terms, newbie)
Posted
by
Post marked as solved
1 Replies
294 Views
Hi there! I am trying to map the Apple Music API endpoints to MusicKit. For example, I am looking at the catalog playlist endpoints. To get a catalog playlist by its identifier, it is: let request = MusicCatalogResourceRequest<Playlist>(matching: \.id, equalTo: "pl.f4d106fed2bd41149aaacabb233eb5eb") let response = try await request.response() print(response.items) For multiple identifiers, it is:   let request = MusicCatalogResourceRequest<Playlist>(matching: \.id, memberOf: ["pl.f4d106fed2bd41149aaacabb233eb5eb", "pl.4b364b8b182f4115acbf6deb83bd5222"]) let response = try await request.response() print(response.items) To get its relationship like more by curator and featured artists, I can set the properties: var request = MusicCatalogResourceRequest<Playlist>(matching: \.id, equalTo: "pl.f4d106fed2bd41149aaacabb233eb5eb") request.properties = [.featuredArtists, .moreByCurator, .tracks] let response = try await request.response() print(response.items) My question is, how can I map the endpoint Get a Catalog Playlist's Relationship Directly by Name" to MusicKit: https://api.music.apple.com/v1/catalog/{storefront}/playlists/{id}/{relationship} The possible value of the relationship can be curator, library, or tracks. Where can I set these relationship values in the MusicKit request? Thank you!
Posted
by
Post marked as solved
4 Replies
504 Views
Hi there! I am trying to fetch a record label's top and latest releases. For example, for "Big Machine Label Group", I can see the top and latest releases on Apple Music. I get the latest and top releases if I use the endpoint to get a catalog record label and query parameters to extend. https://api.music.apple.com/v1/catalog/us/record-labels/1552967199?views=top-releases,latest-releases However, I am getting nil for these values using MusicCatalogResourceRequest. Here's the code: let request = MusicCatalogResourceRequest<RecordLabel>(matching: \.id, equalTo: "1552967199") let response = try await request.response() guard let recordLabel = response.items.first else { return } print(recordLabel.topReleases) print(recordLabel.latestReleases) I cannot add properties for these either to get detailed info because I think there is no PartialMusicProperty when Root is RecordLabel. Can you point me to what I am doing wrong?
Posted
by
Post marked as solved
3 Replies
485 Views
Hi there! How do I go about accessing the details of the curator? For example, if I hit the following endpoint to access details about a playlist: https://api.music.apple.com/v1/catalog/us/playlists/pl.047294ae14a24e5993d1f7ab2b127188 Then, in the response, I see the curator containing the ID under relationships: "curator": {  "href": "/v1/catalog/us/playlists/pl.047294ae14a24e5993d1f7ab2b127188/curator",  "data": [   {    "id": "976439548",    "type": "apple-curators",    "href": "/v1/catalog/us/apple-curators/976439548"   }  ] } Using this ID, I can get more information like the editorial notes, kind, artwork, etc. If I use MusicKit to get details about the playlist: let id = MusicItemID("pl.047294ae14a24e5993d1f7ab2b127188") let request = MusicCatalogResourceRequest<Playlist>(matching: \.id, equalTo: id) let response = try await request.response() guard let playlist = response.items.first else { return } print(playlist.curatorName) It does not expose the Curator object but only the curatorName. How can I access the ID of the curator?
Posted
by
Post marked as solved
1 Replies
417 Views
Hi there! I went through the Apple Music API and stumbled upon Get a Catalog Song's Relationship Directly by Name, an endpoint to fetch a song's relationship by using its identifier. If you take a look at the example given on the page: https://api.music.apple.com/v1/catalog/us/songs/1572278914/albums And see the response, it has a property called audioTraits: “audioTraits”: [ “lossy-stereo”, “lossless”, “atmos”, “spatial” ] And another one hasTimeSyncedLyrics: “hasTimeSyncedLyrics”: true Although, I cannot find these two properties in MusicKit's Song. If I hit the API directly using a developer token generated, it does not have these properties as well. I know Apple cannot disclose if these properties will be available in the future or not, but curious nonetheless.
Posted
by
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
Post not yet marked as solved
2 Replies
608 Views
Hello, I'm using systemMusicPlayer to play Apple Music Live Radio Station got from Apple Music API. But it doesn't work. How can I do that? Error: Test[46751:13235249] [SDKPlayback] Failed to prepareToPlay error: Error Domain=MPMusicPlayerControllerErrorDomain Code=6 "Failed to prepare to play" UserInfo={NSDebugDescription=Failed to prepare to play} My implementation:    let musicPlayerController = MPMusicPlayerController.systemMusicPlayer musicPlayerController.beginGeneratingPlaybackNotifications()      musicPlayerController.setQueue(with: "ra.978194965")     musicPlayerController.play() API response: { “id”: “ra.978194965”, “type”: “stations”, “href”: “/v1/catalog/us/stations/ra.978194965”, “attributes”: { “artwork”: { “width”: 4320, “url”: “https://is2-ssl.mzstatic.com/image/thumb/Features114/v4/e5/10/76/e5107683-9e51-ebc5-3901-d8fbd65f2c2a/source/{w}x{h}sr.jpeg”, “height”: 1080, “textColor3”: “332628”, “textColor2”: “120509”, “textColor4”: “33272a”, “textColor1”: “000000”, “bgColor”: “f4f4f4”, “hasP3”: false }, “url”: “https://music.apple.com/us/station/apple-music-1/ra.978194965”, “mediaKind”: “audio”, “supportedDrms”: [ “fairplay”, “playready”, “widevine” ], “requiresSubscription”: false, “name”: “Apple Music 1”, “kind”: “streaming”, “radioUrl”: “itsradio://music.apple.com/us/station/ra.978194965”, “playParams”: { “id”: “ra.978194965”, “kind”: “radioStation”, “format”: “stream”, “stationHash”: “CgkIBRoFlaS40gMQBA”, “mediaType”: 0 }, “editorialNotes”: { “name”: “Apple Music 1”, “short”: “The new music that matters.”, “tagline”: “The new music that matters.” }, “isLive”: true } },``` Thank you! Best regards, MichaelNg
Posted
by
Post not yet marked as solved
1 Replies
401 Views
Hi - Of course I may be doing something wrong, but I'm getting exactly the opposite of what I would expect from ApplicationMusicPlayer.shared.state.playbackStatus It returns .playing when the music is paused and .paused when the music is playing. Am I holding it wrong? Thanks, Daniel
Posted
by
Post not yet marked as solved
1 Replies
566 Views
Hi, I'm answering the questions on whether or not my app uses encryption. Do calls using MusicKit mean that I have to answer "Yes"? Do these calls qualify for the exemptions referred to in the App Store question: "Does your app qualify for any of the exemptions provided in Category 5, Part 2 of the U.S. Export Administration Regulations?"
Posted
by
Post not yet marked as solved
2 Replies
356 Views
Based on a twitter thread this morning I want to be clear that before asking this I did run test code... What does MusicKit's MusicSubscription canBecomeSubscriber indicate. It is returning false for me - is that because I'm already a subscriber? The docs say it is "A capability that allows your app to present subscription offers for Apple Music." So will it return false if the user is already a subscriber? Is there a condition in which it returns false if your user is not already a subscriber? (i.e. is there any reason they can't subscribe from my app using the .musicSubscriptionOffer() modifier? Thank you, Daniel
Posted
by
Post marked as solved
6 Replies
615 Views
What is the best approach to retrieve playlists using MusicKit. I can't seem to guess from the docs how to use the API to accomplish this, as well as retrieving tracks from a playlist. I am in the process of migrating code from Apple Music API to MusicKit and I potentially could use MusicDataRequest to retrieve playlists using the Apple Music API endpoints, but I want to be sure there are no better alternatives. Sample code would definitely help.
Posted
by
Post not yet marked as solved
1 Replies
305 Views
I have two questions related to the id for Playlist and Song. (1) There are two properties named id in each type. One is defined to be a MusicItemID and one is an ObjectIdentifier. How does one distinguish between them? What is the difference in how we are two use them. (2) Suppose the user has built a custom playlist of Song items in my app. Should I persist the MusicItemID and then retrieve the Song later using a MusicCatalogResourceRequest? It's a fun API to play with but there's little documentation. Thank you, Daniel
Posted
by
Post marked as solved
2 Replies
561 Views
Hi all, I am playing songs via ApplicationMusicPlayer with MusicKit for Swift and I am running into an issue where shuffle mode is sometimes automatically turned on. Even though there was no code related to shuffle mode. Here's a snippet //myQueue is an array of Tracks let player = ApplicationMusicPlayer.shared player.queue = ApplicationMusicPlayer.Queue(for: myQueue) // player.state.shuffleMode = .off // I tried explicitly setting shuffle mode off, which has no effect try await player.play() This issue is not easily reproducible, it occurs rarely and at random. But once this issue occurs it persists even after uninstalling and reinstalling the app. When I tried it to reproduce it with another device and everything works properly. Anyone else running into this issue? For Apple Engineers, here is the ticket: FB9816030
Posted
by
Post marked as solved
6 Replies
1k Views
For my app that heavily uses both ShazamKit and MusicKit, I need to be able to check if the matched song is in the user's library or not. I couldn't find an easy way to do this with MusicKit so I first then turned to the Apple Music API as they introduced the new parameter ?relate=library during this year's WWDC. When I first tried it, it worked as expected, and was very happy to have gotten it to work. However, it stopped working lately and now I turned to use MPMediaLibrary as that still works but is a lot slower in performance. Anyone has any idea why the ?relate=library stopped working for me or know a better way to check if the Song exists in the user's library? func checkInLibrary(from appleMusicID: String) async { do { let countryCode = try await MusicDataRequest.currentCountryCode let libURL = URL(string: "https://api.music.apple.com/v1/catalog/\(countryCode)/songs/\(appleMusicID)?relate=library")! let request = MusicDataRequest(urlRequest: URLRequest(url: libURL)) let dataResponse = try await request.response() print(dataResponse.debugDescription)               } catch { // I'm handling errors here }}
Posted
by
Post marked as solved
1 Replies
425 Views
Hello, I am trying to get recommendations based on the identifier of multiple tracks. But I am unable to get any results Here is the code I have used to try to get recommendations based on one album let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: URL(string: "https://api.music.apple.com/v1/me/recommendations/1571344275")!)) let dataResponse = try await dataRequest.response() For this I am getting the response: Failed to perform MusicDataRequest.Context(   url: https://api.music.apple.com/v1/me/recommendations/1571344275,   currentRetryCounts: [.other: 1] ) with MusicDataRequest.Error(   status: 404,   code: 40400,   title: "Resource Not Found",   detailText: "Resource with requested id was not found", I have tried used the identifier of songs/albums, to no success. What am I doing wrong?
Posted
by
Post marked as solved
8 Replies
955 Views
Having trouble getting the data from MusicKit Searches back to my SwiftUI view. Normally I would use a @State variable for the decodable structure, but with MusicKit you dont need to decode anything and I can't figure out how to best get the data back to my view. I call the MusicKit function using .onAppear in my SwiftUI view func getAlbum() async throws -> MusicItemCollection<Album> {         var request = MusicCatalogResourceRequest<Album>(matching: \.id, equalTo: "1440881121")         let response = try await request.response()         print(response.debugDescription)         return response.items        printing debugDescription give these results: MusicCatalogResourceResponse<Album>(   items: [     Album(       id: "1440881121",       title: "Colors",       artistName: "Beck",       contentRating: "explicit",       copyright: Fonograf Records/Capitol Records; ℗ 2017 Fonograf Records, under exclusive license to UMG Recordings, Inc.,       genreNames: [         "Alternative",         "Music"       ],       isCompilation: false,       isComplete: true,       isDigitalMaster: true,       isSingle: false,       releaseDate: "2017-10-13",       trackCount: 11,       upc: "00602557176827" Hoe would you access all of the data in the debugDescription and use it in your SwiftUI view? I can only access the standard name and id. Is anyone using Codable to move the data through a data model? The documentation is not making sense to me even though I am usually ok using it. Also, should I be using `func getAlbum() async throws -> MusicCatalogResourceResponse {' instead of using MusicItemCollection? Thanks
Posted
by
Post marked as solved
1 Replies
387 Views
I'm trying to construct what I would consider a tracklist of an Album from MusicKit for Swift, but the steps I've had to take don't feel right to me, so I feel like I am missing something. The thing is that I don't just want a bag of tracks, I want their order (trackNumber) AND what disc they're on (discNumber), if more than one disc. At the moment, I can get to the tracks for the album with album.with([.tracks]) to get a (MusicItemCollection<Track>), but each Track DOES NOT have a discNumber. Which means, in multi disc Albums all the tracks are munged together. To get to the discNumber's, I've had to get an equivalent Song using the same ID, which DOES contain the discNumber, as well as the trackNumber. But this collection is not connected to the Album strongly, so I've had to create a containing struct to hold both the Album (which contains Track's) and some separate Song's, making my data model slightly more complex. (Note that you don't appear to be able to do album.with([.songs]) to skip getting to a Song via a Track.) I can't get my head around this structure - what is the difference between a Track and a Song? I would think that the difference is that a Track is a specific representation on a specific Album, and a Song is a more general representation that might be shared amongst more Album's (like compilations). But therefore, surely discNumber should actually be on the Track as it is specific to the Album, and arguably Song shouldn't even have trackNumber of it's own? In any case, can anyone help with what is the quickest way to get get the trackNumber's and discNumbers' of each actual track on an Album (starting with an MusicItemID) please? var songs = [Song]() let detailedAlbum = try await album.with([.tracks]) if let tracks = detailedAlbum.tracks { for track in tracks { let resourceRequest = MusicCatalogResourceRequest<Song>(matching: \.id, equalTo: track.id) async let resourceResponse = resourceRequest.response() guard let song = try await resourceResponse.items.first else { break } songs.append(song) } }
Posted
by
Post not yet marked as solved
2 Replies
544 Views
Hi, I am trying to use MusicDataRequest from MusicKit to get the user's library artists (https://api.music.apple.com/v1/me/library/artists). This works well, until I am trying to use pagination with it. The data returned by this endpoint contains a "next" property, which reads /v1/me/library/artists?offset=25. Replacing the URL as such resulting in https://api.music.apple.com/v1/me/library/artists?offset=25 no longer works, as the request returns an error: MusicDataRequest.Error( status: 400, code: 40008, title: "Invalid Path Value", detailText: "Unknown library resource type 'artists?offset=25'", ... ) It seems like the request cannot handle query parameters and considers them as part of the request's path. Is there any way to use query parameters with MusicDataRequest? Thanks for any response.
Posted
by
Post marked as solved
2 Replies
496 Views
I am trying to use MusicDataRequest to search for albums, artists, and tracks using a search term like the album's names. If I use an albums Id, for example, I get results. The following code gets me results. First is the data model, the I have a class with code for authorization and then the function that searches using Music Kit struct MyAlbumResponse: Decodable {     let data: [Album] } class music {     @State var isAuthorizedForMusicKit = false     var searchTerm = ""     func requestMusicAuthorization() {         Task.detached {             let authorizationStatus = await MusicAuthorization.request()             if authorizationStatus == .authorized {                 self.isAuthorizedForMusicKit = true             } else {                 }             }         } func album() async throws {         let auth = requestMusicAuthorization()         let url = URL(string: "https://api.music.apple.com/v1/catalog/US/albums/1440881121")!         let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: url))         let dataResponse = try await dataRequest.response()         let decoder = JSONDecoder()         let albumResponse = try decoder.decode(MyAlbumResponse.self, from: dataResponse.data)         print(albumResponse.data)     } The above code returns the results I expect. But If I change the function to use the search endpoint, I do not get any results. I dont get any errors either. The data model is also different. struct AlbumSearchResponse: Decodable {     var albums: Albums }      struct Albums: Codable {     var data: [AlbumsDatum]     var href, next: String } struct AlbumsDatum: Codable {     var attributes: Attributes     var href, id, type: String } struct Attributes: Codable {     var artistName: String     var artwork: Artwork     var copyright: String     var genreNames: [String]     var isComplete, isMasteredForItunes, isSingle: Bool     var name: String     var playParams: PlayParams     var releaseDate: String     var trackCount: Int     var url: String     var editorialNotes: EditorialNotes? } class music {     @State var isAuthorizedForMusicKit = false     var searchTerm = ""          func requestMusicAuthorization() {         Task.detached {             let authorizationStatus = await MusicAuthorization.request()             if authorizationStatus == .authorized {                 self.isAuthorizedForMusicKit = true             } else {                                                       }             }         } func musicSearch() async throws {         var auth = requestMusicAuthorization()         let url = URL(string: "https://api.music.apple.com/v1/catalog/us/search?term=colors&limit=10&types=albums")!         let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: url))         let dataResponse = try await dataRequest.response()         let decoder = JSONDecoder()         let albumSearchResponse = try decoder.decode(AlbumSearchResponse.self, from: dataResponse.data)         print(albumSearchResponse.albums)         } I have gone through all of the documentation and example applications but can't find an answer to this. I dont understand why the search endpoint would be not usable, if that is the case. The workaround I have been using is to use MusicCatalogSearchRequest instead, but this does not return enough attributes and I cannot figure out how to have it return more attributes such as totalTracks, copyright, etc. I would be fine using the method if there is a way to add attributes to be included with the results. Here is the code I am using that works. It is also under the same class as the other functions. func Search() async throws {         let auth = requestMusicAuthorization()         let searchTerm = "colors"         Task {                 do {                     // Issue a catalog search request for albums matching the search term.                     var searchRequest = MusicCatalogSearchRequest(term: searchTerm, types: [Album.self])                     searchRequest.limit = 20                     let searchResponse = try await searchRequest.response()                     print(searchResponse)                 }             }         } any and all help is much appreciated. Thanks
Posted
by
Post not yet marked as solved
0 Replies
253 Views
How do we use MusicKit to search for the new Siri playlists for mood etc? I understand that Voice subscribers can't search for songs using API searches - I'm asking a question in the opposite direction. If full subscribers know the names of the new playlists they can access and play them - are there searches that will surface them? Thank you Daniel
Posted
by