Try the Apple Music API endpoint: https://api.music.apple.com/v1/catalog/us/search?term=weeknd&types=albums,apple-curators,artists,curators,music-videos,playlists,record-labels,songs,stations&with=topResults. It also gives only top results restricted to 3 for some reason, which is weird.
Post
Replies
Boosts
Views
Activity
You can avoid adding the tokens yourself if you are targeting iOS 15+ and take advantage of MusicKit instead. Most of the code can be reduced to:
let url = URL(string: "https://api.music.apple.com/v1/me/library/playlists")!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = data
let request = MusicDataRequest(urlRequest: urlRequest)
let response = try await request.response()
if response.urlResponse.statusCode == 201 {
debugPrint("Created new playlist!")
} else {
debugPrint("Could not create the playlist")
}
I tried both the playlists on iOS 16, Beta 6, and 7, and it works. Have you tried setting the playlist directly to the queue? Does that help solve the problem?
My code:
let request = MusicCatalogResourceRequest<Playlist>(matching: \.id, equalTo: "pl.u-BNA6rpjIRXy7Dj")
let response = try await request.response()
guard let playlist = response.items.first else { return }
ApplicationMusicPlayer.shared.queue = [playlist]
try await ApplicationMusicPlayer.shared.play()
Hi there! That code snippet looks like something from my blog post. Before writing it, I saw many third-party apps live on the App Store using the artist's artwork, probably with a similar trick of fetching it. So, I do not think that may be a reason for rejection. (I can be wrong, of course)
Also, this year, MusicKit added the artwork property to the Artist structure. I asked the team during WWDC about it, and here is the response from them:
Hi Rudrank! Yes, we have worked hard with business to make sure it is compliant with licensing agreement for use in your app. Please reference section 4.5.2 for guidance of how artist images can be used in your app.
(ii) Using the MusicKit APIs is not a replacement for securing the licenses you might need for a deeper or more complex music integration. For example, if you want your app to play a specific song at a particular moment, or to create audio or video files that can be shared to social media, you'll need to contact rights-holders directly to get their permission (e.g. synchronization or adaptation rights) and assets. Cover art and other metadata may only be used in connection with music playback or playlists (including App Store screenshots displaying your app's functionality), and should not be used in any marketing or advertising without getting specific authorization from rights-holders. Make sure to follow the Apple Music Identity Guidelines when integrating Apple Music services in your app.
MusicItemID("1603171516") is an identifier from the Apple Music catalog, whereas the other one MusicItemID("i.KoJeg8VCZLNZZq") is an identifier from your music library. So, when you use a catalog request for a user library track, it will give an error.
You can use the Apple Music API and MusicDataRequest to overcome this:
guard let url = URL(string: "https://api.music.apple.com/v1/me/library/albums/i.KoJeg8VCZLNZZq/tracks") else { return }
let request = MusicDataRequest(urlRequest: .init(url: url))
let response = try await request.response()
let tracks = try JSONDecoder().decode(MusicItemCollection<Track>.self, from: response.data)
Or, you can use the new structure MusicLibraryRequest introduced in iOS 16:
var request = MusicLibraryRequest<Album>()
request.filter(matching: \.id, equalTo: "i.KoJeg8VCZLNZZq")
let response = try await request.response()
Subscribing to this thread. I tried the particular ID using Apple Music API, which only shows the playlist, in your case, "After School Radio Playlist". In the Apple Music app, however, there are Season 1 and Series 2 that has many stations. Curious if they are even exposed for third-party developers to access.
For now, I did this:
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
extension Array where Element == PartialMusicAsyncProperty<Song> {
public static var all: Self {
[.audioVariants, .albums, .artists, .composers, .genres, .musicVideos, .artistURL, .station]
}
}
You can update your method to handle the errors and concurrency, and then add it as the target:
button.addTarget(self,
action: #selector(requestMusicAuthorization),
for: .touchUpInside)
@objc func requestMusicAuthorization() {
Task {
do {
let authorizationStatus = await MusicAuthorization.request()
if authorizationStatus == .authorized {
isAuthorizedForMusicKit = true
} else {
// User denied permission.
}
} catch {
print(error)
}
}
}
If this does not work, can you tell what is the error you get when the app crashes?
My confusion stemmed from the fact that the most played playlists are added in the results even though the type is only Song.self.
If I hit the endpoint:
https://api.music.apple.com/v1/catalog/us/charts?types=songs&chart=most-played&with=cityCharts
The corresponding result only has the most played songs and city top charts:
"results": {
"order": [
"most-played:songs",
"city-top:cityCharts"
]
}
But MusicCatalogChartsRequest also adds the most played playlists
I agree. I can see a lot of use-case for these three properties in my app as well and would love to use them as a part of the song structure
Any update on this? It is still returning nil in Xcode 13.4
While Joe will be able to provide a perfect answer, you can use the following structure to decode the relationship:
struct RecentlyAdded: Decodable {
var data: [RecentlyAddedData]
struct RecentlyAddedData: Decodable {
var relationships: Relationships
struct Relationships: Decodable {
var catalog: MusicItemCollection<Album>
}
}
}
I am not sure how you can leverage Album and associate the relationship directly with it. Also, if you don't know, the recently-added endpoint provides playlists and stations resources apart from albums.
Looking forward to Joe's answer.
From what I understand, dataContainer will be an array and you are expecting a dictionary there
Hi @JoeKun, with the current solution and the response from the endpoint, it only fetches one item at a time. How would I go about creating a MusicItemCollection out of it? The Search for Catalog Resources has a very nice response as it provides an array of albums, songs, etc.
But the Get Catalog Search Suggestions has one response model per music item, be it an album, song. Etc.
Any suggestion?
Edit: Hacky workaround
switch topResult.content {
case .album(let album): self.albums += MusicItemCollection(arrayLiteral: album)
case .artist(let artist): self.artists += MusicItemCollection(arrayLiteral: artist)
case .song(let song): self.songs += MusicItemCollection(arrayLiteral: song)
case .curator(let curator): self.curators += MusicItemCollection(arrayLiteral: curator)
default: ()
}
Do you think I should use MusicItemCollection in this way?
You can get the "Favourite Mix" and "New Music Mix" if you hit the recommendations API that returns a collection of playlists. Have you tried that?
https://api.music.apple.com/v1/me/recommendations