Post

Replies

Boosts

Views

Activity

Reply to App hangs while opening from background
I've been seeing intermittent crashes like this for years working with applicationQueuePlayer and now ApplicationMusicPlayer. I've heard from more users seeing this issue than usual since iOS 16.5 came out. Below is one such crash log I got today. I submitted FB12464849 just now with a couple of crash logs. Unfortunately I don't have a sysdiagnose to include, but I'll try to get one from any additional users that report issues like this. Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: FRONTBOARD 2343432205 <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:[application<com.talkingsmall.Albums>:11253] failed to terminate gracefully after 5.0s ProcessVisibility: Background ProcessState: Running WatchdogEvent: process-exit WatchdogVisibility: Background WatchdogCPUStatistics: ( "Elapsed total CPU time (seconds): 3.530 (user 2.080, system 1.450), 11% CPU", "Elapsed application CPU time (seconds): 0.008, 0% CPU" ) reportType:CrashLog maxTerminationResistance:Interactive> Triggered by Thread: 0 Thread 0 Crashed: 0 libsystem_kernel.dylib 0x20ecd3c84 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x20ece6b54 mach_msg2_internal + 80 2 libsystem_kernel.dylib 0x20ece6e2c mach_msg_overwrite + 540 3 libsystem_kernel.dylib 0x20ecd41c8 mach_msg + 24 4 libdispatch.dylib 0x1d727a20c _dispatch_mach_send_and_wait_for_reply + 548 5 libdispatch.dylib 0x1d727a59c dispatch_mach_send_with_result_and_wait_for_reply + 60 6 libxpc.dylib 0x22fb6f218 xpc_connection_send_message_with_reply_sync + 240 7 Foundation 0x1ca0f7f38 __NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY__ + 16 8 Foundation 0x1ca08b2e4 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 2192 9 Foundation 0x1ca089ae0 -[NSXPCConnection _sendSelector:withProxy:arg1:] + 116 10 Foundation 0x1ca089a18 _NSXPCDistantObjectSimpleMessageSend1 + 60 11 MediaPlayer 0x1dfe52108 -[MPMusicPlayerApplicationController _establishConnectionIfNeeded] + 1768 12 MediaPlayer 0x1dfe1b8dc -[MPMusicPlayerController onServer:] + 52 13 MediaPlayer 0x1dfe1a9b8 -[MPMusicPlayerController _nowPlaying] + 372 14 MediaPlayer 0x1dfe21adc -[MPMusicPlayerController nowPlayingItem] + 24 15 MusicKit 0x23b98a7d0 -[MusicKit_SoftLinking_MPMusicPlayerController nowPlayingItem] + 24 16 MusicKit 0x23bedc7f4 0x23b966000 + 5728244 17 MusicKit 0x23bedce34 0x23b966000 + 5729844 18 MusicKit 0x23bede139 0x23b966000 + 5734713 19 MusicKit 0x23bdb629d 0x23b966000 + 4522653 20 MusicKit 0x23bb12fa1 0x23b966000 + 1757089 21 libswift_Concurrency.dylib 0x1da155dd9 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) + 1
Topic: Programming Languages SubTopic: Swift Tags:
Jun ’23
Reply to Is Apple going to stop people from abusing MusicKit developer token taken from music.apple.com
Well isn't this interesting! With absolutely no disrespect meant to the MusicKit team, who are no doubt limited by time, resources, and internal corporate priorities us outsiders have no idea about, It is frustrating to play around with this token and see so many of the features I would love to include in my app, such as: Deleting library items Time-synced lyrics Artist images Available audio qualities The MusicKit API and web API have already come a long way towards leveling the playing field for third party Apple Music apps, but there are still lots of gaps, which can make our apps feel like second-class citizens. Maybe there are licensing issues preventing features like lyrics, but it is impossible for developers to know the surrounding context, and we are just stuck filing feedbacks and awaiting WWDC each year. If the permissions included in this token were officially supported, my app would be better for it. Here's hoping!
Topic: Media Technologies SubTopic: General Tags:
Feb ’23
Reply to SwiftUI NavigationLink freezing when tapped
I recently finished implementing programmatic SwiftUI navigation in my app and I ran into this. In my experience, it was related to using a different custom type for the navigationDestinations on different screens and having their root NavigationStack path bound to a NavigationPath. To fix it, I ended up making my own NavigationDestination enum with a list of all possible navigation destinations in my app. Now, every .navigationDestionation in my app is for NavigationDestination.self and the root NavigationStack is bound to an array of [NavigationDestination]. No more freezing!
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jan ’23
Reply to Request: An API to remove from Library/Playlist.
I would also love the ability to delete items from a user's library. In case any Apple folks are looking for feedbacks regarding this, shortly after WWDC I filed a feedback (FB10042390) to add that functionality to the new MusicLibrary class and last year I filed one to add the functionality to the Apple Music API as FB9195700. Fingers crossed this gets added!
Topic: Media Technologies SubTopic: General Tags:
Jul ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
@JoeKun Got it -- that makes sense. Indeed, thanks to the excellent API design, many of the use-cases I can think of are covered by other functions, such as being able to use with(_:preferredSource:) to pull in Library and Catalog information in one fell swoop. The one thing I can't find a solution for is being able to get a link to share the catalog version of the library album or song resource. The URL property seems to always return nil. Perhaps that could still be populated with the link to the resource using the catalog ID (if available for a given resource)? Is your expectation that the /me/library/albums/[id]?relate=catalog API endpoint should still work using this new ID approach? I'm able to return a result for a library song using the below MusicDataRequest, but I notice that the id for a library song is still the the old school i.XXXXXXXX format: MusicDataRequest(urlRequest: URLRequest(url: URL(string: "https://api.music.apple.com/v1/me/library/songs/i.XMDXXbxtOl0kZ84?relate=catalog")!)) Now that the underlying MPMediaItemPropertyAlbumPersistentID is being used as the local ID for albums, the below MusicDataRequest returns a "Resource with Requested id was not found" error. MusicDataRequest(urlRequest: URLRequest(url: URL(string: "https://api.music.apple.com/v1/me/library/albums/-8844999249623188175?relate=catalog")!)) One way or another, it would be very helpful to have a reliable way of translating between catalog and local IDs. On another note, I've made a little more progress on investigating the issue of some MPMediaItemPropertyAlbumPersistentIDs not returning an album. If I modify my code to convert the unsignedUInt64 returned from the albumPersistentID to a signed Int64 as follows, I'm able to successfully return an album for any ID I give it. It's easy enough to do, but probably confusing for folks not expecting to have to do that. let idString = String(Int64(bitPattern: rep.albumPersistentID)) Thanks!
Topic: Media Technologies SubTopic: General Tags:
Jul ’22
Reply to Exposing library-related metadata on library Songs
@JoeKun This is fantastic news, and in my early testing these properties are working great. I have two quick questions for whenever you get a chance. The description of lastPlayedDate uses some specific phrasing that caught my eye: "The date when the user last played the song on this device." Does it really mean it will only show the date the item was played on that device, or will it report the last play time across any device linked to the user's iCloud Music Library, the way MPMediaItem's lastPlayedDate works? How is lastPlayedDate determined for the Album object? There are a handful of albums in my test library where none of the songs have play counts, last play times, or last skip times, but the MusicKit album itself has a value for this property. Thanks!
Topic: Media Technologies SubTopic: General Tags:
Jul ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
@JoeKun this is amazing! I'm so grateful for all of these improvements. Having the ability to return MusicKit Album objects from an MPMediaItemPropertyAlbumPersistentID makes it so much simpler for me to adopt all this awesome new stuff. I have noticed a couple of issues, for which I've filed feedbacks: FB10581774 - Non-alphanumeric/whitespace characters don't work in equalTo matching When testing the new LibraryAlbumFilter properties, I think I've found an issue where matching on \.artistName or \.title fails to return results when using the equalTo match type and matching on a string containing non-alphanumeric or whitespace characters. The below code fails to return any results when using equalTo, but using the contains version of the filter function correctly returns all the R.E.M. albums in my library. I have also reproduced this same issue when matching on \.title when the album name contains parentheses. var nameRequest = MusicLibraryRequest<Album>.init() nameRequest.filter(matching: \.artistName, equalTo: "R.E.M.") do { let nameResponse = try await nameRequest.response() print(nameResponse.items) } catch { print("name request error: \(error)") } FB10581868 - Some MPMediaItemPropertyAlbumPersistentID matches fail Using the below code successfully returns MusicKit albums in most cases, but sometimes it fails to. Here's my code for the match starting with an MPMediaItem called rep. let idString = String(rep.albumPersistentID) var request = MusicLibraryRequest<Album>() request.filter(matching: \.id, equalTo: MusicItemID(idString)) do { let response = try await request.response() print(response.items) } catch { print("id request error: \(error)") } In cases where matching on this ID doesn’t work, I then do a backup search by .artistName and .title, which returns the album and shows a different ID. The ones that fail show an ID with a huge negative number. It seems like the original MPMediaItemPropertyAlbumPersistentID is unsigned, but the ID MusicKit is using is? Something like that? Here's what prints when I print the ID: Looking for Defeater - Abandoned (Deluxe Edition), id: 9601744824086363441 Here's what prints when I show the results of the .artistName and .title match (using contains, because as described above, using equalTo will fail because of the parens in the album title :D) MusicItemCollection<Album>( items: [ Album(id: "-8844999249623188175", title: "Abandoned (Deluxe Edition)", artistName: "Defeater") ] ) Should I be converting the MPMediaItemPropertyAlbumPersistentID to a string like this, or is there another to instantiate it as a MusicItemID? FB10582021 Expose catalogID if present for Library albums Being able to use an album’s MPMediaItemPropertyAlbumPersistentID to fetch the library version is great, but unless I’m missing something, you then lose access to the album's Apple Music catalog ID. It would be great to be able to still access the catalog ID as well as the local ID. Running dump() on the fetched object, it looks like the catalog ID is embedded in some of the properties, such as the Play Parameters. ▿ playParameters: Optional(MusicKit.PlayParameters(id: -8844999249623188175, kind: "album", isLibrary: Optional(true), catalogID: Optional(MusicKit.MusicCatalogID(value: 1485062012, kind: MusicKit.MusicCatalogID.Kind.adamID)), deviceLocalID: Optional(MusicKit.MusicDeviceLocalID(value: -8844999249623188175, databaseID: 9C47D30D-37C1-4F5C-B5AF-010C9A1052F1)), rawValues: [:])) As always, please let me know if I can provide any other information here or in the Feedbacks.
Topic: Media Technologies SubTopic: General Tags:
Jul ’22
Reply to MusicLibraryRequest to get all tracks from a playlist (iOS 16 beta)
I've been trying to get better at structured concurrency, so I took a stab at a function that collects all of the tracks from a library playlist. I think the key here is using the hasNextBatch property on MusicItemCollection. I'm far from on expert in this world, so I'm sure this code can be improved. In the meantime, here's what I came up with. It correctly returns the number of songs on playlists with more than 100 songs.    func getTracksFromPlaylist(name: String) async throws {         var request = MusicLibraryRequest<Playlist>.init()         request.filter(text: name)         let result = try! await request.response()         if let first = result.items.first {             let withTracks = try await first.with(.tracks)             guard let startingTracks = withTracks.tracks else {                 return             }                       try await getAllTracksFromPlaylist(startingTracks: startingTracks, group: nil)         }     }      func getAllTracksFromPlaylist(startingTracks: MusicItemCollection<Track>, group: ThrowingTaskGroup<[Track],Error>?) async throws  { //If the group didn't come in as nil, that means startingTracks has a next batch that needs to be fetched and processed         if var group = group {                 if let currentSetToProcess = try await startingTracks.nextBatch() { //Add the tracks from this batch to the group                      group.addTask {                         return Array(currentSetToProcess)                     } //If this set has a next batch, run the function again. Once currentSetToProcess.hasNextBatch returns false, the group will complete since it is not awaiting anything else.                     if currentSetToProcess.hasNextBatch {                        try await getAllTracksFromPlaylist(startingTracks: currentSetToProcess, group: group)                     }                 }            //If the group came in as nil, create the group and work through the first batch of tracks.         } else {             try await withThrowingTaskGroup(of: [Track].self, body: { group in //The array to store the final set of tracks                 var allTracks: [Track] = []               //Add the starting tracks to the group                 group.addTask {                     return Array(startingTracks)                 } //If there are more than 100 tracks on the playlist, this is true and means we need to loop through and get the other tracks.                 if startingTracks.hasNextBatch {                     try await getAllTracksFromPlaylist(startingTracks: startingTracks, group: group)                 }                                  //As arrays of tracks are added to the group, append them to our allTracks array.                 for try await tracks in group {                     allTracks.append(contentsOf: tracks)                 }           //Finally, when the group has returned all of the tracks, print the final amount.                 print(allTracks.count)                   })         }     }
Topic: Media Technologies SubTopic: General Tags:
Jun ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
Thanks, @JoeKun! My bad -- yes, I suppose just because they aren't the key paths I want doesn't mean they aren't key paths to begin with ;) I guess the proper request is something like: please add the following properties to the following protocols to enable more specific filtering in MusicLibraryRequests: LibrarySongFilter albumTitle artistName composerName title LibraryAlbumFilter artistName title LibraryArtistFilter name
Topic: Media Technologies SubTopic: General Tags:
Jun ’22
Reply to App hangs while opening from background
I've been seeing intermittent crashes like this for years working with applicationQueuePlayer and now ApplicationMusicPlayer. I've heard from more users seeing this issue than usual since iOS 16.5 came out. Below is one such crash log I got today. I submitted FB12464849 just now with a couple of crash logs. Unfortunately I don't have a sysdiagnose to include, but I'll try to get one from any additional users that report issues like this. Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: FRONTBOARD 2343432205 <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:[application<com.talkingsmall.Albums>:11253] failed to terminate gracefully after 5.0s ProcessVisibility: Background ProcessState: Running WatchdogEvent: process-exit WatchdogVisibility: Background WatchdogCPUStatistics: ( "Elapsed total CPU time (seconds): 3.530 (user 2.080, system 1.450), 11% CPU", "Elapsed application CPU time (seconds): 0.008, 0% CPU" ) reportType:CrashLog maxTerminationResistance:Interactive> Triggered by Thread: 0 Thread 0 Crashed: 0 libsystem_kernel.dylib 0x20ecd3c84 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x20ece6b54 mach_msg2_internal + 80 2 libsystem_kernel.dylib 0x20ece6e2c mach_msg_overwrite + 540 3 libsystem_kernel.dylib 0x20ecd41c8 mach_msg + 24 4 libdispatch.dylib 0x1d727a20c _dispatch_mach_send_and_wait_for_reply + 548 5 libdispatch.dylib 0x1d727a59c dispatch_mach_send_with_result_and_wait_for_reply + 60 6 libxpc.dylib 0x22fb6f218 xpc_connection_send_message_with_reply_sync + 240 7 Foundation 0x1ca0f7f38 __NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY__ + 16 8 Foundation 0x1ca08b2e4 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 2192 9 Foundation 0x1ca089ae0 -[NSXPCConnection _sendSelector:withProxy:arg1:] + 116 10 Foundation 0x1ca089a18 _NSXPCDistantObjectSimpleMessageSend1 + 60 11 MediaPlayer 0x1dfe52108 -[MPMusicPlayerApplicationController _establishConnectionIfNeeded] + 1768 12 MediaPlayer 0x1dfe1b8dc -[MPMusicPlayerController onServer:] + 52 13 MediaPlayer 0x1dfe1a9b8 -[MPMusicPlayerController _nowPlaying] + 372 14 MediaPlayer 0x1dfe21adc -[MPMusicPlayerController nowPlayingItem] + 24 15 MusicKit 0x23b98a7d0 -[MusicKit_SoftLinking_MPMusicPlayerController nowPlayingItem] + 24 16 MusicKit 0x23bedc7f4 0x23b966000 + 5728244 17 MusicKit 0x23bedce34 0x23b966000 + 5729844 18 MusicKit 0x23bede139 0x23b966000 + 5734713 19 MusicKit 0x23bdb629d 0x23b966000 + 4522653 20 MusicKit 0x23bb12fa1 0x23b966000 + 1757089 21 libswift_Concurrency.dylib 0x1da155dd9 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) + 1
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Jun ’23
Reply to Issues with MusicLibraryRequest on macOS/Mac Catalyst
This is still an issue in the second beta seeds of Sonoma and Xcode.
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jun ’23
Reply to Is Apple going to stop people from abusing MusicKit developer token taken from music.apple.com
Well isn't this interesting! With absolutely no disrespect meant to the MusicKit team, who are no doubt limited by time, resources, and internal corporate priorities us outsiders have no idea about, It is frustrating to play around with this token and see so many of the features I would love to include in my app, such as: Deleting library items Time-synced lyrics Artist images Available audio qualities The MusicKit API and web API have already come a long way towards leveling the playing field for third party Apple Music apps, but there are still lots of gaps, which can make our apps feel like second-class citizens. Maybe there are licensing issues preventing features like lyrics, but it is impossible for developers to know the surrounding context, and we are just stuck filing feedbacks and awaiting WWDC each year. If the permissions included in this token were officially supported, my app would be better for it. Here's hoping!
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Feb ’23
Reply to SwiftUI NavigationLink freezing when tapped
I recently finished implementing programmatic SwiftUI navigation in my app and I ran into this. In my experience, it was related to using a different custom type for the navigationDestinations on different screens and having their root NavigationStack path bound to a NavigationPath. To fix it, I ended up making my own NavigationDestination enum with a list of all possible navigation destinations in my app. Now, every .navigationDestionation in my app is for NavigationDestination.self and the root NavigationStack is bound to an array of [NavigationDestination]. No more freezing!
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jan ’23
Reply to iOS 16.0 beta 7 broke Text(Date(), style: .timer) in SwiftUI widgets
Disappointing that this wasn't fixed by the iOS 16 RC but I'm hoping that since it's working in iPadOS 16.1 that it will be fixed as of iOS 16.1.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to iOS 16.0 beta 7 broke Text(Date(), style: .timer) in SwiftUI widgets
I'm having this issue too. Glad I checked the forums! I submitted FB11388263 and mentioned the other two FBs in this thread.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Aug ’22
Reply to MusicKit background threads warning
This happens to me too, even if I've set the function as a @MainActor. I posted about it here and submitted FB10967076 about it.
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Aug ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
Just bumping this thread to note that FB10581868 has been resolved as of beta 4 and I no longer see failures for negative MPMediaItemPropertyAlbumPersistentID values. Hooray! Thanks for that. The other feedbacks mentioned this thread are still unresolved. 🤞
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’22
Reply to Request: An API to remove from Library/Playlist.
I would also love the ability to delete items from a user's library. In case any Apple folks are looking for feedbacks regarding this, shortly after WWDC I filed a feedback (FB10042390) to add that functionality to the new MusicLibrary class and last year I filed one to add the functionality to the Apple Music API as FB9195700. Fingers crossed this gets added!
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
@JoeKun Got it -- that makes sense. Indeed, thanks to the excellent API design, many of the use-cases I can think of are covered by other functions, such as being able to use with(_:preferredSource:) to pull in Library and Catalog information in one fell swoop. The one thing I can't find a solution for is being able to get a link to share the catalog version of the library album or song resource. The URL property seems to always return nil. Perhaps that could still be populated with the link to the resource using the catalog ID (if available for a given resource)? Is your expectation that the /me/library/albums/[id]?relate=catalog API endpoint should still work using this new ID approach? I'm able to return a result for a library song using the below MusicDataRequest, but I notice that the id for a library song is still the the old school i.XXXXXXXX format: MusicDataRequest(urlRequest: URLRequest(url: URL(string: "https://api.music.apple.com/v1/me/library/songs/i.XMDXXbxtOl0kZ84?relate=catalog")!)) Now that the underlying MPMediaItemPropertyAlbumPersistentID is being used as the local ID for albums, the below MusicDataRequest returns a "Resource with Requested id was not found" error. MusicDataRequest(urlRequest: URLRequest(url: URL(string: "https://api.music.apple.com/v1/me/library/albums/-8844999249623188175?relate=catalog")!)) One way or another, it would be very helpful to have a reliable way of translating between catalog and local IDs. On another note, I've made a little more progress on investigating the issue of some MPMediaItemPropertyAlbumPersistentIDs not returning an album. If I modify my code to convert the unsignedUInt64 returned from the albumPersistentID to a signed Int64 as follows, I'm able to successfully return an album for any ID I give it. It's easy enough to do, but probably confusing for folks not expecting to have to do that. let idString = String(Int64(bitPattern: rep.albumPersistentID)) Thanks!
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’22
Reply to Exposing library-related metadata on library Songs
@JoeKun This is fantastic news, and in my early testing these properties are working great. I have two quick questions for whenever you get a chance. The description of lastPlayedDate uses some specific phrasing that caught my eye: "The date when the user last played the song on this device." Does it really mean it will only show the date the item was played on that device, or will it report the last play time across any device linked to the user's iCloud Music Library, the way MPMediaItem's lastPlayedDate works? How is lastPlayedDate determined for the Album object? There are a handful of albums in my test library where none of the songs have play counts, last play times, or last skip times, but the MusicKit album itself has a value for this property. Thanks!
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
@JoeKun this is amazing! I'm so grateful for all of these improvements. Having the ability to return MusicKit Album objects from an MPMediaItemPropertyAlbumPersistentID makes it so much simpler for me to adopt all this awesome new stuff. I have noticed a couple of issues, for which I've filed feedbacks: FB10581774 - Non-alphanumeric/whitespace characters don't work in equalTo matching When testing the new LibraryAlbumFilter properties, I think I've found an issue where matching on \.artistName or \.title fails to return results when using the equalTo match type and matching on a string containing non-alphanumeric or whitespace characters. The below code fails to return any results when using equalTo, but using the contains version of the filter function correctly returns all the R.E.M. albums in my library. I have also reproduced this same issue when matching on \.title when the album name contains parentheses. var nameRequest = MusicLibraryRequest<Album>.init() nameRequest.filter(matching: \.artistName, equalTo: "R.E.M.") do { let nameResponse = try await nameRequest.response() print(nameResponse.items) } catch { print("name request error: \(error)") } FB10581868 - Some MPMediaItemPropertyAlbumPersistentID matches fail Using the below code successfully returns MusicKit albums in most cases, but sometimes it fails to. Here's my code for the match starting with an MPMediaItem called rep. let idString = String(rep.albumPersistentID) var request = MusicLibraryRequest<Album>() request.filter(matching: \.id, equalTo: MusicItemID(idString)) do { let response = try await request.response() print(response.items) } catch { print("id request error: \(error)") } In cases where matching on this ID doesn’t work, I then do a backup search by .artistName and .title, which returns the album and shows a different ID. The ones that fail show an ID with a huge negative number. It seems like the original MPMediaItemPropertyAlbumPersistentID is unsigned, but the ID MusicKit is using is? Something like that? Here's what prints when I print the ID: Looking for Defeater - Abandoned (Deluxe Edition), id: 9601744824086363441 Here's what prints when I show the results of the .artistName and .title match (using contains, because as described above, using equalTo will fail because of the parens in the album title :D) MusicItemCollection<Album>( items: [ Album(id: "-8844999249623188175", title: "Abandoned (Deluxe Edition)", artistName: "Defeater") ] ) Should I be converting the MPMediaItemPropertyAlbumPersistentID to a string like this, or is there another to instantiate it as a MusicItemID? FB10582021 Expose catalogID if present for Library albums Being able to use an album’s MPMediaItemPropertyAlbumPersistentID to fetch the library version is great, but unless I’m missing something, you then lose access to the album's Apple Music catalog ID. It would be great to be able to still access the catalog ID as well as the local ID. Running dump() on the fetched object, it looks like the catalog ID is embedded in some of the properties, such as the Play Parameters. ▿ playParameters: Optional(MusicKit.PlayParameters(id: -8844999249623188175, kind: "album", isLibrary: Optional(true), catalogID: Optional(MusicKit.MusicCatalogID(value: 1485062012, kind: MusicKit.MusicCatalogID.Kind.adamID)), deviceLocalID: Optional(MusicKit.MusicDeviceLocalID(value: -8844999249623188175, databaseID: 9C47D30D-37C1-4F5C-B5AF-010C9A1052F1)), rawValues: [:])) As always, please let me know if I can provide any other information here or in the Feedbacks.
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’22
Reply to MusicLibraryRequest to get all tracks from a playlist (iOS 16 beta)
I've been trying to get better at structured concurrency, so I took a stab at a function that collects all of the tracks from a library playlist. I think the key here is using the hasNextBatch property on MusicItemCollection. I'm far from on expert in this world, so I'm sure this code can be improved. In the meantime, here's what I came up with. It correctly returns the number of songs on playlists with more than 100 songs.    func getTracksFromPlaylist(name: String) async throws {         var request = MusicLibraryRequest<Playlist>.init()         request.filter(text: name)         let result = try! await request.response()         if let first = result.items.first {             let withTracks = try await first.with(.tracks)             guard let startingTracks = withTracks.tracks else {                 return             }                       try await getAllTracksFromPlaylist(startingTracks: startingTracks, group: nil)         }     }      func getAllTracksFromPlaylist(startingTracks: MusicItemCollection<Track>, group: ThrowingTaskGroup<[Track],Error>?) async throws  { //If the group didn't come in as nil, that means startingTracks has a next batch that needs to be fetched and processed         if var group = group {                 if let currentSetToProcess = try await startingTracks.nextBatch() { //Add the tracks from this batch to the group                      group.addTask {                         return Array(currentSetToProcess)                     } //If this set has a next batch, run the function again. Once currentSetToProcess.hasNextBatch returns false, the group will complete since it is not awaiting anything else.                     if currentSetToProcess.hasNextBatch {                        try await getAllTracksFromPlaylist(startingTracks: currentSetToProcess, group: group)                     }                 }            //If the group came in as nil, create the group and work through the first batch of tracks.         } else {             try await withThrowingTaskGroup(of: [Track].self, body: { group in //The array to store the final set of tracks                 var allTracks: [Track] = []               //Add the starting tracks to the group                 group.addTask {                     return Array(startingTracks)                 } //If there are more than 100 tracks on the playlist, this is true and means we need to loop through and get the other tracks.                 if startingTracks.hasNextBatch {                     try await getAllTracksFromPlaylist(startingTracks: startingTracks, group: group)                 }                                  //As arrays of tracks are added to the group, append them to our allTracks array.                 for try await tracks in group {                     allTracks.append(contentsOf: tracks)                 }           //Finally, when the group has returned all of the tracks, print the final amount.                 print(allTracks.count)                   })         }     }
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jun ’22
Reply to TabView selection deprecated?!
Same question here. I'm hoping this will become clearer in future beta seeds.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jun ’22
Reply to Thoughts on MusicLibraryRequest as a replacement for MPMediaQuery
Thanks, @JoeKun! My bad -- yes, I suppose just because they aren't the key paths I want doesn't mean they aren't key paths to begin with ;) I guess the proper request is something like: please add the following properties to the following protocols to enable more specific filtering in MusicLibraryRequests: LibrarySongFilter albumTitle artistName composerName title LibraryAlbumFilter artistName title LibraryArtistFilter name
Topic: Media Technologies SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jun ’22