Trakt export import #9

Manually merged
marvin8 merged 9 commits from feat/issue-4-phase-1c-trakt-import into main 2026-10-09 23:16:15 +00:00
Collaborator

One-time import of a Trakt data export zip into the watch ledger, per issue #4 and spec §8.2: a pure-local export zip parser (history, aggregates, ratings, hidden-recommendations), a worker trakt_import job, a per-user upload in settings with import status, and the xique import-trakt CLI.

  • Episode history collapses to show-level watch events (season/episode granularity stays phase 3); aggregates backfill only items with no ledger events at all.
  • Re-importing the same zip is a full no-op: dedupe rides the existing watch_events uniqueness, trakt history ids ride source_ref.
  • upsert_media gains trakt_id/tvdb_id and preserve-if-present enrichment so imports never blank Jellyfin metadata; ledger writes accept true source timestamps.
  • Uploads stream to XIQUE_IMPORT_DIR (128 MiB cap, CSRF, structural validation) and are deleted after a successful parse; the CLI never deletes the operator's own file.
  • main is never parsed inline: upload and CLI both enqueue; the worker is the single parsing path.

Verified against a real export end-to-end (CLI → worker): 794 media rows, 4,396 watch events, 745 ratings, 47 dismissals, replay byte-identical. 210 tests, uv run nox 8/8 green at every commit.

Closes #4

One-time import of a Trakt data export zip into the watch ledger, per issue #4 and spec §8.2: a pure-local export zip parser (history, aggregates, ratings, hidden-recommendations), a worker `trakt_import` job, a per-user upload in settings with import status, and the `xique import-trakt` CLI. - Episode history collapses to show-level watch events (season/episode granularity stays phase 3); aggregates backfill only items with no ledger events at all. - Re-importing the same zip is a full no-op: dedupe rides the existing `watch_events` uniqueness, trakt history ids ride `source_ref`. - `upsert_media` gains `trakt_id`/`tvdb_id` and preserve-if-present enrichment so imports never blank Jellyfin metadata; ledger writes accept true source timestamps. - Uploads stream to `XIQUE_IMPORT_DIR` (128 MiB cap, CSRF, structural validation) and are deleted after a successful parse; the CLI never deletes the operator's own file. - `main` is never parsed inline: upload and CLI both enqueue; the worker is the single parsing path. Verified against a real export end-to-end (CLI → worker): 794 media rows, 4,396 watch events, 745 ratings, 47 dismissals, replay byte-identical. 210 tests, `uv run nox` 8/8 green at every commit. Closes #4

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

This PR is too large to review automatically (3619 lines; limit is 2000). Please consider splitting it into smaller PRs.
marvin8 approved these changes 2026-10-09 23:14:04 +00:00
marvin8 manually merged commit c7ac5a8f3c into main 2026-10-09 23:16:15 +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!9
No description provided.