1use clap::{Parser, Subcommand, Args};
4use std::path::PathBuf;
5
6use crate::VERSION;
7
8#[derive(Parser)]
10#[command(name = "audiobook-forge")]
11#[command(version = VERSION)]
12#[command(about = "Convert audiobook directories to M4B format with chapters and metadata")]
13#[command(long_about = "
14Audiobook Forge is a CLI tool that converts audiobook directories containing
15MP3 files into high-quality M4B audiobook files with proper chapters and metadata.
16
17Features:
18• Automatic quality detection and preservation
19• Smart chapter generation from multiple sources
20• Parallel batch processing
21• Metadata extraction and enhancement
22• Cover art embedding
23")]
24pub struct Cli {
25 #[command(subcommand)]
26 pub command: Commands,
27
28 #[arg(global = true, short, long)]
30 pub verbose: bool,
31}
32
33#[derive(Subcommand)]
34pub enum Commands {
35 Build(BuildArgs),
37
38 Organize(OrganizeArgs),
40
41 #[command(subcommand)]
43 Config(ConfigCommands),
44
45 #[command(subcommand)]
47 Metadata(MetadataCommands),
48
49 Match(MatchArgs),
51
52 Check,
54
55 Version,
57}
58
59#[derive(Args)]
60pub struct BuildArgs {
61 #[arg(short, long)]
63 pub root: Option<PathBuf>,
64
65 #[arg(short, long)]
67 pub out: Option<PathBuf>,
68
69 #[arg(short = 'j', long, value_parser = clap::value_parser!(u8).range(1..=8))]
71 pub parallel: Option<u8>,
72
73 #[arg(long)]
75 pub skip_existing: Option<bool>,
76
77 #[arg(long)]
79 pub force: bool,
80
81 #[arg(long)]
83 pub merge_m4b: bool,
84
85 #[arg(long)]
87 pub normalize: bool,
88
89 #[arg(long)]
91 pub dry_run: bool,
92
93 #[arg(long)]
95 pub prefer_stereo: Option<bool>,
96
97 #[arg(long, value_parser = ["auto", "files", "cue", "id3", "none"])]
99 pub chapter_source: Option<String>,
100
101 #[arg(long)]
103 pub cover_names: Option<String>,
104
105 #[arg(long)]
107 pub language: Option<String>,
108
109 #[arg(long)]
111 pub keep_temp: bool,
112
113 #[arg(long)]
115 pub delete_originals: bool,
116
117 #[arg(long, value_parser = ["low", "medium", "high", "ultra", "maximum", "source"])]
119 pub quality: Option<String>,
120
121 #[arg(long)]
123 pub aac_encoder: Option<String>,
124
125 #[arg(long, hide = true)]
127 pub use_apple_silicon_encoder: Option<bool>,
128
129 #[arg(long)]
131 pub fetch_audible: bool,
132
133 #[arg(long)]
135 pub audible_region: Option<String>,
136
137 #[arg(long)]
139 pub audible_auto_match: bool,
140
141 #[arg(long)]
143 pub config: Option<PathBuf>,
144}
145
146#[derive(Args)]
147pub struct OrganizeArgs {
148 #[arg(short, long)]
150 pub root: Option<PathBuf>,
151
152 #[arg(long)]
154 pub dry_run: bool,
155
156 #[arg(long)]
158 pub config: Option<PathBuf>,
159}
160
161#[derive(Subcommand)]
162pub enum ConfigCommands {
163 Init {
165 #[arg(long)]
167 force: bool,
168 },
169
170 Show {
172 #[arg(long)]
174 config: Option<PathBuf>,
175 },
176
177 Validate {
179 #[arg(long)]
181 config: Option<PathBuf>,
182 },
183
184 Path,
186
187 Edit,
189}
190
191#[derive(Subcommand)]
192pub enum MetadataCommands {
193 Fetch {
195 #[arg(long)]
197 asin: Option<String>,
198
199 #[arg(long)]
201 title: Option<String>,
202
203 #[arg(long)]
205 author: Option<String>,
206
207 #[arg(long, default_value = "us")]
209 region: String,
210
211 #[arg(long)]
213 output: Option<PathBuf>,
214 },
215
216 Enrich {
218 #[arg(long)]
220 file: PathBuf,
221
222 #[arg(long)]
224 asin: Option<String>,
225
226 #[arg(long)]
228 auto_detect: bool,
229
230 #[arg(long, default_value = "us")]
232 region: String,
233
234 #[arg(long)]
236 chapters: Option<PathBuf>,
237
238 #[arg(long, conflicts_with = "chapters")]
240 chapters_asin: Option<String>,
241
242 #[arg(long)]
244 update_chapters_only: bool,
245
246 #[arg(long, default_value = "interactive")]
248 merge_strategy: String,
249 },
250}
251
252#[derive(Args)]
254pub struct MatchArgs {
255 #[arg(long, short = 'f', conflicts_with = "dir")]
257 pub file: Option<PathBuf>,
258
259 #[arg(long, short = 'd', conflicts_with = "file")]
261 pub dir: Option<PathBuf>,
262
263 #[arg(long)]
265 pub title: Option<String>,
266
267 #[arg(long)]
269 pub author: Option<String>,
270
271 #[arg(long)]
273 pub auto: bool,
274
275 #[arg(long, default_value = "us")]
277 pub region: String,
278
279 #[arg(long)]
281 pub keep_cover: bool,
282
283 #[arg(long)]
285 pub dry_run: bool,
286}