1# Jellyfin media migration proof
2
3An initial small preview used a consistent SQLite backup from Zenith, verified by `PRAGMA integrity_check` before and after transfer. Its 4,879 `/media/...` paths matched Zenith's database by sorted path digest. On Zenith, 4,823 resolved in the existing media dataset; the other 56 were already missing at the source (50 videos, 3 trailers, 2 folders, and 1 photo).
4
5The VM mounts Zenith's media tree read-only at `/srv/clover/Media`, which Jellyfin receives as `/media`. Twenty evenly spaced source paths that exist on Zenith also resolved through the VM mount. The staged app is healthy without copying the 3.97 TiB media dataset. [The media cutover plan](media-cutover.md) moves that dataset to the final `/srv/clover/Media` mountpoint while preserving hardlinks and snapshots.
6
7A full preview restore used the existing read-only `storage1/apps@hourly-2026-09-26_01-00` snapshot as its source. [import-jellyfin.sh](import-jellyfin.sh) copied Jellyfin's metadata, artwork, attachments, subtitles, intro-skipper state, and plugins while excluding caches, logs, and transcodes. The copy was 4.7 GB on the Mac and 3.2 GB in the VM's compressed ZFS dataset; checksums matched before the app started. The pinned 10.11.11 image migrated the 10.11.5 database successfully. Both sides had 17,466 base items, 22 users, 7,717 user-data rows, and the same digest for 4,879 media paths after boot. The source and stage also matched counts for 7,149 metadata files, 873 attachments, and 1,574 subtitles. SQLite integrity and HTTPS health passed; the SSO start endpoint redirected to the staged Keycloak client.
8
9Production import (`STUDIO_DEPLOY_HOST=<new-host> STUDIO_DEPLOY_PORT=22 sh tools/import-jellyfin.sh jellyfin`) uses the stopped live source, requires the new Jellyfin job stopped and the real Media ZFS filesystem mounted, snapshots the destination, verifies the copy, assigns Jellyfin's allocated UID, and leaves the new job stopped for cutover. During the preview boot, a three-second Nomad health probe timed out under load and Caddy briefly removed the stage route. The probe now allows 15 seconds; the updated preview deployment passed. The imported Jellyfin settings also automatically installed newer AniList and Intro Skipper plugins after startup.
10
11After a same-machine OS replacement, set `STUDIO_LEGACY_HANDOFF` to the [offline handoff](legacy-handoff.md) directory. The production importer then copies the old app metadata directly between mounted datasets on the new host, without a Mac scratch copy or old Docker daemon. The 3.97 TiB Media dataset remains a ZFS mount and is not copied.
12
13The service binds the reorganized host folders at their original `/media/jellyfin/...` container paths using the shared [config/site.pkl](../config/site.pkl) mapping. Both existing library settings and new-instance setup keep those paths; no database path rewrite is needed. See the [current service layout](media-cutover.md#service-paths-for-the-reorganized-tree). This follows [Jellyfin's migration guidance](https://jellyfin.org/docs/general/administration/migrate/) to preserve the paths seen by the application.