Add conflict policy options: Skip / Auto-number / Override

New ConflictPolicy enum in rename/ (Skip = original/default behavior,
AutoNumber = save as "Name (1).ext" counting up to the first free slot,
Override = replace the conflicting file outright), threaded through
execute_renames/rename_one alongside RenameAction. Override never deletes
a conflicting directory (falls back to Skip for that case); AutoNumber
sidesteps directories the same way by just trying the next number.
execute_rename now takes a conflict argument; undo/history are
deliberately NOT conflict-aware and always use their own fixed
skip-on-conflict policy regardless of what the original rename used.

Frontend: a second segmented selector in the rename confirmation modal
("On conflict: Skip / Auto-number / Override"), with Override styled in
red and its warning copy calling out that it can't be undone.
This commit is contained in:
Renamr Scaffold
2026-08-29 09:50:36 +00:00
parent 21d78b8f3a
commit 7dd9ad2078
5 changed files with 449 additions and 71 deletions
+36 -24
View File
@@ -9,14 +9,19 @@ native file/folder loading and drag-and-drop, local filename-based season/episod
movie title/year* detection ("Match") is working, real online metadata lookups against
TMDB ("Fetch Data") are working for both TV episodes and movies — including fuzzy
title disambiguation, so a search that returns several similarly-named results doesn't
just take TMDB's top-ranked hit — and the actual on-disk operation is wired up
(skip-on-conflict, with a confirmation step showing the full old-path/new-path plan
before anything touches disk, a per-row ✕ to drop an individual file from that plan at
the last step, and a Move/Copy/Symlink selector for what to actually do at each
target). It can also organize files into subfolders — including ones that don't exist
yet — when the naming scheme includes a `/`. Every completed batch is logged to a
history panel that can undo it (moving files back for Move, or just removing what was
created for Copy/Symlink). A single loaded batch can freely mix TV episodes and movies
just take TMDB's top-ranked hit — and the actual on-disk operation is wired up (with a
confirmation step showing the full old-path/new-path plan before anything touches disk,
a per-row ✕ to drop an individual file from that plan at the last step, a Move/Copy/
Symlink selector for what to actually do at each target, and — independently — a Skip/
Auto-number/Override selector for what happens when the computed name already exists:
leave it alone (the original, and still default, behavior), save alongside it as
"Name (1).ext", or replace it outright). It can also organize files into subfolders —
including ones that don't exist yet — when the naming scheme includes a `/`. Every
completed batch is logged to a history panel that can undo it (moving files back for
Move, or just removing what was created for Copy/Symlink — undoing always uses its own
skip-on-conflict policy regardless of what the original rename used, so an undo can
never overwrite something else as a side effect). A single loaded batch can freely mix
TV episodes and movies
— each file only fills in the fields that apply to it. "Match" also parses release-tag
text straight out of the filename — resolution, source (BluRay/HDTV/WEB-DL/…),
video/audio codec, release group — so naming schemes can reference
@@ -110,9 +115,10 @@ to the source file's parent directory, never as an absolute path, and every path
component is validated (`validate_relative_target`) to reject empty segments (a
leading, trailing, or doubled `/` — which also catches an absolute-looking
`/etc/passwd`-style path), `.`/`..` segments, and backslashes (Renamr always uses `/`
for the naming scheme's folder separator regardless of OS). Conflict policy is
unchanged: if the resolved target already exists and isn't the same underlying file,
that item is skipped rather than overwritten.
for the naming scheme's folder separator regardless of OS). If the resolved target
already exists and isn't the same underlying file, what happens next is up to the
chosen conflict policy — Skip (default), Auto-number, or Override; see item 6 of the
porting roadmap below for the full behavior of each.
## Project layout
@@ -127,8 +133,9 @@ crates/renamr-core/ Pure Rust core: naming-expression engine (ported), local
search + episode lookup
and movie search + lookup, both disambiguated via `similarity/`,
tested against a mocked HTTP server via `mockito`), the on-disk
rename engine (`rename/` — skip-on-conflict, Move/Copy/Symlink
actions, can also organize into (auto-created) subfolders when
rename engine (`rename/` — Move/Copy/Symlink actions,
Skip/Auto-number/Override conflict policies, can also organize
into (auto-created) subfolders when
the naming scheme includes `/`) — and a rename history/undo log
(`history/`, a partial `HistoryDialog` port, undo-aware of which
action produced each batch). Not yet ported: full media metadata
@@ -244,17 +251,22 @@ ported from, for anyone picking this up:
6. **Rename engine + CLI** — `net.filebot.cli.CmdlineOperations` (1235 lines) and
`ArgumentBean` (415 lines, the full flag surface: `-rename`, `--db`, `--format`,
`--action`, `--conflict`, `-get-subtitles`, `-script`, etc.). The rename operation is
done (`crates/renamr-core/src/rename`, fixed skip-on-conflict policy, wired to the
UI's Rename button behind a confirmation step) including the `move`-into-subfolder
`--action` variant — a naming scheme like `{n}/{s00e00}` organizes files into
subfolders, creating any missing folders automatically, always scoped to the file's
own directory tree. The `copy`/`symlink` `--action` variants are done too — an action
selector in the confirmation modal picks Move/Copy/Symlink for the whole batch; Copy
and Symlink both leave the source file untouched and produce a new file/link at the
computed target, and both are undoable from the History panel the same as Move (undo
for Copy/Symlink just removes what was created, since there's nothing to move back).
Not yet done: the `--conflict` variants beyond skip (auto-number, override), and the
CLI flag surface itself.
done (`crates/renamr-core/src/rename`, wired to the UI's Rename button behind a
confirmation step) including the `move`-into-subfolder `--action` variant — a naming
scheme like `{n}/{s00e00}` organizes files into subfolders, creating any missing
folders automatically, always scoped to the file's own directory tree. The
`copy`/`symlink` `--action` variants are done too — an action selector in the
confirmation modal picks Move/Copy/Symlink for the whole batch; Copy and Symlink both
leave the source file untouched and produce a new file/link at the computed target,
and both are undoable from the History panel the same as Move (undo for Copy/Symlink
just removes what was created, since there's nothing to move back). The `--conflict`
variants are done too — a second selector in the same modal picks Skip (default,
leaves the conflicting file alone), Auto-number (`"Name (1).ext"`, counting up to the
first free slot), or Override (replaces the conflicting file outright — the one
irreversible option, called out with red styling in the UI; undoing that batch later
restores the *source*, never what got overwritten, since undo always uses its own
fixed skip-on-conflict policy no matter which policy the original rename used). Not
yet done: the CLI flag surface itself.
7. **The rest of the UI** — the Rename panel (file loading, drag-drop, live preview,
local TV/movie matching, confirmed rename with per-item exclude, rename history/undo,
Align Up/Down reordering, naming-scheme Presets with `1`-`9` hotkeys) is built; the