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>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-16 02:06:04 +03:00
1 parent a87ee98faa
commit 741b258ac1
55 files changed
+2724 -964

No files matched your search

+42 -32
View File
@@ -35,8 +35,6 @@ Problems are numbered; delete a line when its fix ships.
- D11 Login-only sites: error texts say which cookies were used.
**Problems:**
- P7 Sat-out people get tracked as watched on Jellyfin.
- P9 The watched rule (position coverage) misses real watches (D3).
- P25 ssh to Gitea blocked through the proxy (pushes go over https).
- P30 Shaders don't work on Windows. Fix in 1.2.1-dev.3 (list read-back
check; Windows hwdec `auto-copy`): a Windows user must confirm shaders
@@ -61,16 +59,12 @@ the automatic continuation and countdown, relay state), the device
(client id, library and folders, match corrections, watch history,
settings, notification prefs, what this app is sourcing) and the
integrations (Jellyfin played/resume, AniList list).
6. What's next (decides which/when, asks the pipeline to prepare;
continuation and countdown as server state, shared cancel) + Watch
tracking (time In from the presence history, device history, Jellyfin
now, AniList later). Fixes P7 P9; D3.
7. Release 1.3.0: publish the manifest (protocol 16 makes it a required
update for 1.2.x) and update the VPS dedicated server in the same
window; check a 1.2.x app gets a clear "update the app" message.
Composition root (in place, ARCHITECTURE "Composition root"): the
remaining `.instance` singletons move into `AppGraph` as the steps touch
them; `singletons_test` holds the count (today: AppSettings 55,
them; `singletons_test` holds the count (today: AppSettings 49,
JellyfinAccounts 10, UpdateController 8, Profile 8, FolderStore 6,
AppYtDlp 2, RecentLinks 3).
Not in the restructure: P25 (ops).
@@ -113,6 +107,30 @@ your server leaves them there without you, unwarned; a join refused
after dialling (wrong password) costs your own member there (`bye`, back
as a new member). Your server writes its session log even when you are
alone.
Left of step 6 (what's next, watch tracking): a human check, on Linux
now, of the server's countdown and the end card in real use (Cancel
from another screen, a seek stopping it, "Waiting for" while the one who
puts it up is gone), of a file continuation on the real folder (Bleach
"skips 66–107" across its folders, SAO S3 into its OP/ED folder, the
last episode of a show) and of Jellyfin's played state and resume point
under time In against a real Jellyfin (a full watch, one sat out, a
resume), and of a dev server restarted mid-episode (what played comes
back where it was for everyone, a Jellyfin item passed on to a guest
re-fed: only files and links are covered by tests). Not built: AniList
progress (the tracker's `records` are its seam); nothing resumes a file
or link at the history's resume point (it only keeps it); no watched
marks on Files' episode rows (only "Next" follows the history) and no
way to see or clear the history. The continuation of a file comes only
from the app that put it up (only it has the file). "Play the next episode
automatically" is the setting of whoever puts an episode up; Up next's
own items count down whatever it says. A play request the performer
does not act on ends after 30 s without a new countdown for that item
(Play now remains). A warm relay waiting for a `gone` source holds the
countdown even when the one who puts the item up is there. After a
server restart, a relayed file or link whose member is not back, or a
Jellyfin item nobody back has an account for, cannot be put back (the
apps let go after 30 s); a server-fetched Up next item is lost (its
address stayed with the old server).
Left of step 5 (media pipeline): a human check, on Linux now and on
Windows at 1.3.0, of a page link in "Everyone fetches it" through the
app's own resolve (YouTube's 1080p video + audio EDL, Bilibili with its
@@ -131,6 +149,14 @@ CDN wants per-track headers that differ gets the first track's (as
mpv's hook did); Bilibili's danmaku is dropped, not shown. The Jellyfin
item this member put up re-feeds its relay after an app restart (the
state still names it the source).
Relay start (P29's rest): a seek into what the source has not sent
plays after about 2.8 s in the e2e; a human check of a real session
on dev.8+. The source's in-flight window still starts at 256 KiB and
grows with the measured rate, so the speed climbs from low after a
seek or a new link; the start of a freshly put-up link was never
measured on its own. Levers if it still shows: start the window from
the last rate, prefetch from the source as soon as a link goes up,
a smaller gate buffer when only the relay is behind.
Left of step 4 (library): a human check of the Files library on the
real folder (`/mnt/torrents/Torrents/Binux/`: Bleach over three folders
with 66–107 missing, SAO S3 Alicization with OP/ED, Re.Zero S04E17, the
@@ -142,9 +168,7 @@ swapper's bytes (now chosen by the ref's AniList id). Relay logins are
sent at Invite: an account linked or signed in again later relays only
after Stop sharing and Invite. "Season N" without a name walks AniList's
sequels, which can land on the wrong cour where AniList splits seasons;
Wrong show? fixes it. The next episode of a local show lives on its page
(from Recent); no countdown or "Continues with" for files yet (backlog
2). The `library` box keeps every AniList entry seen (no pruning);
Wrong show? fixes it. The `library` box keeps every AniList entry seen (no pruning);
AniList's episode titles exist only where it lists streaming episodes.
Left of step 2: system notifications need a human check (Linux: the
notification shows and a click brings the window up, also on Wayland,
@@ -170,13 +194,8 @@ Opened in step 1: [PROTOCOL.md](PROTOCOL.md) is proto 16 (version
ranges and the refusal frame, error codes and close codes, lasting members by client id with takeover and `seq`, grace and
`bye`, presence and `PresencePolicy`, `state.hold`, feed ids, `seq` and
replay, relay `sourceGone` and source resume, lasting `queue[].by`,
`auto` items and `cancel`, `media.ref`, `members[].app`/`caps`), server,
`auto` items, `cancel` and `state.advance`, `media.ref`, `members[].app`/`caps`), server,
core and app. Still open on the wire, frozen at the 1.3.0 release:
- `state.advance` (step 6): the server starts the countdown when the
media finishes and an item is first, sets `queuePlay` at its end and
holds it while the item's performer or source is `gone`. Today it is
parsed and broadcast but never started; `auto` items and `cancel` are
live.
- `hello.client` optionally derived per server (HMAC of an install
secret and the dialled host:port).
- TLS: `/health.tls` is always false; `wss://` only with a CA-valid
@@ -207,12 +226,7 @@ core and app. Still open on the wire, frozen at the 1.3.0 release:
seeks are shared, and only real ranges (segments, OP/ED chapters) should
ever be skipped.
2. **Files**: the next episode of a local show (the library's
`nextAfter`, gaps included) at the end of one, with the countdown, and
under Up next's "Continues with". Tracking for file series comes with
step 6.
3. **yt-dlp follow-ups** (see ARCHITECTURE "yt-dlp"): check that the
2. **yt-dlp follow-ups** (see ARCHITECTURE "yt-dlp"): check that the
bundled Windows libmpv plays the app's `edl://` URLs (video + audio
with headers) through media_kit. YouTube: yt-dlp wants a JS runtime
(deno) for full extraction.
@@ -229,15 +243,15 @@ core and app. Still open on the wire, frozen at the 1.3.0 release:
- Thumbnails and scrubbing previews of a relayed media with tracks
should open the video track's URL alone, not the EDL.
4. **AniList account**: sign in (OAuth via a localhost callback), "My list"
3. **AniList account**: sign in (OAuth via a localhost callback), "My list"
filter on the Schedule from the user's AniList lists. This is the
Schedule's personal tracking; AnimeFlow has no per-user follow.
5. **Ops**: Check shaders on Windows; run the relay e2e "the source drops
4. **Ops**: Check shaders on Windows; run the relay e2e "the source drops
uncleanly and comes back" a few times under the full suite (its
predecessor failed about half the time there).
6. **Windows: first real use.** Check the rename at 1.3.0: a 1.2.x
5. **Windows: first real use.** Check the rename at 1.3.0: a 1.2.x
install updates and restarts (`watch_together.exe`, a copy of
`starsync.exe`), the data in `%APPDATA%\foxyz\Starsync` came over from
`%APPDATA%\com.example\watch_together` and Documents, the next update
@@ -247,7 +261,7 @@ core and app. Still open on the wire, frozen at the 1.3.0 release:
fullscreen controls, hosting (firewall prompt), in-app update from one
release to the next. The rest of the desktop tests are not in CI.
7. **Relay follow-ups** (see ARCHITECTURE "Relay"). First real use: owner's
6. **Relay follow-ups** (see ARCHITECTURE "Relay"). First real use: owner's
PC -> VPS -> friend, Jellyfin and a file. Then:
- Source takeover: when the source leaves, another member with an
account on that Jellyfin (or the same file: name, size, hash) takes
@@ -268,9 +282,9 @@ core and app. Still open on the wire, frozen at the 1.3.0 release:
fetch of member-resolved links (the member need not upload or stay)
is worth building.
8. **Jellyfin** (epic, below).
7. **Jellyfin** (epic, below).
9. **Smaller items**
8. **Smaller items**
- Video output robustness: if media_kit's hardware path regresses to
software (see ARCHITECTURE, Media: render mode), vendor a
media_kit_video fix that builds the EGL display from GDK's native
@@ -298,10 +312,6 @@ core and app. Still open on the wire, frozen at the 1.3.0 release:
What is left (the rest is in [ARCHITECTURE.md](ARCHITECTURE.md), "Jellyfin
in a session"):
- Auto-advance cancel for everyone (the next episode and Up next): today
Cancel is per screen (the designated swapper's Cancel stops the swap; a
seek stops all). The wire has it (`queue` `cancel`, `state.advance`);
the app uses it in step 6.
- Sidecar (external) subtitle streams of Jellyfin items: only embedded
tracks are mapped to mpv today.