Hello @dimsumthinking,
As I understand it, you are looking for the playlists associated with the curator named "Blue Note".
In iOS 15, MusicKit for Swift doesn't support curators as a regular MusicItem
in Swift. But you can still get this information with MusicDataRequest.
First, define a custom type for curators:
struct MyCurator: MusicItem, Codable {
struct Attributes: Codable {
let artwork: Artwork?
let name: String
let url: URL?
}
let id: MusicItemID
let attributes: Attributes
}
Technically, for the purpose of this question, you only need the id
, and you don't need any attributes
. But I figured I'd show you that you can very easily also include attributes, including complex ones like artwork
.
Next, define a structure for the catalog search response including curators:
struct MyCuratorCatalogSearchResponse: Codable {
struct Results: Codable {
let curators: MusicItemCollection<MyCurator>?
}
let results: Results
}
Next, build a URL for the catalog search endpoint to search the specific curator you're interested in:
let countryCode = try await MusicDataRequest.currentCountryCode
var curatorSearchURLComponents = URLComponents()
curatorSearchURLComponents.scheme = "https"
curatorSearchURLComponents.host = "api.music.apple.com"
curatorSearchURLComponents.path = "/v1/catalog/\(countryCode)/search"
curatorSearchURLComponents.queryItems = [
URLQueryItem(name: "term", value: "blue note"),
URLQueryItem(name: "types", value: "curators"),
]
let curatorSearchURL = curatorSearchURLComponents.url!
Next, load the response from Apple Music API and find the first item in the curators collection:
let curatorSearchDataRequest = MusicDataRequest(urlRequest: URLRequest(url: curatorSearchURL))
let curatorSearchDataResponse = try await curatorSearchDataRequest.response()
let decoder = JSONDecoder()
let curatorSearchResponse = try decoder.decode(MyCuratorCatalogSearchResponse.self, from: curatorSearchDataResponse.data)
if let curator = curatorSearchResponse.results.curators?.first {
[…]
}
Finally, load the playlists relationship for this curator in the if
block:
var curatorPlaylistsURLComponents = URLComponents()
curatorPlaylistsURLComponents.scheme = curatorSearchURLComponents.scheme
curatorPlaylistsURLComponents.host = curatorSearchURLComponents.host
curatorPlaylistsURLComponents.path = "/v1/catalog/\(countryCode)/curators/\(curator.id.rawValue)/playlists"
let curatorPlaylistsURL = curatorPlaylistsURLComponents.url!
let curatorPlaylistsDataRequest = MusicDataRequest(urlRequest: URLRequest(url: curatorPlaylistsURL))
let curatorPlaylistsDataResponse = try await curatorPlaylistsDataRequest.response()
let curatorPlaylists = try decoder.decode(MusicItemCollection<Playlist>.self, from: curatorPlaylistsDataResponse.data)
print("\(curatorPlaylists)")
And here's the output for this:
MusicItemCollection<Playlist>(
items: [
Playlist(id: "pl.4e3d25ede18c4cd88f1ee51a3a608860", name: "Blue Note: The Finest In Jazz Since 1939", curatorName: "Blue Note Records"),
Playlist(id: "pl.5661da036f0443b79fcb91f795461076", name: "Blue Note: Classic Hits", curatorName: "Blue Note Records"),
Playlist(id: "pl.e4eeb129fb944566bcee6f9a2dc85e87", name: "The Blue Note Monthly", curatorName: "Blue Note Records"),
Playlist(id: "pl.d4b0f96695464be78185c33c59e6c60b", name: "Grant Green: The Finest", curatorName: "Blue Note Records"),
Playlist(id: "pl.ae68cdc95b994fde8009d0bb3ea07fa2", name: "Calm", curatorName: "Blue Note Records"),
Playlist(id: "pl.ad678216ef504fabb74ec33c76dcefff", name: "Jazz Now!", curatorName: "Blue Note Records"),
Playlist(id: "pl.f1e8dc8bbbaf40c3ba47e88edf120243", name: "Soul Jazz", curatorName: "Blue Note Records"),
Playlist(id: "pl.26d4aa9540f84e849630a41274ea8a0a", name: "Blue Note Live!", curatorName: "Blue Note Records"),
Playlist(id: "pl.f52ff4dd03bd49eb89c745a4f140b38a", name: "Blue Note Re:imagined", curatorName: "Blue Note Records"),
Playlist(id: "pl.34f6399ab41941dfb88c776f473008c4", name: "Donald Byrd: The Finest", curatorName: "Blue Note Records")
],
hasNextBatch: true
)
Also, please note raw server responses from Apple Music API often use a structure called a "resource collection"; and here, for any part of the responses parsed in the code listed above that corresponded to such a resource collection, I used MusicKit's MusicItemCollection. Not only does this mean you have fewer custom Codable
data structures to write, but you also get very easy access to the next batch of items, if any, as shown above with the hasNextBatch: true
line of the above output.
Hence, you can even do the following:
if curatorPlaylists.hasNextBatch, let nextBatchOfCuratorPlaylists = try await curatorPlaylists.nextBatch() {
print("\(nextBatchOfCuratorPlaylists)")
}
which will produce the following output:
MusicItemCollection<Playlist>(
items: [
Playlist(id: "pl.fbc158ab86d04b31bf8ae4190c8d3876", name: "McCoy Tyner: The Finest", curatorName: "Blue Note Records"),
Playlist(id: "pl.fd067778d800421cbddf786656a4830b", name: "Most Sampled", curatorName: "Blue Note Records"),
Playlist(id: "pl.4c88e23eb9cf4d59a43237cf4d8b046f", name: "Hard Bop", curatorName: "Blue Note Records"),
Playlist(id: "pl.facaf42f9b534f5aa376b23ab7ac54fd", name: "Art Blakey: The Finest", curatorName: "Blue Note Records"),
Playlist(id: "pl.9476e3f54f3d4b1a82dcbeae98097bfe", name: "Post-Bop", curatorName: "Blue Note Records"),
Playlist(id: "pl.27591bd727064012b5e8f45253020b6e", name: "Joe Henderson: The Finest", curatorName: "Blue Note Records"),
Playlist(id: "pl.0b1d1d87a7664d859bfcb0b6d17ad30b", name: "Herbie Hancock: The Finest", curatorName: "Blue Note Records"),
Playlist(id: "pl.d7f6fb544a7047ac83e63311d78905a6", name: "Blue Groove", curatorName: "Blue Note Records"),
Playlist(id: "pl.e8905ab964034cae88e18f6719f1f3ed", name: "Lee Morgan: The Finest", curatorName: "Blue Note Records"),
Playlist(id: "pl.84499d12b2e548599b3e81d1a467605d", name: "Classic Ballads", curatorName: "Blue Note Records")
],
hasNextBatch: true
)
I hope this helps.
Best regards,