- Host/swap send refs only; pasted Jellyfin links become refs; the host
hands the relay its own app-obtained credential.
- Each viewer resolves with their own account (token in a header) or
via the relay, else a clear blocked card with Link account.
- Per-account progress reporting (Playing/Progress/Stopped), 401 marks
the account expired.
- Previous/next episode in the controls (< > / Shift+P/N), floating
Next episode pill near the end, auto-advance countdown (one
designated swapper), track carry-over per series.
- Swap panel uses the shared MediaPicker; browser location remembered
per server and opens on the current series.
- Fix: states are applied one at a time (a stale pause could land
after a newer play).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Media can be a Jellyfin ref {serverId, itemId, mediaSourceId, title,
subtitle, runtimeSecs}; the server never stores or broadcasts a URL
or token for it.
- Optional server-side Jellyfin credential (serve map / --jellyfin
file) enables GET /j/<sid>/<token>/<itemId>: range-faithful proxy of
the active item only, exact client header fields, upstream aborted on
disconnect, bytes counted. welcome.relayUrl / state.relay advertise it.
- Members report jf access (own account vs relay).
- /m now sends the real Content-Type (Relic overrode it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Auth (Quick Connect incl. the Initiate 400 fix: Content-Length + full
client header; password), server identity and link parsing, browsing
(views, resume, next up, latest, paged items, search, seasons,
episodes, next episode), images, PlaybackInfo and stream URLs,
progress reporting and user data, and a track matcher for carrying
audio/subtitle choices across episodes. Fixture tests plus env-gated
live tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- User seeks are intercepted at the player (SyncPlayer), previewed
locally, sent once 300 ms after the drag ends; own echoes are matched
by seekSeq and never re-applied; the landed check can't reapply a
stale target. 1 s position poll removed.
- ping/pong clock offset (min-RTT ClockSync); positions use server time.
- Reports carry duration; buffer gate is min(4 s, remaining - 2 s);
new finished transport instead of a HELD stall at the end.
- cache/readahead 150 s, 256 MiB demuxer cache, pins read back.
- Resumed reports put a stale ready member back in the set; hello.resume
takes over the old member after an unclean drop (no ghost).
- Docs: roadmap rendering findings (HW path works; shaders verified).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- serve(Map config, events) is the one server entrypoint: the app
hosts it via Isolate.spawn (crash surfaced on the Host card, logs
forwarded as [server]); bin/server.dart is the dedicated server,
compiled into the bundle as watch-together-server. --headless gone.
- Host identity via a per-hosting hostKey in hello, replacing the
loopback heuristic.
- Rename room -> server across code, files and wire (t:"state",
/health name); protocol bumped to 5.
- CI compiles the server binary; isolate smoke tests in server and
desktop suites. Docs updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Reject non-finite numerics at protocol parse and in the engine
(a 1e400 seek became Infinity and broke every broadcast).
- Reject empty swaps; sanitize URL-looking media names.
- Blank password = open server; defaults no longer 'change-me'.
- Loopback peers (the in-process host) can't be kicked.
- /health no longer exposes media/transport; file URLs use the
host the client dialled instead of 127.0.0.1.
- Count served bytes as streamed, not as requested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Private-server headroom over any pipeline PNG. The 8-min
auto-unready warning now mirrors the 10-min action guard: no toast
when self isn't ready, since there's nothing to lose.
64 KiB rejected normal 128px PNGs. 128 KiB fits any 128x128 PNG
(raw <= 64 KiB, worst-case base64 ~95 KiB chars) while still
bounding abuse. PNG kept for transparency. Pipeline now measures
the encoded base64 against RelayConstants (was checking the wrong
variable with its own 512 KiB limit) and drops dead crop code.
Server policy, still v4. Trade noted: avatars ride the 1 Hz room
broadcast, uplink scales with cap; hash-reference follow-up later.