Skip to content

Repository files navigation

Jellyfin Watch Sync for Silo

Stateless watch_sync_provider.v1 adapter that exports watched and unwatched state from a Silo profile to the same Jellyfin user.

Status

Early pilot. Version 0.1 implements:

  • per-profile API-key exchange;
  • Jellyfin user discovery through GET /Users/Me;
  • exact movie and episode resolution by Jellyfin, IMDb, TMDB, or TVDB ID;
  • idempotent watched and unwatched export;
  • typed Silo faults for credentials, permissions, rate limits, transient failures, and rejected mappings.

It does not yet import watched/progress state, scrobble playback, or reuse Silo History Import records.

No supported Silo release can install this pilot yet. Connection setup depends on Silo Server PR #550, and runtime admission remains a separate security and end-to-end validation gate.

Connection model

Each trusted Silo profile supplies:

  1. its HTTPS Jellyfin server URL; and
  2. a personal Jellyfin access token in Silo's API-key field.

The token must identify the intended Jellyfin user. A server-wide administrative API key is not sufficient because it has no user identity. Silo validates and encrypts the resulting credential bundle; this plugin never persists credentials.

Per-connection server fields require Silo Server PR #550. Reusing the already-working History Imports server and user mappings is being designed in Silo Server issue #584.

The server URL is profile-controlled because self-hosted Jellyfin may run on a LAN. The plugin restricts requests to fixed Jellyfin API paths, requires HTTPS, rejects URL credentials/query/fragment, and never follows redirects. Operators must still treat profiles as trusted until Silo provides a plugin egress policy; runtime admission should restrict this process to approved Jellyfin destinations.

Safety properties

  • Mutations use the authenticated user's /UserPlayedItems/{itemId} endpoint and never accept a target user ID.
  • Every mutation batch revalidates /Users/Me against the encrypted user binding.
  • Batches larger than the advertised 25-event limit fail before network access.
  • Media must match an exact stable provider ID. Missing and ambiguous mappings fail closed.
  • DatePlayed is omitted intentionally: Jellyfin increments PlayCount whenever that parameter is supplied, which is unsafe under Silo's at-least-once event delivery.
  • Redirects are not followed, preventing credential forwarding to another endpoint.
  • Upstream response bodies and credentials are never included in returned errors.

Compatibility

  • Plugin SDK: v0.13.2.
  • Plugin API: v1, capability watch_sync_provider.v1.
  • Architectures: Linux amd64/arm64 and macOS arm64.
  • Required host feature: per-connection provider configuration from Silo Server PR #550 or a later release containing it.

Install and verify

These steps apply only after the runtime-admission and Silo compatibility gates above pass and a signed-off release exists.

  1. Download checksums.txt, repository.json, and the binary or deterministic archive matching the host from the same GitHub release.

  2. Verify the selected artifact before use. On Linux:

    artifact=plugin-linux-amd64
    grep " $artifact$" checksums.txt | sha256sum -c -

    On macOS:

    artifact=plugin-darwin-arm64
    grep " $artifact$" checksums.txt | shasum -a 256 -c -
  3. In Silo's admin Plugin Hub, open Manage sources → Advanced and add the custom catalog URL: https://github.com/Overbuffer/silo-jellyfin-watch-sync/releases/latest/download/repository.json.

  4. Install the plugin, then connect each trusted profile using its personal Jellyfin token and HTTPS server URL.

Checksums detect corruption or mismatched assets; they are not an independent signature because the release workflow publishes both artifact and checksum. Silo community-catalog approval/provenance remains required for this pilot.

Pilot smoke, upgrade, and rollback

Before enabling exports for real profiles, use a disposable test profile and media item: connect, mark watched, confirm Jellyfin changed once, retry the same event, mark unwatched, and confirm convergence. Record Silo/plugin/Jellyfin logs without credentials. This real E2E is mandatory; mocked tests do not replace it.

For upgrades, review release notes, verify checksums, retain the previous release assets, then update through the same catalog source. Credential schema 1 is forward-checked; reconnect if a future release rejects it.

Rollback means disabling the plugin and reinstalling the retained prior release through Silo's supported archive workflow. Removing the catalog source alone does not stop an installed plugin. Already-exported Jellyfin watched state is not automatically reversed.

Development

Requires Go 1.26.5 or newer within the 1.26 release line.

make test
make vet
make build
make build-all

To use Nix without installing Go globally:

nix shell nixpkgs#go --command make test

Architecture

Silo profile connection
  owns encrypted token, server binding, outbox, retry, reconciliation
        |
        v
this plugin
  validates identity, resolves exact media, translates desired state
        |
        v
Jellyfin user API
  owns remote watched state

The credential bundle contains a schema version, normalized server URL, and immutable Jellyfin user subject. This provides a migration seam for replacing duplicated connection data with an opaque History Import reference later.

License

MIT

About

Jellyfin watch-state sync provider for Silo Server

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages