- WerkoutNSFWSheet: wrap content in ScrollView + ViewThatFits(in: .horizontal)
so iPad's narrow sheet width falls back to VStack and content scrolls.
- Tighten padding on compact layouts (38→24).
- Revert AAC-preference in pinAudioSelection (stream is all AAC, no Dolby).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds [AUDIO]-prefixed logs to both single-stream and multi-stream players:
1 Hz heartbeat with rate/timeControl/mute/volume/bitrate/route, plus
immediate events on rate, isMuted, volume, currentItem, media selection,
access-log, error-log, and system audio route/interruption changes.
Grep Xcode console for `[AUDIO]` or `[AUDIO SYSTEM]` to isolate.
Also reverts the AAC-preference in pinAudioSelection: the
ballgame.treytartt.com master playlist is already all mp4a.40.2 stereo,
so the Dolby-DRC theory doesn't fit. Pin simply selects the default
audible option now.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: the quality upgrade path called replaceCurrentItem mid-stream,
which re-loaded the HLS master manifest and re-picked an audio rendition,
producing a perceived loudness jump 10-30s into playback. .moviePlayback
mode amplified this by re-initializing cinematic audio processing on each
variant change.
- Start streams directly at user's desiredResolution; remove
scheduleQualityUpgrade, qualityUpgradeTask, and the 504p->best swap.
- Switch AVAudioSession mode from .moviePlayback to .default in both
MultiStreamView and SingleStreamPlayerView.
- Pin the HLS audio rendition by selecting the default audible
MediaSelectionGroup option on every new AVPlayerItem, preventing
ABR from swapping channel layouts mid-stream.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SingleStream: pass preserveServerResolutionWhenBest=false so "best"
always reaches the server for a full multi-variant manifest. Increase
buffer to 8s and enable automaticallyWaitsToMinimizeStalling so AVPlayer
can measure bandwidth and select higher variants. Add quality monitor
that nudges AVPlayer if observed bandwidth far exceeds indicated bitrate.
MultiStream: remove broken URL-param resolution detection that falsely
skipped upgrades, log actual indicatedBitrate instead. Extend upgrade
check windows from [2,4,7]s to [2,4,7,15,30]s for slow-to-stabilize
streams.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Memory: clean observers even during PiP, nil player on tile disappear,
track/cancel Werkout monitor tasks, add highlight player cleanup.
Data: add scenePhase-triggered reload on day change, unconditional
10-minute full schedule refresh, keep fast 60s score refresh for live games.
Audio: set mute state before playback starts, use consistent .moviePlayback
mode, add audio session interruption recovery handler.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README.md with build/architecture overview
- Game Center screen with at-bat timeline, pitch sequence, spray chart,
and strike zone component views
- VideoShuffle service: per-model bucketed random selection with
no-back-to-back guarantee; replaces flat shuffle-bag approach
- Refresh JWT token for authenticated NSFW feed; add josie-hamming-2
and dani-speegle-2 to the user list
- MultiStreamView audio focus: remove redundant isMuted writes during
startStream and playNextWerkoutClip so audio stops ducking during
clip transitions; gate AVAudioSession.setCategory(.playback) behind
a one-shot flag
- GamesViewModel.attachPlayer: skip mute recalculation when the same
player is re-attached (prevents toggle flicker on item replace)
- mlbTVOSTests target wired through project.yml with
GENERATE_INFOPLIST_FILE; VideoShuffleTests covers groupByModel,
pickRandomFromBuckets, real-distribution no-back-to-back invariant,
and uniform model distribution over 6000 picks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>