1

I'm using the Apple Music API to get albums, tracks, playlists, etc from the user's music library. I would like to prepend these songs to the systemMusicPlayer's queue. This works great for songs that are from the catalog and a catalogID. However, if the user uploaded music from their Mac to the Cloud Music Library, it refuses to queue. Let's take a look at the request, response, and the code.

The Issue

The URL request to the Apple Music API looks like this:

https://api.music.apple.com/v1/me/library/albums/\(id)?include=tracks

This returns the album with the requested id. If we look into the album's tracks, we get the following JSON response (I replaced irrelevant details like the song and artist):

{
  "id" : "i.9oJNEa6Iz66G2l",
  "attributes" : {
    "genreNames" : [
      "Alternative"
    ],
    "discNumber" : 0,
    "hasLyrics" : false,
    "albumName" : "The Album Name",
    "artwork" : {
      "url" : "thealbumurl",
      "width" : null,
      "height" : null
    },
    "durationInMillis" : 866379,
    "artistName" : "The artist name",
    "trackNumber" : 1,
    "playParams" : {
      "reporting" : false,
      "isLibrary" : true,
      "id" : "i.9oJNEa6Iz66G2l",
      "kind" : "song"
    },
    "name" : "The song title"
  },

  "href" : "\/v1\/me\/library\/songs\/i.9oJNEa6Iz66G2l",
  "type" : "library-songs"
}

Finally, I get the playParams dictionary, initialize MPMusicPlayerPlayParameters with it, and prepend it to the queue:

if let givenParams = attributes["playParams"].dictionaryObject {
    // Returns ["id": i.9oJNEa6Iz66G2l, "reporting": 0, "kind": song, "isLibrary": 1]
    let parameters = MPMusicPlayerPlayParameters(dictionary: givenParams)
    let descriptor = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: [parameters])
    player.prepend(descriptor)
}

As I said, this works fine if the playParams are from a catalog song, and usually I can convert library songs into catalog songs unless the user uploaded the song to iTunes, themselves. Then, I'm thrown an error

[SDKPlayback] prependQueueDescriptor failed error: Error Domain=MPMusicPlayerControllerErrorDomain Code=6 "Failed to prepare queue for prepend" UserInfo={NSDebugDescription=Failed to prepare queue for prepend}

What I've Learned

I've found what I think might be the issue. I want to look closely at the playParams dictionary given (as seen above):

"playParams" : {
    "reporting" : false,
    "isLibrary" : true,
    "id" : "i.9oJNEa6Iz66G2l",
    "kind" : "song"
 }

And here is the playParams of a catalog song so you can see the difference:

"playParams" : {
    "kind" : "song",
    "id" : "1596173449"
 }

Which, as I've said, works perfectly. From what I can tell, MPMusicPlayerPlayParameters doesn't like it when the id starts with i. as seen in the response's playParams. Even though I'm giving MPMusicPlayerPlayParameters the rest of the dictionary containing "isLibrary" and the corresponding value. The whole purpose of the API's playParams is exactly for using it with MPMusicPlayerPlayParameters as stated by it's own documentation saying

A set of properties and methods used to modify how items are played, based on play parameters returned from MusicKit API results.

I am about to just not allow users to play songs they've uploaded themselves, which of course I don't want to do. What can I try next?

halfer
  • 19,824
  • 17
  • 99
  • 186
Jacob Cavin
  • 2,169
  • 3
  • 19
  • 47
  • Why do you think "doesn't like it when the id starts with i"? And what's the type of 'id' in MPMusicPlayerPlayParameters? – Asteroid Jun 06 '22 at 19:48

0 Answers0