Post

Replies

Boosts

Views

Activity

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.9k
Jun ’22
Delete song from playlist using Music Kit JS (or the API)?
I've got an app that allows a user to add songs to playlists in their library.I'd like to be able to delete songs as well, but it appears that there is no way to do this?It's baffling that this fundamental functionality is missing. Is there some super important reason that this is not possible? If so, what might that be?Are there plans to allow this functionality in the future?Thanks...
2
0
3.4k
Jun ’22
Get Songs from Apple Music API recently added
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                     }                 }             ]         } ]
2
0
1.8k
May ’22
Missing play parameters when trying to play with MusicKit - potential storefront issue
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" )}
2
1
3.5k
Mar ’22
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.5k
Dec ’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
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.6k
Nov ’21
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.
Replies
6
Boosts
0
Views
1.9k
Activity
Jun ’22
Delete song from playlist using Music Kit JS (or the API)?
I've got an app that allows a user to add songs to playlists in their library.I'd like to be able to delete songs as well, but it appears that there is no way to do this?It's baffling that this fundamental functionality is missing. Is there some super important reason that this is not possible? If so, what might that be?Are there plans to allow this functionality in the future?Thanks...
Replies
2
Boosts
0
Views
3.4k
Activity
Jun ’22
Get Songs from Apple Music API recently added
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                     }                 }             ]         } ]
Replies
2
Boosts
0
Views
1.8k
Activity
May ’22
Missing play parameters when trying to play with MusicKit - potential storefront issue
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" )}
Replies
2
Boosts
1
Views
3.5k
Activity
Mar ’22
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()     }   }
Replies
8
Boosts
0
Views
5.5k
Activity
Dec ’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!
Replies
2
Boosts
0
Views
1.2k
Activity
Dec ’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!
Replies
2
Boosts
0
Views
3.6k
Activity
Nov ’21