Jukeboxx iOS V3
The same backend used in the Jukeboxx Web App is used here, mostly Backblaze – a robust and low-cost cloud storage provider – for hosting a streamable copy of your music collection. See the Motivation section for details on backend architecture and motivation, which is generally the same as the web app’s.
Download for Offline Playback
The biggest functionality difference between this native iOS app and the web app is the ability to download music for offline playback. Since the media is deployed as HLS on a CDN, it can be streamed natively with iOS’ built-in
AVPlayer. However, to persist HLS streams, the app uses
AVAssetDownloadURLSession to obtain a file URL pointing to disk. Once the download to the home directory is finished, the app saves this key and path tuple into a local manifest file. Unfortunately, one limitation is that this workflow is not supported on simulators and requires device testing.
Reactive UI with CwlSignal
The other big difference is the UI framework – the web app uses React, a battle-hardened and widely-used framework for reactive UI. For the iOS app I wanted to use a similar paradigm (this was before SwiftUI :) in Swift (so this precluded React Native which has developers writing JSX mostly). I pored through Cocoa with Love’s articles on reactive programming, which culminated in CwlSignal and thought I’d give it a spin!
I found that it allows you to neatly bin away signaling and data changes from the according UI reactions. This led to some neat componentization where I was able to define reusable UI components that had a “signal” interface and not just a OO-style “getter/setter” interface. As long as the controller or parent-view that owned the view could feed it the right signals (or omit them where appropriate), the view could be used.
Compared to React, I found it more boilerplate-y just because you spend many lines of code wiring many signal sources to sinks. However, once that’s out of the way, the rest of the code is simple and easy layout/styling code or straightforward reactive functions. This limitation fundamentally derives from the fact that CwlSignal is merely a Swift library (albeit with some syntax sugar like overloading
+=) while React invents JSX to allow even more terseness than possible with vanilla JS. Note for instance, how many language additions SwiftUI required in Swift before it could be released.
Overall, I remember being content and having fun developing with CwlSignal, but when I looked at the code again some months later, it took me some time to pore through and realize what was going on (that syntax sugar!). SwiftUI and Combine are the 800lb gorillas in the room though, so it’s unavoidable that any future work I do with Swift will be giving those frameworks a spin instead. Sadly, it looks like Matt has come to the same conclusion as well.
Jukeboxx fits your use case if:
- You own a library of music files
- You want to stream your library from anywhere
I built this system because, while Spotify is great for discovery, I have music (e.g. remixes, exclusives) not available on streaming services, and because I personally enjoy organizing and owning my music collection. The downside is that it’s a) labor intensive to stay organized and b) not available beyond my laptop. To solve a) I discovered Beets, a music library manager that autotags your music by cross-referencing MusicBrainz. For b), I landed on Backblaze for file hosting, since it’s fast, reliable, and the cheapest (practically free!1), and Jukeboxx for playback. My set up is as follows:
Legend: ✊ denotes a manual process, 🤖 for automated
- ✊ Buy high fidelity music (FLAC ripped from CD or online from 7Digital)
- ✊ Save it onto my external hard drive
- 🤖 Import it into my Beets library
- 🤖 Transcode the tracks into a streamable format
- 🤖 Download album and artist artwork from MusicBrainz and Spotify
- 🤖 Sync the streamified tracks, artwork, and library info to Backblaze
- ✊ Play the music in Jukeboxx in any browser!
If you want to give it a spin, try the demo! I’ll be publicly releasing Jukeboxx iOS V3 and its related automation tools soon, after a bit more polish, so that others can self-serve their music. Stay tuned!
If you played music non-stop, every minute of every day, it would come out to ~$3 USD a year 🙀 ↩︎