ShowShark Release Notes v2026.03.23 [Coming Soon]
Overview
At first I thought it'd be pretty simple to implement downloads and offline playback. I'd need a workaround for the realtime pacing that happens on the server while transcoding (ie, transcode as fast as possible), and I'd need to save it to "disk" (client side) for offline playback. What I discovered is that my early decision to use PCM audio for everything had a meaningful downside: the audio portion of the data stream accounted for 5/6ths (or more!) of the data transfer. Video, the seemingly more complex portion, was a tiny fraction. I only noticed this because I decided to write the audio packets to one file and the video frames to another file, so that I could independently access each "stream" during playback (batching audio packets and video frames to reduce messaging overhead would otherwise mean that I'd need to do extra buffering on the client to better mux the two streams when writing them to a single file). Anyway, like I said, 80% of the data was just audio (and associated overhead).
I'm still happy I started with PCM audio for everything because it reduced the complexity of getting things working initially – audio/video synchronization in particular. Starting from a solid foundation and iterating on that (adding AAC audio) was still challenging, but do-able, and WAY easier than trying to debug synchronization issues while wondering if AAC encoding / decoding was a contributing factor.
I've more-or-less got ShowShark where I want it to be for basic usefulness with just tweaks and minor features on the horizon at the moment. I've got a ridiculous feature list, but I'm going to be judicious in deciding on feature creep here.
Offline Downloads
- Download videos for offline playback -- save any video from your library to your device for viewing without a server connection. Tap the new Download button on any media detail view to queue a download, with your current subtitle selection included
- Offline playback with full controls -- play downloaded content using the same decode and sync pipeline as live streaming, with support for play, pause, resume, and seeking via a persisted seek index of keyframe positions
- Downloads management view accessible from the server list (no active connection required), with In Progress, Completed, and Failed sections plus row actions for cancel, retry, delete, and play
- Downloads grouped by content topic -- completed downloads are organized by their associated movie, show, or album rather than shown as a flat list, making it easier to find what you saved
- Storage usage summary shown in the downloads view so you can see how much space your offline content is using
- Maximum-speed downloads -- download sessions bypass the real-time pacing used for live streaming, so files download as fast as your connection and the server's encoder allow
- Downloads accessible on all platforms with navigation wired through iOS, iPad, macOS, tvOS, and watchOS
Audio
- AAC audio codec for streaming and downloads -- audio is now encoded as AAC (192 kbps) instead of uncompressed PCM (~1.5 Mbps stereo), reducing audio bandwidth by roughly 8x while maintaining full A/V sync. The server probes for available AAC encoders at runtime (avenc_aac preferred, voaacenc fallback) and falls back to PCM if neither is available
- Client-side AAC decoding via AVAudioConverter with ADTS frame parsing, encoder delay trimming, and multichannel output support. The codec preference is preserved across seek, resume, and reconnect flows
Bug Fixes
- Fixed race condition causing corrupt offline packages – with fast encoders (e.g. H.264), the server's stream initialization message could arrive before the client had registered the download session writer, causing the offline package to start with a video frame instead of initialization data and making it unplayable. The download session registry now buffers operations that arrive before registration and replays them in order once the writer is ready