ShowShark Server Features
ShowShark Server is a macOS application that manages a media library, transcodes video and audio on the fly, and streams content to ShowShark Client apps over the local network.
Networking
- WebSocket over TLS (WSS) for secure client-server communication
- Optional plain WebSocket (WS) listener for reverse proxy setups (e.g., Caddy or nginx terminating TLS upstream)
- Configurable ports for both listeners (default WSS: 18080, plain WS: 18081)
- Bonjour/mDNS service advertisement for automatic server discovery by clients
- Persistent server UUID across restarts so clients can identify the server reliably
- Protocol Buffers (SwiftProtobuf) for all message serialization
- MessageEnvelope wrapper with request-response correlation IDs
- 40+ distinct message types across authentication, browsing, playback, thumbnails, channels, library, and lyrics
interactiveVideoservice class and TCP_NODELAY (Nagle disabled) on all listeners for low-latency streaming- Maximum 100 concurrent client connections, 5 per IP address
- Sequential message receive loop per client with fire-and-forget Tasks for slow operations (playback, thumbnails)
- HTTP polling server for watchOS clients: POST
/login(HTTP Basic Auth, returns bearer token), POST/send(protobuf messages with synchronous responses), GET/poll(25-second long-poll with batched length-prefixed messages), 120-second inactivity timeout with automatic session eviction
Authentication & Security
- Password-based authentication with device name and device identifier tracking
- Per-IP authentication throttling with escalating delays (1s, 2s, 4s, 8s cap) on failed login attempts, auto-expiring after 15 minutes
- Session management with per-connection tracking
- Known device registration with last-connected timestamps
- Self-signed TLS certificate generation and keychain storage
Media Library
Scanning & Indexing
- Recursive media file discovery across configured filesystem locations
- Movie, TV show, and music library scanning with automatic content classification
- TV show episode filename parsing:
s03e12,s01e01-03(ranges),e12,3x12formats - Music filename parsing:
01 - Song Title.mp3,01. Title.flac - Blu-ray disc (BDMV) directory detection and indexing
- Image files and photo directories automatically excluded from library scanning
- Duplicate detection via in-memory Set for O(1) path lookups
- Incremental scanning: cast/genre linking only runs for newly created records
Database
- SQLite database with actor-based thread safety
- Tables: movies, shows, episodes, files, artists, albums, songs, genres, people, and linking tables
- Movie ratings: G, PG, PG-13, R, NC-17, NR, Unrated
- TV ratings: TV-Y, TV-Y7, TV-G, TV-PG, TV-14, TV-MA, NR
- Consolidated schema with incremental migration support
- UNIQUE indexes to prevent duplicate records
- Batch query methods to eliminate N+1 query patterns
Library Maintenance
- Orphaned file detection and user-confirmed cleanup
- Deleted-location cleanup for removed media locations
- Excluded-directory cleanup
- Image file cleanup for incorrectly-indexed records
- Cascading deletion: removing a file cascades to its parent movie/episode/show if no files remain
- Automatic daily cleanup scheduler (3:00 AM)
Library Search
- Multi-field search across titles, overviews, genres, actors, and years (bitmask-controlled)
- Cross-type results: movies, shows, genres, actors, artists, albums, songs, photo albums
- Genre-scoped browsing by media type (Movies, TV Shows, Music) via
GenreMediaTypeenum - Genre lists fetched in a single request via
GetGenreListsRequest(movie, show, and music genres) - Music genre browsing with artist, album, and song queries (LIMIT 200, ordered by title)
- Library stats endpoint (
GetLibraryStatsRequest): aggregate counts for movies, shows, episodes, artists, albums, songs - Detail queries: movie detail with cast, show detail with seasons/episodes, episode detail, album detail with songs, artist detail with discography, genre media, actor filmography
Metadata Providers
TMDB (The Movie Database)
- Bearer token authentication
- Movie and TV show search, detail retrieval with credits
- Poster and backdrop images
- Top 10 cast members with profile photos, character names, and ordering
- US content certification from release dates and content ratings endpoints
- Genre extraction
OMDB (Open Movie Database)
- API key authentication (accepts both keys and URLs)
- Rotten Tomatoes scores
- MPAA and TV ratings
- Genre and cast names
Hybrid Metadata Strategy
- TMDB for images, cast photos, genres + OMDB for Rotten Tomatoes scores and ratings
- Fallback: TMDB certification endpoints when OMDB is unavailable
- Rate limiting: 1 request/second per provider (token bucket)
- Disk-based metadata cache
Music Metadata
- MusicBrainz for artist and album identification
- Cover Art Archive for high-quality album art
- Last.fm as fallback for album art
- ID3v2, Vorbis Comment, and FLAC tag extraction (artist, album, title, track number, disc number, genre, duration, embedded album art)
Lyrics
- LRCLib integration for synced lyrics
- LRC format parsing into timestamped lines
- Plain text lyrics fallback
- Song info resolution from DataStore when title/artist not provided in request
- File-based lyrics caching
Person/Cast Metadata
- Provider-agnostic storage:
external_id+external_source(not TMDB-specific) - Person photos proxied through server via virtual path prefix to prevent direct client access to external APIs
- SSRF protection on image proxying
Video Transcoding
Input Formats
- Containers: MKV, MP4, MOV, AVI, WebM, MPEG-PS (.vob), MPEG-TS (.ts/.m2ts), plus auto-detect
- Video codecs: H.264, H.265/HEVC, MPEG-1, MPEG-2, MPEG-4/DivX/Xvid, VC-1, VP8, VP9, AV1
- Audio codecs: AAC, MP3, AC-3, E-AC-3, DTS, DTS-HD, DTS-HD Master Audio, Dolby TrueHD, FLAC, Vorbis, Opus, LPCM, WMA, MP1, MP2, ALAC
Output
- Video: H.264 or H.265/HEVC via VideoToolbox hardware encoding (client-selectable)
- Audio: AAC at 44.1kHz stereo
- Client-configurable target bitrate, output dimensions (4K/1080p/720p), and encoding quality
- Dynamic GOP sizing computed from source framerate (3-4 second intervals)
Audio Processing
- DC offset removal via FIR high-pass filter (
audiowsinclimit mode=high-pass cutoff=20 length=501) - Channel-aware surround-to-stereo downmix gain compensation: 1-2ch 1.0x, 3-4ch 1.8x, 5-6ch 2.5x, 7+ch 3.0x
- Audio packet coalescing for all profiles (200ms target, 96KB max) — reduces audio sends from ~31/sec to ~5/sec
- Float clamping, NaN replacement, E-AC-3 channel-mask muting
- VBR MP3 special handling for accurate duration queries
Video Processing
- PAR (pixel aspect ratio) correction to 1:1 via
videoscale - PTS interpolation for B-frame videos with missing timestamps
- Subtitle burn-in support (text and bitmap)
- HDR content detection
- NAL unit parsing: Annex-B to AVCC/HVCC conversion with VPS/SPS/PPS extraction
- H.264 and H.265 keyframe detection for stream initialization
Streaming Pipeline
- Full teardown-and-restart architecture: pause = stop + remember position; resume/seek = start at new position
- Single code path for seek, resume, reconnection, and initial playback
- Software pacing: audio and video streams paced to wall clock via PTS
- Startup transport boost: 5-second initial burst for fast client buffer fill
- Startup keyframe gating: video waits for first keyframe before emitting; audio gated until video anchor established
- Adaptive startup buffer sizing computed from actual source framerate and audio packet cadence
- Direct
ClientConnectionreference at stream start bypasses per-send actor chain (eliminates ~70 unnecessary actor context switches per second) - Nonisolated
sendStreamData()onClientConnectionleveragesNWConnection.send()thread safety for concurrent video/audio/subtitle Tasks - Realtime transcoding performance monitoring: stops session if throughput falls below 70% realtime
- Legacy AVI compatibility profile for MPEG-4/XviD + MPEG audio containers
Adaptive Bitrate (ABR) Streaming
- Buffer-based AIMD (Additive Increase / Multiplicative Decrease) controller adjusts encoder bitrate mid-session
- Client sends
PlaybackStatusReportevery 2 seconds with buffer level and throughput estimate - Buffer zones: <0.5s critical (halve bitrate, bypasses cooldown), 0.5-1.5s low (15% decrease), 1.5-5.0s healthy (increase if throughput headroom, else hold), >5.0s high (15% increase, skips throughput ceiling)
- Resolution-based max bitrate ceilings: 4K=20 Mbps, 1080p=10 Mbps, 720p=6 Mbps, 480p-and-below=3 Mbps
- EWMA smoothing on decreases to prevent oscillation; direct application of increases for fast ramp-up
- 100 kbps quantization, 5% minimum change threshold, 4-second cooldown between adjustments
- Conservative 2 Mbps starting bitrate; fast connections ramp to ~10 Mbps in ~48 seconds
- Quality parameter hardcoded to 0.5 server-side
target_bitrate=0inStartPlaybackRequestenables adaptive mode (default); non-zero preserves fixed bitrate- Dynamic encoder bitrate adjustment via
setEncoderBitrate()on namedvideoencoderGStreamer elements usingg_object_set_property BitrateChangeNotificationsent back to client; live encoder bitrate shown in Status tab- Per-session ABR controllers keyed by session ID, cleaned up on stop/completion
Automatic Codec Selection
- Server validates encoder availability via GStreamer element factory before accepting client codec preference
- Auto-override HEVC to H.264 encoding when source uses software decoding (dav1d, vp9dec, avdec_mpeg2video, etc.) — VideoToolbox HEVC achieves only ~12 fps from CPU memory buffers vs ~162 fps for H.264
- Override checks actual decoder string rather than maintaining a separate codec list — automatically correct when hardware decode support expands (e.g., AV1 on M3+)
Demo Mode
- 15-minute stream limit for non-upgraded users
- Structured end-of-stream notification with reason (
DEMO_LIMIT) - Cancellable: if server is upgraded before timeout fires, limit is removed
HLS Transcoding (watchOS)
- GStreamer-based HLS transcoding via
GStreamerHLSSessionfor watchOS clients using AVPlayer - HTTP file server for HLS segment delivery with keep-alive connections
- 2-second target segment duration for fast startup (~2s to first segment vs ~6s at default)
- Output sized to 198x242 at 400 kbps with letterboxing (aspect ratio preserved via
add-borders=true) - Real-time pacing via GStreamer
clocksyncelement on video branch (paces pipeline at 1x speed) - Explicit demuxer and decoder chains per format (fixes DTS audio corruption from decodebin auto-plugging)
- Format-specific demuxers: matroskademux for MKV, qtdemux for MP4, with explicit audio decoder chains (dcaparse+avdec_dca for DTS, aacparse+avdec_aac for AAC, etc.)
#EXT-X-PLAYLIST-TYPE:EVENTinjected into playlists so AVPlayer buffers from start instead of chasing live edge- All segments retained on disk (max-files=0, playlist-length=10000) for slow client pacing
- Wait for first HLS segment before returning URL to client (prevents initial 404s)
- HLS sessions visible in server Status tab with codec, position, and progress tracking
- Configurable HLS toggle and port in server Settings
Blu-ray Disc Playback
- libbluray 1.3.4 integration via Swift actor wrapper for thread-safe C API access
- BDMV directory detection: checks for
BDMV/index.bdmv+BDMV/STREAM/structure - Title scanning with 120-second minimum filter (excludes menus and trailers)
- Content classification: movie (single or 2x longest title), TV season (multiple similar durations), ambiguous
- Chapter, clip, video/audio/subtitle stream metadata extraction
- Multi-clip seamless playback via appsrc feeding of M2TS data
- M2TS PES pre-scan: detects first video IDR keyframe and audio positions before pipeline start
- IDR cross-packet scanning: accumulates video PES payload across TS packets
- Multi-codec keyframe detection: H.264, HEVC, MPEG-1/2, VC-1
- Segment-direct A/V alignment using
gst_segment_to_stream_timefor domain-independent content time (eliminates ~1-2s desync from epoch-stripping) - Pre-IDR frame dropping to prevent corrupt leading frames after seeks
- 192-byte M2TS packet handling (4-byte timestamp prefix + 188-byte TS packet)
- BDMV-specific cache keys for thumbnails
- Disc size caching to avoid repeated directory tree walks
- Virtual path convention:
#bdmvsuffix with optional:titleNfor specific titles
iCloud Photos Integration
- Photos framework integration with authorization management
- Album browsing: My Albums, Shared Albums, Smart Albums
- Pagination for large albums (offset/limit)
- Album search with case-insensitive substring matching (in-memory for Smart Albums)
- High-quality image fetching with iCloud network access
- Video export to temporary directory with hash-based filenames
- EXIF metadata extraction: date taken, GPS coordinates
- Automatic temp file cleanup on app startup
Thumbnail Generation
- GStreamer-based video thumbnail generation at specified time offsets
- Batch thumbnail generation: reuses single pipeline, seeks in sorted order
- Serialized generation: only one GStreamer thumbnail pipeline runs at a time (FIFO queue)
- Non-blocking: cache misses spawn background Tasks instead of blocking the message receive loop
- Album art thumbnails served from DataStore
- Image thumbnails via ImageIO with hardware-accelerated scaling and EXIF orientation support
- Person photo thumbnails proxied from TMDB
- iCloud photo thumbnails via PhotosManager
- Photo metadata extraction: EXIF date, GPS coordinates (only for full-size views, never grid thumbnails)
- Disk caching with SHA256-based keys in sharded subdirectories (256 hex-prefix dirs)
- Consecutive failure detection (3 failures = likely EOS, stops batch)
Channels
Video Channels
- Virtual TV channels with 24-hour scheduled programming from the media library
- Content filtering: by genre, actor, movie title, show title, media path, content rating, media type
- Blacklist support for excluding specific content
- Programming scheduler with sorted (alphabetical) and randomized ordering modes
- Anti-repetition logic to avoid scheduling the same content consecutively
- Hourly schedule refresh via ProgrammingCoordinator
- JSON persistence of schedules
Music Channels
- Continuous music playback channels
- Filtering by artist, album, song, and genre
- Blacklist support for excluding specific songs
Photo Channels
- Synchronized photo slideshow channels from filesystem folders and/or iCloud Photo Library albums
- Deterministic scheduling via SplitMix64 PRNG with seeded shuffle
- Configurable slide interval (5-60 seconds)
- All clients show the same photo at the same time
- Maximum 10,000 items per channel
- Automatic seed rotation after full collection cycle
- Hybrid source support: filesystem images + iCloud album assets
Channel Operations
- CRUD operations for all channel types
- Channels sorted alphabetically via
localizedStandardCompare - Channel current program with offset and remaining time
- Channel thumbnail generation
- Program guide with time range queries (overview, content rating, Rotten Tomatoes score, artist/album info)
Content Discovery / Recommendation Engine
Discovery Modes
- Similar To: Multi-factor similarity scoring against a seed title — weighted components: keyword overlap (0.30), embedding cosine similarity (0.25), genre overlap (0.20), cast overlap (0.10), year proximity (0.10), rating proximity (0.05); embedding weight redistributes proportionally when unavailable; returns top 10 most similar items
- By Feel: Filters library by time commitment (quick/medium/long/epic with media-type-aware runtime thresholds) and mood (light & fun, intense, thought-provoking, heartwarming, dark & edgy) via keyword-to-mood cluster mapping; binary search narrowing when pool exceeds 10 candidates, splitting along highest-quality dimension (keyword cluster, genre, decade, content rating, vote average) each round
- By Genre: Top 20 candidates in selected genre sorted by vote average
Engine Infrastructure
RecommendationEngineactor with session management, 10-minute session expiry cleanup- Binary search representative tracking:
shownMediaIdsSet ensures fresh titles every round - Database schema: keywords table, media_keywords junction table, embeddings table, metadata_version column, vote_average columns
- TMDB keyword and vote average fetching integrated into library scanning with incremental metadata versioning
- Protobuf schema: recommendation session, pick, and skip message types
Play History
- Server-backed play history replacing device-local persistence
play_historytable with per-client, per-file tracking across movies, shows/episodes, and music- Music history collapsed to one entry per artist+album via partial unique index (songs without album metadata create individual entries)
- CRUD operations: add, get, delete, update offset
- Periodic and final offset updates from client during playback
- Media context IDs (movie/show/episode/artist/album/song) preserved per entry for library-link navigation
- Channel-context playback writes history entries like library playback
File Browsing
- Virtual path system mapping client paths to filesystem paths
- Root listing with configured locations, custom display names, and custom SF Symbol icons
- Recursive directory browsing within locations
- Pagination support (offset/limit) for large directories and iCloud photo albums
- BDMV directories presented as single playable items (not navigable as folders)
- Library ID fields (movie_id, show_id, episode_id, album_id) populated on DirectoryEntry during browse responses for client-side library navigation
- iCloud Photos browsing via
__photos__virtual path intercept - Supported file extensions:
- Video:
.mp4,.m4v,.mov,.avi,.mkv,.wmv,.flv,.webm,.mpeg,.mpg,.3gp,.ts,.mts,.m2ts - Audio:
.mp3,.m4a,.aac,.flac,.wav,.aiff,.ogg,.wma,.opus,.alac - Image:
.jpg,.jpeg,.png,.heic,.heif,.gif,.tiff,.tif,.webp,.bmp
- Video:
Server Administration UI
Status Tab
- Server running/stopped indicator
- Service status rows for WSS, optional WS, HTTP Polling (with client count), and HLS listeners
- Active listener ports
- Active transcoding sessions (video, audio, BDMV, HLS) with live position/duration and encoder bitrate
- Connected device list with device name, IP address, and connection time
- Firewall self-diagnostic: detects when macOS Application Firewall silently blocks incoming connections after Xcode rebuild; runs 30 seconds after startup then hourly; alerts user once with fix instructions; auto-clears when resolved
- Form/Section layout matching macOS System Settings appearance
Locations Tab
- Add/remove media folders with security-scoped bookmarks
- Custom display names per location (inline editing)
- Custom SF Symbol icons per location (searchable picker with ~6,000 system symbols)
- Alphabetical sorting by display name
- Orphaned metadata cleanup for deleted locations
Library Tab
- Trigger and monitor library scans with progress indicator
- Library statistics: counts for movies, shows, episodes, artists, albums, songs
- Manual database cleanup with confirmation
- Library validation: test-transcode indexed video files with live pass/fail progress, persisted results to disk, failure list sheet, mutual exclusion with scan/cleanup operations; validates regular files via
GStreamerTranscodingSessionand BDMV discs viaGStreamerBlurayTranscodingSessionwith PTS-span criteria (10s video + 10s audio) - Empty state instructions when no locations or media are configured
Channels Tab
- Video, Music, and Photo channel editors with full filter configuration
- Channel list management (create, edit, delete)
- Manual schedule refresh
Providers Tab
- TMDB and OMDB provider configuration with API key entry
- Two-step type selection flow (Movie & TV Show vs. Music sections)
- Provider status display
- Quick link to provider websites
- Lyrics provider configuration (LRCLib)
- TMDB API key guidance with step-by-step instructions
Devices Tab
- Known device list with name, identifier, and last connected time
Settings Tab
- WSS port configuration with validation
- Plain WS listener toggle and port
- HTTP Polling port configuration with cross-port conflict detection
- HLS service toggle and port configuration
- Master password management
About Tab
- App name, version, copyright, and support links (email + website)
- Log submission: toggle file-based logging with 24-hour auto-disable, daily rolling log files, gzip compression, upload to cloud with reference ID, context sheet for name/email/issue description
Upgrade Tab
- License status display
- Purchase flow with Stripe checkout
- Apple Sign In authentication
Licensing & Payments
- Sign in with Apple OAuth
- Server update notifications sent to clients after login
Server Log Gathering
- File-based log sink (
FileLogWriter) with daily rolling files, serial DispatchQueue, and 24-hour auto-disable toggle - All
AppLoggeroutput mirrored to file when logging is enabled LogGathererfilters log files by timestamp;LogCompressoruses gzip with 20MB max file size validation- Upload via
LogSubmissionAPIClientto Cloudflare Worker with metadata query parameters - 8-character alphanumeric reference ID returned to user with Copy button
Directory Exclusion
- Exclude specific directories from library scanning while keeping them browsable
- Security-scoped bookmarks for persistent exclusion access
- Excluded directories skipped during scanning and cleanup