Files
sync_replay_project/docs/HOW-IT-WORKS.md
T
foxyzandClaude Opus 5.5 d8d487c189 Sync fixes: clean seeks, clock offset, end of file, 2.5 min read-ahead (proto 6)
- 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>
2026-10-07 01:20:18 +03:00

3.7 KiB

How it works

A five-minute tour. Details: ARCHITECTURE.md, wire format: PROTOCOL.md.

The pieces

  your PC                          friend's PC
 +-------------------+            +-------------------+
 | app  (mpv inside) |            | app  (mpv inside) |
 +---------+---------+            +---------+---------+
           | sync (WebSocket)               | sync (WebSocket)
           v                                v
        +----------------------------------------+
        |  server  (who is ready, where are we)  |
        +----------------------------------------+

 video bytes come from somewhere else:
   - a link (Jellyfin, any http/https URL): each app fetches it directly
   - a file on the host's disk: the server streams it (/m/... endpoint)
  • App: the desktop window. It draws the video with mpv, shows who is here, and sends what you do (ready, seek, chat).
  • Server: keeps one shared clock and the list of people. It never sees video frames, only "position 123 s, playing". There is exactly one server and one watch session on it.
  • Jellyfin (or any web host): where a link's video lives. The server does not touch it today; each app downloads it itself.

Ways to run

  • Host from the app: the app you click Host in also runs the server. Simplest. The server lives as long as that app.
  • Dedicated server: watch-together-server, a separate program in the release tarball, for an always-on box. See the README.

Friends join either way with the Join card on Home.

One session, start to finish

  1. Connect. The app opens a WebSocket to the server and says hello (version, password, name, avatar). Wrong password or version: refused with a reason. Otherwise the server answers with a welcome and the current state.
  2. Catch up. The app opens the current video, jumps to where the server says we are, and buffers. A new arrival is not ready yet and never holds anyone back.
  3. Ready gate. Press Space to say you are ready. The server starts playback only when everyone who is ready has at least 4 seconds buffered (or what is left, near the end). At the end everyone stops and the server stays finished until someone seeks back or changes the video. If two or more people are ready, one person alone cannot start it for the others. A lone viewer can play alone.
  4. Play. The server owns the clock. Each app compares its mpv position to the clock: a small lead slows mpv a little (0.95x), a big gap (over 5 s) jumps. If someone's buffer runs dry the server pauses everyone and resumes when they have caught up.
  5. Seek. Anyone can seek, anytime. The server moves the clock and everybody follows. Seeking does not change anyone's ready flag.
  6. Swap. Anyone can change the video by pasting another link. Everybody stops at 0, ready flags clear, and the gate runs again.
  7. Leave. Closing or leaving drops you from the server; the others keep going. If you vanish without saying goodbye, you are marked stale after 15 s (stops blocking) and removed after 30 s. The app reconnects by itself and takes over your old place (same member, ready flag and video).

There are no roles: anyone can seek, swap, force-ready others and kick anyone except the host.

Where video comes from

  • Link: you paste an http(s) URL. Every app plays it directly with mpv. Works for a Jellyfin direct-download link or any file on the web.
  • Local file (host only): you pick a file on your disk. The server streams it to everyone, host included, over HTTP with range requests, each with a per-person token. Nothing is stored or converted.
  • No transcoding, ever. Quality is whatever the file is.