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)
}
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)
}