swiftxcodempmusicplayercontroller

Cannot convert value of type 'PlayParameters?' to expected argument type '[MPMusicPlayerPlayParameters]'


I am trying to create a music player with Swift and MusicKit, but I am getting this error when trying to load up the queue with the selected album from MusicKit. I don't get why the playparameters for the album and MPMusicPlayerPlayParametersQueueDescriptor are different.

let player = MPMusicPlayerController.applicationMusicPlayer
let queue  = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: heavyRotation[album].playParameters)
player.prepareToPlay()
player.play()

Error on let queue line:

Cannot convert value of type 'PlayParameters?' to expected argument type '[MPMusicPlayerPlayParameters]'

NEW EDIT

        var requestURLComponents = URLComponents()
        requestURLComponents.scheme = "https"
        requestURLComponents.host = "api.music.apple.com"
        requestURLComponents.path = "/v1/me/history/heavy-rotation"
        
        requestURLComponents.queryItems = [
            URLQueryItem(name: "limit", value: "5")
        ]
        
        guard let url = requestURLComponents.url else { return }
        
        let request = MusicDataRequest(urlRequest: URLRequest(url: url))
        do {
            let response = try await request.response()
            let decodedResponse = try JSONDecoder().decode(MusicItemCollection<Album>.self, from: response.data)
            heavyRotation = decodedResponse
//            print(response.debugDescription)
        } catch {
            print("error")
            print(error)
            print(error.localizedDescription)
        }

...

Button(action: {
    Task {
        guard let album = heavyRotation[album] as Album? else { return }
        print(album)
        let player = ApplicationMusicPlayer.shared
        player.queue = [album]
        try await player.prepareToPlay()
        try await player.play()
    }
}) {
    Image(systemName: "play.fill")
        .frame(width: 50, height: 50, alignment: .center)
        .fontSize(30)
        .foregroundColor(.white)
}

Solution

  • While MusicKit's PlayParameters is a structure and an opaque object, MPMusicPlayerPlayParameters initializers expect a [String: Any] dictionary. You'll have to encode and decode the PlayParameters to MPMusicPlayerParameters.

    Here's your example:

    guard let parameters = heavyRotation[album].playParameters else { return }
    
    let data = try JSONEncoder().encode(parameters)
    let playParameters = try JSONDecoder().decode(MPMusicPlayerPlayParameters.self, from: data)
    
    let queue = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: [playParameters])
    
    let player = MPMusicPlayerController.applicationMusicPlayer
    player.setQueue(with: queue)
    player.prepareToPlay()
    player.play()
    

    If you're using MusicKit for Swift and its music player, you can directly set the album to the queue like this:

    guard let album = heavyRotation[album] else { return }
    
    let player = ApplicationMusicPlayer.shared
    player.queue = [album]
    try await player.prepareToPlay()
    try await player.play()
    

    Update - If you're trying to play an album from the library, then I had problems with that as well. As a workaround, you can get the album's local ID and then make another request to the catalog. If there's an album on Apple Music, then it should work.

    Here's an example that works fine for me:

    do {
      /// First request to get the heavy rotation albums
      guard let url = URL(string: "https://api.music.apple.com/v1/me/history/heavy-rotation") else { return }
      
      let request = MusicDataRequest(urlRequest: URLRequest(url: url))
      let response = try await request.response()
      
      let heavyRotationAlbums = try JSONDecoder().decode(MusicItemCollection<Album>.self, from: response.data)
      
      /// Get the first album
      guard let album = heavyRotationAlbums.first else { return }
      
      /// Get the local album ID
      let albumID = album.id
    
      /// Another request to get the album from Apple Music Catalog
      guard let catalogURL = URL(string: "https://api.music.apple.com/v1/me/library/albums/\(albumID)/catalog") else { return }
    
      let catalogRequest = MusicDataRequest(urlRequest: URLRequest(url: catalogURL))
      let catalogResponse = try await catalogRequest.response()
    
      let albums = try JSONDecoder().decode(MusicItemCollection<Album>.self, from: catalogResponse.data)
    
      /// Get the same album, but with the catalog ID
      guard let catalogAlbum = albums.first else { return }
    
      /// Encode the parameters 
      let data = try JSONEncoder().encode(catalogAlbum.playParameters)
    
      /// Decode the parameters to `MPMusicPlayerPlayParameters`
      let playParameters = try JSONDecoder().decode(MPMusicPlayerPlayParameters.self, from: data)
      
      // Create the queue
      let queue = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: [playParameters])
      
      let player = MPMusicPlayerController.applicationMusicPlayer
    
      /// Set the queue
      player.setQueue(with: queue)
      try await player.prepareToPlay()
    
      /// Finally, play the album!
      player.play()
    } catch {
      print(error)
    }