subx_cli/cli/convert_args.rs
1//! Subtitle format conversion command-line arguments and options.
2//!
3//! This module defines the command-line interface for the `convert` subcommand,
4//! which handles subtitle format conversion between different standards like SRT,
5//! ASS, VTT, and SUB. It provides comprehensive format conversion capabilities
6//! with encoding support and optional file preservation.
7//!
8//! # Supported Formats
9//!
10//! - **SRT (SubRip)**: Most widely used subtitle format
11//! - **ASS (Advanced SubStation Alpha)**: Rich formatting and styling support
12//! - **VTT (WebVTT)**: Web-optimized subtitle format for HTML5 video
13//! - **SUB (MicroDVD/SubViewer)**: Frame-based subtitle format
14//!
15//! # Examples
16//!
17//! ```bash
18//! # Convert SRT to ASS format
19//! subx convert input.srt --format ass --output output.ass
20//!
21//! # Batch convert all SRT files in a directory to VTT
22//! subx convert ./subtitles/ --format vtt
23//!
24//! # Convert with specific encoding
25//! subx convert input.srt --format ass --encoding utf-8 --keep-original
26//! ```
27
28#![allow(clippy::needless_borrows_for_generic_args)]
29// src/cli/convert_args.rs
30use clap::{Args, ValueEnum};
31use std::path::PathBuf;
32
33/// Command-line arguments for subtitle format conversion.
34///
35/// The convert command transforms subtitle files between different formats
36/// while preserving timing information and content structure. It supports
37/// both single file and batch directory processing.
38///
39/// # Examples
40///
41/// ```rust
42/// use subx_cli::cli::ConvertArgs;
43/// use subx_cli::cli::OutputSubtitleFormat;
44/// use std::path::PathBuf;
45///
46/// let args = ConvertArgs {
47/// input: PathBuf::from("input.srt"),
48/// format: Some(OutputSubtitleFormat::Ass),
49/// output: Some(PathBuf::from("output.ass")),
50/// keep_original: true,
51/// encoding: "utf-8".to_string(),
52/// };
53/// ```
54#[derive(Args, Debug)]
55pub struct ConvertArgs {
56 /// Input file or directory path containing subtitle files.
57 ///
58 /// For single file conversion, specify the exact file path.
59 /// For batch processing, specify a directory path and all
60 /// supported subtitle files will be processed.
61 pub input: PathBuf,
62
63 /// Target output format for converted subtitles.
64 ///
65 /// If not specified, the default format from configuration
66 /// will be used. Supported formats include SRT, ASS, VTT, and SUB.
67 ///
68 /// # Examples
69 ///
70 /// ```bash
71 /// --format srt # Convert to SubRip format
72 /// --format ass # Convert to Advanced SubStation Alpha
73 /// --format vtt # Convert to WebVTT format
74 /// --format sub # Convert to MicroDVD/SubViewer format
75 /// ```
76 #[arg(long, value_enum)]
77 pub format: Option<OutputSubtitleFormat>,
78
79 /// Output file path for the converted subtitle.
80 ///
81 /// If not specified for single file conversion, the output will use
82 /// the same name as input with the appropriate extension.
83 /// For batch processing, files are saved with new extensions in the
84 /// same directory or a format-specific subdirectory.
85 #[arg(short, long)]
86 pub output: Option<PathBuf>,
87
88 /// Preserve the original files after conversion.
89 ///
90 /// By default, original files are preserved. Use this flag to explicitly
91 /// keep originals during batch processing operations.
92 #[arg(long)]
93 pub keep_original: bool,
94
95 /// Character encoding for input and output files.
96 ///
97 /// Specifies the character encoding to use when reading input files
98 /// and writing output files. UTF-8 is the default and recommended
99 /// encoding for maximum compatibility.
100 ///
101 /// # Supported Encodings
102 ///
103 /// - UTF-8 (default, recommended)
104 /// - UTF-16LE, UTF-16BE
105 /// - Windows-1252 (Western European)
106 /// - ISO-8859-1 (Latin-1)
107 /// - GBK, GB2312 (Chinese)
108 /// - Shift_JIS (Japanese)
109 ///
110 /// # Examples
111 ///
112 /// ```bash
113 /// --encoding utf-8 # UTF-8 encoding (default)
114 /// --encoding windows-1252 # Windows Western European
115 /// --encoding gbk # Chinese GBK encoding
116 /// ```
117 #[arg(long, default_value = "utf-8")]
118 pub encoding: String,
119}
120
121/// Supported output subtitle formats for conversion operations.
122///
123/// This enum defines all subtitle formats that SubX can generate as output.
124/// Each format has specific characteristics and use cases:
125///
126/// - **SRT**: Simple, widely supported, good for basic subtitles
127/// - **ASS**: Advanced formatting, styling, and positioning capabilities
128/// - **VTT**: Web-optimized, supports HTML5 video elements
129/// - **SUB**: Frame-based timing, used in some legacy systems
130///
131/// # Format Characteristics
132///
133/// | Format | Timing | Styling | Web Support | Compatibility |
134/// |--------|--------|---------|-------------|---------------|
135/// | SRT | Time | Basic | Good | Excellent |
136/// | ASS | Time | Rich | Limited | Good |
137/// | VTT | Time | Medium | Excellent | Good |
138/// | SUB | Frame | Basic | Poor | Limited |
139///
140/// # Examples
141///
142/// ```rust
143/// use subx_cli::cli::OutputSubtitleFormat;
144///
145/// let srt_format = OutputSubtitleFormat::Srt;
146/// assert_eq!(srt_format.as_str(), "srt");
147/// assert_eq!(srt_format.file_extension(), ".srt");
148/// ```
149#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
150pub enum OutputSubtitleFormat {
151 /// SubRip (.srt) format - most widely supported subtitle format.
152 ///
153 /// Features:
154 /// - Simple time-based format
155 /// - Basic text formatting (bold, italic, underline)
156 /// - Excellent player compatibility
157 /// - Small file size
158 Srt,
159
160 /// Advanced SubStation Alpha (.ass) format - professional subtitle format.
161 ///
162 /// Features:
163 /// - Rich styling and formatting options
164 /// - Precise positioning and animation
165 /// - Multiple font and color support
166 /// - Advanced timing controls
167 Ass,
168
169 /// WebVTT (.vtt) format - web-optimized subtitle format.
170 ///
171 /// Features:
172 /// - HTML5 video element support
173 /// - CSS-like styling capabilities
174 /// - Cue positioning and alignment
175 /// - Web accessibility features
176 Vtt,
177
178 /// MicroDVD/SubViewer (.sub) format - frame-based subtitle format.
179 ///
180 /// Features:
181 /// - Frame-based timing (not time-based)
182 /// - Basic text formatting
183 /// - Legacy format support
184 /// - Compact file structure
185 Sub,
186}
187
188impl OutputSubtitleFormat {
189 /// Returns the format identifier as a string.
190 ///
191 /// This method provides the lowercase string representation of the format,
192 /// which is used for command-line arguments and configuration files.
193 ///
194 /// # Examples
195 ///
196 /// ```rust
197 /// use subx_cli::cli::OutputSubtitleFormat;
198 ///
199 /// assert_eq!(OutputSubtitleFormat::Srt.as_str(), "srt");
200 /// assert_eq!(OutputSubtitleFormat::Ass.as_str(), "ass");
201 /// assert_eq!(OutputSubtitleFormat::Vtt.as_str(), "vtt");
202 /// assert_eq!(OutputSubtitleFormat::Sub.as_str(), "sub");
203 /// ```
204 pub fn as_str(&self) -> &'static str {
205 match self {
206 OutputSubtitleFormat::Srt => "srt",
207 OutputSubtitleFormat::Ass => "ass",
208 OutputSubtitleFormat::Vtt => "vtt",
209 OutputSubtitleFormat::Sub => "sub",
210 }
211 }
212
213 /// Returns the file extension for this format including the dot prefix.
214 ///
215 /// This method provides the standard file extension used for each
216 /// subtitle format, which is useful for generating output filenames.
217 ///
218 /// # Examples
219 ///
220 /// ```rust
221 /// use subx_cli::cli::OutputSubtitleFormat;
222 ///
223 /// assert_eq!(OutputSubtitleFormat::Srt.file_extension(), ".srt");
224 /// assert_eq!(OutputSubtitleFormat::Ass.file_extension(), ".ass");
225 /// assert_eq!(OutputSubtitleFormat::Vtt.file_extension(), ".vtt");
226 /// assert_eq!(OutputSubtitleFormat::Sub.file_extension(), ".sub");
227 /// ```
228 pub fn file_extension(&self) -> &'static str {
229 match self {
230 OutputSubtitleFormat::Srt => ".srt",
231 OutputSubtitleFormat::Ass => ".ass",
232 OutputSubtitleFormat::Vtt => ".vtt",
233 OutputSubtitleFormat::Sub => ".sub",
234 }
235 }
236}
237
238impl std::fmt::Display for OutputSubtitleFormat {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 write!(f, "{}", self.as_str())
241 }
242}
243
244// Test parameter parsing behavior
245#[cfg(test)]
246mod tests {
247 use super::*;
248 use crate::cli::{Cli, Commands};
249 use clap::Parser;
250 use std::path::PathBuf;
251
252 #[test]
253 fn test_convert_args_default_values() {
254 let cli = Cli::try_parse_from(&["subx-cli", "convert", "in_path"]).unwrap();
255 let args = match cli.command {
256 Commands::Convert(c) => c,
257 _ => panic!("Expected Convert command"),
258 };
259 assert_eq!(args.input, PathBuf::from("in_path"));
260 assert_eq!(args.format, None);
261 assert_eq!(args.output, None);
262 assert!(!args.keep_original);
263 assert_eq!(args.encoding, "utf-8");
264 }
265
266 #[test]
267 fn test_convert_args_parsing() {
268 let cli = Cli::try_parse_from(&[
269 "subx-cli",
270 "convert",
271 "in",
272 "--format",
273 "vtt",
274 "--output",
275 "out",
276 "--keep-original",
277 "--encoding",
278 "gbk",
279 ])
280 .unwrap();
281 let args = match cli.command {
282 Commands::Convert(c) => c,
283 _ => panic!("Expected Convert command"),
284 };
285 assert_eq!(args.input, PathBuf::from("in"));
286 assert_eq!(args.format.unwrap(), OutputSubtitleFormat::Vtt);
287 assert_eq!(args.output, Some(PathBuf::from("out")));
288 assert!(args.keep_original);
289 assert_eq!(args.encoding, "gbk");
290 }
291}