Changing a movie's root does not move its files #235

Closed
opened 2026-08-25 08:46:54 +01:00 by naps62-yolo · 1 comment
Owner

PATCH /api/movies/{id} accepts root_id, and the movie detail page offers a
root/audience dropdown that calls it. The handler writes the movies.root_id
column and nothing else: the video file is not relocated, media_files.path
is not rewritten, and the sidecars beside it are not moved.

So after changing a movie's root the database says the title belongs to one
root while its file physically lives under another. §7.4's layout — and the
audit-by-ls property that depends on it — is silently untrue for that title,
and §5.2's per-root audio rules are being applied to a file that is not in that
root.

Nothing else in the codebase relocates an imported file either: the reconcile
loop's nine actions all leave placement alone, and PUT /api/roots/{id}
rewrites a root's path without touching the files under it.

Implementing the move is the fix, and it has to be one unit of work:

  1. Derive the new §7.4 folder from the destination root.
  2. Move the title folder, which takes the sidecars with it because §15 puts
    them inside it.
  3. Rewrite media_files.path and subtitle_files.path, in the same
    transaction as the movies.root_id update.
  4. Refresh Jellyfin once, as import already does (§7.5).

Until that exists, the dropdown offers an operation arr cannot honour — so
either build it or stop offering it.

Found while investigating #234, which turned out to be downstream of this: the
subtitle rows cannot be kept in step with a move that never happens.

`PATCH /api/movies/{id}` accepts `root_id`, and the movie detail page offers a root/audience dropdown that calls it. The handler writes the `movies.root_id` column and nothing else: the video file is not relocated, `media_files.path` is not rewritten, and the sidecars beside it are not moved. So after changing a movie's root the database says the title belongs to one root while its file physically lives under another. §7.4's layout — and the audit-by-`ls` property that depends on it — is silently untrue for that title, and §5.2's per-root audio rules are being applied to a file that is not in that root. Nothing else in the codebase relocates an imported file either: the reconcile loop's nine actions all leave placement alone, and `PUT /api/roots/{id}` rewrites a root's path without touching the files under it. Implementing the move is the fix, and it has to be one unit of work: 1. Derive the new §7.4 folder from the destination root. 2. Move the title folder, which takes the sidecars with it because §15 puts them inside it. 3. Rewrite `media_files.path` and `subtitle_files.path`, in the same transaction as the `movies.root_id` update. 4. Refresh Jellyfin once, as import already does (§7.5). Until that exists, the dropdown offers an operation arr cannot honour — so either build it or stop offering it. Found while investigating #234, which turned out to be downstream of this: the subtitle rows cannot be kept in step with a move that never happens.
naps62-yolo added the area/apitype/bugdifficulty/moderate labels 2026-08-25 08:46:54 +01:00
Author
Owner

Duplicate of #228, which was filed 17 minutes earlier from a parallel session —
neither of us could see the other's issue.

Closing this one rather than #228 because #228 carries an operator ruling this
issue does not have: every root shares one filesystem, so the move is a
directory rename rather than a copy, and the hardlinks survive it. It also
covers series, which have no root control at all today.

Your three extra findings are not lost — I have copied them onto #228:
subtitle_files.path must be rewritten with media_files.path, Jellyfin needs
the §7.5 refresh afterwards, and PUT /api/roots/{id} has the same defect one
level up.

#228 is in the "Feedback pass 2" milestone. If the subtitles milestone would
rather own this work, say so on #228 and take it — the point is that one session
does it, not which.

Duplicate of #228, which was filed 17 minutes earlier from a parallel session — neither of us could see the other's issue. Closing this one rather than #228 because #228 carries an operator ruling this issue does not have: every root shares one filesystem, so the move is a directory rename rather than a copy, and the hardlinks survive it. It also covers series, which have no root control at all today. Your three extra findings are not lost — I have copied them onto #228: `subtitle_files.path` must be rewritten with `media_files.path`, Jellyfin needs the §7.5 refresh afterwards, and `PUT /api/roots/{id}` has the same defect one level up. #228 is in the "Feedback pass 2" milestone. If the subtitles milestone would rather own this work, say so on #228 and take it — the point is that one session does it, not which.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yolo/arr#235