Commit Graph
35 Commits
Author SHA1 Message Date
Renamr Scaffold 25dedc1c36 Remove remaining user-visible FileBot mentions
The full rebrand (session 9, seventh delivery) covered the app's own
identity - name, icon, no FileBot/FB-Mod branding visible - but two
literal "FileBot" mentions were still reachable by the end user, both
found via a targeted grep for FileBot/Filebot/filebot/FB-Mod across every
string actually rendered to a user (JSX text and CLI help/usage text),
as opposed to source comments and README documentation, which still
legitimately explain what this project is a rewrite of and aren't shown
inside the running app:

- The Naming Scheme editor's own inline help text described the FileBot-
  style short field names ({n}, {s00e00}, {t}, etc.) as "FileBot's own
  short field names" - reworded to just "Short field names", same
  meaning, no brand name.
- The CLI's -h/--help output described -non-strict as "Accepted for
  FileBot script compatibility" - reworded to "Accepted for compatibility
  with existing rename scripts".

Grepped the whole frontend and every Rust source string (not just these
two files) to confirm nothing else user-visible remained - tauri.conf.json,
Cargo.toml, and package.json were already clean. What's left after this
is exclusively source-code comments/doc-comments and README.md, none of
which the app itself ever displays.

Verified via cargo test --workspace (193/193, unaffected - text-only
change) + npm run build (clean).
2026-08-30 04:41:43 +00:00
Renamr Scaffold 9b620bb7d2 Match now automatically runs Fetch Data right after - one click, not two
Requested directly: "when you click Match, I would prefer it to do what
the lookup does. pulls the info, renames properly. just one less step
needed." Match's local filename scan and Fetch Data's online lookup were
two separate button clicks with no relationship between them in code -
Fetch Data just happened to require Match to have already run.

New runMatchAndFetch() wraps both: runs the same local match as before,
then - if it found anything recognizable and either a credential-free
source (TVmaze) is selected or the needed credential is already saved -
immediately fetches real online metadata for it too, exactly as if the
user had clicked both buttons in sequence. The standalone "Fetch Data"
button next to New Names is untouched and still works on its own, for
re-fetching after changing the metadata source or fixing a guessed name
by hand.

Two supporting changes made this safe to chain:
- runMatching() now computes its updated items as a plain array
  (`items.map(...)`) instead of the usual `setItems((prev) =>
  prev.map(...))` functional-update form, and returns that array. Chaining
  straight into runFetch() needed the *actual* just-matched items, not
  `items` React state - which wouldn't reflect the match yet, since
  setItems() only queues a re-render rather than updating what this
  function's own closure sees.
- runFetch() gained itemsOverride/silentIfEmpty/chained options: read
  targets from the array just handed to it rather than state; skip the
  "Run Match first" message when Match simply found nothing to look up
  (its own message already covers that); and skip auto-opening the
  Settings modal on a missing credential when chained, so someone who
  hasn't set up Fetch Data (or doesn't want to) isn't interrupted by a
  popup on every single Match click - the status line still explains why
  fields are staying blank either way.

Also fixed a status-message race: both functions clear their own status
after a timeout, and chaining them naively could let Match's leftover
timer blank out Fetch Data's result message early (observed while
testing: a fast TVmaze lookup's "Fetched..." message got wiped a few
seconds later by Match's own stale timer). Match now skips scheduling its
success-path timer when chained, so whichever step actually finishes last
owns the status line's timer.

Verified via npm run build (clean, no Rust changes needed) + an 11-check
Playwright script against npm run dev (mocking
window.__TAURI_INTERNALS__.invoke): confirmed Match triggers guess_episode
then automatically fetch_metadata with no separate click, in that order;
the fetched episode name reaches the live preview; a missing TMDB token
still runs the local match and explains the gap in the status line
without forcing the Settings modal open; and clicking Match with nothing
loaded is handled gracefully.

Updated the naming-scheme editor's inline help text and the Match
button's tooltip to describe the new combined behavior.
2026-08-30 04:33:38 +00:00
Renamr Scaffold b409d67510 Naming scheme editor: clickable field tokens + persist across restarts
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.
2026-08-30 04:20:59 +00:00
Renamr Scaffold ecd98d6c57 Fix serde field-naming bug that blanked show/episode names, real renames, and Undo
`#[serde(tag = "status", rename_all = "camelCase")]` on a tagged enum only
renames the tag's own values ("Found" -> "found"), not the field names
inside each struct-like variant - so `series_name` stayed `series_name` on
the wire instead of becoming `seriesName`. The frontend only ever reads
camelCase, so these fields came back `undefined`, and JSON.stringify
silently drops undefined keys when Tauri invoke args are serialized -
making the bug invisible rather than throwing.

This is why Fetch Data (TMDB/TVmaze/OMDb) blanked out {show name} and
{episode name} in naming schemes even on a full "found" result: reported
by the user with screenshots showing the naming preview correct after
Match but blank after Fetch Data.

The same pattern existed in 4 more places, fixed identically by adding
`rename_all_fields = "camelCase"` alongside the existing tag/rename_all:
- metadata.rs: FetchOutcome (the reported bug) and MovieFetchOutcome
- episodes.rs: EpisodeListOutcome
- history/mod.rs: RevertOutcome (restoredPath) - broke Undo reconciliation
- rename/mod.rs: RenameOutcome (newPath) - broke post-rename item tracking
  after a REAL on-disk rename; RenamePanel.tsx calls
  fileNameFromPath(result.outcome.newPath), which throws on undefined,
  so this was likely the most severe of the five.

No frontend changes needed - the TypeScript side already expected
camelCase throughout. Added 5 permanent regression tests (one per fixed
enum, two in metadata.rs) that assert the exact camelCase JSON keys and
assert the old snake_case keys are absent. cargo test --workspace: 186 ->
191 passing. npm run build: clean, no frontend diff.
2026-08-30 04:12:17 +00:00
Renamr Scaffold e219e8f2a8 Wire real media probing into Filter and List panels
Extends the sixteenth delivery's container-header probing
(probe_media_files) beyond the Rename panel: Filter and List now run the
same batched probe alongside their existing local scan, using the same
override rule everywhere - a filename tag wins when present, otherwise a
real probed value fills in.

List: {width}/{height}/{fps}/{duration}/{file size} are now available in
naming-scheme-style expressions (no filename-tag equivalent exists), and a
probed {resolution}/{video codec}/{audio codec} fills in when the filename
didn't already carry that tag.

Filter: gained Resolution and Video codec chip rows (populated from the
same merged filename-tag-or-probed value, with an Unknown bucket for files
with neither) so a batch can be narrowed by either. Each result row's
subtitle now also shows the resolved resolution when one exists.

Verified via cargo check/test --workspace (unaffected, frontend-only
change) + npm run build (clean) + a 15-check Playwright script against
npm run dev covering both panels: filename-tag resolution winning over a
conflicting probed value, probed fields filling in for an otherwise-
unmatched file, the new Filter chip rows narrowing results correctly.
Updated README (status paragraph, Filter section, List section, Real
media-file probing section, roadmap item 1).
2026-08-30 03:48:22 +00:00
Renamr Scaffold 23c9ca609f Expanded scripting/naming helpers: pad, sort_name/sort_initial, upper/lower_initial, acronym, validate_file_name, space/space_with, colon/colon_with
Ports the next slice of FileBot's ExpressionFormatMethods.java as Rhai-callable
methods usable inside any { } naming-scheme expression, alongside the existing
any/all_of/concat helpers:

- pad/pad_with: left-pad a value's string form (default '0'), non-mutating,
  non-truncating - deliberately a different Rhai method name for the 3-arg
  custom-char form (pad_with) since Rhai's own built-in pad(length, char)
  right-pads and mutates in place, which collides in behavior (not API) with
  what FileBot's zero-padded season/episode numbers need.
- sort_name/sort_initial: move a leading The/A/An article to the end for
  alphabetical sorting, e.g. "The Office" -> "Office, The".
- upper_initial/lower_initial: case-convert only the first character.
- acronym: first letter of each word, uppercased.
- validate_file_name: strip characters illegal in filenames, collapse
  whitespace runs, trim trailing dots.
- space/space_with, colon/colon_with: separator and colon normalization.

16 new unit tests in functions.rs (143 lib tests total, up from 126) plus 3
new integration tests in expression_format.rs demonstrating the helpers used
inside real naming-scheme expressions (14 total, up from 11). Verified via
cargo test --workspace, cargo check --workspace, and npm run build, all
clean. Updated README (status paragraph and porting-roadmap item 2).
2026-08-30 03:24:19 +00:00
Renamr Scaffold 1291ae086d Add real media-file probing (session 9, sixteenth delivery)
Wires real container-header probing into the Rename panel's Match step, the
first item on the porting roadmap: aurora-curator-core::probe reads actual
resolution, frame rate, duration, and video/audio codecs straight from a
file's own header (mp4 crate for MP4/M4V/MOV, matroska crate for MKV/WebM,
no ffmpeg/MediaInfo dependency), batched through a new probe_media_files
Tauri command. Probed values fill {resolution}/{video codec}/{audio codec}
only when a filename release tag hasn't already, and populate five bindings
with no filename-tag equivalent at all: {width}, {height}, {fps},
{duration}, {file size}. 8 new Rust unit tests against real ffmpeg-generated
fixture files (161 -> 169 total), verified end to end with a 15-check
Playwright script against npm run dev, and README updated (status
paragraph, project layout, a new "Real media-file probing" section, and
roadmap item 1 narrowed to what's still missing).
2026-08-29 18:07:54 +00:00
Renamr Scaffold 03768c398d Add List panel (session 9, fifteenth feature)
Renders a naming-scheme-style expression per loaded file via the same
render_expression engine the Rename panel's live preview uses, fed by
the same local guess_episode/guess_movie/guess_release_info matching
Filter already uses. Copy List and Export to File... (a new
export_text_list Tauri command - the only new backend surface this
feature needed) round it out. Closes out all six original sidebar
panels as real screens.
2026-08-29 17:28:38 +00:00
Renamr Scaffold bfcec9135a Add Filter panel: narrow a loaded batch by extension, kind, filename, and season
Fully local, and adds no new Rust/Tauri commands at all - reuses pick_files plus the
same guess_episode/guess_movie/guess_release_info local matchers "Match" already calls
in the Rename panel, just applied to a second, independently-loaded file list and
rendered as toggleable filter criteria instead of a rename preview.

New src/components/FilterPanel.tsx/.css: Load Files scans the batch immediately,
toggleable chips appear for every extension and media kind actually present, a
filename-contains text field and a season number field (TV only) narrow further, and
Copy File Paths exports whatever currently matches to the clipboard.

Verified with a 21-check Playwright script against npm run dev (chip toggling, the
filename/season filters, the no-match empty state, and the clipboard export).
2026-08-29 17:01:15 +00:00
Renamr Scaffold 316dbfc1ff Add SFV panel: compute/verify CRC32/MD5/SHA1 checksums, .sfv/.md5/.sha1 sidecar files
Fully local feature - no network access, no credentials. New aurora-curator-core::sfv
module streams file hashing in 64KB chunks and handles both the traditional .sfv
format (CRC32, "name checksum" layout) and the GNU coreutils md5sum/sha1sum sidecar
convention (.md5/.sha1, "checksum  name" layout), dispatched on a shared ChecksumKind
enum. New src-tauri/src/sfv.rs wraps it in three Tauri commands - compute_checksums
(per-file error isolation), save_checksum_file (native Save dialog), and
verify_checksum_file (resolves each entry against the checksum file's own parent
directory, reports OK/Mismatch/Missing per entry). New SfvPanel.tsx/.css wires it all
into the sidebar's SFV screen - load files, pick a checksum type, Compute, Save, or
Verify against an existing checksum file.

14 new core-crate tests + 1 new src-tauri test, all passing (workspace: 160/160).
Verified end-to-end with a 22-check Playwright script against npm run dev.
2026-08-29 15:59:05 +00:00
Renamr Scaffold ed26391651 Add Episodes panel: search a series, browse a season's episode list
New src-tauri/src/episodes.rs exposes browse_episodes, reusing the
existing AnyTvClient::fetch_season machinery Fetch Data already built
(via a build_tv_client helper factored out of metadata.rs) so this
panel needs no credentials of its own - it reads whatever TV source
(TMDB/TVmaze/OMDb) is already configured in Fetch Data Settings.

New EpisodesPanel.tsx/.css: series name + season stepper, an episode
list (number/title/air date), and a Copy list button that copies the
season as plain text. Wired into App.tsx's sidebar routing as the
second stub panel (after Subtitles) to become a real screen.

145/145 Rust tests passing (+1), npm run build clean, 15/15 Playwright
checks against npm run dev (mocked Tauri bridge) covering search,
the empty-season case, a not-found series, the season stepper, Copy
list, and the blank-query guard.
2026-08-29 15:35:27 +00:00
Renamr Scaffold b47d28375b Add OpenSubtitles subtitle search + download (new Subtitles panel)
New web client (crates/aurora-curator-core/src/web/opensubtitles.rs, 9 tests):
search, login, download, and fetch-subtitle-text against OpenSubtitles' REST
API. Search only needs a free app-level API key; download additionally needs
the end user's own OpenSubtitles account login (username/password -> JWT),
since downloads are quota-limited per account. Settings gained three new
fields (opensubtitles_api_key/username/password) following the existing
TMDB/OMDb credential pattern, with one deliberate exception: the password is
never returned to the frontend, only whether one is saved
(has_opensubtitles_password), since it's a real account password rather than
an API token.

New src-tauri/src/subtitles.rs wraps search/download as Tauri commands and
writes a downloaded subtitle right next to its video file
(Show.S01E01.mkv -> Show.S01E01.en.srt).

New src/components/SubtitlesPanel.tsx is the first real screen behind a
sidebar entry besides Rename (previously a stub) - load a video, auto-fill
the search form from the same local guess_episode/guess_movie Match uses,
search, and download with live remaining/allowed quota shown per result.

TheTVDB was considered instead but deliberately skipped for now: its v4 API
requires either a paid commercial license or a per-end-user paid TheTVDB
subscription just to log in, unlike every other source in this app.

144 tests passing (workspace). Updated README (status paragraph, project
layout, new "Subtitles" section, roadmap items 5/6/7).
2026-08-29 14:08:17 +00:00
Renamr Scaffold c158befa83 Add OMDb as a datasource: TV episodes (third option alongside TMDB/TVmaze) and movies (new second option alongside TMDB)
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.
2026-08-29 12:25:45 +00:00
Renamr ScaffoldandClaude Sonnet 5 22a3da9f6f Add CLI flag surface: -rename/--format/--db/--action/--conflict/-non-strict/-h
Ports FileBot's net.filebot.cli flag surface so Aurora Curator can be scripted,
not just driven through the GUI. Argument parsing and file-expansion are pure
Rust in aurora-curator-core::cli (14 unit tests, no Tauri/network dependency);
orchestration lives in src-tauri/src/cli.rs, which reuses the exact same
binding vocabulary the GUI's RenamePanel.tsx builds client-side and the exact
same TMDB/TVmaze season-caching lookup fetch_metadata already uses, so a
naming scheme renders identically whether it's typed into the app or passed
via --format.

main.rs branches to CLI mode before any Tauri App/window is built at all,
using tauri::async_runtime::block_on to drive the async metadata lookups
(confirmed safe standalone by reading Tauri's own async_runtime.rs) and a
hand-rolled settings::cli_tmdb_token() that replicates Tauri's own
app_config_dir() computation (dirs::config_dir().join(identifier), pinned
against tauri.conf.json by a new test) so a token saved through the GUI's
Fetch Data Settings is found from the CLI path too - the CLI still never
accepts a token as an argument.

Deliberately not ported: --output <dir> (the rename engine's safety
invariant against escaping the source directory tree would need to be
relaxed) and -non-strict is accepted as a no-op (local matching has no
confidence score to loosen).

16 new tests in src-tauri (10 in cli.rs, 1 pinning settings::
APP_CONFIG_IDENTIFIER) plus 14 in aurora-curator-core's cli module - full
workspace suite is 113 passing. README updated with a new "Command-line
usage" section and roadmap item 6 marked done for the CLI surface.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QLbx8ov7zMcdDPEqQm4Y98
2026-08-29 11:30:51 +00:00
Renamr Scaffold 5763c6313b Add TVmaze as a second, user-selectable TV metadata source for Fetch Data
TV episodes can now resolve against either TMDB (default) or TVmaze - picked
via a segmented source picker in the renamed "Fetch Data Settings" modal.
TVmaze is free and needs no API token at all; movies still always resolve
against TMDB regardless of the choice, since TVmaze has no movie catalog.

- New TvmazeClient (crates/aurora-curator-core/src/web/tvmaze.rs): search +
  season/episode lookup against api.tvmaze.com, filtering out unnumbered
  specials rather than panicking on them (TVmaze returns every season's
  episodes in one flat list, unlike TMDB's per-season endpoint).
- New TvMetadataSource setting (settings.rs), persisted alongside the TMDB
  token, defaulting to Tmdb for schema-evolution safety.
- metadata.rs now branches TV fetches through an AnyTvClient wrapper so the
  existing per-(series, season) caching loop doesn't care which source
  produced a result; the movie-fetch path is untouched.
- Frontend: TMDB/TVmaze picker in Fetch Data Settings, persisted on change;
  Fetch Data's token gating now only requires a TMDB token when it's actually
  needed (movies always, TV only when TMDB is the chosen source) instead of
  unconditionally blocking on it.

cargo test --workspace: 88/88 passing (81 + 7 new TVmaze + 3 new settings).
npm run build passing. Playwright verification: 18/18 checks (picker renders
and persists across reload, TV Fetch Data succeeds on TVmaze with zero TMDB
token configured, movies still correctly demand a token even with TVmaze
selected, switching back to TMDB still works end-to-end).
2026-08-29 10:44:12 +00:00
Renamr Scaffold 7097b1ede7 Rebrand: Renamr -> Aurora Curator (new logo/app icon, renamed crate aurora-curator-core, package/identifier/window-title updates, README + in-app text) 2026-08-29 10:07:09 +00:00
Renamr Scaffold 7dd9ad2078 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.
2026-08-29 09:50:36 +00:00
Renamr Scaffold 21d78b8f3a Add Align Up/Down list reordering and naming-scheme Presets
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).
2026-08-29 09:39:52 +00:00
Renamr Scaffold 94eb26f778 Add release-tag naming-scheme fields (resolution, source, codecs, group)
Match now also parses filename-only release-tag text - resolution, source
(BluRay/HDTV/WEB-DL/...), video/audio codec, and release group - via a new
guess_release_info() in renamr-core's matching module, wired through a new
guess_release_info Tauri command and called alongside the existing TV/movie
guess for every file. Naming schemes can now reference
{resolution}/{source}/{video codec}/{audio codec}/{release group}, or
FileBot's own short names ({vf}/{source}/{vc}/{ac}/{group}).
2026-08-29 09:29:14 +00:00
Renamr ScaffoldandClaude Sonnet 5 fd4e6f66f0 Add Move/Copy/Symlink rename actions, with undo support for all three
- 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]>
2026-08-29 04:31:16 +00:00
Renamr ScaffoldandClaude Sonnet 5 aab8e28246 Add per-item exclude to the rename confirmation modal
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]>
2026-08-29 04:12:35 +00:00
Renamr ScaffoldandClaude Sonnet 5 45a9f5d523 Add movie support to Fetch Data: local title/year guessing plus TMDB movie lookup
- renamr-core::matching: guess_movie() extracts a movie title (and release year, if
  present) from a filename using the same year/quality-token boundary heuristics real
  release names follow, as a fallback when guess_episode() finds no season/episode
  marker.
- renamr-core::web::tmdb: search_movie()/lookup_movie() mirror the TV client, reusing
  the same Sorensen-Dice title-disambiguation as lookup_episode(), narrowed further by
  TMDB's own primary_release_year filter when a year was locally guessed. Also exposed
  search_tv_best_match() and fixed a latent gap where the real Fetch Data command path
  (metadata.rs::fetch_season) bypassed the fuzzy show-name disambiguation entirely,
  doing its own raw first-result selection instead of reusing it.
- src-tauri: new guess_movie command and fetch_movie_metadata command/types
  (MovieFetchQuery/Outcome/Result), registered alongside the existing TV commands.
- Frontend: Item now tracks mediaKind ("tv"/"movie"/null); Match tries guess_episode
  then falls back to guess_movie; Fetch Data resolves TV and movie targets via their
  own commands concurrently and merges results. A single batch can mix TV and movie
  files - each only fills in the fields that apply to it. Movie fields ({movie name},
  {year}, reusing {airdate} for release date, matching FileBot's own unified binding)
  are documented in the naming-scheme field reference.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-29 04:04:16 +00:00
Renamr Scaffold 93b5ac5e56 Add rename history with undo
- 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.
2026-08-29 03:44:38 +00:00
Renamr Scaffold 658a235e05 Let the naming scheme organize files into subfolders
- rename::rename_one now resolves new_name relative to the source file's
  own directory, allowing / as a subdirectory separator (e.g. a naming
  scheme like {show name}/{episode name}) instead of rejecting it. Missing
  intermediate directories are created automatically via create_dir_all.
- New validate_relative_target() replaces the old is_plain_filename():
  still rejects anything that could escape the source directory (empty
  path segments - which also catches a leading-slash absolute path -
  and . / .. segments) plus backslashes (Renamr always treats / as the
  scheme's folder separator regardless of OS), but now allows a
  legitimate multi-segment relative path through.
- The "Unchanged" check now compares the full resolved target path to the
  source, not just the filename, since a computed name can now include
  directory components.
- 6 new tests: organizing into a new subfolder, nested subfolders that
  don't exist yet, conflict detection still works for organized targets,
  and rejection of backslashes / doubled / leading / trailing slashes.
- Frontend: naming-scheme editor hint explains the / convention, and the
  rename confirmation modal notes when a plan will create new subfolders.
- No changes needed in the naming-expression engine itself - it already
  treats / between two {} scriptlets as ordinary literal text.
2026-08-29 03:36:06 +00:00
Renamr Scaffold 855f9bea24 Disambiguate Fetch Data's TMDB search results by name similarity
- New crates/renamr-core/src/similarity module: a partial port of the
  scoring idea behind FileBot's EpisodeMetrics.java - normalizes titles
  (lowercase, strips a trailing release-year parenthetical, collapses
  punctuation/whitespace) and scores them with a Sorensen-Dice coefficient
  over character bigrams. best_title_match() picks whichever candidate is
  textually closest to the query, provided it clears a minimum threshold;
  ties keep the earlier (i.e. TMDB-ranked) candidate.
- TmdbClient::lookup_episode now uses best_title_match instead of blindly
  taking the first search result, so a more popular but differently-named
  show can no longer beat an exact-but-lower-ranked match to the top - and
  reports NotFound instead of guessing when nothing in the results is a
  plausible match at all.
- 7 new tests (5 in similarity, 2 in tmdb) including the concrete regression
  case this fixes: searching "Chuck" with TMDB returning "Chucky" ranked
  above "Chuck" now correctly picks "Chuck".
- Also fixes a gitignore gap from last delivery: the _to_delete*/ scratch-dir
  pattern used to work around this repo's mounted-folder git-lock quirk had
  only ever been applied directly on the device, never carried back into the
  zip this delivery is built from - so the last delivery's cp -rf silently
  reintroduced the untracked-lock-file risk. Fixed in both places now.
2026-08-29 03:27:19 +00:00
Renamr Scaffold 717acb5de1 Broaden .gitignore to _to_delete*/ and untrack second stray scratch dir 2026-08-29 03:16:01 +00:00
Renamr Scaffold 5db1cb414b Untrack accidental _to_delete scratch dir, add it to .gitignore 2026-08-29 03:15:40 +00:00
Renamr Scaffold f89589bc88 Make the naming scheme fully user-editable, with the user's preferred format as default
- 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).
2026-08-29 03:15:21 +00:00
Renamr Scaffold d1fc4039a7 Add TMDB metadata client and Fetch Data: real episode titles/air dates via TMDB, with a Settings modal for the API token 2026-08-29 03:01:19 +00:00
Renamr Scaffold bab9bfa1ec Add local season/episode matching and on-disk rename (skip-on-conflict, confirm-first) 2026-08-29 02:42:31 +00:00
Renamr Scaffold d0c29048be Fix long filenames overflowing the window instead of truncating: flex/grid items need explicit min-width:0 to shrink below content size 2026-08-29 02:15:49 +00:00
Renamr Scaffold bab05826ef Fix freeze on file/folder picker dialogs: use the non-blocking dialog API instead of blocking_pick_files()/blocking_pick_folder(), which deadlock when called from a command handler 2026-08-29 02:10:56 +00:00
Renamr Scaffold 07ce595f77 Add real file loading: native file/folder picker + OS drag-and-drop, backed by real Rust commands (pick_files/pick_folder/expand_dropped_paths) 2026-08-29 02:06:14 +00:00
Renamr Scaffold 87e150f31b Rebuild UI as a faithful recreation of the original Aurora-themed layout: sidebar panel nav, two-pane rename list, live naming-scheme preview 2026-08-29 01:55:54 +00:00
Renamr Scaffold e01852f292 Initial Renamr scaffold: Tauri (Rust core + React/TS UI), naming-expression engine ported+tested 2026-08-29 01:43:12 +00:00