Files
sync_replay_project/docs/ROADMAP.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.9 KiB

Roadmap

Backlog and epics, in order. Done work lives in git history. Check an item off by deleting it in the same commit as the code. Wire changes also edit PROTOCOL.md.

Backlog

  1. Shaders. Per-viewer local setting using mpv glsl-shaders (set after the player is created), shipping Anime4K presets (bloc97, MIT). Shaders only apply on media_kit's hardware path (verified with a test shader); warn when the software fallback is active. The hardware path is fragile: media_kit borrows whatever EGL context GDK left current on the main thread (upstream media-kit#1404), so a VideoController created before the first frame, an X11 session, or a Flutter/GDK change can silently fall back to software. Log which path media_kit picked; a vendored media_kit_video fix (build the EGL display from GDK's native display) is the durable answer if it regresses. The video freeze after GPU idle is not explained by this; next suspect is media_kit's context switching on the raster thread with NVIDIA.

  2. Windows build + CI. There is no Windows runner. Try ubuntu2610/flutter_build (LLVM-MinGW + Wine gen_snapshot) on the Linux runner, fallback a GitHub Actions mirror. The manifest needs per-platform URLs and release_publish.sh must handle a second platform. The updater's Windows apply path exists but is untested. The tarball's watch-together-server needs a Windows dart compile exe too. Desktop tests are not in CI either.

  3. Jellyfin (epic, below).

  4. Smaller items

    • Link conveniences: a link swap in session updates the remembered media; show the open link with an open-in-browser button; the session's swap panel reuses Home's MediaPicker.
    • Time UI: remaining time, scrubber preview.
    • mpv / mpv.net shortcut parity.
    • Sounds: replace NoopSfxService (cues already fire). Candidates: Kenney Interface Sounds (CC0), ObsydianX Pack 1 (CC0), akx/Notifications (CC0); playback via flutter_soloud. Keep seek/pause/resume near silent.
    • Chaos suite: host drop 5 s / 30 s, viewer stall, 20-seek storm, long outage with cache exhaustion (tool/shaper.dart --kill-after); assert no OOM, no stuck session, drift recovers.
    • Chat history pane (today: activity log only).
    • Avatar caching: serve avatar bytes once by hash instead of base64 in every state broadcast.
    • The state broadcast carries the full media URL, which can include an api_key.
    • TLS: document a reverse proxy in front of the server.
    • Playlist: queue-add, queue-skip, auto-advance like a swap.
    • Sidecar subtitles.

Epic: Jellyfin

  • Each viewer logs in to Jellyfin themselves (Quick Connect or password).
  • Several Jellyfin servers can be linked, keyed by ServerId.
  • The sync server shares only {ServerId, ItemId}. Pasted Jellyfin links are recognised and reduced to that pair.
  • Viewers with an account direct-play /Videos/{id}/stream?static=true with their own token and report Playing / Progress / Stopped, so watched state and Continue Watching update per account.
  • Guests without an account play through the sync server, which fetches with a credential that stays server-side (the host's own or a configured one).
  • Next episode: the successor in /Shows/{seriesId}/Episodes (NextUp means first unwatched, not next-after-X); audio and subtitle track matching by language, then title, then codec/channels.
  • Library browser; anyone can put up items.

Spike facts (Jellyfin 10.11.11): /Videos/{id}/stream?static=true&mediaSourceId= serves the original with byte ranges (206). PlaybackInfo gives PlaySessionId and DirectPlay. All audio and subtitle tracks are embedded in the mkv. Quick Connect is enabled but /QuickConnect/Initiate returned 400: investigate (likely missing client/device fields in the auth header).

Deferred

P2P, Android. Never: transcoding, web clients.