diff --git a/Cargo.lock b/Cargo.lock index e176cc2..e3fa851 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,34 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "aurora-curator" +version = "0.1.0" +dependencies = [ + "aurora-curator-core", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tokio", + "walkdir", +] + +[[package]] +name = "aurora-curator-core" +version = "0.1.0" +dependencies = [ + "mockito", + "regex", + "reqwest 0.12.28", + "rhai", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "autocfg" version = "1.5.1" @@ -2770,34 +2798,6 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" -[[package]] -name = "renamr" -version = "0.1.0" -dependencies = [ - "renamr-core", - "serde", - "serde_json", - "tauri", - "tauri-build", - "tauri-plugin-dialog", - "tokio", - "walkdir", -] - -[[package]] -name = "renamr-core" -version = "0.1.0" -dependencies = [ - "mockito", - "regex", - "reqwest 0.12.28", - "rhai", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "reqwest" version = "0.12.28" diff --git a/Cargo.toml b/Cargo.toml index f1a47e5..3dc7186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["crates/renamr-core", "src-tauri"] +members = ["crates/aurora-curator-core", "src-tauri"] [workspace.package] version = "0.1.0" diff --git a/README.md b/README.md index 7a0d82a..6ef77d6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Renamr +# Aurora Curator 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. @@ -48,7 +48,7 @@ The original is a ~20k+ line Java/Swing app built with Ant. The goals were: fast startup and UI, faster matching/renaming, a codebase that's actually pleasant to work in, and a genuine rebrand — not a coat of paint. -Renamr is **Tauri**: a Rust core (`crates/renamr-core`, `src-tauri`) plus a +Aurora Curator is **Tauri**: a Rust core (`crates/aurora-curator-core`, `src-tauri`) plus a 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 @@ -69,7 +69,7 @@ template syntax compatible with FileBot conventions, so existing automation most keeps working. One deliberate gap: FileBot's `{ }` expressions ran arbitrary **Groovy** code -(JVM-only). Renamr's Rust core has no Groovy engine, so expressions are evaluated with +(JVM-only). Aurora Curator's Rust core has no Groovy engine, so expressions are evaluated with [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 @@ -79,7 +79,7 @@ translate directly. ### Naming scheme syntax Every `{ }` token in an expression is resolved in this order -(`crates/renamr-core/src/format/expression.rs::compile_scriptlet`): +(`crates/aurora-curator-core/src/format/expression.rs::compile_scriptlet`): 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. @@ -109,12 +109,12 @@ a subfolder" rather than rejecting it. 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 -(`crates/renamr-core/src/rename/mod.rs::rename_one` → `fs::create_dir_all`). This is +(`crates/aurora-curator-core/src/rename/mod.rs::rename_one` → `fs::create_dir_all`). This is 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 -`/etc/passwd`-style path), `.`/`..` segments, and backslashes (Renamr always uses `/` +`/etc/passwd`-style path), `.`/`..` segments, and backslashes (Aurora Curator always uses `/` 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 @@ -123,7 +123,7 @@ porting roadmap below for the full behavior of each. ## Project layout ``` -crates/renamr-core/ Pure Rust core: naming-expression engine (ported), local +crates/aurora-curator-core/ Pure Rust core: naming-expression engine (ported), local filename-based season/episode *and movie title/year* matching (ported, `matching/`), plus filename-based release-tag parsing in the same module (`guess_release_info` — resolution, source, video/ @@ -141,7 +141,7 @@ crates/renamr-core/ Pure Rust core: naming-expression engine (ported), local action produced each batch). Not yet ported: full media metadata bindings, other web datasource clients (TVDB/AniDB/etc). No Tauri dependency, so it builds and unit-tests standalone. -src-tauri/ Tauri app shell: exposes renamr-core as commands to the frontend +src-tauri/ Tauri app shell: exposes aurora-curator-core as commands to the frontend (naming-scheme rendering, filename matching for both TV and movies, TMDB metadata fetch — `metadata.rs` for TV episodes, plus a movie-fetch command alongside it — executing a rename @@ -172,7 +172,7 @@ toolchain; macOS/Windows need Xcode / the VS Build Tools + WebView2 respectively ```sh # Rust core (no UI deps needed): -cargo test -p renamr-core +cargo test -p aurora-curator-core # Full app in dev mode (opens a native window): npm install @@ -182,10 +182,10 @@ npm run tauri dev npm run tauri build ``` -Verified in the environment this was built in: `cargo test -p renamr-core` (all +Verified in the environment this was built in: `cargo test -p aurora-curator-core` (all passing, including the TMDB 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 -renamr` (compiles clean against real Tauri + GTK/WebKit system libraries), and `npm run +aurora-curator` (compiles clean against real Tauri + GTK/WebKit system libraries), and `npm run build` (TypeScript type-checks, Vite bundles). The actual GUI window has **not** been visually verified anywhere yet — that sandbox has no display. Run `npm run tauri dev` on your machine to see and click through it for the first time. @@ -196,7 +196,7 @@ Everything else in the app works fully offline; "Fetch Data" is the one feature needs a (free) [TMDB](https://www.themoviedb.org/) account: 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" — Renamr uses the Bearer + **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, click the key icon ("TMDB Settings") next to Fetch Data and paste the token in. It's saved locally in the OS app-config directory and only ever sent to @@ -210,38 +210,38 @@ 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 properties. A filename-tag-based subset is now ported and wired to "Match" - (`guess_release_info` in `crates/renamr-core/src/matching`): `{vf}`/`{resolution}`, + (`guess_release_info` in `crates/aurora-curator-core/src/matching`): `{vf}`/`{resolution}`, `{source}`, `{vc}`/`{video codec}`, `{ac}`/`{audio codec}`, `{group}`/`{release group}`. What's still missing is everything MediaBindingBean derives from actually *probing* the media file (real video/audio stream resolution, duration, bitrate, - frame rate, file size/hash, etc.) — Renamr ships no ffprobe/MediaInfo dependency, so + frame rate, file size/hash, etc.) — Aurora Curator ships no ffprobe/MediaInfo dependency, so those bindings only work when a release name happens to carry the info as text. 2. **String/expression helper methods** — `net.filebot.format.ExpressionFormatMethods` (636 lines): FileBot-specific Groovy string extensions like `.pad()`, `.sortName()`. Only a small subset (`any`, `all_of`, `concat`) is ported so far - (`crates/renamr-core/src/format/functions.rs`); Rhai's built-ins cover some of the + (`crates/aurora-curator-core/src/format/functions.rs`); Rhai's built-ins cover some of the rest already. 3. **Matching/similarity engine** — `net.filebot.similarity.*`. Local filename-based - season/episode detection is done (`crates/renamr-core/src/matching`, ported from the + season/episode detection is done (`crates/aurora-curator-core/src/matching`, ported from the pattern-matching half of `SeasonEpisodeMatcher.java`, adapted to Rust's `regex` crate 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 - (`crates/renamr-core/src/similarity`, a partial port of the *scoring* idea behind + (`crates/aurora-curator-core/src/similarity`, a partial port of the *scoring* idea behind `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 - of the original `EpisodeMetrics`) is not ported — Renamr doesn't do date-based + of the original `EpisodeMetrics`) is not ported — Aurora Curator doesn't do date-based episode identification. 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, AniDB, OMDb, TVmaze, OpenSubtitles, etc. TMDB is done for both TV and movies - (`crates/renamr-core/src/web/tmdb.rs`, `reqwest` + `serde_json`, Bearer-token auth) — + (`crates/aurora-curator-core/src/web/tmdb.rs`, `reqwest` + `serde_json`, Bearer-token auth) — 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 — both wired to "Fetch Data", disambiguating multi-result searches via the @@ -251,7 +251,7 @@ ported from, for anyone picking this up: 6. **Rename engine + CLI** — `net.filebot.cli.CmdlineOperations` (1235 lines) and `ArgumentBean` (415 lines, the full flag surface: `-rename`, `--db`, `--format`, `--action`, `--conflict`, `-get-subtitles`, `-script`, etc.). The rename operation is - done (`crates/renamr-core/src/rename`, wired to the UI's Rename button behind a + done (`crates/aurora-curator-core/src/rename`, wired to the UI's Rename button behind a confirmation step) including the `move`-into-subfolder `--action` variant — a naming scheme like `{n}/{s00e00}` organizes files into subfolders, creating any missing folders automatically, always scoped to the file's own directory tree. The @@ -275,7 +275,7 @@ ported from, for anyone picking this up: not the original's drag-and-drop-within-a-list interaction. 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 - (`crates/renamr-core/src/history`, `src-tauri/src/history.rs`). Every successful + (`crates/aurora-curator-core/src/history`, `src-tauri/src/history.rs`). Every successful 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 diff --git a/crates/renamr-core/Cargo.toml b/crates/aurora-curator-core/Cargo.toml similarity index 89% rename from crates/renamr-core/Cargo.toml rename to crates/aurora-curator-core/Cargo.toml index 506981c..9589513 100644 --- a/crates/renamr-core/Cargo.toml +++ b/crates/aurora-curator-core/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "renamr-core" +name = "aurora-curator-core" version.workspace = true edition.workspace = true license.workspace = true -description = "Renamr core: naming-expression engine, media matching, and rename engine (UI-agnostic)." +description = "Aurora Curator core: naming-expression engine, media matching, and rename engine (UI-agnostic)." [dependencies] # Embeddable scripting engine powering the {expression} naming-scheme language. diff --git a/crates/renamr-core/src/format/engine.rs b/crates/aurora-curator-core/src/format/engine.rs similarity index 100% rename from crates/renamr-core/src/format/engine.rs rename to crates/aurora-curator-core/src/format/engine.rs diff --git a/crates/renamr-core/src/format/expression.rs b/crates/aurora-curator-core/src/format/expression.rs similarity index 100% rename from crates/renamr-core/src/format/expression.rs rename to crates/aurora-curator-core/src/format/expression.rs diff --git a/crates/renamr-core/src/format/functions.rs b/crates/aurora-curator-core/src/format/functions.rs similarity index 100% rename from crates/renamr-core/src/format/functions.rs rename to crates/aurora-curator-core/src/format/functions.rs diff --git a/crates/renamr-core/src/format/mod.rs b/crates/aurora-curator-core/src/format/mod.rs similarity index 93% rename from crates/renamr-core/src/format/mod.rs rename to crates/aurora-curator-core/src/format/mod.rs index d0c32c5..e32b830 100644 --- a/crates/renamr-core/src/format/mod.rs +++ b/crates/aurora-curator-core/src/format/mod.rs @@ -1,4 +1,4 @@ -//! Renamr's naming-scheme expression language. +//! Aurora Curator's naming-scheme expression language. //! //! A format string is literal text with `{ ... }` scriptlets spliced in, e.g. //! `"{n} - {s00e00} - {t}"` diff --git a/crates/renamr-core/src/history/mod.rs b/crates/aurora-curator-core/src/history/mod.rs similarity index 98% rename from crates/renamr-core/src/history/mod.rs rename to crates/aurora-curator-core/src/history/mod.rs index 18a6833..6422bcb 100644 --- a/crates/renamr-core/src/history/mod.rs +++ b/crates/aurora-curator-core/src/history/mod.rs @@ -1,5 +1,5 @@ //! Rename history: a persisted log of past rename batches (what changed, from what to -//! what) and the ability to revert one - Renamr's only safety net beyond the +//! what) and the ability to revert one - Aurora Curator's only safety net beyond the //! confirmation-before-execute step, since a plain filesystem rename has no OS-level //! undo. Loosely inspired by `net.filebot.HistoryDialog`/the original's rename-history //! log, but as a flat JSON-backed undo stack (see [`push_batch`]) rather than a full @@ -93,7 +93,7 @@ fn revert_one(entry: &HistoryEntry, action: RenameAction) -> RevertOutcome { }; } - // The original's parent directory should still exist (nothing in Renamr + // The original's parent directory should still exist (nothing in Aurora Curator // deletes directories), but recreate it defensively in case it was removed // by hand since - cheap, and `create_dir_all` is a no-op when it's already // there. @@ -175,7 +175,7 @@ mod tests { fn temp_dir() -> std::path::PathBuf { let n = COUNTER.fetch_add(1, Ordering::SeqCst); - let dir = std::env::temp_dir().join(format!("renamr_history_test_{}_{}", std::process::id(), n)); + let dir = std::env::temp_dir().join(format!("aurora_curator_history_test_{}_{}", std::process::id(), n)); fs::create_dir_all(&dir).unwrap(); dir } diff --git a/crates/renamr-core/src/lib.rs b/crates/aurora-curator-core/src/lib.rs similarity index 91% rename from crates/renamr-core/src/lib.rs rename to crates/aurora-curator-core/src/lib.rs index 90ba2a9..d6885a5 100644 --- a/crates/renamr-core/src/lib.rs +++ b/crates/aurora-curator-core/src/lib.rs @@ -1,4 +1,4 @@ -//! Renamr core: the UI-agnostic engine behind the Renamr media renamer. +//! Aurora Curator core: the UI-agnostic engine behind the Aurora Curator media renamer. //! //! This crate has no Tauri/UI dependency so it can be built and unit-tested standalone. //! It's the piece being ported first from the original FileBot (Java) codebase; see diff --git a/crates/renamr-core/src/matching/mod.rs b/crates/aurora-curator-core/src/matching/mod.rs similarity index 99% rename from crates/renamr-core/src/matching/mod.rs rename to crates/aurora-curator-core/src/matching/mod.rs index 0bad2ff..ef9b919 100644 --- a/crates/renamr-core/src/matching/mod.rs +++ b/crates/aurora-curator-core/src/matching/mod.rs @@ -175,7 +175,7 @@ pub fn guess_movie(filename: &str) -> Option { /// (capture/rip type), video codec, audio codec, and release group. Ports the /// filename-parsing half of the original FileBot's `ReleaseInfo` class - the same /// regex-based tag recognition `MediaBindingBean` falls back to when no real media -/// probe (ffprobe/MediaInfo) is available, which Renamr never has, so this is the +/// probe (ffprobe/MediaInfo) is available, which Aurora Curator never has, so this is the /// only source for these fields here. Deliberately independent of `guess_episode`/ /// `guess_movie`: a release name carries these tags (or doesn't) regardless of /// whether it's a TV episode or a movie, so callers run this alongside whichever of diff --git a/crates/renamr-core/src/rename/mod.rs b/crates/aurora-curator-core/src/rename/mod.rs similarity index 98% rename from crates/renamr-core/src/rename/mod.rs rename to crates/aurora-curator-core/src/rename/mod.rs index 362fa20..340fa28 100644 --- a/crates/renamr-core/src/rename/mod.rs +++ b/crates/aurora-curator-core/src/rename/mod.rs @@ -17,7 +17,7 @@ //! the caller a confirmation of the full plan (and let them choose both a //! [`RenameAction`] and a [`ConflictPolicy`]) before calling [`execute_renames`]; every //! batch that action actually touches a file for is also recorded to the rename-history -//! log one layer up (`renamr_core::history`), so it can be undone from there. Undoing +//! log one layer up (`aurora_curator_core::history`), so it can be undone from there. Undoing //! always uses skip-on-conflict regardless of what policy the original rename used //! (see `history::revert_one`) - overwriting an unrelated file as a side effect of an //! *undo* would be a much worse surprise than leaving it for the user to sort out by @@ -47,7 +47,7 @@ pub struct RenamePlanItem { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum RenameAction { - /// Renames/moves the file in place - the only action Renamr had before this. The + /// Renames/moves the file in place - the only action Aurora Curator had before this. The /// source file no longer exists afterward; the item now lives at the target path. Move, /// Copies the file's contents to the target path, leaving the source untouched. @@ -118,7 +118,7 @@ pub struct RenameResult { /// no empty components (a leading, trailing, or doubled `/` - which also catches an /// absolute-looking `/etc/passwd`-style path, since splitting it on `/` yields a /// leading empty component), and no `.`/`..` components. Backslashes are rejected -/// outright rather than treated as an alternate separator - Renamr always uses `/` for +/// outright rather than treated as an alternate separator - Aurora Curator always uses `/` for /// the naming scheme's folder separator regardless of OS, so a literal `\` in a /// computed name is almost certainly a mistake, not an intentional Windows path. fn validate_relative_target(name: &str) -> Result<(), &'static str> { @@ -322,7 +322,7 @@ mod tests { /// the real filesystem. Returns (dir, file_path). fn temp_file_setup(file_name: &str, contents: &str) -> (std::path::PathBuf, std::path::PathBuf) { let n = COUNTER.fetch_add(1, Ordering::SeqCst); - let dir = std::env::temp_dir().join(format!("renamr_rename_test_{}_{}", std::process::id(), n)); + let dir = std::env::temp_dir().join(format!("aurora_curator_rename_test_{}_{}", std::process::id(), n)); fs::create_dir_all(&dir).unwrap(); let file = dir.join(file_name); fs::write(&file, contents).unwrap(); diff --git a/crates/renamr-core/src/similarity/mod.rs b/crates/aurora-curator-core/src/similarity/mod.rs similarity index 98% rename from crates/renamr-core/src/similarity/mod.rs rename to crates/aurora-curator-core/src/similarity/mod.rs index 741adfb..098c7ea 100644 --- a/crates/renamr-core/src/similarity/mod.rs +++ b/crates/aurora-curator-core/src/similarity/mod.rs @@ -7,7 +7,7 @@ //! rank first - TMDB ranks by relevance/popularity, not by exact name match, so a //! more popular but differently-named show can otherwise beat an exact-but-less-popular //! one straight to the top of the list. `DateMatcher` (the other half of the original -//! `EpisodeMetrics`) is not ported - Renamr doesn't do date-based episode identification. +//! `EpisodeMetrics`) is not ported - Aurora Curator doesn't do date-based episode identification. use std::collections::HashMap; diff --git a/crates/renamr-core/src/web/mod.rs b/crates/aurora-curator-core/src/web/mod.rs similarity index 100% rename from crates/renamr-core/src/web/mod.rs rename to crates/aurora-curator-core/src/web/mod.rs diff --git a/crates/renamr-core/src/web/tmdb.rs b/crates/aurora-curator-core/src/web/tmdb.rs similarity index 99% rename from crates/renamr-core/src/web/tmdb.rs rename to crates/aurora-curator-core/src/web/tmdb.rs index 68659a4..0950b41 100644 --- a/crates/renamr-core/src/web/tmdb.rs +++ b/crates/aurora-curator-core/src/web/tmdb.rs @@ -37,7 +37,7 @@ struct SearchTvResponse { results: Vec, } -/// One TMDB search hit. Only the fields Renamr actually uses are kept. +/// One TMDB search hit. Only the fields Aurora Curator actually uses are kept. #[derive(Debug, Clone, Deserialize)] pub struct TvResult { pub id: u64, @@ -75,7 +75,7 @@ struct SearchMovieResponse { results: Vec, } -/// One TMDB movie search hit. Only the fields Renamr actually uses are kept. +/// One TMDB movie search hit. Only the fields Aurora Curator actually uses are kept. #[derive(Debug, Clone, Deserialize)] pub struct MovieResult { pub id: u64, diff --git a/crates/renamr-core/tests/expression_format.rs b/crates/aurora-curator-core/tests/expression_format.rs similarity index 97% rename from crates/renamr-core/tests/expression_format.rs rename to crates/aurora-curator-core/tests/expression_format.rs index c49f28a..c7e5d9b 100644 --- a/crates/renamr-core/tests/expression_format.rs +++ b/crates/aurora-curator-core/tests/expression_format.rs @@ -1,5 +1,5 @@ -use renamr_core::format::ExpressionFormat; -use renamr_core::string_bindings; +use aurora_curator_core::format::ExpressionFormat; +use aurora_curator_core::string_bindings; #[test] fn simple_variable_substitution() { diff --git a/index.html b/index.html index 0645dbc..a4b0a05 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - Renamr + Aurora Curator
diff --git a/package-lock.json b/package-lock.json index 5ba8a49..f41099a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "renamr", + "name": "aurora-curator", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "renamr", + "name": "aurora-curator", "version": "0.1.0", "dependencies": { "@tauri-apps/api": "^2.1.1", diff --git a/package.json b/package.json index 406f83c..b2517b3 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "renamr", + "name": "aurora-curator", "private": true, "version": "0.1.0", "type": "module", diff --git a/scripts/gen_icons.py b/scripts/gen_icons.py index 40b7790..428291a 100644 --- a/scripts/gen_icons.py +++ b/scripts/gen_icons.py @@ -1,46 +1,24 @@ #!/usr/bin/env python3 -"""Generates Renamr's app icon set (placeholder branding, easy to swap later). +"""Generates Aurora Curator's app icon set from the real logo mark. + +Source master: scripts/logo/icon-source.png (the folder/aurora/filmstrip mark, +square-padded, transparent background - cropped from the full lockup that also +includes the "AURORA CURATOR" wordmark, which isn't used for the app icon itself). Produces the sizes Tauri's bundler expects in src-tauri/icons/. """ -from PIL import Image, ImageDraw, ImageFont +from PIL import Image import os -OUT = os.path.join(os.path.dirname(__file__), "..", "src-tauri", "icons") +HERE = os.path.dirname(__file__) +SRC = os.path.join(HERE, "logo", "icon-source.png") +OUT = os.path.join(HERE, "..", "src-tauri", "icons") os.makedirs(OUT, exist_ok=True) -SIZE = 1024 -BG_TOP = (91, 76, 245) # indigo -BG_BOTTOM = (56, 189, 178) # teal -FG = (255, 255, 255) +master = Image.open(SRC).convert("RGBA") +if master.size != (1024, 1024): + master = master.resize((1024, 1024), Image.LANCZOS) -def make_master(): - img = Image.new("RGB", (SIZE, SIZE), BG_TOP) - px = img.load() - for y in range(SIZE): - t = y / SIZE - r = int(BG_TOP[0] * (1 - t) + BG_BOTTOM[0] * t) - g = int(BG_TOP[1] * (1 - t) + BG_BOTTOM[1] * t) - b = int(BG_TOP[2] * (1 - t) + BG_BOTTOM[2] * t) - for x in range(SIZE): - px[x, y] = (r, g, b) - - # rounded-square mask - mask = Image.new("L", (SIZE, SIZE), 0) - ImageDraw.Draw(mask).rounded_rectangle([0, 0, SIZE - 1, SIZE - 1], radius=SIZE // 5, fill=255) - canvas = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0)) - canvas.paste(img, (0, 0), mask) - - draw = ImageDraw.Draw(canvas) - font = ImageFont.truetype("/usr/share/fonts/truetype/google-fonts/Poppins-Bold.ttf", int(SIZE * 0.56)) - text = "R" - bbox = draw.textbbox((0, 0), text, font=font) - tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1] - draw.text(((SIZE - tw) / 2 - bbox[0], (SIZE - th) / 2 - bbox[1] - SIZE * 0.02), text, font=font, fill=FG) - - return canvas - -master = make_master() master.save(os.path.join(OUT, "icon-master.png")) sizes = [32, 128, 256, 512, 1024] @@ -62,4 +40,4 @@ try: except Exception as e: print(f"WARN: could not write icon.icns via Pillow ({e}); leaving it out") -print("done:", os.listdir(OUT)) +print("done:", sorted(os.listdir(OUT))) diff --git a/scripts/logo/full-lockup.png b/scripts/logo/full-lockup.png new file mode 100644 index 0000000..110ef32 Binary files /dev/null and b/scripts/logo/full-lockup.png differ diff --git a/scripts/logo/icon-source.png b/scripts/logo/icon-source.png new file mode 100644 index 0000000..b4042d0 Binary files /dev/null and b/scripts/logo/icon-source.png differ diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 6bbb6cf..8a1fbd9 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,18 +1,18 @@ [package] -name = "renamr" +name = "aurora-curator" version.workspace = true edition.workspace = true license.workspace = true [lib] -name = "renamr_lib" +name = "aurora_curator_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] tauri-build = { version = "2", features = [] } [dependencies] -renamr-core = { path = "../crates/renamr-core" } +aurora-curator-core = { path = "../crates/aurora-curator-core" } tauri = { version = "2", features = [] } tauri-plugin-dialog = "2" serde = { version = "1", features = ["derive"] } diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index a373edd..cbc87d2 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -1,7 +1,7 @@ { "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", - "description": "Default permissions for Renamr's main window.", + "description": "Default permissions for Aurora Curator's main window.", "windows": ["main"], "permissions": ["core:default", "dialog:default"] } diff --git a/src-tauri/icons/1024x1024.png b/src-tauri/icons/1024x1024.png index cbe968e..b4042d0 100644 Binary files a/src-tauri/icons/1024x1024.png and b/src-tauri/icons/1024x1024.png differ diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png index ece230f..9599c08 100644 Binary files a/src-tauri/icons/128x128.png and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png index 0114ee9..3329877 100644 Binary files a/src-tauri/icons/128x128@2x.png and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/256x256.png b/src-tauri/icons/256x256.png index 0114ee9..3329877 100644 Binary files a/src-tauri/icons/256x256.png and b/src-tauri/icons/256x256.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png index 015d55d..f628cda 100644 Binary files a/src-tauri/icons/32x32.png and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/512x512.png b/src-tauri/icons/512x512.png index 75cded2..a24bef6 100644 Binary files a/src-tauri/icons/512x512.png and b/src-tauri/icons/512x512.png differ diff --git a/src-tauri/icons/icon-master.png b/src-tauri/icons/icon-master.png index cbe968e..b4042d0 100644 Binary files a/src-tauri/icons/icon-master.png and b/src-tauri/icons/icon-master.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns index 3533f4f..ed24b92 100644 Binary files a/src-tauri/icons/icon.icns and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico index 3eea9f9..3d0e6ba 100644 Binary files a/src-tauri/icons/icon.ico and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/src/history.rs b/src-tauri/src/history.rs index c541b34..24160a7 100644 --- a/src-tauri/src/history.rs +++ b/src-tauri/src/history.rs @@ -1,10 +1,10 @@ //! The Tauri-facing side of rename history/undo: persists the log -//! `renamr_core::history` produces to disk (plain JSON in the OS app-config +//! `aurora_curator_core::history` produces to disk (plain JSON in the OS app-config //! directory, alongside `settings.json`) and exposes it to the UI as two commands - //! list the log, and undo one batch from it. -use renamr_core::history::{self, HistoryBatch, HistoryEntry, RevertResult}; -use renamr_core::rename::{RenameAction, RenameOutcome, RenameResult}; +use aurora_curator_core::history::{self, HistoryBatch, HistoryEntry, RevertResult}; +use aurora_curator_core::rename::{RenameAction, RenameOutcome, RenameResult}; use std::fs; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; @@ -45,7 +45,7 @@ fn now_millis() -> u64 { /// Called right after a rename batch executes (see `execute_rename` in `lib.rs`) - /// records only the entries that were actually renamed/copied/linked, and the action /// that was used to do it (so `undo_rename_batch` later knows whether to move the -/// result back or just delete it - see `renamr_core::history::revert_one`); a file that +/// result back or just delete it - see `aurora_curator_core::history::revert_one`); a file that /// was unchanged, skipped, or failed has nothing to undo. Best-effort: if persisting the /// history fails for some reason, the operation itself already succeeded and shouldn't /// be reported as failed just because its undo record couldn't be saved, so errors here diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e29ef61..89595ec 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -4,10 +4,10 @@ mod metadata; mod presets; mod settings; -use renamr_core::format::ExpressionFormat; -use renamr_core::matching::{self, EpisodeGuess, MovieGuess, ReleaseInfo}; -use renamr_core::rename::{self, ConflictPolicy, RenameAction, RenamePlanItem, RenameResult}; -use renamr_core::string_bindings; +use aurora_curator_core::format::ExpressionFormat; +use aurora_curator_core::matching::{self, EpisodeGuess, MovieGuess, ReleaseInfo}; +use aurora_curator_core::rename::{self, ConflictPolicy, RenameAction, RenamePlanItem, RenameResult}; +use aurora_curator_core::string_bindings; use std::collections::HashMap; use tauri::AppHandle; @@ -42,7 +42,7 @@ fn guess_movie(filename: String) -> Option { /// Guesses release-tag metadata (resolution, source, video/audio codec, release /// group) from a filename's own text using local regex patterns only - no network -/// calls, no real media probing (Renamr never ships an ffprobe/MediaInfo dependency, +/// calls, no real media probing (Aurora Curator never ships an ffprobe/MediaInfo dependency, /// so filename tags are the only source for these fields). Independent of /// `guess_episode`/`guess_movie`: called alongside whichever of those two applies, /// since a release name carries (or doesn't carry) these tags regardless of whether @@ -53,7 +53,7 @@ fn guess_release_info(filename: String) -> Option { } /// Executes a batch of planned on-disk rename/copy/symlink operations (optionally -/// moving/copying files into subfolders - see `renamr_core::rename`). `action` picks +/// moving/copying files into subfolders - see `aurora_curator_core::rename`). `action` picks /// which of the three happens; `conflict` picks what happens when a computed target /// already exists (skip it, save alongside it with an auto-numbered name, or replace /// it) - the UI is expected to have already shown the user the full old-path/new-path @@ -103,5 +103,5 @@ pub fn run() { files::expand_dropped_paths, ]) .run(tauri::generate_context!()) - .expect("error while running Renamr"); + .expect("error while running Aurora Curator"); } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 1fb33d0..e89a402 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -2,5 +2,5 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { - renamr_lib::run(); + aurora_curator_lib::run(); } diff --git a/src-tauri/src/metadata.rs b/src-tauri/src/metadata.rs index ca55aae..ffe1009 100644 --- a/src-tauri/src/metadata.rs +++ b/src-tauri/src/metadata.rs @@ -4,7 +4,7 @@ //! Fetch Data needs a series name and season/episode to search with, which is exactly //! what Match already produces for free, offline. -use renamr_core::web::tmdb::{SeasonEpisode, TmdbClient}; +use aurora_curator_core::web::tmdb::{SeasonEpisode, TmdbClient}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use tauri::AppHandle; @@ -182,7 +182,7 @@ async fn run_movie_fetch(token: String, items: Vec) -> Vec MovieFetchOutcome::NotFound, + Err(aurora_curator_core::web::tmdb::TmdbError::NotFound(_)) => MovieFetchOutcome::NotFound, Err(error) => MovieFetchOutcome::Failed { error: error.to_string() }, }; diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index 46ccf53..755954e 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -1,9 +1,9 @@ //! Small persisted app settings - currently just the TMDB API token ("Fetch Data" needs //! it; everything else in the app works offline without any settings at all). Stored as //! plain JSON in Tauri's per-OS app config directory (e.g. -//! `~/Library/Application Support/com.renamr.app/settings.json` on macOS, -//! `~/.config/renamr/settings.json` on Linux) - not the original FileBot's config -//! location, since that's Java Preferences-backed and OS/JVM-specific; this is Renamr's +//! `~/Library/Application Support/com.auroracurator.app/settings.json` on macOS, +//! `~/.config/aurora-curator/settings.json` on Linux) - not the original FileBot's config +//! location, since that's Java Preferences-backed and OS/JVM-specific; this is Aurora Curator's //! own, analogous location for its own settings. use serde::{Deserialize, Serialize}; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ec0873a..47c9eca 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,8 +1,8 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "Renamr", + "productName": "Aurora Curator", "version": "0.1.0", - "identifier": "com.renamr.app", + "identifier": "com.auroracurator.app", "build": { "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build", @@ -12,7 +12,7 @@ "app": { "windows": [ { - "title": "Renamr", + "title": "Aurora Curator", "width": 1100, "height": 720, "minWidth": 720, diff --git a/src/components/RenamePanel.tsx b/src/components/RenamePanel.tsx index b5788ab..acb752d 100644 --- a/src/components/RenamePanel.tsx +++ b/src/components/RenamePanel.tsx @@ -31,7 +31,7 @@ interface FileEntry { ext: string; } -// Result of the local, filename-only season/episode matcher (renamr-core's +// Result of the local, filename-only season/episode matcher (aurora-curator-core's // `matching` module, exposed via the `guess_episode` Tauri command). No network calls - // this only recognizes patterns already present in the filename text itself. interface EpisodeGuess { @@ -40,7 +40,7 @@ interface EpisodeGuess { episode: number; } -// Result of the local, filename-only movie title/year matcher (renamr-core's +// Result of the local, filename-only movie title/year matcher (aurora-curator-core's // `matching::guess_movie`, exposed via the `guess_movie` Tauri command). Tried as a // fallback whenever `guess_episode` finds no season/episode pattern - a release name // is either a TV episode or a movie, never both. @@ -52,7 +52,7 @@ interface MovieGuess { // What runMatching resolved a file to, before it's written into the item's bindings. type MatchGuess = { kind: "tv"; episode: EpisodeGuess } | { kind: "movie"; movie: MovieGuess }; -// Result of the local, filename-only release-tag matcher (renamr-core's +// Result of the local, filename-only release-tag matcher (aurora-curator-core's // `matching::guess_release_info`, exposed via the `guess_release_info` Tauri command). // Independent of the TV/movie guess above - a release name carries (or doesn't carry) // these tags regardless of what kind of media it is, so this runs alongside whichever @@ -78,7 +78,7 @@ interface RenamePlanEntry { newName: string; } -// Mirrors renamr-core's `RenameOutcome` (serde-tagged on "status"). Conflict policy is +// Mirrors aurora-curator-core's `RenameOutcome` (serde-tagged on "status"). Conflict policy is // fixed at skip - a colliding target is never overwritten, just reported. type RenameOutcome = | { status: "renamed"; newPath: string } @@ -91,15 +91,15 @@ interface RenameResult { outcome: RenameOutcome; } -// Mirrors renamr-core's `RenameAction` - what actually happens at each computed target. -// "move" relocates the file in place (the only action Renamr had before); "copy" and +// Mirrors aurora-curator-core's `RenameAction` - what actually happens at each computed target. +// "move" relocates the file in place (the only action Aurora Curator had before); "copy" and // "symlink" both leave the source file exactly where it is and produce a new file // elsewhere, which is why only "move" updates the loaded item's own path/name (see // confirmRename below). type RenameAction = "move" | "copy" | "symlink"; -// Mirrors renamr-core's `ConflictPolicy` - what happens when a computed target already -// exists. "skip" (the default, and the only behavior Renamr had before) leaves the +// Mirrors aurora-curator-core's `ConflictPolicy` - what happens when a computed target already +// exists. "skip" (the default, and the only behavior Aurora Curator had before) leaves the // conflicting file alone; "autoNumber" saves alongside it as "Name (1).ext" instead; // "override" replaces it outright (irreversible for whatever gets overwritten). type ConflictPolicy = "skip" | "autoNumber" | "override"; @@ -115,7 +115,7 @@ interface FetchQuery { episode: number; } -// Mirrors renamr-core's `FetchOutcome` (serde-tagged on "status"). +// Mirrors aurora-curator-core's `FetchOutcome` (serde-tagged on "status"). type FetchOutcome = | { status: "found"; seriesName: string; episodeTitle: string; airDate: string | null } | { status: "notFound" } @@ -135,7 +135,7 @@ interface MovieFetchQuery { year: number | null; } -// Mirrors renamr-core's `MovieFetchOutcome` (serde-tagged on "status"). +// Mirrors aurora-curator-core's `MovieFetchOutcome` (serde-tagged on "status"). type MovieFetchOutcome = | { status: "found"; title: string; releaseDate: string | null } | { status: "notFound" } @@ -146,7 +146,7 @@ interface MovieFetchResult { outcome: MovieFetchOutcome; } -// Rename history / undo. Mirrors renamr-core's `history` module (serde-tagged on +// Rename history / undo. Mirrors aurora-curator-core's `history` module (serde-tagged on // "status" for the outcome, same convention as RenameOutcome/FetchOutcome above). interface HistoryEntry { source: string; @@ -263,9 +263,9 @@ const SAMPLE_ITEMS: Item[] = [ ]; // The user's own preferred naming scheme (their words: "I personally like {show name} - -// {season number}x{episode number} - {episode name}") - this is Renamr's default now, +// {season number}x{episode number} - {episode name}") - this is Aurora Curator's default now, // not just an example. `{show name}`/`{season number}`/etc. are multi-word plain-field -// binding names, which work via renamr-core's ExpressionFormat plain-field-name +// binding names, which work via aurora-curator-core's ExpressionFormat plain-field-name // fallback (ExpressionError-free even though they aren't valid Rhai identifiers). const SAMPLE_EXPRESSION = "{show name} - {season number}x{episode number} - {episode name}"; // The matching engine isn't ported yet, so real loaded files only have their own @@ -395,10 +395,10 @@ export default function RenamePanel() { const [renaming, setRenaming] = useState(false); // What to actually do at each computed target - chosen in the confirmation modal, // remembered across modal opens within the session (defaults to "move", matching - // Renamr's original and only behavior before copy/symlink existed). + // Aurora Curator's original and only behavior before copy/symlink existed). const [renameAction, setRenameAction] = useState("move"); // What to do when a computed target already exists - same remembered-across-opens - // pattern as renameAction, defaults to "skip" (Renamr's original and only behavior + // pattern as renameAction, defaults to "skip" (Aurora Curator's original and only behavior // before auto-number/override existed). const [conflictPolicy, setConflictPolicy] = useState("skip"); // TMDB token state for "Fetch Data". `null` = not checked yet, `false` = checked and @@ -545,10 +545,10 @@ export default function RenamePanel() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - // Local, filename-based season/episode/movie detection (renamr-core's `matching` + // Local, filename-based season/episode/movie detection (aurora-curator-core's `matching` // module). Tries `guess_episode` first; when a filename carries no season/episode // marker, falls back to `guess_movie` (a release name is either a TV episode or a - // movie, never both - see the doc comment on `guess_movie` in renamr-core). Populates + // movie, never both - see the doc comment on `guess_movie` in aurora-curator-core). Populates // TV bindings (`{n}`/`{s00e00}`/`{season}`/`{episode}`/etc.) or movie bindings // (`{n}`/`{y}`/etc.) accordingly - no network calls, no metadata lookup, so it's // distinct from (and much cheaper than) "Fetch Data" online matching. @@ -727,7 +727,7 @@ export default function RenamePanel() { // local state and report the outcome. Only "move" relocates the source file, so only // "move" updates a loaded item's own id/name/bindings to point at the new path - // "copy"/"symlink" leave the source exactly where it was and produce an additional - // file elsewhere that Renamr doesn't separately track as a loaded item. + // file elsewhere that Aurora Curator doesn't separately track as a loaded item. const confirmRename = async () => { if (!renamePlan || renamePlan.length === 0) return; setRenaming(true); @@ -805,7 +805,7 @@ export default function RenamePanel() { setRenamePlan((prev) => (prev ? prev.filter((p) => p.id !== id) : prev)); }; - // Rename history / undo - Renamr's only safety net beyond the confirm-before-execute + // Rename history / undo - Aurora Curator's only safety net beyond the confirm-before-execute // step, since a filesystem rename has no OS-level undo. `execute_rename` records a // batch of every successfully-renamed file after each Rename; this panel lists those // batches and can revert one back to its original paths. @@ -1310,7 +1310,7 @@ export default function RenamePanel() {

Match scans filenames locally for season/episode or movie title/year patterns, plus release-tag text like resolution, source (BluRay/HDTV/WEB-DL/…), video/audio codec, and release group — none of this - needs a network call, since it's all parsed straight from the filename itself (Renamr has no video/audio + needs a network call, since it's all parsed straight from the filename itself (Aurora Curator has no video/audio file prober, so a tag that isn't in the filename text just won't be available). Fetch Data resolves the season/episode or movie guess against real TMDB metadata for the real title, episode title, and air/release date — needs a free TMDB API token set in TMDB Settings first. A batch can diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 734024b..6797ec0 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -47,7 +47,7 @@ export default function Sidebar({

- Renamr + Aurora Curator v{APP_VERSION}
diff --git a/src/theme.css b/src/theme.css index f6b3e15..e407af4 100644 --- a/src/theme.css +++ b/src/theme.css @@ -1,6 +1,7 @@ -/* Renamr "Aurora" theme — ported 1:1 (hex values) from the original FB-Mod fork's +/* Aurora Curator's UI theme — ported 1:1 (hex values) from the original FB-Mod fork's AuroraTheme.java / HeaderPanel.java / MainFrame.java so the rewrite looks like a - continuation of that design rather than a random restyle. */ + continuation of that design rather than a random restyle. (The app takes its name, + "Aurora Curator", from this same Aurora theme.) */ :root { --dock: #08252b; --dock-deep: #051115;