use std::path::PathBuf;
use clap::Parser;
use strum::VariantArray as _;
#[derive(Parser, Debug)]
#[command(version, about)]
pub struct SacadArgs {
#[clap(flatten)]
pub query: SearchQuery,
#[clap(flatten)]
pub search_opts: SearchOptions,
pub output_filepath: PathBuf,
#[clap(flatten)]
pub image_proc: ImageProcessingArgs,
#[clap(short, long, default_value_t = log::Level::Info)]
pub verbosity: log::Level,
}
#[derive(Parser, Debug)]
#[command(version, about)]
pub struct SacadRecursiveArgs {
pub lib_root_dir: PathBuf,
#[clap(flatten)]
pub search_opts: SearchOptions,
#[clap(value_parser = CoverOutput::from_arg)]
pub output: CoverOutput,
#[clap(short, long)]
pub ignore_existing: bool,
#[clap(flatten)]
pub image_proc: ImageProcessingArgs,
#[clap(short, long, default_value_t = log::Level::Info)]
pub verbosity: log::Level,
}
#[derive(Clone, Debug)]
pub enum CoverOutput {
Embed,
Pattern(CoverOutputPattern<String>),
}
impl CoverOutput {
#[expect(clippy::unnecessary_wraps)]
fn from_arg(s: &str) -> Result<Self, std::convert::Infallible> {
if s == "+" {
Ok(CoverOutput::Embed)
} else {
Ok(CoverOutput::Pattern(CoverOutputPattern(s.to_owned())))
}
}
}
#[derive(Clone, Debug)]
pub struct CoverOutputPattern<S>(pub S);
#[derive(Parser, Debug)]
pub struct SearchQuery {
pub artist: String,
pub album: String,
}
#[derive(Parser, Debug)]
pub struct SearchOptions {
pub size: u32,
#[clap(short = 't', long = "size-tolerance", default_value_t = 25)]
pub size_tolerance_prct: u32,
#[clap(short = 's', long, default_values_t = SourceName::VARIANTS.to_vec())]
pub cover_sources: Vec<SourceName>,
}
impl SearchOptions {
pub(crate) fn matches_min_size(&self, size: u32) -> bool {
let min_size = self.size - self.size * self.size_tolerance_prct / 100;
size >= min_size
}
pub(crate) fn matches_max_size(&self, size: u32) -> bool {
debug_assert!(self.matches_min_size(size));
let max_size = self.size + self.size * self.size_tolerance_prct / 100;
size <= max_size
}
}
#[derive(Parser, Debug)]
pub struct ImageProcessingArgs {
#[clap(short, long)]
pub preserve_format: bool,
}
#[derive(
Debug,
Copy,
Clone,
Eq,
PartialEq,
Hash,
strum::EnumString,
strum::VariantArray,
strum::AsRefStr,
strum::Display,
)]
#[strum(serialize_all = "lowercase")]
#[expect(missing_docs)]
pub enum SourceName {
CoverArtArchive,
Deezer,
Discogs,
Itunes,
LastFm,
}