2026-08-29 10:07:09 +00:00
|
|
|
|
# Aurora Curator
|
2026-08-29 01:43:12 +00:00
|
|
|
|
|
|
|
|
|
|
A fast, cross-platform media renamer — a ground-up rewrite of FileBot (via its FB-Mod
|
|
|
|
|
|
fork), built from scratch as its own project: new stack, new architecture, new branding.
|
|
|
|
|
|
|
2026-08-29 02:42:31 +00:00
|
|
|
|
**Status: early scaffold, but the core loop works end to end.** The naming-expression
|
|
|
|
|
|
engine is ported and tested, the faithfully-recreated two-pane UI is wired to real
|
2026-08-29 04:04:16 +00:00
|
|
|
|
native file/folder loading and drag-and-drop, local filename-based season/episode *and
|
2026-08-29 10:44:12 +00:00
|
|
|
|
movie title/year* detection ("Match") is working, real online metadata lookups
|
|
|
|
|
|
("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
|
2026-08-29 12:25:45 +00:00
|
|
|
|
take the source's top-ranked hit. TV episodes can resolve against TMDB, TVmaze, or
|
|
|
|
|
|
OMDb, and movies against TMDB or OMDb — each picked independently in Fetch Data
|
|
|
|
|
|
Settings, TMDB stays the default for both, TVmaze needs no API token at all (it has no
|
|
|
|
|
|
movie catalog, so it's TV-only), and TMDB/OMDb each need their own free saved
|
|
|
|
|
|
credential before a batch resolved against them will succeed. The actual on-disk operation is wired up (with a
|
2026-08-29 09:50:36 +00:00
|
|
|
|
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
|
2026-08-29 09:29:14 +00:00
|
|
|
|
— 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
|
|
|
|
|
|
`{resolution}`/`{source}`/`{video codec}`/`{audio codec}`/`{release group}` (or
|
2026-08-29 18:07:54 +00:00
|
|
|
|
FileBot's own `{vf}`/`{source}`/`{vc}`/`{ac}`/`{group}`), and now also probes each
|
|
|
|
|
|
file's own container header for its real resolution, frame rate, duration, and
|
|
|
|
|
|
codecs — no ffmpeg/MediaInfo dependency required — filling in `{resolution}`/
|
|
|
|
|
|
`{video codec}`/`{audio codec}` whenever the filename itself didn't already carry
|
|
|
|
|
|
that tag, plus `{width}`/`{height}`/`{fps}`/`{duration}`/`{file size}`, which have no
|
2026-08-30 04:53:04 +00:00
|
|
|
|
filename-tag equivalent at all; see "Real media-file probing" below. A separate **Hash
|
|
|
|
|
|
Files** button computes real `{crc32}`/`{md5}`/`{sha1}` checksums on demand (deliberately
|
|
|
|
|
|
not automatic, since it reads a file's entire contents — see "Hash Files" below). The Align
|
2026-08-29 18:07:54 +00:00
|
|
|
|
Up/Down buttons reorder the (shared) file list — the two
|
2026-08-29 09:39:52 +00:00
|
|
|
|
panes always stay positionally paired — and up to 9 naming schemes can be saved as
|
|
|
|
|
|
presets, recalled with a click or a `1`-`9` keypress (persisted locally, same pattern as
|
2026-08-29 11:30:51 +00:00
|
|
|
|
Settings/History). The app can also be driven entirely from the command line —
|
|
|
|
|
|
`aurora-curator -rename --format "<naming scheme>" [options] <file-or-folder>...` — for
|
|
|
|
|
|
scripting batch renames without opening the window at all; see "Command-line usage"
|
2026-08-29 14:08:17 +00:00
|
|
|
|
below. A new Subtitles panel searches and downloads subtitle files from
|
|
|
|
|
|
[OpenSubtitles](https://www.opensubtitles.com/) — load a video, its title/season/episode
|
|
|
|
|
|
(or movie title/year) auto-fills from the same local matching "Match" uses, pick a
|
|
|
|
|
|
result, and the subtitle is saved right next to the video ready for any player to pick
|
2026-08-29 15:35:27 +00:00
|
|
|
|
up automatically; see "Subtitles" below. A new Episodes panel searches a series by
|
|
|
|
|
|
name and browses a full season's episode list — episode number, title, air date — using
|
|
|
|
|
|
whichever TV source (TMDB/TVmaze/OMDb) is already configured in Fetch Data Settings, no
|
2026-08-29 15:59:05 +00:00
|
|
|
|
separate credentials needed; see "Episodes" below. A new SFV panel computes and verifies
|
|
|
|
|
|
CRC32/MD5/SHA1 checksums for a loaded set of files, and reads and writes the classic
|
|
|
|
|
|
`.sfv`/`.md5`/`.sha1` sidecar-file formats — entirely local, no network access or
|
2026-08-29 17:01:15 +00:00
|
|
|
|
credentials of any kind; see "SFV" below. A new Filter panel loads a batch of files and
|
|
|
|
|
|
narrows it down by extension, TV/Movie/Unmatched kind, filename text, and (for TV) season
|
|
|
|
|
|
— all computed from the same local, filename-only matching "Match" uses, with a Copy File
|
2026-08-29 17:28:38 +00:00
|
|
|
|
Paths export for whatever's left; see "Filter" below. A new List panel renders a
|
|
|
|
|
|
user-editable naming-scheme-style expression per loaded file (the same `{ }` syntax and
|
|
|
|
|
|
`render_expression` engine the Rename panel's live preview uses, fed by the same local
|
|
|
|
|
|
matching "Match"/Filter use), with a live "N of M lines rendered" count, a Copy List
|
|
|
|
|
|
clipboard export, and an Export to File… button that writes the whole list to a `.txt`
|
|
|
|
|
|
file via a native Save dialog — this closes out the full original panel set (Rename/
|
2026-08-29 18:07:54 +00:00
|
|
|
|
Episodes/Subtitles/SFV/Filter/List); see "List" below. Real media-file probing (real
|
|
|
|
|
|
resolution, frame rate, duration, and codecs read straight from a video file's own
|
|
|
|
|
|
container header, not guessed from its filename) is wired into the Rename panel's
|
2026-08-30 03:48:22 +00:00
|
|
|
|
"Match" step, and now the Filter and List panels' own local scans too — Filter gained
|
|
|
|
|
|
Resolution/Video codec filter chips from it, and List's expressions can reference the
|
|
|
|
|
|
same probed fields — see "Real media-file probing" below. The naming-expression engine's Rhai
|
2026-08-30 03:24:19 +00:00
|
|
|
|
scripting layer also gained a batch of FileBot-style string helpers — `.pad()`,
|
|
|
|
|
|
`.sort_name()`/`.sort_initial()`, `.upper_initial()`/`.lower_initial()`, `.acronym()`,
|
|
|
|
|
|
`.validate_file_name()`, `.space()`/`.space_with()`, `.colon()`/`.colon_with()` — callable
|
|
|
|
|
|
inside any `{ }` naming-scheme expression, e.g. `{n.sort_name()}/S{s.pad(2)}E{e.pad(2)}`;
|
|
|
|
|
|
see "Porting roadmap" below.
|
2026-08-29 01:43:12 +00:00
|
|
|
|
|
2026-08-29 03:15:21 +00:00
|
|
|
|
The naming scheme is fully user-editable from the app (the "Naming Scheme" button next
|
|
|
|
|
|
to the New Names list) — the default is `{show name} - {season number}x{episode
|
|
|
|
|
|
number} - {episode name}`, but it's just a starting point, not a fixed template.
|
|
|
|
|
|
Plain, human-readable, multi-word field names like `{show name}` work directly (no
|
|
|
|
|
|
Rhai knowledge needed), FileBot's own short field names (`{n}`, `{s00e00}`, `{t}`)
|
|
|
|
|
|
still work side by side with them, and real Rhai script is available for anyone who
|
|
|
|
|
|
wants it (e.g. `{show name.to_upper()}`). See "Naming scheme syntax" below for how
|
2026-08-30 04:20:59 +00:00
|
|
|
|
that's implemented. Every field name shown in the editor is also a clickable button —
|
|
|
|
|
|
click one to insert it at the cursor instead of typing it out by hand. Whatever's
|
|
|
|
|
|
currently in the editor is saved to disk as you type (debounced) and restored the next
|
|
|
|
|
|
time the app opens, so a custom scheme survives a restart instead of resetting to the
|
|
|
|
|
|
sample expression above; the 1-9 preset slots (a separate, explicitly-named save) are
|
|
|
|
|
|
still there alongside this for switching between several schemes on purpose.
|
2026-08-29 03:15:21 +00:00
|
|
|
|
|
2026-08-29 01:43:12 +00:00
|
|
|
|
## Why a rewrite, and why this stack
|
|
|
|
|
|
|
|
|
|
|
|
The original is a ~20k+ line Java/Swing app built with Ant. The goals were: faster
|
|
|
|
|
|
startup and UI, faster matching/renaming, a codebase that's actually pleasant to work
|
|
|
|
|
|
in, and a genuine rebrand — not a coat of paint.
|
|
|
|
|
|
|
2026-08-29 10:07:09 +00:00
|
|
|
|
Aurora Curator is **Tauri**: a Rust core (`crates/aurora-curator-core`, `src-tauri`) plus a
|
2026-08-29 01:43:12 +00:00
|
|
|
|
TypeScript/React frontend (`src`), compiled to a small native binary per platform
|
|
|
|
|
|
(Windows/macOS/Linux) with a system webview instead of shipping a bundled browser
|
|
|
|
|
|
engine. That's the concrete "faster" win over both the original JVM/Swing app and
|
|
|
|
|
|
an Electron-style rewrite: quick cold start, small binary, real OS-native windowing.
|
|
|
|
|
|
|
|
|
|
|
|
An earlier attempt used Kotlin + Compose Multiplatform to stay on the JVM and reuse
|
|
|
|
|
|
FileBot's Java logic directly. That was abandoned (nothing was salvaged into this repo)
|
|
|
|
|
|
after discovering the sandbox this was originally built in blocks Maven Central and the
|
|
|
|
|
|
Gradle Plugin Portal, making it impossible to compile or test. Tauri was chosen as the
|
|
|
|
|
|
replacement because both halves — Cargo via crates.io, npm via the public npm registry
|
|
|
|
|
|
— are reachable, so every piece described as "done" below is actually compiled/tested,
|
|
|
|
|
|
not just written and hoped for.
|
|
|
|
|
|
|
|
|
|
|
|
### Compatibility notes
|
|
|
|
|
|
|
|
|
|
|
|
Goal: keep CLI flags, config file locations, and the *outer* `{ }` naming-scheme
|
|
|
|
|
|
template syntax compatible with FileBot conventions, so existing automation mostly
|
|
|
|
|
|
keeps working.
|
|
|
|
|
|
|
|
|
|
|
|
One deliberate gap: FileBot's `{ }` expressions ran arbitrary **Groovy** code
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(JVM-only). Aurora Curator's Rust core has no Groovy engine, so expressions are evaluated with
|
2026-08-29 01:43:12 +00:00
|
|
|
|
[Rhai](https://rhai.rs/) instead. Simple bindings (`{n}`, `{s00e00}`, `{t}`) are
|
|
|
|
|
|
identical. More complex chained-method expressions will need small syntax tweaks
|
|
|
|
|
|
(e.g. Groovy's `.toUpperCase()` → Rhai's `.to_upper()`) — Rhai already ships most of the
|
|
|
|
|
|
common string/array methods FileBot's expression helpers wrapped, so most patterns
|
|
|
|
|
|
translate directly.
|
|
|
|
|
|
|
2026-08-29 03:15:21 +00:00
|
|
|
|
### Naming scheme syntax
|
|
|
|
|
|
|
|
|
|
|
|
Every `{ }` token in an expression is resolved in this order
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(`crates/aurora-curator-core/src/format/expression.rs::compile_scriptlet`):
|
2026-08-29 03:15:21 +00:00
|
|
|
|
|
|
|
|
|
|
1. **A single bare identifier** (`{n}`, `{season}`) is a direct binding lookup — the
|
|
|
|
|
|
fast path, and how FileBot's own short field names keep working unmodified.
|
|
|
|
|
|
2. Otherwise it's **compiled as Rhai script** (`{n.to_upper()}`, `{n + " " + t}`) —
|
|
|
|
|
|
real code, with every current binding available as a script variable.
|
|
|
|
|
|
3. If it's *neither* a valid identifier *nor* valid Rhai, but it still only contains
|
|
|
|
|
|
letters, digits, underscores and spaces (e.g. `{show name}`, `{episode number}`),
|
|
|
|
|
|
it falls back to a **literal multi-word binding key** instead of raising a syntax
|
|
|
|
|
|
error — this is what lets a human-typed field name with spaces work as a plain
|
|
|
|
|
|
lookup without anyone needing to know Rhai. Anything that isn't a plausible field
|
|
|
|
|
|
name (stray punctuation, unmatched brackets, etc.) still surfaces as a real syntax
|
|
|
|
|
|
error at that point, exactly as before.
|
|
|
|
|
|
|
|
|
|
|
|
An undefined binding contributes an empty string rather than failing outright (so
|
|
|
|
|
|
`{n}{missing}` still renders); the overall expression only errors if the *total*
|
|
|
|
|
|
rendered output would be empty.
|
|
|
|
|
|
|
2026-08-29 03:36:06 +00:00
|
|
|
|
`/` between two `{ }` scriptlets (or anywhere in the literal text) needs no special
|
|
|
|
|
|
handling in the expression engine at all — it's just ordinary literal text, the same as
|
|
|
|
|
|
a space or a dash. It only becomes meaningful one layer up, at rename time (see
|
|
|
|
|
|
"Organizing into subfolders" below): a scheme like `{show name}/{episode name}` renders
|
|
|
|
|
|
to a name containing a real `/`, and the rename engine treats that as "put this file in
|
|
|
|
|
|
a subfolder" rather than rejecting it.
|
|
|
|
|
|
|
|
|
|
|
|
### Organizing into subfolders
|
|
|
|
|
|
|
|
|
|
|
|
A naming scheme that includes `/` (e.g. `{show name}/Season {season number}/{episode
|
|
|
|
|
|
number} - {episode name}`) moves the file into that subfolder as part of renaming,
|
|
|
|
|
|
creating any missing intermediate folders automatically
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(`crates/aurora-curator-core/src/rename/mod.rs::rename_one` → `fs::create_dir_all`). This is
|
2026-08-29 03:36:06 +00:00
|
|
|
|
still always scoped to the file's own directory tree — the target is resolved relative
|
|
|
|
|
|
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
|
2026-08-29 10:07:09 +00:00
|
|
|
|
`/etc/passwd`-style path), `.`/`..` segments, and backslashes (Aurora Curator always uses `/`
|
2026-08-29 09:50:36 +00:00
|
|
|
|
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.
|
2026-08-29 03:36:06 +00:00
|
|
|
|
|
2026-08-29 01:43:12 +00:00
|
|
|
|
## Project layout
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-08-29 10:07:09 +00:00
|
|
|
|
crates/aurora-curator-core/ Pure Rust core: naming-expression engine (ported), local
|
2026-08-29 04:04:16 +00:00
|
|
|
|
filename-based season/episode *and movie title/year* matching
|
2026-08-29 09:29:14 +00:00
|
|
|
|
(ported, `matching/`), plus filename-based release-tag parsing in
|
|
|
|
|
|
the same module (`guess_release_info` — resolution, source, video/
|
|
|
|
|
|
audio codec, release group), text-similarity scoring for
|
|
|
|
|
|
disambiguating search results (`similarity/`, partial
|
2026-08-29 12:25:45 +00:00
|
|
|
|
`EpisodeMetrics` port), three web metadata clients — `web/tmdb.rs`
|
|
|
|
|
|
(TV search + episode lookup and movie search + lookup),
|
2026-08-29 10:44:12 +00:00
|
|
|
|
`web/tvmaze.rs` (TV search + episode lookup only — TVmaze has no
|
2026-08-29 12:25:45 +00:00
|
|
|
|
movie catalog, and no API key/auth at all), and `web/omdb.rs` (TV
|
|
|
|
|
|
*and* movie search + lookup, single flat root-URL REST API, plain
|
|
|
|
|
|
`apikey` query-param auth rather than TMDB's Bearer token) — all
|
|
|
|
|
|
three disambiguated via
|
2026-08-29 10:44:12 +00:00
|
|
|
|
`similarity/` and tested against a mocked HTTP server via
|
2026-08-29 14:08:17 +00:00
|
|
|
|
`mockito`, plus a fourth web client that isn't a metadata
|
|
|
|
|
|
lookup at all — `web/opensubtitles.rs` (search + login +
|
|
|
|
|
|
download against OpenSubtitles' REST API; search only needs an
|
|
|
|
|
|
app-level API key, download additionally needs the end user's own
|
|
|
|
|
|
account login, since downloads are quota-limited per account —
|
2026-08-29 15:35:27 +00:00
|
|
|
|
see "Subtitles" below). The Episodes panel adds no new core-crate
|
|
|
|
|
|
code of its own — it reuses `metadata::AnyTvClient::fetch_season`
|
|
|
|
|
|
(the same season-resolving call `AnyTvClient` already made available
|
|
|
|
|
|
to "Fetch Data" and the CLI) from the Tauri side, so `web/tmdb.rs`/
|
|
|
|
|
|
`tvmaze.rs`/`omdb.rs`'s existing season-episode-list methods are
|
2026-08-29 15:59:05 +00:00
|
|
|
|
exactly what it browses. `sfv/` computes CRC32/MD5/SHA1 checksums
|
|
|
|
|
|
(streamed in 64KB chunks so large video files aren't loaded whole
|
|
|
|
|
|
into memory) and parses/builds both sidecar-file conventions the
|
|
|
|
|
|
SFV panel supports — the traditional `.sfv` layout (CRC32 only,
|
|
|
|
|
|
`<name> <checksum>` per line) and the GNU coreutils
|
|
|
|
|
|
`md5sum`/`sha1sum` layout (`<checksum> <name>`) used for `.md5`/
|
|
|
|
|
|
`.sha1` — dispatched on a shared `ChecksumKind` enum, plus
|
|
|
|
|
|
entry-verification against real files on disk (`Ok`/`Mismatch`/
|
|
|
|
|
|
`Missing` per entry). No network access, no credentials — entirely
|
|
|
|
|
|
local, unlike every other panel added this session. The on-disk
|
2026-08-29 09:50:36 +00:00
|
|
|
|
rename engine (`rename/` — Move/Copy/Symlink actions,
|
|
|
|
|
|
Skip/Auto-number/Override conflict policies, can also organize
|
|
|
|
|
|
into (auto-created) subfolders when
|
2026-08-29 11:30:51 +00:00
|
|
|
|
the naming scheme includes `/`), a rename history/undo log
|
2026-08-29 04:31:16 +00:00
|
|
|
|
(`history/`, a partial `HistoryDialog` port, undo-aware of which
|
2026-08-29 18:07:54 +00:00
|
|
|
|
action produced each batch), pure `-rename` command-line
|
2026-08-29 11:30:51 +00:00
|
|
|
|
argument parsing/file expansion (`cli/` — no Tauri or network
|
2026-08-29 18:07:54 +00:00
|
|
|
|
dependency at all, see "Command-line usage" below), and real
|
|
|
|
|
|
media-file container probing (`probe/` — real resolution, frame
|
|
|
|
|
|
rate, duration, and codecs read straight from a video file's own
|
|
|
|
|
|
header via two pure-Rust container parsers, the `mp4` crate for
|
|
|
|
|
|
ISO-BMFF containers and the `matroska` crate for EBML/Matroska
|
|
|
|
|
|
containers, no ffmpeg/MediaInfo system dependency; see "Real
|
|
|
|
|
|
media-file probing" below). Not yet ported: other web datasource
|
|
|
|
|
|
clients (TheTVDB/AniDB/etc), and everything MediaBindingBean
|
|
|
|
|
|
derives that neither a filename tag nor `probe/`'s two supported
|
|
|
|
|
|
container families can provide (other containers like .avi/.wmv,
|
|
|
|
|
|
audio-only metadata like bitrate/sample rate). No Tauri
|
|
|
|
|
|
dependency, so it builds and unit-tests standalone.
|
2026-08-29 10:07:09 +00:00
|
|
|
|
src-tauri/ Tauri app shell: exposes aurora-curator-core as commands to the frontend
|
2026-08-29 04:04:16 +00:00
|
|
|
|
(naming-scheme rendering, filename matching for both TV and
|
2026-08-29 10:44:12 +00:00
|
|
|
|
movies, metadata fetch — `metadata.rs` for TV episodes (against
|
2026-08-29 12:25:45 +00:00
|
|
|
|
whichever of TMDB/TVmaze/OMDb is the stored TV source) plus a
|
|
|
|
|
|
movie-fetch command alongside it (against whichever of TMDB/OMDb
|
|
|
|
|
|
is the stored movie source — independent of the TV source)
|
|
|
|
|
|
— executing a rename
|
2026-08-29 04:04:16 +00:00
|
|
|
|
plan, native file/folder dialogs, drag-and-drop expansion), plus
|
2026-08-29 14:08:17 +00:00
|
|
|
|
`settings.rs` (TMDB token, OMDb API key, OpenSubtitles API key +
|
|
|
|
|
|
account login, and which TV *and* movie
|
|
|
|
|
|
metadata source Fetch Data uses — independent settings; the
|
|
|
|
|
|
OpenSubtitles password is the one credential this module never
|
|
|
|
|
|
returns to the frontend, only whether one is saved),
|
|
|
|
|
|
`subtitles.rs` (search/download commands wrapping
|
|
|
|
|
|
`aurora-curator-core::web::opensubtitles`, saving a downloaded
|
2026-08-29 15:35:27 +00:00
|
|
|
|
subtitle right next to its video file), `episodes.rs` (the
|
|
|
|
|
|
`browse_episodes` command backing the Episodes panel — series
|
|
|
|
|
|
search + one season's episode list, via a `build_tv_client` helper
|
|
|
|
|
|
now shared with `metadata.rs`'s `fetch_metadata`, so both read the
|
2026-08-30 04:53:04 +00:00
|
|
|
|
same stored TV-source setting and credential), `sfv.rs` (four
|
|
|
|
|
|
commands backing the SFV panel and the Rename panel's Hash Files
|
|
|
|
|
|
button — `compute_checksums` over a batch of loaded files with
|
|
|
|
|
|
per-file error isolation, `save_checksum_file` via a native "Save
|
|
|
|
|
|
File" dialog, `verify_checksum_file`, which reads and parses a
|
|
|
|
|
|
picked `.sfv`/`.md5`/`.sha1` file and resolves each entry's bare
|
|
|
|
|
|
filename relative to that file's own parent directory, and
|
|
|
|
|
|
`compute_naming_hashes` — all four wrapping
|
|
|
|
|
|
`aurora-curator-core::sfv`, which does the actual algorithm/format
|
|
|
|
|
|
work; `compute_naming_hashes` calls the crate's
|
|
|
|
|
|
`compute_all_checksums` rather than `compute_checksum` three times,
|
|
|
|
|
|
streaming each file once instead of three),
|
2026-08-29 12:25:45 +00:00
|
|
|
|
`history.rs` (rename history/undo
|
2026-08-29 11:30:51 +00:00
|
|
|
|
log), `presets.rs` (up to 9 saved naming schemes) — all three
|
2026-08-29 17:28:38 +00:00
|
|
|
|
stored as JSON in the OS app-config directory — `list.rs` (a
|
|
|
|
|
|
single `export_text_list` command backing the List panel's Export
|
|
|
|
|
|
to File… button: opens a native "Save File" dialog and writes
|
|
|
|
|
|
whatever already-rendered, newline-joined text the frontend hands
|
|
|
|
|
|
it to a `.txt` file — the only new Tauri surface List needed, since
|
|
|
|
|
|
matching each file and rendering its line both reuse existing
|
2026-08-29 18:07:54 +00:00
|
|
|
|
commands, see below), `probe.rs` (a single `probe_media_files`
|
|
|
|
|
|
command backing real media probing in the Rename panel's Match
|
|
|
|
|
|
step: batch-probes every loaded file's real container header off
|
|
|
|
|
|
the main thread, wrapping `aurora-curator-core::probe` — see "Real
|
|
|
|
|
|
media-file probing" below) — `cli.rs` (the
|
2026-08-29 11:30:51 +00:00
|
|
|
|
`-rename` command-line mode's orchestration: builds and executes a
|
|
|
|
|
|
rename plan against `aurora-curator-core::cli`'s parsed arguments,
|
|
|
|
|
|
with no Tauri `App`/window ever created for it — `main.rs` branches
|
|
|
|
|
|
to it before the GUI is touched at all), and app
|
2026-08-29 04:04:16 +00:00
|
|
|
|
metadata/icons/window config (tauri.conf.json).
|
2026-08-29 02:42:31 +00:00
|
|
|
|
src/ React + TypeScript UI (Vite). Faithful recreation of the original
|
|
|
|
|
|
two-pane rename screen (Aurora theme) wired to real file loading,
|
2026-08-29 04:04:16 +00:00
|
|
|
|
drag-and-drop, live naming-scheme preview, local TV/movie
|
2026-08-29 18:07:54 +00:00
|
|
|
|
matching, real media-file probing (`probe_media_files`, batched
|
|
|
|
|
|
alongside the local matching calls in `RenamePanel.tsx`'s
|
|
|
|
|
|
`runMatching`), metadata fetch for both (behind a Fetch Data Settings
|
2026-08-29 12:25:45 +00:00
|
|
|
|
modal holding independent TV-source (TMDB/TVmaze/OMDb) and
|
|
|
|
|
|
movie-source (TMDB/OMDb) pickers plus the TMDB token and OMDb key
|
|
|
|
|
|
inputs), a
|
2026-08-29 10:44:12 +00:00
|
|
|
|
confirm-before-touching-disk modal for the actual
|
2026-08-29 09:39:52 +00:00
|
|
|
|
rename, a History panel that can undo a past rename, Align Up/Down
|
|
|
|
|
|
list reordering, and a Presets panel (plus `1`-`9` hotkeys) for
|
2026-08-29 14:08:17 +00:00
|
|
|
|
saved naming schemes. `SubtitlesPanel.tsx` is a separate top-level
|
|
|
|
|
|
panel (its own Subtitle Settings modal, its own credential state)
|
|
|
|
|
|
reached from the sidebar's "Subtitles" entry — the first sidebar
|
|
|
|
|
|
entry besides Rename to be a real screen rather than a stub.
|
2026-08-29 15:35:27 +00:00
|
|
|
|
`EpisodesPanel.tsx` is the second: a series-search + season-browse
|
|
|
|
|
|
screen with no settings modal of its own at all — it deliberately
|
|
|
|
|
|
has no separate credentials UI, reading whatever TV source/token
|
|
|
|
|
|
Fetch Data Settings (in the Rename panel) already has saved.
|
2026-08-29 15:59:05 +00:00
|
|
|
|
`SfvPanel.tsx` is the third: load a set of files, compute
|
|
|
|
|
|
checksums in any of CRC32/MD5/SHA1, save them as a sidecar
|
|
|
|
|
|
checksum file via a native Save dialog, or pick an existing
|
|
|
|
|
|
checksum file and verify the files it lists against what's
|
|
|
|
|
|
actually on disk (OK/mismatch/missing per entry) — no settings
|
|
|
|
|
|
modal at all, since the feature needs no credentials or network
|
2026-08-29 17:01:15 +00:00
|
|
|
|
access. `FilterPanel.tsx` is the fourth: load a set of files and
|
|
|
|
|
|
narrow them down with toggleable extension/kind chips, a
|
|
|
|
|
|
filename-contains text field, and a season number field (TV
|
|
|
|
|
|
only) — adds no new Rust/Tauri commands at all, reusing
|
|
|
|
|
|
`pick_files`/`guess_episode`/`guess_movie`/`guess_release_info`
|
|
|
|
|
|
exactly as the Rename panel's own "Match" does, just applied to
|
|
|
|
|
|
a second, independently-loaded file list and rendered as
|
2026-08-29 17:28:38 +00:00
|
|
|
|
criteria instead of a rename preview. `ListPanel.tsx` is the
|
|
|
|
|
|
fifth and last: load a set of files, edit a naming-scheme-style
|
|
|
|
|
|
expression (rendered per file via the same `render_expression`
|
|
|
|
|
|
command the Rename panel's live preview calls, fed by the same
|
|
|
|
|
|
local matching Filter uses), see a live "N of M lines rendered"
|
|
|
|
|
|
list, Copy List to the clipboard, or Export to File… via the one
|
|
|
|
|
|
new `export_text_list` command above — closing out the full
|
|
|
|
|
|
original panel set.
|
2026-08-29 10:44:12 +00:00
|
|
|
|
scripts/gen_icons.py Regenerates src-tauri/icons/ from the real logo mark
|
|
|
|
|
|
(`scripts/logo/icon-source.png`, cropped from the supplied
|
|
|
|
|
|
lockup) — replace that source image to change the look.
|
2026-08-29 01:43:12 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Building
|
|
|
|
|
|
|
|
|
|
|
|
Prerequisites: Rust (stable) + Cargo, Node.js 18+, and Tauri's platform prerequisites
|
2026-08-30 06:13:22 +00:00
|
|
|
|
(see https://v2.tauri.app/start/prerequisites/ for the full, up-to-date list).
|
|
|
|
|
|
|
|
|
|
|
|
**Linux:** `libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
|
|
|
|
|
|
librsvg2-dev` plus a C toolchain (`build-essential` on Debian/Ubuntu). Bundling the
|
|
|
|
|
|
installers additionally needs `patchelf` (for the `.deb`/`.rpm`) — `npm run tauri build`
|
|
|
|
|
|
will also download a few small `linuxdeploy` helper tools from GitHub the first time it
|
|
|
|
|
|
builds an `.AppImage`, so a network connection is needed for that step.
|
|
|
|
|
|
|
|
|
|
|
|
**macOS:** Xcode (or at least the Xcode Command Line Tools — `xcode-select --install`).
|
|
|
|
|
|
No other system packages are needed.
|
|
|
|
|
|
|
|
|
|
|
|
**Windows:** Rust via [rustup](https://rustup.rs/), using the default MSVC toolchain
|
|
|
|
|
|
(not the GNU one). [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio)
|
|
|
|
|
|
(or full Visual Studio) with the **"Desktop development with C++"** workload, which
|
|
|
|
|
|
provides the linker Rust's MSVC toolchain needs. The **WebView2 Runtime** — this is
|
|
|
|
|
|
already preinstalled on any up-to-date Windows 10/11 machine, so you usually don't need
|
|
|
|
|
|
to do anything; if you hit a WebView2-related error, grab the Evergreen bootstrapper from
|
|
|
|
|
|
Microsoft. You do **not** need to separately install NSIS or WiX — Tauri's bundler
|
|
|
|
|
|
downloads NSIS automatically the first time it builds the `.exe` installer.
|
2026-08-29 01:43:12 +00:00
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
# Rust core (no UI deps needed):
|
2026-08-29 10:07:09 +00:00
|
|
|
|
cargo test -p aurora-curator-core
|
2026-08-29 01:43:12 +00:00
|
|
|
|
|
|
|
|
|
|
# Full app in dev mode (opens a native window):
|
|
|
|
|
|
npm install
|
|
|
|
|
|
npm run tauri dev
|
|
|
|
|
|
|
|
|
|
|
|
# Production build (installer/bundle for your current OS):
|
|
|
|
|
|
npm run tauri build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-30 06:13:22 +00:00
|
|
|
|
`npm run tauri build` produces a native installer for whichever OS you run it on — there
|
|
|
|
|
|
is no cross-compilation; build on Windows to get a `.exe`/`.msi`, on Linux for
|
|
|
|
|
|
`.deb`/`.rpm`/`.AppImage`, on macOS for a `.app`/`.dmg`.
|
|
|
|
|
|
|
|
|
|
|
|
Verified so far: `cargo test --workspace` (199 tests passing, including the TMDB,
|
|
|
|
|
|
TVmaze, OMDb, and OpenSubtitles client tests — those run against a local mock HTTP
|
|
|
|
|
|
server via `mockito`, no live network or API key needed to build/test), `cargo check -p
|
|
|
|
|
|
aurora-curator` (compiles clean against real Tauri + GTK/WebKit system libraries), and
|
|
|
|
|
|
`npm run build` (TypeScript type-checks, Vite bundles). The production build
|
|
|
|
|
|
(`npm run tauri build`) has been run end-to-end and the resulting app **launches and
|
|
|
|
|
|
runs correctly outside of dev mode** on both macOS (`.app`, confirmed by hand) and Linux
|
|
|
|
|
|
(`.deb`/`.rpm`/`.AppImage`, built and smoke-tested in a real Ubuntu environment). Windows
|
|
|
|
|
|
is the one platform not yet built/verified — if you hit anything building there, please
|
|
|
|
|
|
open an issue.
|
2026-08-29 03:01:19 +00:00
|
|
|
|
|
2026-08-29 10:44:12 +00:00
|
|
|
|
### Setting up metadata sources (for "Fetch Data")
|
2026-08-29 03:01:19 +00:00
|
|
|
|
|
|
|
|
|
|
Everything else in the app works fully offline; "Fetch Data" is the one feature that
|
2026-08-29 10:44:12 +00:00
|
|
|
|
talks to the network, and it's the only one that needs any setup at all — and even that
|
|
|
|
|
|
setup is optional for TV.
|
2026-08-29 03:01:19 +00:00
|
|
|
|
|
2026-08-29 12:25:45 +00:00
|
|
|
|
TV episodes and movies each have their own independent source picker in the app (click
|
|
|
|
|
|
the key icon, "Fetch Data Settings", next to Fetch Data) — a batch can freely mix TV and
|
|
|
|
|
|
movie files resolved against two different sources at once:
|
2026-08-29 10:44:12 +00:00
|
|
|
|
|
2026-08-29 12:25:45 +00:00
|
|
|
|
- **[TVmaze](https://www.tvmaze.com/)** — TV only (it has no movie catalog). Free, no
|
|
|
|
|
|
account or API token needed at all. Just pick it and go.
|
|
|
|
|
|
- **[TMDB](https://www.themoviedb.org/)** — the default for both TV and movies. Needs a
|
|
|
|
|
|
free account:
|
2026-08-29 10:44:12 +00:00
|
|
|
|
1. Create a TMDB account, then go to Settings → API in your account and generate an
|
|
|
|
|
|
**API Read Access Token** (not the older numeric "API Key" — Aurora Curator uses the
|
|
|
|
|
|
Bearer token method TMDB documents as the default).
|
|
|
|
|
|
2. In the app, open "Fetch Data Settings" and paste the token in. It's saved locally
|
|
|
|
|
|
in the OS app-config directory and only ever sent to `api.themoviedb.org`.
|
2026-08-29 12:25:45 +00:00
|
|
|
|
- **[OMDb](https://www.omdbapi.com/)** — TV and movies, an alternative to TMDB for
|
|
|
|
|
|
either or both. Needs a free API key:
|
|
|
|
|
|
1. Request a free key at <https://www.omdbapi.com/apikey.aspx> (OMDb emails it to you).
|
|
|
|
|
|
2. In the app, open "Fetch Data Settings" and paste the key into the OMDb field. It's
|
|
|
|
|
|
saved locally in the OS app-config directory and only ever sent to
|
|
|
|
|
|
`www.omdbapi.com`.
|
2026-08-29 10:44:12 +00:00
|
|
|
|
|
2026-08-29 12:25:45 +00:00
|
|
|
|
A batch of TV-only files can run entirely on TVmaze with no credential configured at
|
|
|
|
|
|
all. Otherwise, whichever of TMDB/OMDb is actually selected — for TV, for movies, or
|
|
|
|
|
|
both — needs its own credential saved first; picking TMDB for TV and OMDb for movies (or
|
|
|
|
|
|
any other mix) only needs the two credentials that combination actually uses. Note OMDb
|
|
|
|
|
|
returns a normal-looking (HTTP 200) "no results" response for both a genuine no-match and
|
|
|
|
|
|
an invalid API key, so a bad key currently surfaces as "not found" rather than a clearer
|
|
|
|
|
|
credential error — a known OMDb API limitation, not something Aurora Curator can
|
|
|
|
|
|
distinguish from its response alone.
|
2026-08-29 01:43:12 +00:00
|
|
|
|
|
2026-08-29 11:30:51 +00:00
|
|
|
|
## Command-line usage
|
|
|
|
|
|
|
|
|
|
|
|
The same binary that opens the GUI can also run a batch rename straight from a script or
|
|
|
|
|
|
terminal — a port of FileBot's `net.filebot.cli` flag surface (`-rename`, `--format`,
|
|
|
|
|
|
`--db`, `--action`, `--conflict`), with a couple of deliberate differences noted below.
|
|
|
|
|
|
Passing `-rename` (or `-h`/`--help`) on the command line skips the window entirely:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
aurora-curator -rename --format "{show name} - {season number}x{episode number} - {episode name}" \
|
|
|
|
|
|
--action move --conflict skip ~/Downloads/some-show/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- `--format "<naming scheme>"` (required) — the same expression syntax as the GUI's
|
|
|
|
|
|
Naming Scheme field: FileBot short names (`{n}`, `{s00e00}`, `{t}`), human-readable
|
|
|
|
|
|
aliases (`{show name}`, `{episode name}`, `{movie name}`, `{resolution}`, `{video
|
|
|
|
|
|
codec}`, `{release group}`, …), or real Rhai script. `{name}`/`{ext}` fall back to the
|
|
|
|
|
|
file's own current filename/extension when nothing else matched it.
|
2026-08-29 12:25:45 +00:00
|
|
|
|
- `--db <tmdb|tvmaze|omdb>` (optional) — resolves TV episodes against that online source
|
2026-08-29 11:30:51 +00:00
|
|
|
|
before rendering names, the command-line equivalent of clicking "Fetch Data" after
|
2026-08-29 12:25:45 +00:00
|
|
|
|
Match. Movies are also looked up online whenever this is `tmdb` or `omdb` — TVmaze has
|
|
|
|
|
|
no movie catalog, so `--db tvmaze` only affects the TV half of a batch — and with no
|
|
|
|
|
|
`--db` at all every file uses local filename matching only, same as Match without Fetch
|
|
|
|
|
|
Data in the GUI. `--db tmdb`/`--db omdb` each need the matching token/key that's already
|
2026-08-29 11:30:51 +00:00
|
|
|
|
been saved through the app's own Fetch Data Settings at least once — **the CLI never
|
2026-08-29 12:25:45 +00:00
|
|
|
|
accepts an API token or key as an argument**, so there's nothing secret to leak into
|
|
|
|
|
|
your shell history or a script.
|
2026-08-29 11:30:51 +00:00
|
|
|
|
- `--action <move|copy|symlink|test>` (default `move`) — what to do at each computed
|
|
|
|
|
|
target; `test` prints the full plan and touches nothing on disk, useful for checking a
|
|
|
|
|
|
naming scheme before committing to it.
|
|
|
|
|
|
- `--conflict <skip|auto-number|override>` (default `skip`, `autonumber`/`auto` also
|
|
|
|
|
|
accepted) — what happens when the computed target already exists.
|
|
|
|
|
|
- `-non-strict` — accepted for compatibility with existing FileBot scripts, but is a
|
|
|
|
|
|
genuine no-op here: the local matcher has no confidence score to loosen, and online
|
|
|
|
|
|
disambiguation (`similarity::best_title_match`) always runs regardless of this flag.
|
|
|
|
|
|
- Every remaining argument is treated as an input file or folder; folders are expanded
|
|
|
|
|
|
recursively (hidden files/dotfolders skipped), matching exactly what the GUI's own
|
|
|
|
|
|
"Select Folder…" and drag-and-drop do.
|
|
|
|
|
|
|
|
|
|
|
|
Deliberately **not** ported: FileBot's `--output <dir>` flag. The rename engine is
|
|
|
|
|
|
scoped, as a safety invariant, to never move a file outside its own source directory
|
|
|
|
|
|
tree (see "Organizing into subfolders" above) — a naming scheme's own `/` already covers
|
|
|
|
|
|
organizing into a subfolder, and relaxing that invariant just for `--output` wasn't
|
|
|
|
|
|
judged worth it.
|
|
|
|
|
|
|
2026-08-29 15:35:27 +00:00
|
|
|
|
## Episodes
|
|
|
|
|
|
|
|
|
|
|
|
The Episodes sidebar panel searches for a TV series by name and browses one season's
|
|
|
|
|
|
full episode list — episode number, title, and air date — as a standalone reference,
|
|
|
|
|
|
independent of whatever files (if any) are loaded in the Rename panel.
|
|
|
|
|
|
|
|
|
|
|
|
Type a series name, pick a season (the +/− stepper re-queries automatically once you've
|
|
|
|
|
|
searched at least once), and click **Browse**. A season with a real series match but no
|
|
|
|
|
|
episodes of its own (e.g. asking for season 99 of a 5-season show) comes back as a clear
|
|
|
|
|
|
"no episodes found for season N" message rather than an error; a series name that
|
|
|
|
|
|
doesn't match anything at all surfaces the underlying source's own not-found message. A
|
|
|
|
|
|
**Copy list** button copies every row as plain text (`Series Name - SxEE - Episode
|
|
|
|
|
|
Title`, one per line) to the clipboard — handy for pasting into a naming reference or
|
|
|
|
|
|
anywhere outside the app.
|
|
|
|
|
|
|
|
|
|
|
|
Unlike Subtitles, this panel has **no settings or credentials of its own**: it reuses
|
|
|
|
|
|
whichever TV source — TMDB, TVmaze, or OMDb — is already configured in the Rename
|
|
|
|
|
|
panel's Fetch Data Settings, and the same season-lookup call ("Fetch Data" and the
|
|
|
|
|
|
`-rename --db` CLI both already made) is exactly what it browses. If nothing is
|
|
|
|
|
|
configured yet (only relevant for TMDB/OMDb — TVmaze needs no credential), Browse
|
|
|
|
|
|
reports the same "open Settings to add one" message Fetch Data itself would.
|
|
|
|
|
|
|
2026-08-29 14:08:17 +00:00
|
|
|
|
## Subtitles
|
|
|
|
|
|
|
|
|
|
|
|
The Subtitles sidebar panel searches and downloads subtitle files from
|
|
|
|
|
|
[OpenSubtitles](https://www.opensubtitles.com/) — the first thing in Aurora Curator that
|
|
|
|
|
|
fetches an actual media file (a subtitle) rather than title/air-date text.
|
|
|
|
|
|
|
|
|
|
|
|
**Load Video File…** picks one video, then reuses the exact same local filename-based
|
|
|
|
|
|
matching "Match" uses (`guess_episode`/`guess_movie`) to pre-fill the search form with a
|
|
|
|
|
|
show title + season/episode, or a movie title + year — all editable before searching,
|
|
|
|
|
|
and usable on their own with no video loaded at all if you'd rather just type a title.
|
|
|
|
|
|
Results show the release name, language, an **HD** badge, a **Hash match** badge when
|
|
|
|
|
|
OpenSubtitles matched the file by an exact content hash rather than a text search (a
|
|
|
|
|
|
much stronger signal than a title match alone), an **HI** badge for hearing-impaired
|
|
|
|
|
|
tracks, the uploader, and the download count. Downloading saves the file right next to
|
|
|
|
|
|
the video with the language code inserted before the extension (`Show.S01E01.mkv` →
|
|
|
|
|
|
`Show.S01E01.en.srt`) — the convention most media players look for automatically, so
|
|
|
|
|
|
there's nothing further to configure.
|
|
|
|
|
|
|
|
|
|
|
|
OpenSubtitles splits credentials in a way no other source in this app does:
|
|
|
|
|
|
|
|
|
|
|
|
- **Searching** only needs a free **API key** — register an account at
|
|
|
|
|
|
[opensubtitles.com](https://www.opensubtitles.com/) and create one under Account → API
|
|
|
|
|
|
Consumers, then paste it into Subtitle Settings.
|
|
|
|
|
|
- **Downloading** additionally needs your own OpenSubtitles account **username and
|
|
|
|
|
|
password**, entered in the same Settings panel — OpenSubtitles logs you in to check a
|
|
|
|
|
|
daily download quota tied to your account (shown after every successful download as
|
|
|
|
|
|
"N/M downloads left today"; the exact number depends on your account's standing with
|
|
|
|
|
|
OpenSubtitles and can change on their end, so Aurora Curator always shows the live
|
|
|
|
|
|
figure it gets back rather than a hardcoded promise). Search works with no login at
|
|
|
|
|
|
all, so you can browse what's available before deciding whether to save a password.
|
|
|
|
|
|
|
|
|
|
|
|
Like every other credential in this app, both are stored locally in the OS app-config
|
|
|
|
|
|
directory and only ever sent to `api.opensubtitles.com` — with one extra precaution
|
|
|
|
|
|
specific to a real account password: Aurora Curator never sends the saved password back
|
|
|
|
|
|
to its own interface once it's saved (every other credential's "already saved" check
|
|
|
|
|
|
does briefly see the real value; the password doesn't), and the Settings panel only ever
|
|
|
|
|
|
shows *whether* a password is on file, never the value itself.
|
|
|
|
|
|
|
2026-08-29 15:59:05 +00:00
|
|
|
|
## SFV
|
|
|
|
|
|
|
|
|
|
|
|
The SFV sidebar panel computes and verifies file checksums — CRC32, MD5, or SHA1 — and
|
|
|
|
|
|
reads and writes the classic sidecar checksum-file formats, recreating original
|
|
|
|
|
|
FileBot's SFV panel. Unlike every other panel added this session, it's **entirely
|
|
|
|
|
|
local**: no network access, no credentials, nothing to configure.
|
|
|
|
|
|
|
|
|
|
|
|
**Load Files…** picks one or more files, then choose a checksum type from the segmented
|
|
|
|
|
|
control (CRC32 defaults to the traditional `.sfv` file format; MD5/SHA1 use the GNU
|
|
|
|
|
|
coreutils `md5sum`/`sha1sum` sidecar convention instead). **Compute** hashes every loaded
|
|
|
|
|
|
file (streamed in 64KB chunks, so even large video files don't need to fit in memory) and
|
|
|
|
|
|
lists each one's checksum, or an **ERROR** badge for any individual file that couldn't be
|
|
|
|
|
|
read — one bad file never aborts the rest of the batch. **Save Checksum File…** opens a
|
|
|
|
|
|
native Save dialog (defaulted to the loaded files' own folder name, e.g. `movies.sfv`)
|
|
|
|
|
|
and writes every successfully-computed checksum out in the chosen format; only files that
|
|
|
|
|
|
computed successfully are included.
|
|
|
|
|
|
|
|
|
|
|
|
**Verify Checksum File…** goes the other direction: pick an existing `.sfv`/`.md5`/
|
|
|
|
|
|
`.sha1` file (no need to have loaded its files first) and every entry it lists is
|
|
|
|
|
|
resolved against the real files sitting next to it on disk and reported as **OK**,
|
|
|
|
|
|
**MISMATCH** (actual checksum shown alongside the expected one), or **MISSING** (the
|
|
|
|
|
|
referenced file isn't there). Checksum comparison is case-insensitive, since some tools
|
|
|
|
|
|
write hex digests in uppercase and others in lowercase.
|
|
|
|
|
|
|
2026-08-29 17:01:15 +00:00
|
|
|
|
## Filter
|
|
|
|
|
|
|
|
|
|
|
|
The Filter sidebar panel loads a batch of files (independent of whatever's loaded in the
|
|
|
|
|
|
Rename panel) and narrows it down before you decide what to do with it elsewhere — copy
|
2026-08-30 03:48:22 +00:00
|
|
|
|
the matching paths out, or just get a sense of what's actually in a folder. It scans every
|
|
|
|
|
|
loaded file with the exact same local, filename-only matchers "Match" uses
|
|
|
|
|
|
(`guess_episode`/`guess_movie`/`guess_release_info`) and turns the results into filter
|
|
|
|
|
|
criteria instead of a rename preview — no network calls, so scanning even a large batch is
|
|
|
|
|
|
effectively instant. It also runs the same batched `probe_media_files` real container-header
|
|
|
|
|
|
probe "Match" and List do (see "Real media-file probing" below), so a file's resolution/
|
|
|
|
|
|
video codec can come from real probing even when nothing in its filename says so.
|
2026-08-29 17:01:15 +00:00
|
|
|
|
|
|
|
|
|
|
**Load Files…** loads and scans a batch in one step. Toggleable chips then appear for
|
|
|
|
|
|
every **extension** actually present (e.g. MKV/MP4/TXT) and every **kind** Aurora Curator
|
|
|
|
|
|
locally recognized (TV/Movies/Unmatched) — click a chip to exclude that group, click it
|
2026-08-30 03:48:22 +00:00
|
|
|
|
again to bring it back. **Resolution** and **Video codec** chip rows appear the same way
|
|
|
|
|
|
whenever at least one loaded file actually has a value for either (a filename tag wins
|
|
|
|
|
|
when present, otherwise a real probed value fills in — same override rule as everywhere
|
|
|
|
|
|
else this delivery touches; files with neither fall into their own "Unknown" chip rather
|
|
|
|
|
|
than being silently excluded). A **filename contains** field does a live, case-insensitive
|
2026-08-29 17:01:15 +00:00
|
|
|
|
substring search, and a **season** field (shown only while the TV chip is enabled) narrows
|
|
|
|
|
|
to a single season number, automatically excluding anything that isn't a TV episode in
|
2026-08-30 03:48:22 +00:00
|
|
|
|
that season. Each result row's subtitle also shows a resolved resolution when one exists
|
|
|
|
|
|
(e.g. `Unmatched · 480p` for a file Match couldn't identify as TV or a movie but still got
|
|
|
|
|
|
a real probed resolution for). The results list updates live with an "N of M files match"
|
|
|
|
|
|
count, and **Copy File Paths** writes every currently-matching file's full path, one per
|
|
|
|
|
|
line, to the clipboard.
|
2026-08-29 17:01:15 +00:00
|
|
|
|
|
2026-08-29 17:28:38 +00:00
|
|
|
|
## List
|
|
|
|
|
|
|
|
|
|
|
|
The List sidebar panel loads a batch of files (independent of whatever's loaded
|
|
|
|
|
|
elsewhere) and renders a naming-scheme-style expression against each one, so the result
|
|
|
|
|
|
can be copied or exported as a plain text list — a playlist, a batch-rename preview to
|
|
|
|
|
|
check by eye, a checklist for another tool, whatever the expression is written for.
|
|
|
|
|
|
It's the last of the six original sidebar panels (Rename/Episodes/Subtitles/SFV/Filter/
|
|
|
|
|
|
List) and, like Filter, adds no new local-matching logic — it reuses the exact same
|
|
|
|
|
|
`guess_episode`/`guess_movie`/`guess_release_info` calls "Match" and Filter already use.
|
|
|
|
|
|
The one genuinely new piece is a single Tauri command, `export_text_list`, which opens a
|
|
|
|
|
|
native Save dialog and writes whatever text the frontend hands it to a `.txt` file —
|
|
|
|
|
|
everything else (matching, and rendering each file's line) reuses commands that already
|
|
|
|
|
|
existed.
|
|
|
|
|
|
|
2026-08-30 03:48:22 +00:00
|
|
|
|
**Load Files…** loads a batch and scans it locally, the same way Filter does — including
|
|
|
|
|
|
the same batched real container-header probe (see "Real media-file probing" below), so
|
|
|
|
|
|
List's expressions get real probed values too, not just filename-tag ones. The **Format**
|
|
|
|
|
|
field holds the expression rendered against each file — the exact same `{ }` syntax the
|
|
|
|
|
|
naming scheme uses, run through the same `render_expression` command the Rename panel's
|
|
|
|
|
|
live preview calls. `{name}`/`{ext}` always work (they're the file's own name/extension);
|
|
|
|
|
|
`{show name}`/`{season number}`/`{episode number}`, `{movie name}`/`{year}`, and the
|
|
|
|
|
|
release-tag fields (`{resolution}`/`{source}`/`{video codec}`/`{audio codec}`/`{release
|
|
|
|
|
|
group}`) fill in once the local scan recognizes a file; `{width}`/`{height}`/`{fps}`/
|
|
|
|
|
|
`{duration}`/`{file size}` come straight from real probing (no filename-tag equivalent
|
|
|
|
|
|
exists), and a probed `{resolution}`/`{video codec}`/`{audio codec}` fills in whenever the
|
|
|
|
|
|
filename didn't already carry that tag — there's no Fetch Data step here, List stays
|
|
|
|
|
|
local-only like Filter. A file whose rendered line comes out empty (e.g. an expression
|
|
|
|
|
|
that only references a field this particular file never matched) shows an "(empty)"
|
|
|
|
|
|
placeholder rather than blocking the rest of the list, and the results header tracks
|
|
|
|
|
|
"N of M lines rendered" live as the expression changes. **Copy List** copies every line, in
|
|
|
|
|
|
file order, newline-joined, to the clipboard; **Export to File…** opens a native Save
|
|
|
|
|
|
dialog (defaulted to `list.txt`) and writes the same text to disk.
|
2026-08-29 17:28:38 +00:00
|
|
|
|
|
2026-08-29 18:07:54 +00:00
|
|
|
|
## Real media-file probing
|
|
|
|
|
|
|
|
|
|
|
|
Unlike every panel above, this isn't a new sidebar screen — it's a naming-scheme
|
2026-08-30 03:48:22 +00:00
|
|
|
|
binding source wired into the Rename panel's "Match" step, the Filter panel's scan, and
|
|
|
|
|
|
the List panel's scan alike, closing (part of) the gap the porting roadmap has called out
|
|
|
|
|
|
since the beginning: FileBot's
|
2026-08-29 18:07:54 +00:00
|
|
|
|
`MediaBindingBean` doesn't just parse tags out of a release name, it also reads a
|
|
|
|
|
|
video file's own container header for its real resolution, frame rate, duration, and
|
|
|
|
|
|
codecs — a naming scheme can reference those even when the filename itself doesn't
|
|
|
|
|
|
carry a tag for them, or came from a mislabeled/renamed-already release. Aurora
|
|
|
|
|
|
Curator ships no ffmpeg/MediaInfo dependency for this — two pure-Rust container
|
|
|
|
|
|
parsers do the actual reading: the `mp4` crate for ISO-BMFF containers (`.mp4`/`.m4v`/
|
|
|
|
|
|
`.mov`) and the `matroska` crate for EBML/Matroska containers (`.mkv`/`.webm`). Any
|
|
|
|
|
|
other extension, or a file that fails to parse as its container, just yields no probed
|
|
|
|
|
|
values — probing is always a best-effort enrichment layered on top of filename
|
|
|
|
|
|
matching, never a hard requirement, so an unsupported or corrupt file can't break
|
|
|
|
|
|
Match.
|
|
|
|
|
|
|
2026-08-30 03:48:22 +00:00
|
|
|
|
Clicking **Match** (Rename), or loading a batch into **Filter** or **List**, now also
|
|
|
|
|
|
probes every loaded file's real container header (`probe_media_files`, one batched Tauri
|
|
|
|
|
|
round trip off the main thread) alongside the existing filename-based guessing — all
|
|
|
|
|
|
three panels call the exact same command the exact same way. The result feeds the same
|
|
|
|
|
|
bindings the release-tag parser already populates — `{resolution}`/`{vf}`, `{video
|
|
|
|
|
|
codec}`/`{vc}`, `{audio codec}`/`{ac}` — but only when the filename itself didn't already
|
|
|
|
|
|
carry that tag; an explicit release-group tag always wins over a probed value, since a
|
|
|
|
|
|
release group's own tag is usually deliberate. Five bindings have no filename-tag
|
|
|
|
|
|
equivalent at all, so they're only ever available this way: `{width}`, `{height}`,
|
|
|
|
|
|
`{fps}`, `{duration}` (`h:mm:ss`, or `m:ss` under an hour), and `{file size}`
|
|
|
|
|
|
(human-readable, e.g. `1.4 GB`) — all formatted once on the Rust side so the UI never
|
|
|
|
|
|
reimplements that logic. Rename's Match status line, List's scan status, and Filter's
|
|
|
|
|
|
scan status all report how many loaded files were actually probed (`"N probed from
|
|
|
|
|
|
file"`), the naming-scheme editor's field-reference list has a "Real file probing" group
|
|
|
|
|
|
listing all five width/height/fps/duration/file-size bindings, and the Filter panel adds
|
|
|
|
|
|
its own **Resolution**/**Video codec** chip rows (populated from the same merged
|
|
|
|
|
|
filename-tag-or-probed value) so a batch can be narrowed by either, not just by
|
|
|
|
|
|
extension/kind/name/season.
|
2026-08-29 18:07:54 +00:00
|
|
|
|
|
2026-08-30 04:53:04 +00:00
|
|
|
|
## Hash Files
|
|
|
|
|
|
|
|
|
|
|
|
A naming-scheme binding source, same idea as real media-file probing above, but for
|
|
|
|
|
|
`{crc32}`/`{md5}`/`{sha1}` — reuses the SFV panel's own hasher
|
|
|
|
|
|
(`aurora_curator_core::sfv`) rather than a separate implementation. Unlike Match's other
|
|
|
|
|
|
local steps (filename parsing, container-header probing), this is deliberately **not**
|
|
|
|
|
|
wired into Match automatically: a checksum needs the file's *entire* contents streamed
|
|
|
|
|
|
through, not just a small header or filename, so hashing a batch of large video files
|
|
|
|
|
|
can take real time — running it unasked on every Match click would make Match
|
|
|
|
|
|
unpredictably slow for schemes that don't even use a hash field. Instead, the Rename
|
|
|
|
|
|
panel's New Names list has its own **Hash Files** button next to Fetch Data; clicking it
|
|
|
|
|
|
computes all three checksums for every loaded file in one pass per file (not three
|
|
|
|
|
|
separate passes) and fills in `{crc32}`/`{md5}`/`{sha1}` for whichever files succeeded,
|
|
|
|
|
|
reporting how many hashed vs. failed (a file that's moved or deleted between loading and
|
|
|
|
|
|
hashing, a permissions problem, etc. — kept per-file, so one bad file doesn't block the
|
|
|
|
|
|
rest of the batch). The naming-scheme editor's field-reference list has a "File hashing"
|
|
|
|
|
|
group with all three as clickable buttons.
|
|
|
|
|
|
|
2026-08-29 01:43:12 +00:00
|
|
|
|
## Porting roadmap (not yet done)
|
|
|
|
|
|
|
|
|
|
|
|
Roughly in priority order — each references the original FileBot source file it's
|
|
|
|
|
|
ported from, for anyone picking this up:
|
|
|
|
|
|
|
|
|
|
|
|
1. **Full naming-scheme bindings** — `net.filebot.format.MediaBindingBean` (1354 lines):
|
|
|
|
|
|
all the `{n}`, `{s00e00}`, `{airdate}`, `{vf}` (video format), etc. binding
|
2026-08-29 18:07:54 +00:00
|
|
|
|
properties. A filename-tag-based subset is ported and wired to "Match"
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(`guess_release_info` in `crates/aurora-curator-core/src/matching`): `{vf}`/`{resolution}`,
|
2026-08-29 09:29:14 +00:00
|
|
|
|
`{source}`, `{vc}`/`{video codec}`, `{ac}`/`{audio codec}`, `{group}`/`{release
|
2026-08-29 18:07:54 +00:00
|
|
|
|
group}`. Real container probing (`crates/aurora-curator-core/src/probe`, see "Real
|
|
|
|
|
|
media-file probing" below) now covers the other half MediaBindingBean derives from
|
|
|
|
|
|
actually reading the file — real resolution/video codec/audio codec fill in
|
|
|
|
|
|
whenever the filename didn't already carry that tag, plus `{width}`/`{height}`/
|
|
|
|
|
|
`{fps}`/`{duration}`/`{file size}`, which have no filename-tag equivalent at all —
|
2026-08-30 03:48:22 +00:00
|
|
|
|
for the two container families it supports (MP4/M4V/MOV and MKV/WebM). Probed
|
|
|
|
|
|
bindings are now wired into all three panels that do local matching — Rename's
|
|
|
|
|
|
Match step, and the Filter and List panels' own scans (Filter also gained
|
2026-08-30 04:53:04 +00:00
|
|
|
|
Resolution/Video codec filter chips from it). File hashing is done too —
|
|
|
|
|
|
`{crc32}`/`{md5}`/`{sha1}` reuse the SFV panel's own hasher (all three computed in a
|
|
|
|
|
|
single pass over the file, rather than reading it three times), wired to the Rename
|
|
|
|
|
|
panel's own "Hash Files" button rather than Match, since a full-file read is much
|
|
|
|
|
|
slower than everything else Match does and shouldn't run unasked for every batch
|
|
|
|
|
|
(see "Hash Files" below). Still missing: probing for other containers (.avi, .wmv,
|
|
|
|
|
|
...) and audio-only metadata (bitrate, sample rate, channel layout).
|
2026-08-29 01:43:12 +00:00
|
|
|
|
2. **String/expression helper methods** — `net.filebot.format.ExpressionFormatMethods`
|
|
|
|
|
|
(636 lines): FileBot-specific Groovy string extensions like `.pad()`, `.sortName()`.
|
2026-08-30 03:24:19 +00:00
|
|
|
|
Ported so far (`crates/aurora-curator-core/src/format/functions.rs`): `any`, `all_of`,
|
|
|
|
|
|
`concat`, plus a newer batch of naming/scripting helpers — `pad`/`pad_with`
|
|
|
|
|
|
(left-pad, non-mutating; note this is a deliberately different name collision-avoidance
|
|
|
|
|
|
from Rhai's own built-in `pad(length, char)`, which right-pads and mutates in place —
|
|
|
|
|
|
not a fit for FileBot's zero-padded season/episode numbers), `sort_name`/`sort_initial`
|
|
|
|
|
|
(moves a leading "The"/"A"/"An" article to the end, e.g. `{n.sort_name()}` turns
|
|
|
|
|
|
`"The Office"` into `"Office, The"`), `upper_initial`/`lower_initial`, `acronym`,
|
|
|
|
|
|
`validate_file_name` (strips characters illegal in filenames, collapses whitespace,
|
|
|
|
|
|
trims trailing dots), and `space`/`space_with`/`colon`/`colon_with` (separator/colon
|
|
|
|
|
|
normalization). Rhai's built-ins cover some of the rest already. Still not ported:
|
|
|
|
|
|
FileBot's CSV/file-reading and shell-quoting helpers (`csv`, `read_lines`,
|
|
|
|
|
|
`quote_bash`, `quote_powershell`, etc.).
|
2026-08-29 02:42:31 +00:00
|
|
|
|
3. **Matching/similarity engine** — `net.filebot.similarity.*`. Local filename-based
|
2026-08-29 10:07:09 +00:00
|
|
|
|
season/episode detection is done (`crates/aurora-curator-core/src/matching`, ported from the
|
2026-08-29 02:42:31 +00:00
|
|
|
|
pattern-matching half of `SeasonEpisodeMatcher.java`, adapted to Rust's `regex` crate
|
2026-08-29 04:04:16 +00:00
|
|
|
|
which lacks lookahead/lookbehind — wired to the "Match" button), and so is a local
|
|
|
|
|
|
movie title/year heuristic (`guess_movie` in the same module) used as a fallback
|
|
|
|
|
|
whenever a filename carries no season/episode marker — a release name is either a TV
|
|
|
|
|
|
episode or a movie, never both. Title disambiguation is also done
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(`crates/aurora-curator-core/src/similarity`, a partial port of the *scoring* idea behind
|
2026-08-29 04:04:16 +00:00
|
|
|
|
`EpisodeMetrics.java`'s fuzzy title-matching cascade — Sorensen-Dice similarity over
|
|
|
|
|
|
normalized-title character bigrams), shared by both the TV and movie TMDB lookups:
|
|
|
|
|
|
"Fetch Data" picks whichever TMDB search result is textually closest to the local
|
|
|
|
|
|
guess rather than just trusting TMDB's relevance/popularity-ranked first hit, and
|
|
|
|
|
|
reports "not found" instead of guessing when nothing in the results is a plausible
|
|
|
|
|
|
match at all. `DateMatcher` (numbering/air-date-based identification, the other half
|
2026-08-29 10:07:09 +00:00
|
|
|
|
of the original `EpisodeMetrics`) is not ported — Aurora Curator doesn't do date-based
|
2026-08-29 04:04:16 +00:00
|
|
|
|
episode identification.
|
2026-08-29 01:43:12 +00:00
|
|
|
|
4. **Media detection** — `net.filebot.media.MediaDetection` (1356 lines): ties file-name
|
|
|
|
|
|
parsing + matching together to auto-identify what a file is.
|
|
|
|
|
|
5. **Web datasource clients** — `net.filebot.web.*` (~40 files): TheMovieDB, TheTVDB,
|
2026-08-29 12:25:45 +00:00
|
|
|
|
AniDB, OMDb, TVmaze, OpenSubtitles, etc. Three are done: TMDB, for both TV and movies
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(`crates/aurora-curator-core/src/web/tmdb.rs`, `reqwest` + `serde_json`, Bearer-token auth) —
|
2026-08-29 04:04:16 +00:00
|
|
|
|
search-by-name plus per-season episode lookup for TV, search-by-title (optionally
|
|
|
|
|
|
narrowed by release year via TMDB's own `primary_release_year` filter) for movies —
|
2026-08-29 12:25:45 +00:00
|
|
|
|
TVmaze, for TV only (`crates/aurora-curator-core/src/web/tvmaze.rs`, same `reqwest` +
|
2026-08-29 10:44:12 +00:00
|
|
|
|
`serde_json` shape, no auth at all — TVmaze has no movie catalog to search, and its
|
|
|
|
|
|
per-show episode endpoint returns every season in one flat list rather than TMDB's
|
|
|
|
|
|
per-season lookup, so the client fetches once and filters locally, skipping any
|
2026-08-29 12:25:45 +00:00
|
|
|
|
unnumbered/special episodes rather than panicking on them) — and OMDb, for both TV
|
|
|
|
|
|
and movies (`crates/aurora-curator-core/src/web/omdb.rs`, same `reqwest` + `serde_json`
|
|
|
|
|
|
shape but a single flat root-URL REST API rather than TMDB's per-resource paths, plain
|
|
|
|
|
|
`apikey` query-param auth rather than a Bearer token, and human-text release dates
|
|
|
|
|
|
(`"16 Jul 2010"`/`"N/A"`) normalized to ISO form locally; a movie search result only
|
|
|
|
|
|
carries a bare year, so `lookup_movie` follows up with a by-ID detail request to get
|
|
|
|
|
|
the actual release date). All three are wired to "Fetch
|
|
|
|
|
|
Data" — independent "TV episode source" (TMDB/TVmaze/OMDb) and "Movie source"
|
|
|
|
|
|
(TMDB/OMDb) pickers in Fetch Data Settings choose which source a batch's TV and movie
|
|
|
|
|
|
items resolve against respectively (TMDB stays the default for both; a batch can mix
|
|
|
|
|
|
sources across its TV and movie halves) — disambiguating multi-result searches via
|
2026-08-29 10:44:12 +00:00
|
|
|
|
the similarity-scoring pass described in item 3 above rather than blindly trusting
|
2026-08-29 15:35:27 +00:00
|
|
|
|
any source's top-ranked hit. The same per-season episode-list methods these three
|
|
|
|
|
|
clients already exposed for Fetch Data are also what the new Episodes panel browses
|
|
|
|
|
|
directly (see "Episodes" above) — no new client code, just a new UI on top of what
|
|
|
|
|
|
was already there. **OpenSubtitles is also done, but as a subtitle source
|
2026-08-29 14:08:17 +00:00
|
|
|
|
rather than a fourth title-metadata source** — `crates/aurora-curator-core/src/web/opensubtitles.rs`,
|
|
|
|
|
|
wired to the new Subtitles panel (see "Subtitles" above) rather than to Fetch Data's
|
|
|
|
|
|
TV/movie pickers, since it fetches subtitle files, not episode/movie titles. All
|
|
|
|
|
|
other sources (TheTVDB, AniDB) are not yet started — **TheTVDB was deliberately
|
|
|
|
|
|
skipped**: as of this writing its v4 API requires either a paid commercial license or
|
|
|
|
|
|
the "user-supported" model, where every end user needs their own paid TheTVDB
|
|
|
|
|
|
subscription (~$12/year) just to get the PIN its login flow requires, unlike the
|
|
|
|
|
|
three free-to-use sources above — worth revisiting if that changes.
|
2026-08-29 01:43:12 +00:00
|
|
|
|
6. **Rename engine + CLI** — `net.filebot.cli.CmdlineOperations` (1235 lines) and
|
|
|
|
|
|
`ArgumentBean` (415 lines, the full flag surface: `-rename`, `--db`, `--format`,
|
2026-08-29 03:36:06 +00:00
|
|
|
|
`--action`, `--conflict`, `-get-subtitles`, `-script`, etc.). The rename operation is
|
2026-08-29 10:07:09 +00:00
|
|
|
|
done (`crates/aurora-curator-core/src/rename`, wired to the UI's Rename button behind a
|
2026-08-29 09:50:36 +00:00
|
|
|
|
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
|
2026-08-29 11:30:51 +00:00
|
|
|
|
fixed skip-on-conflict policy no matter which policy the original rename used). The
|
|
|
|
|
|
CLI flag surface is done too — `-rename`/`--format`/`--db`/`--action`/`--conflict`/
|
|
|
|
|
|
`-non-strict`/`-h` (`crates/aurora-curator-core/src/cli` for pure argument parsing and
|
|
|
|
|
|
directory expansion, `src-tauri/src/cli.rs` for the orchestration — local matching,
|
2026-08-29 12:25:45 +00:00
|
|
|
|
optional TMDB/TVmaze/OMDb lookup, and the actual rename, all without ever constructing a
|
2026-08-29 14:08:17 +00:00
|
|
|
|
Tauri `App`); see "Command-line usage" above. `--output <dir>` and `-script`/the rest
|
|
|
|
|
|
of FileBot's non-rename CLI modes are not ported. `-get-subtitles` has no CLI analog
|
|
|
|
|
|
yet — subtitle fetching (see "Subtitles" above) is GUI-only so far, reached from its
|
|
|
|
|
|
own sidebar panel rather than a command-line flag.
|
2026-08-29 02:42:31 +00:00
|
|
|
|
7. **The rest of the UI** — the Rename panel (file loading, drag-drop, live preview,
|
2026-08-29 09:39:52 +00:00
|
|
|
|
local TV/movie matching, confirmed rename with per-item exclude, rename history/undo,
|
2026-08-29 14:08:17 +00:00
|
|
|
|
Align Up/Down reordering, naming-scheme Presets with `1`-`9` hotkeys) is built, and so
|
2026-08-29 15:59:05 +00:00
|
|
|
|
are the Subtitles panel (search + download via OpenSubtitles, see "Subtitles" above),
|
|
|
|
|
|
the Episodes panel (series search + season browse with a Copy list export, no
|
2026-08-29 17:01:15 +00:00
|
|
|
|
credentials of its own, see "Episodes" above), the SFV panel (compute/verify
|
2026-08-29 15:59:05 +00:00
|
|
|
|
CRC32/MD5/SHA1 checksums, read/write `.sfv`/`.md5`/`.sha1` sidecar files, entirely
|
2026-08-29 17:28:38 +00:00
|
|
|
|
local with no credentials at all, see "SFV" above), the Filter panel (extension/
|
2026-08-29 17:01:15 +00:00
|
|
|
|
kind/filename/season narrowing over a locally-scanned batch, no new Rust/Tauri
|
2026-08-29 17:28:38 +00:00
|
|
|
|
surface at all, see "Filter" above), and the List panel (a naming-scheme-style
|
|
|
|
|
|
expression rendered per file via the same `render_expression` engine, with a Copy
|
|
|
|
|
|
List clipboard export and an Export to File… `.txt` writer behind one new
|
|
|
|
|
|
`export_text_list` command, see "List" above) — **all six of the original sidebar
|
|
|
|
|
|
panels are now real screens**, closing out the panel set FileBot itself shipped.
|
2026-08-29 17:01:15 +00:00
|
|
|
|
Align Up/Down is button-based
|
2026-08-29 14:08:17 +00:00
|
|
|
|
(swaps the selected file with its neighbor), not the original's
|
|
|
|
|
|
drag-and-drop-within-a-list interaction.
|
2026-08-29 03:44:38 +00:00
|
|
|
|
8. **Undo/history for renames** — done, as a flat JSON-backed undo stack rather than a
|
|
|
|
|
|
full port of `net.filebot.HistoryDialog`'s session/element log
|
2026-08-29 10:07:09 +00:00
|
|
|
|
(`crates/aurora-curator-core/src/history`, `src-tauri/src/history.rs`). Every successful
|
2026-08-29 03:44:38 +00:00
|
|
|
|
rename is recorded to a `history.json` in the OS app-config directory (same location
|
|
|
|
|
|
as `settings.json`); the History panel lists past batches and can revert one back to
|
|
|
|
|
|
its original paths, skipping (never overwriting) any file whose original path now
|
|
|
|
|
|
has something else at it. Capped at the 50 most recent batches.
|
2026-08-29 02:42:31 +00:00
|
|
|
|
9. **Packaging** — code signing, auto-update, installers per platform via
|
2026-08-29 01:43:12 +00:00
|
|
|
|
`npm run tauri build`.
|