- 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>
92 lines
3.5 KiB
Markdown
92 lines
3.5 KiB
Markdown
# mlbTVOS
|
|
|
|
Personal MLB streaming app for Apple TV and iPhone/iPad, built with SwiftUI.
|
|
Streams live and archived MLB games, plus a few non-MLB channels
|
|
(MLB Network, an authenticated private feed).
|
|
|
|
## Targets
|
|
|
|
- `mlbTVOS` — tvOS application (primary)
|
|
- `mlbIOS` — iOS/iPadOS application (shares most sources with the tvOS target)
|
|
- `mlbTVOSTests` — Swift Testing unit tests
|
|
|
|
The Xcode project is generated from `project.yml` via
|
|
[XcodeGen](https://github.com/yonaskolb/XcodeGen). After editing
|
|
`project.yml` or adding/removing source files, run:
|
|
|
|
```sh
|
|
xcodegen generate
|
|
```
|
|
|
|
## Building
|
|
|
|
Requires Xcode 26.3+ and tvOS/iOS 18.0 SDKs.
|
|
|
|
```sh
|
|
# tvOS
|
|
xcodebuild build -project mlbTVOS.xcodeproj -scheme mlbTVOS \
|
|
-destination 'platform=tvOS Simulator,name=Apple TV 4K (3rd generation)'
|
|
|
|
# Tests
|
|
xcodebuild test -project mlbTVOS.xcodeproj -scheme mlbTVOSTests \
|
|
-destination 'platform=tvOS Simulator,name=Apple TV 4K (3rd generation)'
|
|
```
|
|
|
|
## Features
|
|
|
|
### Dashboard
|
|
Today's live/scheduled/final games, standings ticker, and special channel
|
|
entry points. Tapping a game opens the Game Center with at-bat timeline,
|
|
pitch sequence, spray chart, and strike zone overlays.
|
|
|
|
### Multi-stream view
|
|
Up to four simultaneous streams in an adaptive grid. Only one stream holds
|
|
audio focus at a time; tap any tile to transfer focus. Streams can be
|
|
single broadcasts, team-filtered feeds, or special channels.
|
|
|
|
### Single-stream player
|
|
Full-screen AVPlayer with HLS adaptive streaming, custom HTTP headers,
|
|
and automatic retry on failure.
|
|
|
|
### Special playback channels
|
|
- **MLB Network** — 24/7 channel via the public MLB stream
|
|
- **Werkout NSFW** — authenticated private feed served by
|
|
[`ofapp`](https://gitea.treytartt.com) on the home server; uses a JWT
|
|
cookie and rotates clips through a per-model random shuffle
|
|
|
|
### Video shuffle (per-model random)
|
|
`VideoShuffle` groups clips by source folder (e.g. which model/creator
|
|
the video came from) and picks randomly one bucket at a time, excluding
|
|
the previously-played bucket. This guarantees **no back-to-back** same
|
|
source and produces a roughly uniform distribution across sources even
|
|
when one source dominates the raw data by a large factor. See
|
|
`mlbTVOS/Services/VideoShuffle.swift` and
|
|
`mlbTVOSTests/VideoShuffleTests.swift` for the pure functions and
|
|
their test coverage.
|
|
|
|
## Architecture
|
|
|
|
- **`mlbTVOS/mlbTVOSApp.swift`** — app entry point, creates a single
|
|
`GamesViewModel` injected into the environment
|
|
- **`mlbTVOS/ViewModels/GamesViewModel.swift`** — observable state store
|
|
for games, standings, active streams, audio focus, and video shuffle
|
|
bags; fetches from MLB Stats API and the auxiliary stream service
|
|
- **`mlbTVOS/ViewModels/GameCenterViewModel.swift`** — per-game live
|
|
data (at-bats, pitches, box score) used by the Game Center screen
|
|
- **`mlbTVOS/Services/`** — API clients (`MLBStatsAPI`,
|
|
`MLBServerAPI`) and pure helpers (`VideoShuffle`)
|
|
- **`mlbTVOS/Views/`** — SwiftUI screens and component library
|
|
(`Components/AtBatTimelineView`, `PitchSequenceView`, `SprayChartView`,
|
|
`StrikeZoneView`, etc.)
|
|
|
|
All new Swift code uses Swift 6 strict concurrency
|
|
(`SWIFT_STRICT_CONCURRENCY: complete`).
|
|
|
|
## Configuration
|
|
|
|
No secret management is set up. The authenticated feed cookie is
|
|
hardcoded in `mlbTVOS/Views/DashboardView.swift`
|
|
(`SpecialPlaybackChannelConfig.werkoutNSFWCookie`) and must be refreshed
|
|
manually when the JWT expires — generate a new one from the `ofapp`
|
|
server's `jwt_secret` using the same `userId` and a longer `exp`.
|