Once upon a time Cs contained Last.fm support. I was still very green, and it was implemented poorly, but this was also at the time of the significant Last.fm redesign, and things were equally screwy server-side. It became impossible to tell which errors were mine, what might be an issue on the other end. All that was clear was it didn’t work as reliably as it needed to.
Eventually I cut the feature. It was the first significant feature I ever cut from Cs, but it was also relatively easy to drop a tangential feature that wasn’t working properly. If it couldn’t be done properly, I preferred to not do it at all.
It’s likely pretty clear where this is going. Cs now contains a sizeable chunk of features that have been built upon undocumented functionality and characteristics of the iOS media player API. Undocumented doesn’t mean restricted or forbidden, but it is subject to change without notice. Through the first half of Cs’ life these changes were very minimal. In some instances they could even be exploited to provide new features or improve performance. It was fine as long as it kept working, but it was built on sand. In iOS 11, and now 12, that sand shifted leaving a whole family of interrelated features teetering precariously. For the last 18 months a huge portion of my available development time has been taken up with tinkering like a mechanic trying to keep an old jalopy on the road.
Here’s a good example: the Apple API provides no visibility to the contents of the system queue. Cs uses a “technically allowed but unsupported” method to retrieve these items. It uses only properties that are publicly available, and it’s crazy slow, but it could be reliably used to capture the system queue. The ability to compare and sync with the system queue became the foundation for much of the advanced queueing features, like detecting discrepancies for Queue Resume. In iOS 11, an undocumented change meant that now this method only returned the first 500 items. Now, the system had to be rebuilt with Queue Resume essential to recontextualizing the queue in Cs, or the first change would truncate longer queues to only 500 tracks. In iOS 12, the system started only returning the first 100 items (and everything could freeze and crash at potentially any time because the system API might just not respond and cause the app to time out). Now, a whole network of features are dependent on layers built upon an undocumented behaviour that cannot be relied upon, nor modified.
This was pretty quickly reflected in the reviews. Cs’ overall rating has started to slip, and I see a lot of variations of “I used to love this app” nowadays. The economics of the App Store are harsh to both developers and existing (non-subscribing) users. Cs has a roughly 90% monthly churn, so most of these users (even the 5-star reviewers) will move on soon enough. The reality is that success and growth for Cs’ economic model are driven by delivering new users an optimal experience. Pushing the problematic features behind the “Advanced Queueing” setting and disabling this by default helped, but it is quite literally sweeping the problem under the rug.
For the last week or so I have been working on a new, API-safe branch of Cs. A version of the app based (almost) exclusively on documented API features. Certainly in regards to the media player API. The idea is to do only what can be done well, reasonably “safely,” and future-proof. The casualties would look something like this:
Queue Management: The first casualty is explicit queue management. Tracks can still be queued up to Play Next, or Play Later, but not viewing, reordering, or deleting from the queue.
Playback History: Not technically impossible, but nowhere to live. And easy enough to reproduce with a Recently Played smart playlist.
Resume Queue: I won’t lie, I didn’t shed tears over this one.
Shuffle Modes: Without the custom queue layer it isn’t possible to shuffle by album or grouping.
Shake to Shuffle: Could only work when Cs was running, which is not representative of the full listening experience. This is a strict cut, but that’s the idea.
Ratings and Love: The ratings API was never updated to account for iCloud Music Library. Changes never propagated to the cloud, and in worst cases the cloud would actually overwrite local ratings. The Love API was never officially documented.
Today Widget: Without ratings/love this brings no value over the iOS default.
Tab-Specific Search: I 😍 the new integrated NavBar search bars, but they are buggy as hell when you put them in multiple tabs. I still have to jump through hoops just to keep the single Search tab working with the “More” tab.
Multi-Genre Support: I have mixed feelings about this one. Technically, it could stay but the current implementation has a significant issue that can’t be worked around without seriously affecting performance. This is about doing less flawlessly, so it has to go.
It’s a substantial shift, and one that I know will kill the “pet feature” for a lot of users. At the same time, it’s clear that a new approach is needed in order for Cs to remain viable moving forward. As always, it’s likely entirely up to your listening habits; I’ve personally found the change refreshing. I’m not yet sure if, when or how the API-safe version will be released. But it’s something I’m working on and I’d love to hear back from you in the comments.