Music Kit API library ID into something i can use on the device

Hi,


i'm playing around a little bit with the muscia kit REST Api.

As long i'm accesing the catalog, e.g. https://api.music.apple.com/v1/catalog/de/search?term=james+brown&limit=2&types=artists,albums, the api return store ids. I then can use the store ids together with MPMusicPlayerController.

But if i'm accessing my library, the id is something like i.addWKtl6kQE. Is there any way to translate this id in something usefull for MPMusicPlayerController? Right now i'm only able to use the store id and the persistent id together with MPMusicPlayerController.

So from that point there is no connection between playing songs on a device and using the Music Kit API?

  • I am not able to play the song after 30 seconds i am getting preview url in the api not the full song url is there any update on this ? Thanks

Add a Comment

Replies

I am also having the same issue

If that song is a song that was added via apple music then when you look for the song in your library you want to reference the playbackStoreID https://developer.apple.com/documentation/mediaplayer/mpmediaitempropertyplaybackstoreid?language=objc


However if that song was added from an album you copied over from your computer to your device then you'd have to search the api for the corresponding track id assuming you can find it and it is offered on Apple Music

Thank you for the answer. But that is not the solution.


Every request to https://api.music.apple.com/v1/catalog/... return a playback store id (like 234762374) i can use on the device.

But calls to https://api.music.apple.com/v1/me/... will return something like i.addWKtl6kQE. There is no respondig id on the device. So i have no idea how to search for these kind of ids.

The Interacting with Apple Music Content content sample may help you with this. It shows how to play back local content in the users library as well as from Apple Music using the MPMusicPlayerController.


Interacting with Apple Music Content

https://developer.apple.com/sample-code/wwdc/2017/Interacting-with-Apple-Music-Content.zip

Thank you for the reply. I already checked the sample code. But that is a very good point to see my problem.

Can you please change one static definition in AppleMusciRequestFactory.swift for me?


Just static let recentlyPlayedPathURLString = "/v1/me/recent/played"

into static let recentlyPlayedPathURLString = "/v1/me/library/recently-added"


And in MediaItem.swift

enum MediaType: String {

case songs, albums, stations, playlists, libraryalbums = "library-albums"

}


Then the recent tab will show the last 10 entries you added to your media lib. Just search the catalog and press + on the right side of an entry.


Now back to the problem: recent/played will return media catalog ids. E.g. 21332844. library/recently-added will return ids like i.addWKtl6kQE. How i can pass this id (i.addWKtl6kQE) to MPMusicPlayerController.systemMusicPlayer?


Can you change the example in a way that i can press play in the recent list and get the right song?



Sincerely

Did you ever find a solution to this?

Hi,


I'm also stuck with the same issue now. Did you ever find a solution to this s**king problem?

I have ran into the same issue. I have found that when using a song id from a user's music library, the music player plays a different song from their music library, or does not play a song at all.

Would be great if the personal library song id vended could be the same playbackID as the search catalog, or the song id would play the correct song.

Here looking for the answer to this too, did you ever find a solution?

Has anyone figured this out yet?


I'm trying to use the library id (e.g. l.NP4oWSo) to play my library content from the Apple Music API (e.g. /v1/me/library/albums). I want to be consistent in using the MusicKit APIs vs using an MPMediaItemCollection, which is what is referenced in the Adding Content to Apple Music example referenced by 3ZS above.


The most consistent way to handle content coming from either the store catalog or the user's library is to use the Play Params returned from MusicKit, which contain metadata about the album or track, including id (l.NP4oWSo format for library items and an larger Integer for catalog items) and even an isLibrary key that is set to true for library items.


So the playParams from MusicKit for a library album item look like:


{
  "id": "l.JmwYn9g",
  "kind": "album",
  "isLibrary": true
}


So my current thinking has been to try and create an MPMusicPlayerPlayParametersQueueDescriptor using the above play param [String: Any] dictionary.


From Apple's own documenatation on this object:


A set of properties and methods used to modify how items are played, based on play parameters returned from MusicKit API results. Use this class to modify the player queue created by a query before the queue begins to play. You can modify when individual items start and stop playing, along with setting the first item to be played.


So this seems like it should, work. I should be able to pass any play parameters from the Apple MusicKit api, per this documentation, and it will take those parameters and figure out how to set the queue and play the item. My code looks like:


let playParams: [String: Any] = ... // from MusicKit api object attributes/playParams

guard let playerPlayParams = MPMusicPlayerPlayParameters(dictionary: playParams) else {
     // handle error if play params can't be parsed by initializer
     return;
}

let queue = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: [playerPlayParams])

let musicPlayerController = MPMusicPlayerController.systemMusicPlayer
musicPlayerController.setQueue(with: queue)
(musicPlayerController as MPMediaPlayback).play()


Alas, this doesn't work. If there's no items in the queue already, it will not play anything, and if there are existing queue items it will not modify them before playback (e.g. plays the current queue).


I really want to work with this API, but so far the documentation has been very lacking and from this thread it seems like this library vs catalog playback issue is very confusing to anyone who is wanting to create awesome Apple Music apps.


I hope someone has figured this out, or someone from Apple will reply to this thread with more info as I've spent a lot of time trying to figure this out and have spent a lot of time documenting the issues in this post. The current example is very lacking in doing anything other than basic playback from the device library or playback of catalog requests (e.g. recently played api queries or search api queries). For those of us wanting to provide users of our MusicKit apps a great experience that references a user's music library in addition to just the catalog, we need to figure out a real way to handle this issue.


And just my 2 cents, as feedback the real differentiator of something like Apple Music vs Spotify, for me anyway, is the ability to have library items alongside streaming catalog items (e.g. stuff you have stored on iTunes Match) and so the inability to work with this via the api in an effective way is frustrating.

Some additional info here that I've found in continuing to play around with this, in case it's helpful to anyone.


The play params for an album will not work I think unless a catalogId is present, and that does not seem to be returned in the play params for albums, but it is returned for tracks.


So for instance, a track will have the following playParams:


{
     "isLibrary": true,
     "reporting": true,
     "id": "i.eoD8YY7F69M2gA",
     "kind": "song",
     "catalogId": "999887109"
}


which then can be used like so:


var playParamList = [MPMusicPlayerPlayParameters]()

// an album is a object of parsed json from MusicKit, including tracks which have also been parsed from
// the MusicKit response

// using for loop here vs map for code readability
for track in album.tracks {
     guard let pp = MPMusicPlayerPlayParameters(dictionary: track.playParams) else {
          continue
     }
                
     playParamList.append(pp)      
}

let q = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: playParamList)
musicPlayerController.setQueue(with: q)
(musicPlayerController as MPMediaPlayback).play()


This actually works...


However, again here you need the catalog id in the playParams payload. I think as far as I can tell you are SOL on any of this if you just have the id that looks like i.eoD8YY7F69M2gA so I'm not sure what the point of having this data is at all really... I'm still totally lost on how you'd play something that didn't have a catalog id but was returned from MusicKit, I just wanted to paste this code here in case someone else was trying to figure out the play params queue descriptor because there aren't any examples anywhere else on the internet.

Thanks for your investigations. Currently I'm working on something else, but I'll look into this.

Hey,


About 2 weeks ago Apple updated their API output to include additional information in the playParams. Specifically, songs saved from the catalog will have a catalogId and reporting set to True. This is GREAT because you can play the song using the catalogId. I have also noticed that songs I have purchased, will have a purchasedId attribute and reporting set to False. The purchasedId did not play the correct song, similar to libraryIds. It looks like this output is experimental by Apple, and those catalogIds/purchasedIds could disappear in the future.


{

attributes = {

albumName = "Songs of Innocence";

artistName = U2;

artwork = {

height = 1200;

url = "https://is5-ssl.mzstatic.com/image/thumb/Features1/v4/75/26/06/75260685-4a6d-7342-9ad8-c5a56e5b8c50/mza_3295371297510140818.jpg/{w}x{h}bb.jpeg";

width = 1200;

};

durationInMillis = 239846;

name = "California (There Is No End to Love)";

playParams = {

id = "i.LVk6rMYU0zNXLD";

isLibrary = 1;

kind = song;

purchasedId = 915794181;

reporting = 0;

};

trackNumber = 3;

};

href = "/v1/me/library/songs/i.LVk6rMYU0zNXLD";

id = "i.LVk6rMYU0zNXLD";

type = "library-songs";

},


So, a strategy is to take the information available from a library song and perform a catalog request and compare to get a 'best match'. Then, you will have a catalogId to play a song. Lots of workarounds I'm trying...

Oh, intersting so that catalogId is new or experimental...


Yeah, the solution I've landed on is to do a catalog search and fill in as much as I can with catalogIds. It would be nice if there were some way to playback from the libraryId though, if the relevant library item does not exist in the apple music catalog.


Thanks @higginator!

Thank you for post, I am having a simular problem with playing a library playlist. I am able to play tracks with a id "i.xxxx" by making playParams, but I can't seem to do the same with a playlist.


playParams = [ "id": "p.4Y0Jg11I26lVaXZ",

"kind": "playlist",

"isLibrary": true,

"globalId": "pl.u-kv9l2aaI7B5gk48"]


Here is a sample of what i have been trying