Hi there,
The following code snippet will open Apple Music on an iOS device to a catalog playlist, using the globalId.
if let url = URL(string: "music://music.apple.com/us/playlist/\(playlist!.attributes.playParams.globalId!)") {
await UIApplication.shared.open(url)
What I'd like to do is open Apple Music using the standard ID, as I don't want to force users to make a playlist public in order to link to it from my app.
This requires the above code to use a library link instead of a catalog link.
I've tried various permutations of the url, but I can't seem to find the secret sauce.
Any tips, would be most appreciated.
Thanks!
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi there,
I don't know if this is possible or not, so I'm asking here.
I'd like to know if there is a way to get a list of an Apple Music public playlist via the Apple Music API.
I don't think that Music Kit is an option here, as these users would not be Apple Music users, but, again, I'm not sure.
The first stumbling block is that I can't seem to figure out how to get an Apple Music users ID or maybe their curator ID, if that's what is needed.
Once I had that, I'm still not sure how to get that user's public playlists.
Any help on this would be appreciated.
Thanks!
I've got an iOS app build on Swift MusicKit that retrieves Apple Music tracks and presents them to a user in a list.
Tapping the track attempts to the track using this function:
func handlePlayThisTrack(track: AppleMusicTrack) async {
do {
let tracksToQueue = sortedTracks.compactMap{$0.track}
if let track = tracksToQueue.first(where: {$0.id.rawValue == track.id}) {
print("track", track)
player.queue = ApplicationMusicPlayer.Queue(for: tracksToQueue, startingAt: track )
try await player.play()
} else {
Logger.log(.error, "Track does not exist in sorted tracks!")
}
} catch {
print(error)
}
}
Sometimes, however, the track does not play, and checking the logs, I see the below.
This only happens on some tracks, but on those that don't work it happens consistently.
When printing the details for a track that doesn't work, it looks like this:
track Track.song(Song(id: "1443100129", title: "She's Not There", artistName: "The Zombies"))
And this looks like all the other tracks that do play.
So I don't know where to look for said missing play parameters mentioned in the error.
I have an inkling that this may have to do with the track not being available due to the country/storefront, and that the error message is misleading.
I'm using the following to get the tracks:
MusicCatalogResourceRequest<Song>(matching: \.isrc, equalTo: isrc) // <= the ISRC of the track I want to fetch
My assumption is that the MusicCatalogResourceRequest would only respond with tracks in my country/storefront, but I think this may not be the case.
Is there any way to create a MusicCatalogRequest in such a way that I only get results that are playable in my country/storefront?
Any advice would be most appreciated. Thanks!
2022-02-25 02:24:56.971343+0700 MusicApp[19452:1186508] [Playback] Failed to insert MusicPlayer.Queue.Entry(id: "F6A04D56-F5C5-4628-B136-5438E188FDA5", transientItem: Track.song(Song(id: "1443100129", title: "She's Not There", artistName: "The Zombies"))) into queue descriptor because it's missing play parameters.
2022-02-25 02:24:57.102432+0700 MusicApp[19452:1186733] [Entitlements] MSVEntitlementUtilities - Process MusicApp PID[19452] - Group: (null) - Entitlement: com.apple.accounts.appleaccount.fullaccess - Entitled: NO - Error: (null)
2022-02-25 02:24:57.104579+0700 MusicApp[19452:1186733] [core] Attempted to register account monitor for types client is not authorized to access: {(
"com.apple.account.iTunesStore"
)}
I am using the MusicKit library for Swift.
With this:
let searchString = “led zeppelin iv deluxe edition”
var albumSearchRequest = MusicCatalogSearchRequest(term: searchString, types: [Album.self])
The response from:
let response = try await albumSearchRequest.response() returns no albums; however searching manually for that exact string in the Music App on either iOS or macOS will return results.
This is really weird and problematic if one is trying to search for albums or tracks specific to certain albums.
I'm working on an idea to use recently added tracks in my app.
From what I can tell, the following endpoint will only supply albums and the id's are not related to any catalog resource:
https://api.music.apple.com/v1/me/library/recently-added
However, if I use the following endpoint, I get access to a semi-deeply-nested data value that contains the goodies I'm looking for:
https://api.music.apple.com/v1/me/library/recently-added?include=catalog
This seems better than doing a search for each item, as I have access to a catalog resource id.
The data in the response is like the below.
You can see under relationships, there's catalog, and in there is data, and in there is href, which is what I want.
My problem is that I'm doing something dumb with the the decode.
I'm using MusicKit's MusicDataRequest, as I don't see a way to get this info via MusicKit methods.
And because of that, I gotta setup the request manually.
If I just decode with the following, using Album as a type, the info I want isn't there for understood reasons.
struct AppleMusicRecentlyAddedRequest: Decodable {
// var next: String?
var items: [Album]?
enum CodingKeys: String, CodingKey {
case next
case data
}
init (from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.items = try container.decodeIfPresent([Album].self, forKey: .data)
}
}
I've attempted to go down the rabbit hole to get at catalog's data with:
struct AppleMusicRecentlyAddedRequest: Decodable {
var items: [???]?
enum CodingKeys: String, CodingKey {
case next
case data
case relationships
case catalog
}
init (from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let dataContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .data)
let relationshipsContainer = try dataContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .relationships)
let catalogContainer = try relationshipsContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .catalog)
self.items = try catalogContainer.decodeIfPresent([???].self, forKey: .data)
}
}
But anything I try for ???, including a complete manual copy of the response in a struct, isn't working, mainly because I'm not very good tat this.
The main error I get is:
Expected to decode Dictionary<String, Any> but found an array instead
Which makes me think I gotta decode catalog data, or something, but I'm at my wits end at this point.
Any tips on how to get at data would be awesome; even better would be just to the the href inside catalog/data for each item in the main response.
@JoeKun, if there's anyway that MusicKit can make this easier, kindly advise.
Thanks.
[
{
"id":"l.WAiAqm3",
"type":"library-albums",
"href":"/v1/me/library/albums/l.WAiAqm3",
"attributes":{
"releaseDate":"2010-12-23",
"artwork":{
"width":1200,
"height":1200,
"url":"https://is4-ssl.mzstatic.com/image/thumb/Music/df/48/bb/mzi.wxowhcmy.jpg/{w}x{h}bb.jpg"
},
"dateAdded":"2022-04-13T07:07:50Z",
"name":"Play With Me Papa",
"artistName":"John Keawe",
"genreNames":[
"New Age"
],
"playParams":{
"id":"l.WAiAqm3",
"kind":"album",
"isLibrary":true
},
"trackCount":1
},
"relationships":{
"catalog":{
"href":"/v1/me/library/albums/l.WAiAqm3/catalog",
"data":[
{
"id":"417478467",
"type":"albums",
"href":"/v1/catalog/us/albums/417478467",
"attributes":{
"artwork":{
"width":600,
"height":600,
"url":"https://is4-ssl.mzstatic.com/image/thumb/Music/df/48/bb/mzi.wxowhcmy.jpg/{w}x{h}bb.jpg",
"bgColor":"ecf2fe",
"textColor1":"3a2212",
"textColor2":"3f2b1b",
"textColor3":"5e4b41",
"textColor4":"615349"
},
"artistName":"John Keawe",
"isSingle":false,
"url":"https://music.apple.com/us/album/play-with-me-papa/417478467",
"isComplete":true,
"genreNames":[
"New Age",
"Music",
"Worldwide"
],
"trackCount":13,
"isMasteredForItunes":false,
"releaseDate":"2010-12-23",
"name":"Play With Me Papa",
"recordLabel":"Homestead Productions",
"upc":"704565719925",
"copyright":"℗ 2010 John Keawe",
"playParams":{
"id":"417478467",
"kind":"album"
},
"isCompilation":false
}
}
]
}
]
Apple provides HTML Embeds for Music Kit JS, as mentioned here.
There is a tool here that you can use to create embeds.
Scroll to Preview Player.
Now, if you set your browser width to less than 490 (right when the thumbnail gets smaller), the player will move vertically if you drag up. Not by much, it's hard to see without a contrasting background.. It's more noticeable in dark mode, as a white background shows clearly, like this:
I'm misusing "drag" here: a simple, vertical scroll will cause this.
Since this happens on Apple's own site, I'm fairly certain that this is not a "me problem," but who knows!
Anyhow, I'm not sure if anyone has come across this. These embeds are pretty handy, and I'm loathe to roll my own player just to fix this.
Any constructive advice would be appreciated.
I've got a web app built with MusicKit that displays a list of songs.
I have player controls for play, pause, skip next, skip, previous, toggle shuffle and set repeat mode.
All of these work by using music.
The play button, when nothing is playing and nothing is in the queue, will enqueue all the tracks and start playing with the below, for example:
await music.setQueue({ songs, startPlaying: true });
I've implemented a progress slider based on feedback from the "playbackProgressDidChange" listener.
Now, how in the world can I set the volume? This seems like it should be simple, but I am at a complete loss here.
The docs say:
"The volume of audio playback, which is set directly on the HTMLMediaElement as the HTMLMediaElement.volume property. This value ranges between 0, which would be muting the audio, and 1, which would be the loudest possible."
Given that all my controls work off the music instance, I don't understand how I can do that.
In this video from WWDC 2022, music web components are touched on briefly. These are also documented very sparsely. The volume docs are here.
For the life of me, I can't even get the volume web component to display in the UI.
It appears that MusicKit Web is hobbled compared to the native implementation, but surely adjusting volume shouldn't be that hard right?
I'd appreciate any insight on how to do this, including how to get web components to work (in a Next JS app).
Thanks.
In MusicKit Web the playback states are provided as numbers.
For example the playbackStateDidChange event listener will return:
{oldState: 2, state: 3, item:...}
When the state changes from playing (2) to paused (3).
Those are pretty easy to guess, but I'm having a hard time with some of the others: completed,
ended,
loading,
none,
paused,
playing,
seeking,
stalled,
stopped,
waiting.
I cannot find a mapping of states to numbers documented anywhere. I got the above states from an enum in a d.ts file that is often incorrect/incomplete.
Can someone help out pointing to the docs or provide a mapping?
Thanks.
Trying to do what I can do pretty easily with a standard post request in a JS app, but now with Swift, and I'm struggling.
I've tried with MusicRequestItem, but that fails, so I went with this and it responds with a 400.
func addTracksToAppleMusicPlaylist(targetPlaylistId: String, tracksToSave: [Song]) async throws -> Void {
let tracks = tracksToSave.compactMap{
AppleMusicPlaylistPostRequest(id: $0.id, type: "songs")
}
do {
print("Saving tracks to Apple Music Playlist: \(targetPlaylistId)")
let tokens = try await self.getAppleMusicTokens()
if let url = URL(string: "https://api.music.apple.com/v1/me/library/playlists/\(targetPlaylistId)/tracks") {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Bearer \(tokens.devToken)", forHTTPHeaderField: "Authorization")
request.addValue("\(tokens.userToken)", forHTTPHeaderField: "Music-User-Token")
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
let data = try encoder.encode(tracks)
request.httpBody = data
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request) {(data, response, error) in
if error == nil {
if let httpResponse = response as? HTTPURLResponse {
print("statusCode: \(httpResponse.statusCode)")
print("response: \(httpResponse)")
}
} else {
print("Error saving tracks to playlist \(String(describing: error))")
}
}
task.resume()
} else {
print("Bad URL!")
}
} catch {
print("Error Saving Tracks to Playlist", error)
throw error
}
}
HI there,
I just started using Xcode cloud.
When building Xcode cloud, two archives are being generated: iOS and macOS.
The macOS archive always errors out with:
xcodebuild: error: Unable to find a destination matching the provided destination specifier: {generic:1, platform:macOS}
I have no intention of my app running on macOS, but if I knew how to fix that, it might be kinda neat.
But really, it's unnecessary, so how do I turn it off?
Thanks,
Kim
Hi there,
I can see dateAdded when looking at the response of a get library playlist request via the Apple Music API, but this does not appear to exist on any tracks within a given library playlist.
I'm assuming that this just isn't there, but I'm asking here, in case I've missed it.
Thanks.