subx_cli/cli/
sync_args.rs

1//! Audio-subtitle synchronization command-line arguments and options.
2//!
3//! This module defines the command-line interface for the `sync` subcommand,
4//! which handles timing alignment between video audio tracks and subtitle files.
5//! It supports both automatic synchronization using audio analysis and manual
6//! adjustment with specified time offsets.
7//!
8//! # Synchronization Methods
9//!
10//! ## Automatic Synchronization
11//! Uses advanced audio analysis to detect speech patterns and align them
12//! with subtitle timestamps:
13//! - **Speech detection**: Identifies speech segments in audio
14//! - **Pattern matching**: Correlates speech timing with subtitle timing
15//! - **Offset calculation**: Determines optimal time shift
16//! - **Confidence scoring**: Evaluates alignment quality
17//!
18//! ## Manual Synchronization
19//! Applies user-specified time offset to all subtitle entries:
20//! - Positive offset: Delays subtitles (subtitles appear later)
21//! - Negative offset: Advances subtitles (subtitles appear earlier)
22//! - Preserves relative timing between subtitle entries
23//!
24//! # Examples
25//!
26//! ```bash
27//! # Automatic synchronization
28//! subx sync video.mp4 subtitle.srt
29//!
30//! # Manual offset: delay subtitles by 2.5 seconds
31//! subx sync video.mp4 subtitle.srt --offset 2.5
32//!
33//! # Batch processing with custom parameters
34//! subx sync video.mp4 subtitle.srt --batch --range 10.0 --threshold 0.8
35//! ```
36
37// src/cli/sync_args.rs
38use clap::Args;
39use std::path::PathBuf;
40
41/// Command-line arguments for audio-subtitle synchronization.
42///
43/// The sync command aligns subtitle timing with video audio tracks using
44/// either automatic audio analysis or manual time offset adjustment.
45/// It provides fine-tuned control over the synchronization process with
46/// configurable parameters for different content types.
47///
48/// # Workflow
49///
50/// 1. **Audio Analysis**: Extract audio features from the video file
51/// 2. **Speech Detection**: Identify speech segments and timing
52/// 3. **Pattern Matching**: Correlate speech patterns with subtitle timing
53/// 4. **Offset Calculation**: Determine optimal time adjustment
54/// 5. **Validation**: Verify synchronization quality
55/// 6. **Application**: Apply timing adjustments to subtitle file
56///
57/// # Examples
58///
59/// ```rust
60/// use subx_cli::cli::SyncArgs;
61/// use std::path::PathBuf;
62///
63/// // Automatic synchronization
64/// let auto_args = SyncArgs {
65///     video: PathBuf::from("movie.mp4"),
66///     subtitle: PathBuf::from("movie.srt"),
67///     offset: None,
68///     batch: false,
69///     range: Some(15.0),
70///     threshold: Some(0.75),
71/// };
72///
73/// // Manual synchronization with 2-second delay
74/// let manual_args = SyncArgs {
75///     video: PathBuf::from("movie.mp4"),
76///     subtitle: PathBuf::from("movie.srt"),
77///     offset: Some(2.0),
78///     batch: false,
79///     range: None,
80///     threshold: None,
81/// };
82/// ```
83#[derive(Args, Debug)]
84pub struct SyncArgs {
85    /// Video file path for audio analysis.
86    ///
87    /// The video file from which audio will be extracted and analyzed
88    /// for speech pattern detection. Supports common video formats:
89    ///
90    /// # Supported Formats
91    /// - MP4, MKV, AVI (most common)
92    /// - MOV, WMV, FLV
93    /// - M4V, 3GP, WEBM
94    /// - VOB, TS, MTS
95    ///
96    /// # Requirements
97    /// - File must contain at least one audio track
98    /// - Audio track should contain speech (not just music/effects)
99    /// - Minimum duration of 30 seconds recommended for accuracy
100    ///
101    /// # Examples
102    /// ```bash
103    /// # Standard video file
104    /// subx sync /path/to/movie.mp4 subtitle.srt
105    ///
106    /// # High-definition video
107    /// subx sync "./Movies/Film (2023) [1080p].mkv" subtitle.srt
108    /// ```
109    pub video: PathBuf,
110
111    /// Subtitle file path to be synchronized.
112    ///
113    /// The subtitle file whose timing will be adjusted to match the
114    /// video's audio track. Supports all major subtitle formats:
115    ///
116    /// # Supported Formats
117    /// - SRT (SubRip): Most common format
118    /// - ASS/SSA (Advanced SubStation Alpha): Rich formatting
119    /// - VTT (WebVTT): Web-optimized format
120    /// - SUB (MicroDVD): Frame-based format
121    ///
122    /// # File Requirements
123    /// - Must contain valid timestamps
124    /// - Should have reasonable subtitle density (not too sparse)
125    /// - Text content should roughly correspond to audio speech
126    ///
127    /// # Examples
128    /// ```bash
129    /// # Various subtitle formats
130    /// subx sync video.mp4 subtitle.srt
131    /// subx sync video.mp4 subtitle.ass
132    /// subx sync video.mp4 subtitle.vtt
133    /// ```
134    pub subtitle: PathBuf,
135
136    /// Manual time offset in seconds (overrides automatic detection).
137    ///
138    /// When specified, disables automatic synchronization and applies
139    /// a fixed time offset to all subtitle entries. Positive values
140    /// delay subtitles (appear later), negative values advance them.
141    ///
142    /// # Precision
143    /// Supports fractional seconds with millisecond precision:
144    /// - 2.5 = 2 seconds, 500 milliseconds
145    /// - -1.25 = -1 second, -250 milliseconds
146    /// - 0.1 = 100 milliseconds
147    ///
148    /// # Use Cases
149    /// - **Fine-tuning**: Small adjustments after automatic sync
150    /// - **Known offset**: When you know the exact timing difference
151    /// - **Problematic audio**: When automatic detection fails
152    /// - **Batch processing**: Apply same offset to multiple files
153    ///
154    /// # Examples
155    /// ```bash
156    /// # Delay subtitles by 2.5 seconds
157    /// subx sync video.mp4 subtitle.srt --offset 2.5
158    ///
159    /// # Advance subtitles by 1 second
160    /// subx sync video.mp4 subtitle.srt --offset -1.0
161    ///
162    /// # Fine adjustment by 300ms
163    /// subx sync video.mp4 subtitle.srt --offset 0.3
164    /// ```
165    #[arg(long)]
166    pub offset: Option<f64>,
167
168    /// Enable batch processing mode for multiple file pairs.
169    ///
170    /// When enabled, optimizes processing for handling multiple video-subtitle
171    /// pairs efficiently. This mode provides enhanced performance and
172    /// consistent parameters across all processed files.
173    ///
174    /// # Batch Mode Features
175    /// - **Parallel processing**: Multiple files processed simultaneously
176    /// - **Consistent parameters**: Same sync settings for all files
177    /// - **Progress tracking**: Overall progress across all files
178    /// - **Error resilience**: Continues processing if individual files fail
179    ///
180    /// # File Discovery
181    /// In batch mode, the command can automatically discover matching pairs:
182    /// - Video and subtitle files with same base name
183    /// - Common naming patterns (e.g., movie.mp4 + movie.srt)
184    /// - Multiple subtitle languages (e.g., movie.en.srt, movie.es.srt)
185    ///
186    /// # Examples
187    /// ```bash
188    /// # Process multiple files in directory
189    /// subx sync --batch /path/to/videos/ /path/to/subtitles/
190    ///
191    /// # Batch with custom parameters
192    /// subx sync --batch --range 20.0 --threshold 0.85 videos/ subs/
193    /// ```
194    #[arg(long)]
195    pub batch: bool,
196
197    /// Maximum offset detection range in seconds.
198    ///
199    /// Defines the maximum time range (both positive and negative) within
200    /// which the automatic synchronization algorithm will search for the
201    /// optimal offset. This parameter balances detection accuracy with
202    /// processing time.
203    ///
204    /// # Default Behavior
205    /// If not specified, uses the value from configuration file
206    /// (`max_offset_seconds`). Common defaults are 10-30 seconds depending
207    /// on content type and expected synchronization accuracy.
208    ///
209    /// # Recommendations
210    /// - **Precise timing**: 5-10 seconds for high-quality sources
211    /// - **Standard content**: 10-20 seconds for most videos
212    /// - **Problematic sync**: 30-60 seconds for heavily offset content
213    /// - **Performance priority**: 5-15 seconds for faster processing
214    ///
215    /// # Trade-offs
216    /// - **Larger range**: Higher chance of finding correct offset, slower processing
217    /// - **Smaller range**: Faster processing, may miss large offsets
218    ///
219    /// # Examples
220    /// ```bash
221    /// # High precision with smaller range
222    /// subx sync video.mp4 subtitle.srt --range 5.0
223    ///
224    /// # Handle large offsets
225    /// subx sync video.mp4 subtitle.srt --range 60.0
226    ///
227    /// # Balanced approach
228    /// subx sync video.mp4 subtitle.srt --range 15.0
229    /// ```
230    #[arg(long)]
231    pub range: Option<f32>,
232
233    /// Correlation threshold for automatic synchronization (0.0-1.0).
234    ///
235    /// Sets the minimum correlation coefficient required between audio
236    /// speech patterns and subtitle timing for a synchronization to be
237    /// considered successful. Higher values require stronger correlation
238    /// but provide more reliable results.
239    ///
240    /// # Scale Interpretation
241    /// - **0.9-1.0**: Excellent correlation (very reliable)
242    /// - **0.8-0.9**: Good correlation (reliable for most content)
243    /// - **0.7-0.8**: Acceptable correlation (may need verification)
244    /// - **0.6-0.7**: Weak correlation (results questionable)
245    /// - **Below 0.6**: Poor correlation (likely incorrect sync)
246    ///
247    /// # Configuration Override
248    /// If not specified, uses the value from configuration file
249    /// (`correlation_threshold`). This allows consistent behavior
250    /// across different synchronization operations.
251    ///
252    /// # Content Type Recommendations
253    /// - **Dialog-heavy content**: 0.8-0.9 (speech patterns clear)
254    /// - **Action/music-heavy**: 0.7-0.8 (speech less prominent)
255    /// - **Documentary/interview**: 0.85-0.95 (clear speech patterns)
256    /// - **Animated content**: 0.75-0.85 (consistent voice patterns)
257    ///
258    /// # Examples
259    /// ```bash
260    /// # High precision requirement
261    /// subx sync video.mp4 subtitle.srt --threshold 0.9
262    ///
263    /// # More permissive for difficult content
264    /// subx sync video.mp4 subtitle.srt --threshold 0.7
265    ///
266    /// # Balanced approach
267    /// subx sync video.mp4 subtitle.srt --threshold 0.8
268    /// ```
269    #[arg(long)]
270    pub threshold: Option<f32>,
271}
272
273/// Synchronization method enumeration.
274///
275/// Defines the approach used for subtitle-audio alignment based on
276/// the provided command-line arguments. The method is automatically
277/// determined by the presence of manual offset parameters.
278///
279/// # Method Selection
280/// - **Manual**: When `--offset` parameter is provided
281/// - **Auto**: When no offset is specified (default behavior)
282///
283/// # Examples
284///
285/// ```rust
286/// use subx_cli::cli::{SyncArgs, SyncMethod};
287/// use std::path::PathBuf;
288///
289/// // Auto sync (no offset specified)
290/// let auto_args = SyncArgs {
291///     video: PathBuf::from("video.mp4"),
292///     subtitle: PathBuf::from("subtitle.srt"),
293///     offset: None,
294///     batch: false,
295///     range: None,
296///     threshold: None,
297/// };
298/// assert_eq!(auto_args.sync_method(), SyncMethod::Auto);
299///
300/// // Manual sync (offset specified)
301/// let manual_args = SyncArgs {
302///     video: PathBuf::from("video.mp4"),
303///     subtitle: PathBuf::from("subtitle.srt"),
304///     offset: Some(2.5),
305///     batch: false,
306///     range: None,
307///     threshold: None,
308/// };
309/// assert_eq!(manual_args.sync_method(), SyncMethod::Manual);
310/// ```
311#[derive(Debug, Clone, PartialEq)]
312pub enum SyncMethod {
313    /// Automatic synchronization using audio analysis.
314    ///
315    /// Performs sophisticated audio-subtitle correlation analysis:
316    /// 1. **Audio extraction**: Extract audio track from video
317    /// 2. **Speech detection**: Identify speech segments and pauses
318    /// 3. **Pattern analysis**: Create timing fingerprint
319    /// 4. **Correlation**: Match patterns with subtitle timing
320    /// 5. **Optimization**: Find best offset within specified range
321    Auto,
322
323    /// Manual synchronization using specified time offset.
324    ///
325    /// Applies a fixed time shift to all subtitle entries:
326    /// - Simple and fast operation
327    /// - Preserves relative timing between subtitles
328    /// - Useful for known timing differences
329    /// - No audio analysis required
330    Manual,
331}
332
333impl SyncArgs {
334    /// Determines the synchronization method based on provided arguments.
335    ///
336    /// This method automatically selects between manual and automatic
337    /// synchronization based on whether a manual offset was specified.
338    /// It provides a convenient way to branch synchronization logic.
339    ///
340    /// # Logic
341    /// - Returns `SyncMethod::Manual` if `offset` field is `Some(value)`
342    /// - Returns `SyncMethod::Auto` if `offset` field is `None`
343    ///
344    /// # Examples
345    ///
346    /// ```rust
347    /// use subx_cli::cli::{SyncArgs, SyncMethod};
348    /// use std::path::PathBuf;
349    ///
350    /// let args = SyncArgs {
351    ///     video: PathBuf::from("video.mp4"),
352    ///     subtitle: PathBuf::from("subtitle.srt"),
353    ///     offset: Some(1.5),
354    ///     batch: false,
355    ///     range: None,
356    ///     threshold: None,
357    /// };
358    ///
359    /// match args.sync_method() {
360    ///     SyncMethod::Manual => println!("Using manual offset: {}", args.offset.unwrap()),
361    ///     SyncMethod::Auto => println!("Using automatic synchronization"),
362    /// }
363    /// ```
364    pub fn sync_method(&self) -> SyncMethod {
365        if self.offset.is_some() {
366            SyncMethod::Manual
367        } else {
368            SyncMethod::Auto
369        }
370    }
371}
372
373#[cfg(test)]
374mod tests {
375    use super::*;
376
377    #[test]
378    fn test_sync_method_selection_manual() {
379        let args = SyncArgs {
380            video: PathBuf::from("video.mp4"),
381            subtitle: PathBuf::from("subtitle.srt"),
382            offset: Some(2.5),
383            batch: false,
384            range: None,
385            threshold: None,
386        };
387        assert_eq!(args.sync_method(), SyncMethod::Manual);
388    }
389
390    #[test]
391    fn test_sync_method_selection_auto() {
392        let args = SyncArgs {
393            video: PathBuf::from("video.mp4"),
394            subtitle: PathBuf::from("subtitle.srt"),
395            offset: None,
396            batch: false,
397            range: None,
398            threshold: None,
399        };
400        assert_eq!(args.sync_method(), SyncMethod::Auto);
401    }
402}