Two usability fixes to the naming-scheme editor, both reported/requested
directly: the field-reference list ({show name}, {episode number}, etc.)
was plain unclickable text, so building a scheme meant typing every field
name out by hand; and the editor's text always reset to the built-in
sample expression on every launch, since nothing ever wrote it to disk -
only the explicit 1-9 preset slots (presets.rs) were persisted.
Field list -> clickable buttons: each field reference is now a real
<button> (.format-field-chip) wired to insertField(), which reads the
input's real DOM selectionStart/selectionEnd and inserts the token at
the caret, then restores focus and moves the caret to just after the
inserted text so clicking several fields in a row builds up
left-to-right. Purely a frontend change - no new Tauri commands needed.
Persistence: added last_naming_scheme to settings.rs's StoredSettings
(same settings.json already used for tv/movie source, credentials,
etc.), plus get_last_naming_scheme/save_last_naming_scheme commands.
RenamePanel.tsx loads it once on mount (restoring the saved scheme
before the user can interact with anything) and saves it back debounced
(600ms after typing settles) as the user edits - gated behind a
schemeLoaded flag so the save effect can never fire before the load
completes and clobber a saved scheme with the not-yet-replaced sample
default. An empty/blank saved value (fresh install) leaves the built-in
sample expression in place, same fallback behavior as every other
optional setting in this file.
Verified via cargo test --workspace (191 -> 193, two new settings.rs
tests: schema-evolution for the new field, and the blank-clears-to-None
behavior) + npm run build (clean) + a 7-check Playwright script against
npm run dev (mocking window.__TAURI_INTERNALS__.invoke): confirmed the
editor restores a mocked saved scheme on launch, clicking a field chip
inserts its token at a caret placed via setSelectionRange (not just
appended), a second click lands immediately after the first rather than
at the old position, and save_last_naming_scheme fires once (debounced)
with the exact edited text rather than on every keystroke.
Updated README's naming-scheme paragraph to describe both.
Movies get their own independent metadata-source setting for the first
time (previously hardcoded to TMDB) so the GUI's Fetch Data Settings now
has two separate pickers - TV episode source (TMDB/TVmaze/OMDb) and
movie source (TMDB/OMDb) - and a batch can freely mix sources across its
TV and movie halves. The -rename CLI's --db flag gained omdb alongside
tmdb/tvmaze, with movies now looked up online for both tmdb and omdb.
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.
Align Up/Down now swaps the selected file with its neighbor in the shared
item list (Original Files and New Names stay positionally paired, matching
the original FileBot's "align" buttons for manually lining up mismatched
lists).
Naming-scheme Presets: up to 9 saved expressions, one per digit slot,
persisted as presets.json (src-tauri/src/presets.rs, same load/save
pattern as settings.rs/history.rs). A new Presets panel lists all 9 slots
with Save Current / Apply / Clear, and a global 1-9 keydown handler applies
a slot instantly from anywhere in the app (ignored while a text field is
focused or a modal is open).
- renamr-core::rename: new RenameAction enum (Move/Copy/Symlink, default Move,
mirroring net.filebot.cli.CmdlineOperations's --action modes). execute_renames() now
takes an action applied to the whole batch. Copy uses fs::copy (source untouched);
Symlink uses std::os::unix::fs::symlink / std::os::windows::fs::symlink_file behind a
cfg(unix)/cfg(windows) split. Same conflict policy (skip, never overwrite) and
auto-created destination folders apply to all three actions. 8 new tests.
- renamr-core::history: HistoryBatch now records which action produced it
(#[serde(default)] so old history.json entries - all implicitly Move - still
deserialize). revert_one() branches on it: Move still moves the file back; Copy/
Symlink undo by deleting the copy/symlink (using symlink_metadata so a broken link is
still recognized as present and removable) - the original was never touched by those
actions, so there's nothing to move back. 3 new tests.
- src-tauri: execute_rename command takes the chosen action and threads it through to
both execute_renames and record_batch.
- Frontend: a Move/Copy/Symlink segmented selector in the "Confirm Rename" modal
(remembered across modal opens, defaults to Move), action-aware subtitle/button
copy, and a status message using the right verb (Renamed/Copied/Symlinked). Only Move
reconciles a loaded item's id/name/bindings to the new path afterward, since Copy/
Symlink leave the source file exactly where it was. History panel now shows a Copy/
Symlink badge on non-Move batches and explains what Undo does for each.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Each row in the "Confirm Rename" plan now has a small x button that drops just that
file from the batch without closing the modal or needing to cancel and re-select
beforehand (previously it was all-or-nothing - "Exclude Selected" on the file list was
the only way to leave a file out, and only before opening Rename at all). Excluding
every row disables the confirm button and shows an empty-plan hint instead of sending
an empty batch. No Rust changes needed - this is pure plan-state filtering in the
frontend, RenamePlanEntry's shape is unchanged.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- New crates/renamr-core/src/history module: HistoryBatch/HistoryEntry
records, revert_batch() moves files back to their original paths
(skip-on-conflict, same policy as rename::execute_renames; recreates a
deleted destination folder defensively), push_batch() maintains a
most-recent-first log capped at 50 batches. A partial port of the idea
behind net.filebot.HistoryDialog, as a flat undo stack rather than a full
session/element log. 6 new tests.
- New src-tauri/src/history.rs: persists the log as history.json in the OS
app-config directory (same location as settings.json). execute_rename now
takes an AppHandle and calls history::record_batch after every rename,
recording only the items that actually got renamed. Two new commands:
list_rename_history and undo_rename_batch.
- Frontend: the History button (previously a no-op) now opens a panel
listing past rename batches with a timestamp, file count, and the
old-name/new-name pairs, each with an Undo button. Undoing reconciles any
currently-loaded item back to its pre-rename path/name, same pattern as
post-rename reconciliation.
- Verified via cargo test (45 total)/check + npm build + a full Playwright
pass: loaded mocked files, renamed them, opened History, undid the batch,
and confirmed both the UI and the (mocked) backend state matched at every
step.
- ExpressionFormat::compile_scriptlet now falls back to treating a {token} as a
literal multi-word binding key when it's neither a valid Rhai identifier nor
valid Rhai script, but still looks like a plain human-typed field name (only
letters/digits/underscores/spaces). This is what lets `{show name}` work
without anyone needing to know Rhai, while real Rhai script (even containing
spaces) still takes priority and genuine syntax errors still surface.
- New default naming scheme app-wide: `{show name} - {season number}x
{episode number} - {episode name}` (previously the terser {n} - {s00e00} -
{t} form). Match/Fetch Data auto-upgrade targets updated to match, and
sample items carry both the short FileBot-style keys and the new
human-readable ones side by side.
- Naming scheme editor UI rewritten: explains the field is fully editable,
lists available fields grouped by when they become available (always /
after Match / after Fetch Data), and clarifies Rhai script is also
supported for anyone who wants it.
- 3 new unit tests for the plain-field-name fallback (multi-word lookup
works, real Rhai still takes priority, genuine syntax errors still error).