use clap::{Parser, Subcommand, Args};
use std::path::PathBuf;
use crate::VERSION;
#[derive(Parser)]
#[command(name = "audiobook-forge")]
#[command(version = VERSION)]
#[command(about = "Convert audiobook directories to M4B format with chapters and metadata")]
#[command(long_about = "
Audiobook Forge is a CLI tool that converts audiobook directories containing
MP3 files into high-quality M4B audiobook files with proper chapters and metadata.
Features:
• Automatic quality detection and preservation
• Smart chapter generation from multiple sources
• Parallel batch processing
• Metadata extraction and enhancement
• Cover art embedding
")]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
#[arg(global = true, short, long)]
pub verbose: bool,
}
#[derive(Subcommand)]
pub enum Commands {
Build(BuildArgs),
Organize(OrganizeArgs),
#[command(subcommand)]
Config(ConfigCommands),
#[command(subcommand)]
Metadata(MetadataCommands),
Match(MatchArgs),
Check,
Version,
}
#[derive(Args)]
pub struct BuildArgs {
#[arg(short, long)]
pub root: Option<PathBuf>,
#[arg(short, long)]
pub out: Option<PathBuf>,
#[arg(short = 'j', long, value_parser = clap::value_parser!(u8).range(1..=8))]
pub parallel: Option<u8>,
#[arg(long)]
pub skip_existing: Option<bool>,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub merge_m4b: bool,
#[arg(long)]
pub normalize: bool,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub prefer_stereo: Option<bool>,
#[arg(long, value_parser = ["auto", "files", "cue", "id3", "none"])]
pub chapter_source: Option<String>,
#[arg(long)]
pub cover_names: Option<String>,
#[arg(long)]
pub language: Option<String>,
#[arg(long)]
pub keep_temp: bool,
#[arg(long)]
pub delete_originals: bool,
#[arg(long, value_parser = ["low", "medium", "high", "ultra", "maximum", "source"])]
pub quality: Option<String>,
#[arg(long)]
pub aac_encoder: Option<String>,
#[arg(long, hide = true)]
pub use_apple_silicon_encoder: Option<bool>,
#[arg(long)]
pub fetch_audible: bool,
#[arg(long)]
pub audible_region: Option<String>,
#[arg(long)]
pub audible_auto_match: bool,
#[arg(long)]
pub config: Option<PathBuf>,
}
#[derive(Args)]
pub struct OrganizeArgs {
#[arg(short, long)]
pub root: Option<PathBuf>,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub config: Option<PathBuf>,
}
#[derive(Subcommand)]
pub enum ConfigCommands {
Init {
#[arg(long)]
force: bool,
},
Show {
#[arg(long)]
config: Option<PathBuf>,
},
Validate {
#[arg(long)]
config: Option<PathBuf>,
},
Path,
Edit,
}
#[derive(Subcommand)]
pub enum MetadataCommands {
Fetch {
#[arg(long)]
asin: Option<String>,
#[arg(long)]
title: Option<String>,
#[arg(long)]
author: Option<String>,
#[arg(long, default_value = "us")]
region: String,
#[arg(long)]
output: Option<PathBuf>,
},
Enrich {
#[arg(long)]
file: PathBuf,
#[arg(long)]
asin: Option<String>,
#[arg(long)]
auto_detect: bool,
#[arg(long, default_value = "us")]
region: String,
#[arg(long)]
chapters: Option<PathBuf>,
#[arg(long, conflicts_with = "chapters")]
chapters_asin: Option<String>,
#[arg(long)]
update_chapters_only: bool,
#[arg(long, default_value = "interactive")]
merge_strategy: String,
},
}
#[derive(Args)]
pub struct MatchArgs {
#[arg(long, short = 'f', conflicts_with = "dir")]
pub file: Option<PathBuf>,
#[arg(long, short = 'd', conflicts_with = "file")]
pub dir: Option<PathBuf>,
#[arg(long)]
pub title: Option<String>,
#[arg(long)]
pub author: Option<String>,
#[arg(long)]
pub auto: bool,
#[arg(long, default_value = "us")]
pub region: String,
#[arg(long)]
pub keep_cover: bool,
#[arg(long)]
pub dry_run: bool,
}