Files
sync_replay_project/docs/HOW-IT-WORKS.md
T
foxyzandClaude Opus 5.5 741b258ac1
ci / core (push) Successful in 29s
ci / server (push) Successful in 53s
ci / updater-windows (push) Failing after 7m45s
Restructure step 6: what's next and watch tracking
- What's next is the server's: state.advance counts down (10 s) when the
  media finishes with an Up next item first, holds while its performer or
  warm source is gone, and sets queuePlay at its end; cancel is shared, a
  seek or swap ends it; the server skips items nobody can put up. Shared
  rules in core whats_next.dart; the app's janitor, per-screen countdown
  and end-of-episode card are gone.
- The continuation (next Jellyfin episode, next file of a local show
  with its gaps) is an auto item under "Continues with", prepared like
  Up next's first item.
- Watch tracking by time In (D3): only time played while this viewer is
  in counts; away, paused, held, jumps and stalls never do (P7, P9).
  WatchTracker + device WatchHistory (files, links); Jellyfin progress
  reads the same watch; records are the AniList seam.
- A server restart no longer loses what played: apps hold their media
  and one offers it back (swap.restore, first offer wins), Up next is
  re-added, the source re-feeds, and the watch carries on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:06:04 +03:00

118 lines
6.2 KiB
Markdown

# How it works
A five-minute tour. Details: [ARCHITECTURE.md](ARCHITECTURE.md), wire format:
[PROTOCOL.md](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 (any http/https URL): the member who put it up passes it on
through the relay (or each app, or the server, fetches it)
- a Jellyfin item: each app plays it with its own Jellyfin account,
friends without one through the server
- a file on the host's disk: the server streams it (/m/... endpoint)
- the relay (/r/...): a member's computer passes a file, a link or a
Jellyfin item on to the server, which keeps a few minutes in memory
and streams it to everyone who needs it
```
- **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 the video lives. For a Jellyfin
item the server only knows which item it is; each app signs in with its
own account and reports what it watched. For friends without an account
the member who put it up passes it on through the server (their sign-in
stays on their computer).
## Ways to run
- **Your server**: every app runs its own server, quietly, from start to
close, reachable only from that computer. You are on it when you are
not in a friend's, so watching alone works like a session (progress,
next episode). Invite opens it to friends on your network (a second
listener on the same server: nothing restarts, the video and Up next
carry on) and copies an invite; Stop sharing closes it again.
- **Dedicated server**: `starsync-server`, a separate program in the
release tarball, for an always-on box. See the README.
Friends join either way with Join a friend in the strip at the top of the
window; guests need no Jellyfin or account. Before connecting, the app
checks the server's version and says who has to update when they do not
match. Joining a friend leaves your server (it stays up); leaving theirs
brings you back.
## 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. Arriving while the video is stopped, you are
waited for; arriving while it plays, you never hold 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.
Everyone who was there before it started must be ready, so 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 and the gate runs again for everyone there; ready flags stay
as they were (a setting unreadies you instead).
7. **What's next.** Up next is one list on the server for everyone, and
an episode you put up is followed by its next one. When a video ends
with something next, the server counts down 10 s on every screen;
anyone can cancel it for everyone (a seek stops it too). At zero the
app that has what plays next puts it up; if that person is away for a
moment, the countdown waits for them.
8. **Leave.** Closing the app or Leave says goodbye and drops you from the
server; the others keep going. If you vanish without a goodbye, after 15 s
of silence you are "gone": you stop blocking but keep your place
(ready flag, sitting out, Up next items, the video you pass on) for
10 minutes. The app keeps playing and reconnects by itself, with an id
of its own, and takes that place back.
There are no roles: anyone can seek, swap, force-ready others, nudge
anyone, and sit anyone out (the host too). Someone sitting out stays
connected and in the chat, but their app loads nothing and nobody waits
for them until they join back.
Watched or not is counted by the time you were there while it played:
sitting out, skipping around or a quick look never counts as watching.
Jellyfin hears it for your account; files and links are remembered on
your computer.
## Where video comes from
- **Link**: you paste an http(s) URL. By default your computer opens it and
passes it on (it plays for everyone whenever it plays for you, cookies
included); under "Other ways" every app plays it directly, or the server
fetches it once. A web page (YouTube, X, ...) goes through yt-dlp, which
the app and the server download and update by themselves.
A pasted Jellyfin link becomes the Jellyfin item below when possible.
- **Jellyfin item**: picked in the app's library browser. Shared as "this
item on this Jellyfin server", never as a link with someone's sign-in.
- **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.