New Apple Watch client with full media browsing, playback, and server connectivity. The watch app connects to the ShowShark Server via HTTP long-polling (since watchOS blocks direct WebSocket connections) and streams media using HLS
HLS video and audio playback on watchOS with optimized transcoding (198x242 at 400 kbps) sized for the watch display and Bluetooth relay throughput. The server generates 2-second HLS segments for fast startup, and the watch buffers several segments before playback begins, showing a countdown timer during buffering
Channels and history on the watch home screen matching the iOS layout -- Video, Audio, and Photo Channel sections (hidden when empty), plus Library and History. Tapping a channel starts playback directly; tapping a history entry resumes from the saved position
Digital Crown volume control during playback, resolving crown sequencer errors that occurred when no view was associated with the Digital Crown
Server disconnect button on the watch library root for returning to the server list
Connecting spinner on the server list with double-tap prevention during connection attempts
Program title display during channel playback instead of the generic channel name
Services unavailable alert after login if the server's HTTP Polling or HLS services are disabled, so users understand why playback won't work
Audio session lifecycle fix preventing repeated playback failures -- uses watchOS async activation and avoids deactivating the audio session between plays
Content Discovery
Recommendation engine with three discovery modes for finding media in your library:
Similar To -- select a movie or show from your library and get the top 10 most similar titles, scored by keyword overlap, genre overlap, cast overlap, year proximity, and rating proximity
By Feel -- filter your library by time commitment (quick / medium / long / epic) and mood (light & fun, intense, thought-provoking, heartwarming, dark & edgy), then narrow results through a binary search flow that presents two candidates side-by-side for you to choose between
By Genre -- browse top-rated titles within a selected genre
Find Similar button on movie and show detail views for quick access to similar content
Discover tab added to all platform navigation views (iOS, iPad, macOS, tvOS, watchOS)
Controlled randomness in the binary search pairing so repeated sessions feel fresh
Adaptive Bitrate Streaming
Fully automatic bitrate adjustment replaces the manual bitrate and quality pickers. The server dynamically adjusts the encoder bitrate mid-session based on real-time client feedback, eliminating the need for users to configure streaming parameters
AIMD algorithm (Additive Increase / Multiplicative Decrease) with buffer-zone logic: critical buffer levels trigger immediate bitrate halving, low buffers reduce by 15%, healthy buffers increase when throughput allows, and high buffers increase regardless of measured throughput
Conservative 2 Mbps startup that works on any connection, ramping to 10 Mbps in about 48 seconds on fast networks
Live encoder bitrate display in the server Status tab during active transcoding sessions
Server-Backed Play History
Play history migrated to the server -- watch history is now stored server-side and shared across all your devices, replacing the previous device-local storage. History entries include full media context (movie, show, episode, artist, album, song IDs) for richer navigation
Music play history collapsed to one entry per album -- listening to multiple tracks from the same album no longer creates separate history entries. The most recent track title is shown as a subtitle
Episode play history now correctly records show and episode IDs, enabling the Library navigation button in playback views
Channel playback positions are saved to history so resuming a video you watched on a channel starts where you left off
History refreshes immediately on tvOS when dismissing a playback modal
Play history resume now auto-advances -- resuming a song from play history restores the full album collection context, so playback continues through the remaining tracks instead of stopping after one song. The saved position is also honored, resuming from where you left off
Library Validation
Validate your media library by running short transcoding tests on all indexed video files. The server plays 10 seconds of video and audio from each file to verify it can be transcoded successfully
Persisted results survive server restarts and are saved after each file, so validation can be interrupted and resumed
Live progress UI with running success/failure counters and a results sheet listing failed files
Mutual-exclusion guards prevent validation from running concurrently with library scans or cleanups
Search filter in the validation results sheet for quickly finding specific failures by path, title, or error description
Per-entry removal -- individual failure entries can be deleted from the results sheet, removing them from memory and disk
Split clear actions -- separate "Clear History" (reset everything) and "Clear Errors" (remove only failures so they can be re-validated while keeping successful results) options replace the single clear button
Resume and clear buttons always visible when results exist, so stopped validations can be resumed without re-running
Failures button hidden when zero -- the "View Current Failures" button only appears during active validation when there are actual failures to review
Stream-end detection fix -- files that produce less than 10 seconds of valid output are now detected immediately when both streams exhaust, instead of waiting for the 30-second timeout. Pipeline teardown is dispatched to a background queue with a timeout to prevent VideoToolbox encoder hangs from blocking indefinitely
ShowShark Validate CLI
New command-line validation tool for testing media file transcoding compatibility without running the full server and client. Run ShowShark Validate -i <media-file> to perform a quick transcoding probe against any file
Server-parity codec negotiation -- mirrors the server's playback startup logic, including HEVC-when-available preference with automatic H.264 fallback
Configurable runtime via --seconds (default 12s) for batch-friendly probing, and --codec to test specific encoder paths (hevc, h264, or unspecified)
Non-zero exit codes on startup or stream errors for scripting and automation use
Console log mirroring so full diagnostic output appears in the terminal during validation runs
Server Logging & Diagnostics
Server log gathering and submission -- enable file-based logging (with 24-hour auto-disable), gather logs filtered by time range, compress with gzip, and submit to the ShowShark support service with a reference ID for tracking
Firewall self-diagnostic detects when macOS Application Firewall silently blocks incoming connections (common after Xcode rebuilds change the app code signature) and displays a warning with fix instructions
Pipeline edge-case registry documenting all known GStreamer transcoding edge cases, their failure modes, current safeguards, and a regression checklist for safer pipeline code changes
Streaming & Encoding
Automatic video codec negotiation -- the client detects hardware H.265 decode support at startup and reports its capabilities to the server, which validates encoder availability before accepting. No user-facing codec picker needed
Automatic HEVC-to-H.264 fallback for software-decoded sources (AV1, VP9, MPEG-2) where VideoToolbox's HEVC encoder achieves only ~12 fps from CPU memory buffers vs ~162 fps for H.264
Intelligent output resolution replaces the persisted global resolution setting. Each session now defaults to an "Auto" mode that computes the optimal resolution as the minimum of the source resolution and the device's native capability (e.g., Apple TV 4K automatically gets 4K, Apple TV HD gets 1080p)
Audio packet coalescing merges 6-8 small buffers into ~200ms packets, reducing audio sends from ~31/sec to ~5/sec
Streaming send path optimized from 3 actor hops to 1, eliminating ~70 unnecessary actor context switches per second during playback
Network QoS improvements -- correct service class (interactiveVideo instead of signaling), TCP_NODELAY to disable Nagle's algorithm, and nonisolated sends that bypass the actor mailbox for thread-safe NWConnection operations
DivX/Xvid codec mapping fix for AVI file playback
AC-3 Dolby decoder selection fix -- the audio pipeline now selects decoders based on actual caps compatibility (audio/x-ac3 vs audio/x-eac3) instead of unconditionally preferring E-AC-3, preventing delayed-link failures on AVI files with true AC-3 audio
Dolby renegotiation safeguards for streams that initially appear as AC-3 with IEC61937 alignment then renegotiate to E-AC-3 mid-stream. Prevents decoder lock-in on the wrong codec during hybrid Dolby playback
H.264 software decode fallback for MP4 files with malformed avcC configuration records (invalid nal_length_size), which cause VideoToolbox hardware decode to fail at session creation
MPEG-PS container detection now inspects actual stream metadata instead of relying on file extensions, correctly handling MPEG Program Stream content mislabeled with .avi extensions
DIV3/MSMPEG4v3 decode path properly detected and routed through decodebin instead of the MPEG-4 Part 2 parser, fixing AVI files using legacy Microsoft codecs
x264 software encoder fallback for legacy MPEG-PS sources where VideoToolbox's hardware H.264 encoder crashes during session creation
Startup pacing stabilized -- the startup transport boost now exits on queue pressure (not just elapsed time), preventing sustained media lead that caused downstream frame drops. MPEG-PS track routing uses caps-based auto-pad linking instead of fragile indexed pad assumptions
Client UI
tvOS button bar redesign -- toolbar buttons (Play, File Details, Thumbnails, Library, Find Similar, Skip) are moved to a consistent in-content button bar across all views, since tvOS toolbar items don't render visibly. Applies to playback views, library detail views, discovery views, and media grid
Unified Play button replaces separate Start Playback and Resume buttons. When a resume position exists, tapping Play shows a confirmation dialog with "Play from beginning" and "Resume from X:XX" options
Go to Library button in player views navigates directly to the corresponding movie, show, or album detail when playing media with a library entry
Thumbnail grid layout replaces text lists in library search results, genre browsing, and actor browsing, with 16:9 thumbnail cards matching the media grid pattern
History section converted to dynamic thumbnail grid matching the channels and library sections
Genre pill layout -- genres display as compact tappable capsule pills in a wrapping flow layout instead of full-width rows
Genre-scoped browsing -- genre sections in the library search empty state are broken down by media type (Movie Genres, TV Show Genres, Music Genres) with type-specific results including artists, albums, and songs for music genres
Search history -- recent library searches are persisted and shown in the search empty state
Library stats overview shows aggregate counts (movies, shows, episodes, artists, albums, songs) in the library search view
Season selector added to show detail views for quick navigation between seasons
tvOS grid density increased to four items per row (from three) with reduced inter-item spacing
tvOS focus/scroll position preserved on back-navigation across media grid, show detail, search, genre, and actor browse views
tvOS channel guide focus indication improved with prominent highlighting on program tiles
Source codec and resolution shown as an "Input" row in the Output Resolution section, replacing the unused video track picker
About sections added to both Server and Client with app info, version, copyright, and support links
TMDB API key guidance added to the Providers settings tab
Server Status tab redesigned with Form/Section layout matching the About and Settings tabs, now also showing HLS and HTTP Poll server status alongside WebSocket listeners
Live directory filter -- when browsing inside folders, a search icon toggles an inline filter bar that performs real-time case-insensitive matching against file and folder names, making it easy to find items in large directories
Server admin views redesigned -- Locations, Library, Channels, Devices, and Providers views all updated to use Form with grouped style for a consistent, native appearance
Devices view time-based sections -- connected devices are grouped into Today, Yesterday, and Earlier sections based on last connection time
Record counts in admin headings -- server admin pages now show the number of items (e.g., "Locations (3)") and the redundant "ShowShark" prefix is removed from page titles
About section legal links -- privacy policy, terms of service, GStreamer license (LGPL), and SQLite license (public domain) links added to the About view
Support website URL displayed in the About support section
Password reveal toggle on the master password field
Subtitles
Adjustable subtitle timing delay from -3s to +3s, with corrected delay direction so the label matches user expectation
Improved subtitle text formatting -- strips SRT/HTML tags, ASS drawing commands, and hard spaces that were previously rendering as literal text
Subtitle settings sheet fixed on macOS where content was invisible due to zero-height List rendering
Channel subtitle button moved inline with the volume control to save vertical space
Lyrics
Lyrics persist across track changes -- switching songs auto-fetches new lyrics without dismissing the lyrics view, replacing the full-screen overlay with an integrated content-switch pattern
Background audio auto-advance fixed to reliably trigger when the app is backgrounded, by moving collection advance logic from SwiftUI .onChange to a manager callback
Song title and artist shown in the lyrics view navigation bar
Lyrics resolution fix when playing songs from folder browse -- the server now prefers database-resolved song metadata over client-provided filenames when looking up lyrics
Manual lyrics scrolling on tvOS -- synced lyric lines are now individually focusable via the Siri Remote, with manual navigation pausing auto-scroll for 5 seconds before resuming (matching iOS/macOS behavior)
Networking & Connectivity
Authentication-aware request handling -- client requests now wait up to 15 seconds for authentication to complete during reconnection instead of immediately failing with a "not connected" error
Connection hammering fix -- added a 2-second minimum interval between connection attempts and a re-entrancy guard on disconnection handling to prevent rapid-fire server hammering
Stale server connections fix -- server-side NWConnection is now properly cancelled when the client disconnects, preventing ghost entries in the active clients list
visionOS connection fix for potential EINVAL failure on physical Vision Pro hardware, replacing an async TLS verify callback with a simpler boolean flag that avoids platform-dependent dispatch timing issues
WebSocket liveness detection -- the client now sends periodic pings and monitors pong responses using RTT-adaptive timeouts (EWMA-smoothed, 2s floor to 15s ceiling). Two consecutive missed pongs trigger disconnection, detecting server crashes and network drops within ~10-12 seconds on LAN instead of hanging indefinitely
Graceful server shutdown -- the server sends WebSocket Close frames to all connected clients before shutting down, giving clients immediate notification instead of waiting for a timeout
Reconnection backoff -- retry intervals now increase incrementally by 1 second per attempt, capping at 5 seconds, replacing the previous fixed-interval behavior
Reconnection stall fix -- when a reconnect attempt gets "Connection refused" (server still down), the client now properly schedules the next retry instead of getting stuck in a state that never transitions to reconnection
Pong frame handling fix -- WebSocket pong frames (which arrive with nil content) no longer kill the client's receive loop. Control frames are now correctly identified and handled without requiring data content
Channel live offset accuracy -- the server is now queried for the current program offset at the moment playback begins, rather than when the playback view first appeared
Navigation & Playback Flow
Playback back-navigation fixed across all Apple platforms -- the back action during active playback now returns from the video surface to the track selection form instead of popping the entire route. PiP restore flow hardened to prevent duplicate route pushes
Photo channel chrome hiding fixed on iOS and macOS -- status bar, window chrome, and navigation bars now properly hide/show with tap-to-toggle, using a preference key to bubble status bar state through NavigationStack
tvOS channel guide back button now correctly dismisses just the program detail (not the entire guide) by making program detail a proper NavigationPath destination
Shared navigation logic -- platform navigation views (iOS, iPad, macOS, tvOS) now share centralized helpers for action handling and destination resolution, reducing ~780 lines of duplicated code while each platform retains its unique layout
Album detail playback context fix -- playing a track from an album detail view reached via play history now correctly carries the album ID, keeping the Library toolbar button visible and auto-advance working
Full-screen photos centered in both playback and viewer screens, with full-screen rendering on tvOS
Server
HTTP Polling and HLS services are now configurable in server settings with individual enable/disable toggles, port configuration, and cross-port conflict validation
HLS transcoding sessions visible in the server Status tab with codec, position, and progress tracking
"HTTPS Polling" renamed to "HTTP Polling" across all server UI since the polling transport no longer uses HTTPS
Performance
15-20 second startup delay eliminated on iOS -- MainActor Tasks created during init() were flooding the executor and starving UIKit's RunLoop. Fixed by deferring task creation to the next RunLoop cycle via DispatchQueue.main.async
Client startup latency reduced by moving Bonjour discovery and network checks off the MainActor into dedicated actor and detached task contexts