Phase 1b: Jellyfin connect and movie sync #8

Manually merged
marvin8 merged 8 commits from feat/issue-3-phase-1b-jellyfin-movie-sync into main 2026-10-08 20:13:51 +00:00
Collaborator

Implements Phase 1b — Jellyfin connect and movie sync, per issue #3.

What this adds

  • Jellyfin connect: per-user base URL validated over https and authenticated with AuthenticateByName; the resulting access token is stored encrypted (Fernet, key derived from XIQUE_SECRET_KEY). The password is used once and never stored or logged.
  • Movie ledger: migration 2 adds jellyfin_connections, media (keyed on provider IDs, never Jellyfin item IDs), watch_events (append-only), ratings, and dismissals — all FK-enforced.
  • Movie delta sync: a jellyfin_sync worker job pages through played movies, upserts the media catalog, appends to the ledger, and mirrors ratings. Re-running is idempotent (no duplicate events). Items without provider IDs are skipped.
  • Settings UI (zero JS): GET /settings, connect, sync-now, and disconnect.
  • Worker hardening (issue #7 items): complete_job/fail_job status guards, recover_stale_jobs wired into worker startup, jobs.status index, poll_interval_seconds Setting, bounded run_worker_cycle batching, and cancellation-safe handler dispatch.
  • Transactional migrations: migration application is now one explicit transaction per migration (BEGIN IMMEDIATE → DDL → version → COMMIT), replacing executescript (which implicitly commits).

Scope

Movies only, as agreed; TV/episode tracking stays in Phase 3 (the schema carries media_type for it). Trakt import (1c), the recommendation engine and browse UI (1d), and containers (1e) are later.

Notes

  • Design spec: .superpowers/specs/2026-10-08-xique-design.md; plan: .superpowers/plans/2026-10-08-xique-02-jellyfin-movie-sync.md (local artifacts, not committed per AGENTS.md).
  • Jellyfin endpoints verified against the Jellyfin OpenAPI spec 12.2.0.
  • Known divergence recorded: the sync re-walks all played movies each run and relies on idempotent upserts, rather than filtering by the stored watermark (spec §8.1 wording). Accepted for 1b; the watermark filter is a follow-up.

Closes #3

Implements Phase 1b — Jellyfin connect and movie sync, per issue #3. ## What this adds - **Jellyfin connect**: per-user base URL validated over https and authenticated with `AuthenticateByName`; the resulting access token is stored **encrypted** (Fernet, key derived from `XIQUE_SECRET_KEY`). The password is used once and never stored or logged. - **Movie ledger**: migration 2 adds `jellyfin_connections`, `media` (keyed on provider IDs, never Jellyfin item IDs), `watch_events` (append-only), `ratings`, and `dismissals` — all FK-enforced. - **Movie delta sync**: a `jellyfin_sync` worker job pages through played movies, upserts the media catalog, appends to the ledger, and mirrors ratings. Re-running is idempotent (no duplicate events). Items without provider IDs are skipped. - **Settings UI** (zero JS): `GET /settings`, connect, sync-now, and disconnect. - **Worker hardening** (issue #7 items): `complete_job`/`fail_job` status guards, `recover_stale_jobs` wired into worker startup, `jobs.status` index, `poll_interval_seconds` Setting, bounded `run_worker_cycle` batching, and cancellation-safe handler dispatch. - **Transactional migrations**: migration application is now one explicit transaction per migration (`BEGIN IMMEDIATE` → DDL → version → `COMMIT`), replacing `executescript` (which implicitly commits). ## Scope Movies only, as agreed; TV/episode tracking stays in Phase 3 (the schema carries `media_type` for it). Trakt import (1c), the recommendation engine and browse UI (1d), and containers (1e) are later. ## Notes - Design spec: `.superpowers/specs/2026-10-08-xique-design.md`; plan: `.superpowers/plans/2026-10-08-xique-02-jellyfin-movie-sync.md` (local artifacts, not committed per AGENTS.md). - Jellyfin endpoints verified against the Jellyfin OpenAPI spec 12.2.0. - Known divergence recorded: the sync re-walks all played movies each run and relies on idempotent upserts, rather than filtering by the stored watermark (spec §8.1 wording). Accepted for 1b; the watermark filter is a follow-up. Closes #3

This PR is too large to review automatically (4145 lines; limit is 2000). Please consider splitting it into smaller PRs.

This PR is too large to review automatically (4145 lines; limit is 2000). Please consider splitting it into smaller PRs.
marvin8 approved these changes 2026-10-08 20:11:47 +00:00
marvin8 manually merged commit 135d3bd324 into main 2026-10-08 20:13:51 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
marvin8/xique!8
No description provided.