Phase 1c — Trakt Import #4
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Reference
marvin8/xique#4
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Users bring watch history from Trakt that predates — or was removed from — their Jellyfin library.
This issue adds a one-time import of a Trakt data export zip into the ledger, so old favourites still seed recommendations and media since deleted from Jellyfin still suppresses itself from suggestions. It covers the export parser, a per-user upload, a CLI path, and a worker import job.
Plan of attack for 1c, from spec §8.2 and inspection of a real export (27,213 history entries: 791 movie watches, 26,422 episode watches; 430 movie / 321 show aggregates; 429 movie / 316 show ratings; 47 hidden-recommendations; every movie/show entry carries tmdb+imdb ids; history ids unique).
Findings
watch_eventsdedupe isUNIQUE (user_id, media_id, watched_at, source); the trakt history id ridessource_refas provenance, so zip re-imports are no-ops with no schema change.upsert_mediacurrently overwritesgenres/overviewunconditionally — a Trakt import (which carries no enrichment) would blank Jellyfin metadata. Needs preserve-if-present semantics, plustrakt_id/tvdb_idsupport.upsert_rating/add_dismissaltake no timestamps; trakt has the truerated_at/hidden_at.Approach
services/trakt_import.py): pure-local zip validation (zipfile+ ≥1watched-history-*.jsonmember) and per-member streaming parse into typed records; structural damage fails, individual unkeyable entries are skipped and counted.media_type="show"); season/episode granularity stays phase 3.watched-movies/showsaggregates backfill only items with zero history events.POST /settings/traktmultipart (CSRF, 128 MiB cap), streams to a newXIQUE_IMPORT_DIR(default<tempdir>/xique-imports), enqueuestrakt_import{path, cleanup: true}; worker parses, deletes the uploaded copy after a successful parse. Job status shown in settings.xique import-trakt ZIP [--user NAME](newxiqueconsole script) — validates + enqueues only; the worker is the single parsing path. Without--user, exactly one user must exist. The operator's own file is never deleted (cleanup: false).Branch:
feat/issue-4-phase-1c-trakt-importCommits:
.gitignoretrakt-export fold → media/ledger write APIs → parser → import service → worker dispatch → settings upload/status → CLI; then review fix wave.No new dependencies (zipfile/argparse are stdlib);
pylock.tomluntouched.Merged via PR #9 (
c7ac5a8). Parser, workertrakt_importjob, settings upload with status, and thexique import-traktCLI are onmain; verified end-to-end against a real export with an idempotent replay.