Fun bug in the MPMedia API
I have had an ongoing bug in my music app that I have finally tracked down now (now that I am re-writing it in swift). It has a few facets. (using systemMusicPlayer)
- I think I have narrowed the issues down to an MPMediaItem that has the following properties.
- MPMediaItemPropertyIsCloudItem = true
- assetURL = nil
- ** these two make sense, but the following corner case (well probably pretty common) threw me for a while**
- The first 2 items can be true, but I believe if you copied it from iTunes, it /can/ be playable (they would play most of the time for me), and there is no way to tell. I have tested this over and over and it seems to be the case, but these MPMediaItems by their existence might only sometimes cause issue, or they are fine. But you cant find out which songs these are.
- If you are playing a queue, and systemMusicPlayer comes across a
song in your library but not downloaded or copied form iTunes, I believe it will automatically skip the
song, similar to systemMusicPlayer.skipToNextItem(), but I think
internally it's a different mechanism.
- 2a. This behavior causes a basically unrecoverable problem if you are using systemMusicPlayer.skipToPreviousItem() and come across an Item that would have been skipped over - meaning, it doesn't recognize that you are trying to move back in the queue and just throws the error and moves the queue forward.
- 2b. As far I I could tell, when the error hits going forward the MPMediaItem never becomes the nowPlayingItem. The problems going backwards get compounded by the MPMediaItem metadata (which is always available weather it is local or not) getting loaded, but the song trying to play immediately sends it forward in the queue again.
OK, so asinine and infuriating.
Now to my question:
I cant do anything about not being able to know if a cloud item is on the device or not (via iTunes). I /should/ be able to just filter out if an item has an assetURL, however, which is a guarantee that it is local and available.
let filter:MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: "ipod", forProperty: MPMediaItemPropertyAssetURL, comparisonType: MPMediaPredicateComparison.Contains)
This returns 0 items. Does anyone know of a way to filter on this property? Doing it here seems like it would be the cleanest, and should leave the query returning items and itemSections. All my tables populate from the queries, and I dont think theres a way to reconstruct one manually.
The URL has a format like this: ipod-library://item/item.m4a?id=5314739480586915369
Now, I suspect it is possible to add catches when populating table views and such, but it feels really messy.
This is ios 9.2.1, Swift 2, Xcode 7.2.1
I have not yet wiped the phone and re-copied the songs. Manually downloading them from the Music app is the only way the items get an assetURL if it was not present.