Files
mov-renamarr/src/cli.rs
2025-12-30 10:52:59 -05:00

158 lines
3.3 KiB
Rust

use std::path::PathBuf;
use std::str::FromStr;
use clap::{Parser, ValueEnum};
use serde::Deserialize;
#[derive(Parser, Debug)]
#[command(name = "mov-renamarr", version, about = "Rename movie files into Radarr-compatible naming")]
pub struct Cli {
#[arg(long, value_name = "DIR")]
pub input: PathBuf,
#[arg(long, value_name = "DIR")]
pub output: Option<PathBuf>,
#[arg(long, value_name = "PATH")]
pub config: Option<PathBuf>,
#[arg(long, value_enum)]
pub provider: Option<ProviderChoice>,
#[arg(long = "api-key-omdb")]
pub api_key_omdb: Option<String>,
#[arg(long = "api-key-tmdb")]
pub api_key_tmdb: Option<String>,
#[arg(long, value_name = "PATH")]
pub cache: Option<PathBuf>,
#[arg(long)]
pub refresh_cache: bool,
#[arg(long)]
pub dry_run: bool,
#[arg(long = "move", conflicts_with = "rename_in_place")]
pub move_files: bool,
#[arg(long = "rename-in-place", conflicts_with = "move_files")]
pub rename_in_place: bool,
#[arg(long)]
pub interactive: bool,
#[arg(
long,
value_name = "PATH",
num_args = 0..=1,
default_missing_value = "__DEFAULT__"
)]
pub report: Option<PathBuf>,
#[arg(long, value_enum)]
pub report_format: Option<ReportFormat>,
#[arg(long)]
pub sidecar_notes: bool,
#[arg(long)]
pub sidecars: bool,
#[arg(long)]
pub overwrite: bool,
#[arg(long)]
pub suffix: bool,
#[arg(long)]
pub min_score: Option<u8>,
#[arg(long)]
pub include_id: bool,
#[arg(long, value_name = "LIST")]
pub quality_tags: Option<String>,
#[arg(long, value_enum)]
pub color: Option<ColorMode>,
#[arg(long, value_enum)]
pub llm_mode: Option<LlmMode>,
#[arg(long, value_name = "URL")]
pub llm_endpoint: Option<String>,
#[arg(long, value_name = "NAME")]
pub llm_model: Option<String>,
#[arg(long, value_name = "SECONDS")]
pub llm_timeout: Option<u64>,
#[arg(long, value_name = "N")]
pub llm_max_tokens: Option<u32>,
#[arg(long, value_parser = parse_jobs_arg)]
pub jobs: Option<JobsArg>,
#[arg(long, value_parser = parse_jobs_arg)]
pub net_jobs: Option<JobsArg>,
#[arg(long, alias = "offline")]
pub no_lookup: bool,
#[arg(long)]
pub verbose: bool,
}
#[derive(Clone, Debug, ValueEnum, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ProviderChoice {
Auto,
Omdb,
Tmdb,
Both,
}
#[derive(Clone, Debug, ValueEnum, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ReportFormat {
Text,
Json,
Csv,
}
#[derive(Clone, Debug, ValueEnum, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ColorMode {
Auto,
Always,
Never,
}
#[derive(Clone, Debug, ValueEnum, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LlmMode {
Off,
Parse,
Assist,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum JobsArg {
Auto,
Fixed(usize),
}
fn parse_jobs_arg(value: &str) -> Result<JobsArg, String> {
if value.eq_ignore_ascii_case("auto") {
return Ok(JobsArg::Auto);
}
let parsed = usize::from_str(value).map_err(|_| "jobs must be an integer or 'auto'".to_string())?;
if parsed == 0 {
return Err("jobs must be >= 1".to_string());
}
Ok(JobsArg::Fixed(parsed))
}