Hello @bigdaddy1,
In iOS 15 and aligned releases, MusicKit for Swift does include some interesting features focused around the Apple Music catalog, such as:
However, as explained in our WWDC session Meet MusicKit for Swift between the timestamps 7:47 and 9:46, it also includes a general purpose data request, MusicDataRequest, which can be used to load data from an arbitrary Apple Music API endpoint.
Of course, this can also be used for the endpoint to get recently played resources. Following the method explained in our WWDC session, you can define a value type that can represent all the different types of recently played resources, which are Album, Playlist and Station:
| enum RecentlyPlayedItem { |
| case album(Album) |
| case playlist(Playlist) |
| case station(Station) |
| } |
Since we are about to use it in a MusicItemCollection, you should make it conform to the MusicItem protocol:
| extension RecentlyPlayedItem: MusicItem { |
| var id: MusicItemID { |
| let id: MusicItemID |
| switch self { |
| case .album(let album): |
| id = album.id |
| case .playlist(let playlist): |
| id = playlist.id |
| case .station(let station): |
| id = station.id |
| } |
| return id |
| } |
| } |
Lastly, we need to make this type conform to the Decodable protocol. The usual pattern to add Decodable conformance to such polymorphic types from Apple Music API requires a custom implementation, but you can still let MusicKit do the heavy lifting by deferring to the Decodable initializers of Album, Playlist and Station:
| extension RecentlyPlayedItem: Decodable { |
| private enum CodingKeys: CodingKey { |
| case type |
| } |
| |
| init(from decoder: Decoder) throws { |
| let values = try decoder.container(keyedBy: CodingKeys.self) |
| let type = try values.decode(String.self, forKey: .type) |
| switch type { |
| case "albums", "library-albums": |
| let album = try Album(from: decoder) |
| self = .album(album) |
| case "playlists", "library-playlists": |
| let playlist = try Playlist(from: decoder) |
| self = .playlist(playlist) |
| case "stations": |
| let station = try Station(from: decoder) |
| self = .station(station) |
| default: |
| let decodingErrorContext = DecodingError.Context( |
| codingPath: decoder.codingPath, |
| debugDescription: "Unexpected type \"\(type)\" encountered for RecentlyPlayedItem." |
| ) |
| throw DecodingError.typeMismatch(RecentlyPlayedItem.self, decodingErrorContext) |
| } |
| } |
| } |
Once you've defined this RecentlyPlayedItem
value type that conforms to both MusicItem and Decodable, you can load recently played items and decode them very easily:
| let url = URL(string: "https://api.music.apple.com/v1/me/recent/played")! |
| |
| let request = MusicDataRequest(urlRequest: URLRequest(url: url)) |
| let response = try await request.response() |
| |
| let decoder = JSONDecoder() |
| let recentlyPlayedItems = try decoder.decode(MusicItemCollection<RecentlyPlayedItem>.self, from: response.data) |
| print("Recently played items: \(recentlyPlayedItems)") |
Here's the sort of output I see when I run this code:
| Recently played items: MusicItemCollection<RecentlyPlayedItem>( |
| items: [ |
| playlist(Playlist( |
| id: "pl.5ee8333dbe944d9f9151e97d92d1ead9", |
| name: "A-List Pop", |
| curatorName: "Apple Music Pop", |
| isChart: "false", |
| kind: "editorial", |
| lastModifiedDate: "2021-12-10", |
| shortDescription: "GAYLE spares no one on “abcdefu.”", |
| standardDescription: "As its title might suggest, GAYLE’s “abcdefu” begins with a list: “F**k you, and your mom, and your sister, and your job,” she sings. “And your broke-*** car, and that shit you call art.” There’s plenty more where that came from. The headliner on A-List Pop this week, it’s a breakup anthem with bite, the Dallas-born, Nashville-based singer-songwriter laying waste to just about everyone and everything in her path, including a couch. “F**k you and your friends that I'll never see again,” she sings, lullaby-style. “Everybody but your dog, you can all f**k off.” Add A-List Pop to your library to stay up on the latest and greatest pop music." |
| )), |
| station(Station( |
| id: "ra.978194965", |
| name: "Apple Music 1", |
| isLive: "true" |
| )), |
| album(Album( |
| id: "560097651", |
| title: "The Heist (Deluxe Edition)", |
| artistName: "Macklemore & Ryan Lewis", |
| contentRating: "explicit", |
| copyright: ℗ 2012 Macklemore, LLC., |
| genreNames: [ |
| "Hip-Hop", |
| "Music", |
| "Hip-Hop/Rap" |
| ], |
| isCompilation: false, |
| isComplete: true, |
| isSingle: false, |
| releaseDate: "2012-10-09", |
| trackCount: 19, |
| upc: "707541525299" |
| )), |
| [...] |
| ], |
| hasNextBatch: true |
| ) |
I hope this helps.
Best regards,