ShowShark Client Features

ShowShark Client is a SwiftUI multiplatform app for iOS, iPadOS, macOS, tvOS, visionOS, and watchOS that connects to a ShowShark Server to browse, stream, and play media.


Platform Support

  • iOS (iPhone): Full-featured with swipe gestures, pull-to-refresh, long-press menus, Picture-in-Picture, background audio, and lock screen controls
  • iPadOS: Sidebar navigation with server list and media browser split view
  • macOS: Native window with sidebar navigation, keyboard shortcuts, media key support, window frame persistence, and single-instance behavior
  • tvOS: Focus-based interface with Siri Remote support, card-style layouts, dedicated server management view, top shelf images, and platform-appropriate app icons
  • visionOS (Apple Vision Pro): Shares iPad navigation layout with native visionOS appearance (no custom backgrounds)
  • watchOS (Apple Watch): Companion app with HLS video/audio playback, server list with Bonjour discovery, media browsing, channel and history sections, Digital Crown volume control, and buffering countdown UI

Server Connection

Discovery & Setup

  • Automatic server discovery via Bonjour/mDNS
  • Discovered servers show server name, preferred address (IPv4 listed first), and additional address count (e.g., "192.168.1.100 (+1 more)")
  • Address picker when adding a discovered server with multiple IPv4/IPv6 addresses
  • IPv6 link-local address support with zone identifiers
  • Add, edit, and delete saved servers with JSON persistence
  • Server form: display name, hostname/IP, port (default 18080), password
  • iOS: swipe-to-delete and swipe-to-edit on saved servers
  • macOS: swipe delete, context menu for edit/delete
  • tvOS: card-based server management view with inline edit/delete buttons and Getting Started help section
  • Hostname display sanitization: hides port suffix and IPv6 zone identifiers in the server list

Connection Lifecycle

  • WebSocket over TLS secure connections
  • Password-based authentication with device name and persistent device identifier
  • Auto-reconnect with attempt tracking and exponential backoff retry intervals
  • Fast-fail on initial connection when host is unreachable (5-second timeout instead of 30)
  • Stale NWConnections properly cancelled to prevent leaked background retries
  • Connection states: disconnected, connecting, connected, waiting, failed, cancelled, reconnecting
  • Visual connection status indicator: colored dot (gray/green/red) or spinner for in-progress states
  • Connection failure alert with actionable error messages
  • Authentication failure alert
  • Media browser stays visible during reconnection if user was previously authenticated
  • Requests automatically wait up to 15 seconds for authentication during reconnection (prevents stale error messages on foreground resume)
  • Authentication generation counter forces view refreshes after re-authentication
  • Server update notification after login (dismissible, with "Ignore" option to suppress per-version)

Media Browsing

Directory Browser

  • Grid-based media browser with dynamic column calculation (responsive to window/screen size)
  • Three sections: Channels (subdivided by video/audio/photo), Library (directories and files), History
  • Section headers from server-provided directory entries
  • Pagination with infinite scroll for large directories and iCloud photo albums (100 items per page)
  • Auto-refresh every 5 minutes while visible
  • Pull-to-refresh on iOS
  • Cmd+R keyboard shortcut and toolbar button for manual refresh on macOS/iPadOS
  • Breadcrumb navigation (iOS/visionOS) with clickable path segments and home button
  • Empty state screens with helpful instructions when no servers or content are available
  • Fresh ScrollView instances per directory to prevent SwiftUI view reuse issues

Grid Items

  • Folder entries: gradient background with SF Symbol icon (custom per-location), 16:9 aspect ratio
  • File entries: thumbnail image, 16:9 aspect ratio
  • Display name resolution: metadata title > display name > raw filename
  • Custom location icons sent from server (SF Symbols)

Media Detail View

  • File information: name, path, size, duration, media type
  • Video track details: resolution, codec, bitrate, frame rate
  • Audio track details: codec, channels (Mono/Stereo/5.1/7.1), bitrate, language
  • Subtitle track details: language, format
  • tvOS: list-based layout with large thumbnail
  • Other platforms: scrollable layout with 600px max thumbnail

Video Playback

Player Controls

  • Automatic video codec negotiation: detects H.265 (HEVC) hardware decode support at startup via VTIsHardwareDecodeSupported, falls back to H.264
  • Intelligent output resolution auto-selection: defaults to min(source resolution, device capability) per session — macOS uses native screen pixels, tvOS uses native screen pixels (4K on Apple TV 4K, 1080p on Apple TV HD), iOS/visionOS capped at 1080p; manual 720p/1080p/4K override available in picker
  • Source video info displayed as "Input" row in resolution section (codec and resolution)
  • Audio track and subtitle track selection before playback
  • Play button in toolbar (iOS/macOS) or tvOS top button bar; when a resume position exists, shows confirmation dialog with "Play from beginning" and "Resume from X:XX" options
  • Seek bar / scrubber with time display (not on tvOS)
  • Auto-hiding controls with timer-based visibility
  • In-app volume slider (0-100%) adjusting player volume without changing system volume, persisted across restarts (excluded on tvOS)

Adaptive Bitrate (ABR) Streaming

  • Fully automatic bitrate adjustment — no user-facing bitrate or quality controls
  • Client sends PlaybackStatusReport every 2 seconds with buffer-ahead level and sliding-window throughput estimate
  • Receives BitrateChangeNotification from server reflecting encoder bitrate changes
  • Throughput estimated from received video/audio frame byte counts via ThroughputEstimator (thread-safe, NSLock-based, 5-second sliding window with EWMA smoothing)
  • Buffer-ahead calculated as last received PTS minus currently displayed PTS
  • ABR reporting starts 3 seconds after playback begins to let startup boost fill the buffer

Resume & Position Tracking

  • Auto-save playback position every 10 seconds
  • Resume button: "Resume at H:MM:SS" appears when a saved position exists
  • "Start Playback" resets to the beginning when a resume position is available
  • Restarts from the beginning if saved position is within the last 60 seconds of duration

Chapter Navigation

  • Chapter list display with expandable chapter picker
  • Previous/next chapter buttons with 3-second threshold for previous chapter behavior
  • Current chapter indicator
  • Starting chapter selection before playback

Subtitle Settings

  • User-adjustable subtitle timing delay from -3 to +3 seconds via subtitle settings sheet
  • Subtitle font size selection (small, medium, large)
  • Subtitle button inline with transport controls (visible during both single video and channel playback)
  • tvOS: focus-aware subtitle button with grouped form styling

Playback Contexts

  • Single video: standard file playback with File Details button in toolbar (iOS/macOS) or tvOS top button bar
  • Channel video: channel program playback with schedule display and auto-advance to next program

Video Rendering

  • AVSampleBufferDisplayLayer for zero-copy video rendering
  • Hardware-accelerated H.264 and H.265 (HEVC) decoding via VideoToolbox
  • Display layer persists through pause/seek (shows last frame, no flush)
  • Display layer persists through Picture-in-Picture transitions

End-of-Stream Handling

  • Single video: dismisses the player
  • Channel playback: auto-advances to next scheduled program
  • Demo limit detection with user-facing message

Library Navigation from Playback

  • "Go to Library" toolbar button (books.vertical icon) appears in VideoPlaybackView, AudioPlaybackView, and MusicChannelPlaybackView when the media has an associated library entry (movie, show, or album)
  • Navigates directly to MovieDetailView, ShowDetailView, or AlbumDetailView

Platform-Specific Video Behavior

  • macOS: Screen sleep prevention, window chrome hidden during playback, click-to-show controls
  • tvOS: Inline icon-only button bar at top of pre-playback content for Play, Thumbnails, Library, and File Details (toolbar items do not render on tvOS); focus-based transport controls; Siri Remote play/pause and directional commands; focus/scroll position preserved on back-navigation
  • iOS: Status bar hidden during playback via PreferenceKey propagation through NavigationStack, navigation bar back button hidden during playback
  • iOS/macOS: Space bar keyboard shortcut for play/pause

Audio Playback

  • Album art display loaded from server
  • Repeat modes: Off, All (loop collection), One (loop current track)
  • Shuffle: randomized playback order within collection
  • Collection-based playback: albums, artists, and folders treated as collections
  • Track navigation: previous/next track with shuffle awareness
  • Auto-advance to next track on completion
  • Scrubber / seek bar with elapsed and remaining time
  • In-app volume slider (same as video, persisted)
  • Space bar play/pause on macOS/iOS
  • macOS: screen sleep prevention during audio playback
  • macOS: card-based layout matching iOS design (rounded rect backgrounds, no list dividers)
  • tvOS: three-zone layout (shuffle left, transport center, repeat right) with default focus on play/pause
  • iOS/macOS: centered playback controls

Audio Engine

  • AVAudioEngine with AVAudioPlayerNode
  • PCM output, configurable sample rate, channels, and bits per sample
  • Per-buffer peak detection with transparent attenuation (target peak 0.98) to prevent clipping distortion
  • Buffer underrun detection and statistics

A/V Synchronization

  • Audio-as-master-clock synchronization
  • 50ms display tolerance, 100ms drop threshold
  • Sync decisions: display (within tolerance), hold (video ahead), drop (video behind)
  • Statistics tracking: dropped, displayed, and held frame counts

Lyrics

  • On-demand synced lyrics during audio playback
  • Lyrics persist across track changes: auto-fetches lyrics for the new song without dismissing the view
  • Content-switch pattern: lyrics replace album art view with compact transport controls bar
  • Song title and artist displayed in lyrics view navigation bar
  • Time-synced line highlighting with auto-scroll following the current playback position
  • tvOS: always auto-scroll
  • iOS/macOS: manual scrolling pauses auto-scroll for 5 seconds before resuming
  • Back action hierarchy: dismisses lyrics first, then dismisses playback view (per-platform: custom toolbar back button on iOS/visionOS, onExitCommand on tvOS, Escape key on macOS)
  • Plain text lyrics fallback when synced lyrics unavailable
  • Source attribution (e.g., "LRCLib")
  • In-memory lyrics cache by file path

Now Playing & Media Controls

  • MPNowPlayingInfoCenter integration: title, artist name, album title, album artwork, duration, elapsed time, playback rate
  • Lock screen and Control Center display during music and video playback
  • Lock screen scrubber for both audio and video via changePlaybackPositionCommand
  • Remote command handling: play, pause, toggle play/pause, next track, previous track (collections), skip forward, skip backward (single file)
  • Album artwork loaded via ThumbnailLoader for MPMediaItemArtwork display
  • Audio-only session mode: .default AVAudioSession mode for music (better for background playback), .moviePlayback for video
  • Available on iOS, macOS, and tvOS
  • macOS media key support: hardware play/pause key controls ShowShark even when not frontmost, with debounce to prevent double-fire

Background Audio (iOS)

  • UIBackgroundModes: audio keeps the app running while audio plays
  • AVAudioSession.Category.playback for uninterrupted audio
  • WebSocket connection stays alive during background audio (async receive loop continues)
  • ~30 second grace period after lock screen pause before potential iOS suspend
  • Auto-reconnect handles recovery after suspend

Picture-in-Picture (iOS)

  • Automatic PiP activation when app is backgrounded during video or channel playback
  • Play/pause and skip controls via AVPictureInPictureController delegate
  • UI restoration when returning from PiP (navigation views re-present playback modals)
  • Deferred teardown when PiP is mid-transition
  • Display layer shared between inline player and PiP

Channels

Channel Types

  • Video channels: virtual TV with scheduled programming
  • Music channels: continuous music with album art and track info
  • Photo channels: synchronized full-screen photo slideshows

Channel Listing

  • Grid display with live thumbnails and channel names
  • Separate sections: Video Channels, Audio Channels, Photo Channels
  • Channel thumbnail caching with 5-minute disk cache expiration
  • Channels sorted alphabetically

Video Channel Playback

  • Wraps the standard video player in a channel context
  • Auto-advances to next program on stream completion
  • Channel schedule display within the player
  • Year appended to titles from metadata

Music Channel Playback

  • Album art display with progress tracking
  • "Up Next" program list showing upcoming schedule
  • Auto-advance on playback completion
  • Now Playing integration

Photo Channel Playback

  • Full-screen slideshow with automatic advancement
  • Photo metadata overlay: date taken and reverse-geocoded GPS location
  • Tap to toggle controls visibility (chrome hidden by default)
  • Screen sleep prevention on all platforms
  • tvOS: truly full-screen with hidden navigation bar and edge-to-edge display

TV Guide (Channel Guide)

  • 24-hour programming grid with horizontal scrolling
  • Current time indicator (red line)
  • Video channels only (music and photo channels excluded from guide)
  • Program tiles with width proportional to duration
  • Thumbnail backgrounds with dark gradient overlay for text readability
  • Color-coded borders: blue for now-playing video, purple for music, gray for past/future
  • Platform-specific time slot widths (tvOS: 800px, others: 500px)

Program Detail

  • Thumbnail, title, channel name, time range, duration, media type
  • Video programs: content rating badge, Rotten Tomatoes score, synopsis/overview
  • Music programs: artist name, album title
  • "Open Player" button for currently playing programs
  • tvOS: pushed onto navigation stack instead of presented as sheet, with focus management
  • Search bar with cancellation of previous in-flight searches
  • Search fields bitmask: title, overview, genre, actor, year (all enabled by default)
  • Result categories: movies, shows, genres, actors, artists, albums, songs, photo albums
  • "Music Albums" section name (distinguished from Photo Albums)
  • Library stats overview above search: aggregate counts for movies, shows, episodes, artists, albums, songs (responsive font sizing for compact-width devices)
  • Empty state shows browsable genre sections (Movie Genres, TV Show Genres, Music Genres) as tappable capsule pills using FlowLayout, plus recent search history (capped at 10, deduplicated, most-recent-first, with Clear button)

Movie Detail

  • Poster/backdrop image
  • Title, year, MPAA rating badge, Rotten Tomatoes score
  • Overview/synopsis
  • Tappable genre pills (navigate to genre browse)
  • Cast member cards with profile photos and character names (tappable, navigate to actor filmography)
  • "Open Player" button

Show Detail

  • Poster/backdrop image
  • Title, TV content rating badge, overview
  • Tappable genre pills
  • Cast member cards with photos (tappable)
  • Season selector for quick navigation between seasons
  • Season/episode listing grouped by season, episodes tappable to episode detail

Episode Detail

  • Title, season/episode label (S01E01 format), duration, overview
  • "Open Player" button
  • tvOS: auto-focus on play button

Genre Browse

  • Genre-scoped browsing by media type: Movies, TV Shows, or Music
  • Movies and Shows sections with 16:9 thumbnail grid cards
  • Music genre browsing with Artists, Albums, and Songs sections
  • Tappable entries navigate to movie, show, album, or artist detail

Actor Browse

  • Actor profile photo header (120px, loaded via server proxy)
  • Filmography: Movies and Shows sections
  • Tappable entries navigate to movie or show detail

Album Detail

  • Album art thumbnail
  • Title, artist name, year, song count
  • "Play All" button
  • Track listing grouped by disc number (multi-disc support)
  • Individual track tapping starts collection playback from that track

Artist Detail

  • Artist name, album count, total track count
  • "Play All" button (loads all album details to build complete artist collection)
  • Discography section: albums with year and track count, tappable to album detail

Content Discovery

Discovery Modes

  • Similar To: Search for a seed title in your library, then view top 10 most similar items ranked by multi-factor similarity scoring (keyword overlap, genre overlap, cast overlap, year proximity, rating proximity, optional embedding cosine similarity)
  • By Feel: Filter library by time commitment (quick/medium/long/epic with media-type-aware thresholds) and mood (light & fun, intense, thought-provoking, heartwarming, dark & edgy); when filtered pool exceeds 10 candidates, initiates binary search narrowing with side-by-side candidate comparison cards
  • By Genre: Browse top 20 candidates in a selected genre sorted by vote average

Discovery UI

  • Wizard flow: media type selection, discovery mode, mode-specific sub-flow, binary search rounds (if applicable), final candidates
  • BinarySearchView: side-by-side candidate cards with thumbnail, title, year, genre chips, overview snippet, and progress indicator
  • RecommendationCandidatesView: scrollable card layout with navigation to movie/show detail
  • "Find Similar" entry point on MovieDetailView and ShowDetailView
  • "Discover" button in media browser toolbar
  • Available on all platforms (iOS, iPad, macOS, tvOS, watchOS)

Photo Viewing

  • Full-screen photo display with left/right navigation
  • Full-size photo loading at screen resolution
  • Adjacent photo prefetching (photos >2 indices away are released from memory)
  • Photo metadata: EXIF date taken and GPS coordinates
  • Reverse geocoding of GPS coordinates to "City, State, Country" with actor-based caching (coordinates rounded to 3 decimal places)
  • Platform input: macOS arrow keys, tvOS directional commands, iOS/visionOS swipe gestures
  • Info bar: filename, position counter (e.g., "3 of 15"), metadata line (date and location)
  • iCloud Photo Library support via __photos__ virtual path prefix

Thumbnails & Caching

Thumbnail Cache

  • Two-tier: NSCache (100MB memory limit) + disk storage (500MB limit)
  • SHA256-based cache keys
  • Sharded disk layout (2-character hex prefix subdirectories)
  • 5-minute cache freshness check for channel thumbnails
  • LRU eviction when disk cache exceeds size limit

Thumbnail Loading

  • Request batching and deduplication
  • Thumbnail sizes: grid (300x200), detail (800x600), person photo (200x300), full photo (screen resolution)
  • Request serialization to prevent server hammering
  • Default thumbnail offset: 300 seconds into the video

Batch Thumbnails (Scrub Grid)

  • Per-minute thumbnail offsets computed from video duration
  • Client-side cache pre-check: cached thumbnails populate immediately
  • Uncached offsets requested from server in a single batch request
  • Progressive loading: images appear as each server response arrives
  • Tap any thumbnail to view full-resolution or jump to playback at that offset

Playback History

Position Tracking

  • Server-backed playback position persistence via periodic and final offset updates
  • Local PlaybackPositionManager as compatibility fallback
  • Positions marked @ObservationIgnored to prevent unnecessary SwiftUI re-renders during auto-save

Play History

  • Server-backed play history: movies, shows/episodes, and music tracked across all clients via PlayHistoryService
  • Dynamic 16:9 thumbnail grid layout matching Channels and Library sections (resizes based on view width)
  • Music history collapsed to one entry per artist+album (displays album title with "Artist - Song Title" subtitle)
  • Channel-watched videos saved to history with playback position
  • Play offset shown below title
  • Media context IDs (movie/show/episode/artist/album/song) preserved for library-link navigation from history items
  • Delete individual items: macOS context menu, iOS long-press, tvOS confirmation dialog
  • Accessibility labels: "Recently played: {title}"

Streaming Architecture

  • Full teardown-and-restart pattern: pause = stop + remember position; resume/seek = start at new position
  • Single code path (startPlayback()) for initial play, seek, resume, and reconnection
  • Mailbox-based stream ingress: packets accepted from any thread, drained by single MainActor task
  • Seek-time ingress flush: pre-seek packets discarded immediately on seek
  • Stale session filtering: incoming packets validated against current session ID
  • StreamDataReceiver protocol: callbacks for stream initialization, video frames, audio samples, errors, and end-of-stream
  • Minimum seek policy: 10-second initial start position, 10-second minimum forward seek delta

First Launch & Onboarding

  • WKWebView-based tutorial on first launch (skipped on tvOS)
  • @AppStorage("hasShownTutorial") to show only once
  • macOS: "Open in Browser" button opens tutorial in Safari, min 600x400 frame
  • iOS: "Open in Browser" opens in system browser
  • "Done" button to dismiss

About

  • App name, version, copyright, and support links (email + website)
  • iOS/iPad/Mac: question mark toolbar button on server list opens About sheet
  • tvOS: "About ShowShark" button on server management screen

App Updates & Cross-Promotion

  • Remote app check via https://app-check.acgao.com/check
  • Detects: app review mode, deprecated versions, available updates
  • App update alert in root view
  • "Other Apps" cross-promotion section in server list sidebar (hidden on tvOS and during App Review)
  • Each promoted app shows icon, name, description; tapping opens link

Theming & Visual Design

Standard Background

  • Dark mode: black base with dark red/orange accent gradient
  • Light mode: light neutral with warm accent
  • tvOS: slightly brighter for TV viewing distance
  • visionOS: no custom background (native appearance)

Platform Styles

  • Platform-specific typography (tvOS uses significantly larger sizes for 10-foot viewing)
  • Platform-specific spacing for grid layout
  • View modifiers for metadata labels, track cards, and picker options

Playback View Modifiers

  • Status bar hidden during active playback (iOS/visionOS)
  • Navigation bar and toolbar hidden during active playback (all platforms)
  • Conditional application based on modal vs. navigation presentation

Accessibility

  • accessibilityLabel on history rows: "Recently played: {title}"
  • Platform-specific accessibility hints on history items
  • accessibilityHidden(true) on decorative elements (chevrons, icons)
  • accessibilityElement(children: .combine) on cast member cards
  • accessibilityLabel on person photos: "Photo of {name}"
  • Combined accessibility labels on cast cards: "{name} as {character}"

Networking Infrastructure

  • Transport protocol abstraction (ServerTransport): WebSocket (iOS/macOS/tvOS/visionOS) or HTTP long-polling (watchOS)
  • NWConnection-based WebSocket over TLS with interactiveVideo service class and TCP_NODELAY
  • HTTP polling transport for watchOS: POST-based send with bearer token auth, long-poll GET for server-pushed messages
  • Self-signed certificate support via sec_protocol_options_set_peer_authentication_required(false)
  • Request-response correlation via RequestCorrelator with timeout handling
  • Protocol Buffers message serialization
  • 2-second minimum interval between connection attempts to prevent server hammering
  • Default port 18080, configurable range 1024-65535