Files
JellyfinSyncPlus/CLAUDE.md
T

3.6 KiB

JellyfinSyncPlus

Custom Jellyfin plugin replacing/augmenting SyncPlay to fix drift when watching remotely with friends. Full architecture and rationale: PLAN.md -- read it before making design changes, it captures decisions already made with the user so they don't need to be re-litigated.

What this is, in one paragraph

Jellyfin's SyncPlay drifts because group members end up on different transcode/direct-play paths and the correction mechanism is weak. This plugin does three things: (1) picks one quality profile the whole group can use, (2) relays one member's ("host") already-transcoding stream to the rest of the group instead of spinning up N independent transcode jobs, (3) runs an active drift-correction loop on top (virtual playhead + NTP-style clock calibration + heartbeat/EMA drift measurement + speed-nudge-or-hard-reseek). See PLAN.md section "Architecture -- three pillars" for the full detail on each.

Real infra this targets -- not hypothetical, verified against the actual repo

  • Jellyfin: linuxserver/jellyfin:10.11.6 in the entertainment k8s namespace. Build the plugin against this exact server version's ABI. If the deployment's pinned tag ever changes, re-check /home/cynic/gitea/entertainment/base/jellyfin/deployment.yaml rather than assuming this file is still current.
  • Config hostPath: /mnt/redundant/k8s/jellyfin/config (where a real Jellyfin's plugins/ directory would live).
  • Deployed via ArgoCD app entertainment, does not auto-sync -- deploys need kubectl patch application entertainment -n argocd --type merge -p '{"operation":{"sync":{"revision":"HEAD"}}}' after a push.
  • Sibling repo /home/cynic/gitea/entertainment holds the k8s manifests. Sibling repo /home/cynic/gitea/MR-Discord is a working example of this exact cluster's tag-push -> Gitea Actions -> build -> deploy pipeline -- copy its .gitea/workflows/ pattern when this project reaches Phase 5 (packaging/release) rather than designing a new one from scratch.

Guardrails -- do not skip these

  • Never restart or redeploy the real k8s Jellyfin pod as part of routine dev iteration. It's a live, shared instance -- a restart interrupts whoever's currently watching something. Use the local throwaway Docker Jellyfin (see PLAN.md "Dev / test / iterate workflow", loop 1) for everyday iteration. Only touch the real pod for a deliberate milestone test, and confirm with the user first each time -- this is not a standing authorization.
  • Never push this repo to a Gitea remote without being asked. No remote has been created for this project yet as of the initial scaffold.
  • Don't assume the public Jellyfin plugin SDK (Jellyfin.Controller NuGet) is sufficient -- SyncPlay group internals and transcode-session state are not part of its stable surface. Expect to need a source checkout of jellyfin/jellyfin@v10.11.6 for some of this. Confirmed in PLAN.md's "Known friction / risks" -- don't rediscover this the hard way mid-phase.

Working conventions for this repo

  • Follow the phase breakdown in PLAN.md in order; don't jump to Phase 3 (drift correction) before Phase 1/2 (quality negotiation, host-relay) are working, since drift correction is meaningless to tune against N independently-transcoding clients.
  • No code exists yet as of this file's creation -- the repo currently contains only PLAN.md and this file. The first real work is Phase 0 (scaffold + confirm a trivial plugin loads in a local dev Jellyfin).
  • Keep PLAN.md's "Open questions" section updated as those questions get resolved -- move resolved ones into "Scope confirmed with user" with the actual decision, don't just delete them.