Renders a naming-scheme-style expression per loaded file via the same render_expression engine the Rename panel's live preview uses, fed by the same local guess_episode/guess_movie/guess_release_info matching Filter already uses. Copy List and Export to File... (a new export_text_list Tauri command - the only new backend surface this feature needed) round it out. Closes out all six original sidebar panels as real screens.
138 lines
5.7 KiB
Rust
138 lines
5.7 KiB
Rust
mod cli;
|
|
mod episodes;
|
|
mod files;
|
|
mod history;
|
|
mod list;
|
|
mod metadata;
|
|
mod presets;
|
|
mod settings;
|
|
mod sfv;
|
|
mod subtitles;
|
|
|
|
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;
|
|
|
|
/// Renders a naming-scheme expression against a set of binding values.
|
|
/// This is the Tauri-facing entry point into the core format engine, used by the
|
|
/// rename-preview panel in the UI so users see live results as they edit a pattern.
|
|
#[tauri::command]
|
|
fn render_expression(expression: String, bindings: HashMap<String, String>) -> Result<String, String> {
|
|
let compiled = ExpressionFormat::compile(&expression).map_err(|e| e.to_string())?;
|
|
compiled
|
|
.format(&string_bindings(bindings))
|
|
.map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// Guesses a season/episode number pair (and series name) from a filename using local
|
|
/// regex patterns only - no network calls, no metadata lookup. Returns `None` when the
|
|
/// filename doesn't carry a recognizable season/episode marker (movies, already-clean
|
|
/// names, etc).
|
|
#[tauri::command]
|
|
fn guess_episode(filename: String) -> Option<EpisodeGuess> {
|
|
matching::guess_episode(&filename)
|
|
}
|
|
|
|
/// Guesses a movie title (and release year, if present) from a filename using local
|
|
/// regex/heuristic patterns only - no network calls. Callers should try
|
|
/// `guess_episode` first and only fall back to this when it returns `None`; see
|
|
/// `matching::guess_movie` for why.
|
|
#[tauri::command]
|
|
fn guess_movie(filename: String) -> Option<MovieGuess> {
|
|
matching::guess_movie(&filename)
|
|
}
|
|
|
|
/// 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 (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
|
|
/// it's an episode or a movie.
|
|
#[tauri::command]
|
|
fn guess_release_info(filename: String) -> Option<ReleaseInfo> {
|
|
matching::guess_release_info(&filename)
|
|
}
|
|
|
|
/// Executes a batch of planned on-disk rename/copy/symlink operations (optionally
|
|
/// 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
|
|
/// plan and both choices, and gotten explicit confirmation before calling this. Runs
|
|
/// off the main thread since real filesystem I/O shouldn't block the UI.
|
|
///
|
|
/// Every successfully-produced item is recorded to the rename history log afterward
|
|
/// (see `history::record_batch`), tagged with `action`, so it can be undone later from
|
|
/// the History panel - a Move undo moves the file back, a Copy/Symlink undo just
|
|
/// removes what was created. `conflict` is NOT recorded - undoing always uses its own
|
|
/// fixed skip-on-conflict policy regardless of what the original rename used.
|
|
#[tauri::command]
|
|
async fn execute_rename(
|
|
app: AppHandle,
|
|
items: Vec<RenamePlanItem>,
|
|
action: RenameAction,
|
|
conflict: ConflictPolicy,
|
|
) -> Vec<RenameResult> {
|
|
let results = tauri::async_runtime::spawn_blocking(move || rename::execute_renames(&items, action, conflict))
|
|
.await
|
|
.unwrap_or_default();
|
|
history::record_batch(&app, &results, action);
|
|
results
|
|
}
|
|
|
|
/// Entry point for the `-rename` command-line mode - see `cli.rs`'s module doc. Never
|
|
/// builds a Tauri `App`/`Builder` at all, unlike [`run`] below. Returns the process
|
|
/// exit code for `main.rs` to pass to `std::process::exit`.
|
|
pub fn run_cli(args: Vec<String>) -> i32 {
|
|
cli::run(args)
|
|
}
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
tauri::Builder::default()
|
|
.plugin(tauri_plugin_dialog::init())
|
|
.invoke_handler(tauri::generate_handler![
|
|
render_expression,
|
|
guess_episode,
|
|
guess_movie,
|
|
guess_release_info,
|
|
execute_rename,
|
|
metadata::fetch_metadata,
|
|
metadata::fetch_movie_metadata,
|
|
settings::get_tmdb_token,
|
|
settings::save_tmdb_token,
|
|
settings::get_omdb_api_key,
|
|
settings::save_omdb_api_key,
|
|
settings::get_tv_metadata_source,
|
|
settings::save_tv_metadata_source,
|
|
settings::get_movie_metadata_source,
|
|
settings::save_movie_metadata_source,
|
|
settings::get_opensubtitles_api_key,
|
|
settings::save_opensubtitles_api_key,
|
|
settings::get_opensubtitles_username,
|
|
settings::has_opensubtitles_password,
|
|
settings::save_opensubtitles_login,
|
|
subtitles::search_subtitles,
|
|
subtitles::download_subtitle,
|
|
episodes::browse_episodes,
|
|
sfv::compute_checksums,
|
|
sfv::save_checksum_file,
|
|
sfv::verify_checksum_file,
|
|
list::export_text_list,
|
|
history::list_rename_history,
|
|
history::undo_rename_batch,
|
|
presets::list_presets,
|
|
presets::save_preset,
|
|
presets::delete_preset,
|
|
files::pick_files,
|
|
files::pick_folder,
|
|
files::expand_dropped_paths,
|
|
])
|
|
.run(tauri::generate_context!())
|
|
.expect("error while running Aurora Curator");
|
|
}
|