Add game center, per-model shuffle, audio focus fixes, README, tests
- 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>
This commit is contained in:
91
README.md
Normal file
91
README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user