Initial commit: watch-together phases 0-4 + presence hardening, internet-tested

This commit is contained in:
foxyz committed 2026-09-12 00:13:43 +03:00
commit 427d851a5b
101 files changed
+11326

No files matched your search

+70
View File
@@ -0,0 +1,70 @@
# mpv HTTP contract (Phase 1, verified against Relic endpoint)
Spike: `tool/range_logger.dart` (Relic, `mountMediaRoute` + `onLog` hook).
Player: stock mpv CLI headless (`--vo=null --ao=null`). Server logs
`METHOD path range=<h> -> status bytes=<n>`.
## Real traces
mp4, 570692 B, full play (`--frames=300`):
```text
get /m/file range=- -> 200 bytes=570692
get /m/file range=bytes=0- -> 206 bytes=570692
```
One no-Range open (mpv probes full length), then a single open-ended
stream to EOF. Small file fits demuxer cache; one connection does it all.
mkv (ffmpeg remux of same file), 562197 B, play + `--start=8` seek:
```text
get /m/file range=bytes=0- -> 206 bytes=562197
get /m/file range=bytes=0- -> 206 bytes=562197
get /m/file range=bytes=562093- -> 206 bytes=104
get /m/file range=bytes=243694- -> 206 bytes=318503
```
Two `bytes=0-` opens (demuxer probe + playback), a 104 B tail read at
`size-104` (Cues-at-EOF probe — mpv expresses it open-ended, not as
`bytes=-n`; the server answers both identically), then a mid-file open
at a cluster boundary for the seek/start position. Seeks always arrive
as a fresh `bytes=N-` connection, never as a mutation of the old one.
Outage: server SIGINT-killed 5 s mid-play (looping file, comma-form
reconnect flags), restarted. mpv kept playing from cache, no error, no
reconnect storm; no new Range request inside the post-restart window.
Short drops are ridden out from cache — matches the north-star case.
Cache-exhaustion reconnect (long drop) is a Phase 5 chaos assertion;
`tool/shaper.dart` (KB/s cap + latency + `--kill-after`) exists for it.
## Server behavior table (all byte-exact tested, 16 server tests)
| Request | Response |
|---|---|
| no Range | 200, exact `Content-Length`, full bytes |
| `bytes=a-b` | 206, `Content-Range: a-b/size`, exact length |
| `bytes=a-` | 206 open-ended to EOF, exact length |
| `bytes=-n` | 206 tail `size-n..EOF` (Cues probe) |
| unsatisfiable start | 416 + `Content-Range: bytes */size` |
| host offline | 503 + `Retry-After: 2` (mpv retries with reconnect flags) |
| bad token / kicked / gone | 401 / 403 / 410 |
Always: `Accept-Ranges: bytes`; `Content-Type` from extension
(mkv `video/x-matroska`, mp4 `video/mp4`, webm, avi, mov, ts, mka/mp3).
## Relic notes
- Range arrives as typed `RangeHeader` (`req.headers.range`), not a raw
string. Multi-range takes the first entry; unit is preserved so
non-`bytes` units still 416. `resolveMediaRequest` in
`packages/server` stays framework-agnostic and is the tested truth.
- Reconnect flag syntax is build-sensitive: this mpv rejected the
colon-joined `--stream-lavf-o=a=1:b=1` form and accepted commas.
The exact media_kit property set is re-verified in Phase 4 through
mpv `set_property`, not CLI flags.
## Remaining manual (human + media_kit, Phase 4)
1.4 GB real file through the endpoint with the pinned buffer props;
long-outage reconnect with cache exhaustion via shaper.