Post

Replies

Boosts

Views

Activity

How to get a catalog playlists of a curator?
Hi there, tl;dr:  How can I get the id of a curator and then with that get a listing of their playlists? I asked about curators a while back, here in this forum, but I can’t find that post, so I’m writing a new one, esp. now new curator features have been added to MusicKit as of WWDC22. Let's say that userB wants to access one of userA's playlists. Since userB has no way of accessing userA’s library, userA’s playlist needs to be accessible as a catalog resource.  This is accomplished by userA manually performing an action in the Music App on macOS or iOS (I wish this could be done programmatically, but no, and that’s off topic). At present, the only way that I know of to determine if a playlist available as a catalog resource is by checking for the hasCatalog property under attributes and/or the globalId property under attributes.playParams. @JoeKun once told me that globalId should be considered opaque and should not be relied upon.  That said, adding "include=catalog" to the request properties of a MusicDataRequest that fetches playlists from userA's Library, like the below will give me access to catalog ID. var playlistRequestURLComponents = URLComponents()     playlistRequestURLComponents.scheme = "https"     playlistRequestURLComponents.host = "api.music.apple.com"     playlistRequestURLComponents.path = "/v1/me/library/playlists"     playlistRequestURLComponents.queryItems = [         URLQueryItem(name:"limit", value: "100"),         URLQueryItem(name:"include", value: "catalog")     ] Note that this can only be performed by userA. And here comes the curator question: If userB wants to get a list of all userA’s catalog playlists (or a specific one) how can that be done? It seems I need to know userA’s curator ID and do some sort of request on that, or I could perhaps get the curator info by performing a MusicCatalogResourceRequest<Playlist> request, adding [.tracks, .moreByCurator] to the request. On the former, I got no idea how to find userA’s curator ID, even if I’m coding with a scope that has Library access for userA. The best I can seem to do is get a curatorName when adding "include-catalog" (as above) to a MusicDataRequest that gets a user's library playlists. On the latter, getting the catalog ID of a playlist requires userA to perform a MusicDataRequest against their library and passing that catalogID to userB so that userB can then access the tracks. This is what my app does now. Ideally though, I'd like to somehow have userB get userA's curator ID and then have userB get userA's catalog playlists without having userA having to do the above. Any thoughts on how to do this would be most appreciated.
4
0
1.9k
Jun ’22
How to set volume with MusicKit Web?
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.
2
0
561
Jan ’25
MusicKit Web Playback States
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.
2
0
398
Feb ’25
Adding tracks to User's Library Playlist
Hi there, I'm creating an iOS 15 app, using the new Swift MusicKit beta. I've got basic "arbitrary" GET calls working with MusicDataRequest, like: fetch playlists and tracks. However, I cannot find good docs for adding tracks to a playlist in a user's library. I guess I could do this the "old way", but then I don't get the super-nice feature of auto dev/user tokens. So the question is: how to a POST, instead of GET in the following: let url = URL(string: "https://api.music.apple.com/v1/me/library/playlists/`\(targetPlaylistId)/tracks") let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: url))
8
0
2.8k
Jun ’22
How do you do a POST to a user's playlist so as to add tracks?
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     } }
1
0
898
Jul ’21
How to get the album info for a song fetched by MusicDataRequest?
I'm slowly learning the new MusicKit beta for swift. I've learned to successfully retrieve tracks of type Song using MusicDataRequest, using the following: ... let countryCode = try await MusicDataRequest.currentCountryCode if let url = URL(string: "https://api.music.apple.com/v1/catalog/\(countryCode)/songs?filter[isrc]=\(isrc)") {   let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: url))   let dataResponse = try await dataRequest.response() ... However, when I decode the data, there does not seem to be any album information that I can see. I've tried adding includes=albums to the URL, but I don't think that's the right approach, because when I veiw the Song struct in MusicKit, I don't see a reference to an Album type anywhere. Any advice on how to retrieve the album information would be most appreciated. Thanks.
7
0
3.9k
Apr ’24
Searching for a track with MusicKit Swift Beta
I'm trying to perform a search for a song by album, artist, & title in the cases when I don't know the song's id (or if there is no isrc match) Reading the docs, it seems that I can only search for one term at a time, but against a list of MusicCatalogSearchable Types So my strategy would be to search for albums by name, then filter the results by artist and title. Two questions here, really: Is the above a good strategy, or is there a better way to do this? For the life of my I cannot figure out from the docs, what to put in place of [MusicCatalogSearchable.Album] in the below. var albumRequest = MusicCatalogSearchRequest(term: album.name, types: [MusicCatalogSearchable.Album]) Xcode doesn't like the above and gives the following error: Type 'MusicCatalogSearchable' has no member 'Album' Sadly, everything I've tried, results in an error. When I look in MusicKit, I see the below, which seems empty to me: @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) public protocol MusicCatalogSearchable : MusicItem { } What am I missing?
4
0
2.9k
Aug ’21
Retrieving a list of tracks from a library playlist
I'm trying to do something that I though would be simple; however, I'm tripping up on something... In brief, I want to get all tracks from a playlist in an AppleMusic authorized user's playlist with the following function:     func getTracksFromAppleMusicPlaylist(playlistId: MusicItemID) async throws -> [Track]? {         print("Fetching AppleMusic Playlists...")         print("Playlist ID: \(playlistId)")         var playlistTracks: [Track]? = []         do {             var playlistRequest = MusicCatalogResourceRequest<Playlist>(matching: \.id, equalTo: playlistId )             playlistRequest.properties = [.tracks]             let playlistResponse = try await playlistRequest.response()             print("Playlist Response: \(playlistResponse)")             let playlistWithTracks = playlistResponse.items             let tracks = playlistWithTracks.flatMap { playlist -> MusicItemCollection<Track> in                 playlist.tracks ?? []             }             playlistTracks = tracks.count > 1 ? tracks : nil         } catch {             print("Error", error)             // handle error         }         return playlistTracks     } This function results in the following error: 2021-08-28 04:25:14.335455+0700 App[90763:6707890] [DataRequesting] Failed to perform MusicDataRequest.Context(   url: https://api.music.apple.com/v1/catalog/us/playlists/p.7XxxsXxXXxX?include=tracks&omit%5Bresource%5D=autos,   currentRetryCounts: [.other: 1] ) with MusicDataRequest.Error(   status: 404,   code: 40400,   title: "Resource Not Found",   detailText: "Resource with requested id was not found",   id: "QMK7GH4U7ITPMUTTBKIOMXXXX",   originalResponse: MusicDataResponse(     data: 159 bytes,     urlResponse: <NSHTTPURLResponse: 0x00000002820c0b60>   ) ). The playlistID being used is a value that has been picked from an existing playlist in the user's library, via a function that uses this code snippet: if let url = URL(string: "https://api.music.apple.com/v1/me/library/playlists?limit=100") {                let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: url)) ... The only thing I can think of is that the playlistId from the above snippet is converted to a string when decoding into a struct, after which it is changed back to a MusicItemID with an init, like MusicItemID(playlistId). Any thoughts? Because I'm at a loss...
10
0
3.6k
Sep ’21
Deep link to Apple Music library playlist from Swift (iOS) app
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!
2
0
3.3k
Nov ’21
Get listing of public playlists for any Apple Music user Swift iOS
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!
2
0
1.2k
Dec ’21
Run async tasks using Background Tasks
I've got an iOS app that performs a series of operations when initialized and when a refresh is performed. In short, that app has: An obervable object (appManager) that houses variables that act as "state" for the app. Methods in the observable object that perform a variety of operations. Here's an example: Perform an API operation to get tokens to perform API actions on remote API service. Perform a fetch on an external database to retrieve some data. Decode that data an place the data into @Published variables, using (DispatchQueue.main.async). Perform another remote API fetch operation on a different endpoint. Put more variables in "state" So when the user opens the app and after init runs, they see what they expect to see. And when they tap a "refresh" button, another function (e.g. getUpdatedAppData()) is called with similar steps to the above, and the app updates the published variables and the view(s) update. The above steps are all performed using async functions, using Swift's new async/await functionality. Everything works swimmingly when the app is in the foreground. What I'd like to do is perform the updateAppData() function using Background tasks as described here.. I have successfully setup the app to register and schedule a task, using BGTaskScheduler, and I can successfully emulate the triggerring of that task by setting a breakpoint and running the following code in the console: e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.example.task"] If the background tasks is something simple, like printing to the console, it seems to work    private func configureBackgroundTasks() {     Logger.log(.info, "Registering background tasks...")     let bgTaskIdentifier = "com.example.task"     BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: DispatchQueue.main) { (task) in       Logger.log(.info, "Performing background task \(bgTaskIdentifier)")       task.setTaskCompleted(success: true)       backgroundTaskManager.scheduleAppRefresh()     }   } However, if the function is something like the below, I can see the function being triggered, when simulating the running of the task, but the function hangs at the start of the first async operation (e.g. fetch tokens above). It seems to "try to complete" (and usuually fails) once the app is brought to the foreground, but that's obviously not what I want to happen. Surely, I'm misunderstanding something and/or doing something wrong, so I'm hoping to get some help here. Thanks in advance for any assistance toward achieving what I'm trying to do here.    private func configureBackgroundTasks() {     Logger.log(.info, "Registering background tasks...")     let bgTaskIdentifier = "com.example.task"     BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: DispatchQueue.main) { (task) in       Logger.log(.info, "Performing background task \(bgTaskIdentifier)")       Task.init {         if let updatedData = await appManager.getUpdateAppData() {           DispatchQueue.main.async {             appManager.data = updatedData           }         }       }       task.setTaskCompleted(success: true)       backgroundTaskManager.scheduleAppRefresh()     }   }
8
0
5.4k
Dec ’21
MusicCatalogSearchRequest does not find Albums that are found when using the Music app with the same search string
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.
2
0
1.3k
Jun ’22
Songs are not always added to Playlist when using Music iOS
First let me state that this is not an issue with MusicKit, but I've raised a radar on this and have received 0 response, which is, sadly, kinda normal. However, it's kind of an important issue and my app relies on this feature to work consistently, so I thought I'd mention it and that the amazing @JoeKun might have an idea how to escalate it. Here's the problem in the iOS Music app: Add a song to an existing playlist Add another song to the same playlist Add another View the playlist More often than not, one of the newly added songs is missing in the playlist to which the song was added. There are entries in Recently Added for newly added songs that are not in the playlist where the songs were added. View the songs in the Music app on Mac. Query the playlist to get all songs via the Apple Music API. The Music app on Mac and the API results align, yet differ from iOS Music app. There are entries in Recently Added for newly added songs that are not in the playlist where the songs were added. In summary, when adding a song to a playlist using the iOS Music app, it sometimes does not add the song. For the record, I am awaiting the confirmation message each time a song is added. Adding tracks via the macOS Music app, seems to always work. This issue only occurs with the iOS app.
6
0
1.8k
Jun ’22
How to prevent macOS archive in Xcode Cloud build?
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
1
0
1.6k
Jul ’23