subx_cli/core/formats/
transformers.rs

1//! Subtitle transformers for converting between different subtitle formats.
2//!
3//! This module provides utility methods to transform subtitle objects
4//! into various target formats using the `FormatConverter`.
5//!
6//! # Examples
7//!
8//! ```rust,ignore
9//! use subx_cli::core::formats::{FormatConverter, Subtitle};
10//! // Convert a subtitle object to a target format
11//! let converter = FormatConverter::new();
12//! let transformed = converter.transform_subtitle(subtitle.clone(), "ass").unwrap();
13//! ```
14
15use crate::core::formats::converter::FormatConverter;
16use crate::core::formats::{Subtitle, SubtitleFormatType};
17
18impl FormatConverter {
19    /// Transforms a subtitle object into the target format.
20    ///
21    /// # Arguments
22    ///
23    /// * `subtitle` - The subtitle object to transform.
24    /// * `target_format` - The desired subtitle format identifier (e.g., "ass", "srt").
25    ///
26    /// # Returns
27    ///
28    /// A `Result<Subtitle>` containing the transformed subtitle object or an error.
29    pub(crate) fn transform_subtitle(
30        &self,
31        subtitle: Subtitle,
32        target_format: &str,
33    ) -> crate::Result<Subtitle> {
34        match (subtitle.format.as_str(), target_format) {
35            ("srt", "ass") => self.srt_to_ass(subtitle),
36            ("ass", "srt") => self.ass_to_srt(subtitle),
37            ("srt", "vtt") => self.srt_to_vtt(subtitle),
38            ("vtt", "srt") => self.vtt_to_srt(subtitle),
39            ("ass", "vtt") => self.ass_to_vtt(subtitle),
40            ("vtt", "ass") => self.vtt_to_ass(subtitle),
41            (source, target) if source == target => Ok(subtitle),
42            _ => Err(crate::error::SubXError::subtitle_format(
43                subtitle.format.to_string(),
44                format!(
45                    "Unsupported conversion: {} -> {}",
46                    subtitle.format, target_format
47                ),
48            )),
49        }
50    }
51
52    /// SRT to ASS conversion
53    pub(crate) fn srt_to_ass(&self, mut subtitle: Subtitle) -> crate::Result<Subtitle> {
54        let _default_style = crate::core::formats::ass::AssStyle {
55            name: "Default".to_string(),
56            font_name: "Arial".to_string(),
57            font_size: 16,
58            primary_color: crate::core::formats::ass::Color::white(),
59            secondary_color: crate::core::formats::ass::Color::red(),
60            outline_color: crate::core::formats::ass::Color::black(),
61            shadow_color: crate::core::formats::ass::Color::black(),
62            bold: false,
63            italic: false,
64            underline: false,
65            alignment: 2,
66        };
67        for entry in &mut subtitle.entries {
68            if self.config.preserve_styling {
69                entry.styling = Some(self.extract_srt_styling(&entry.text)?);
70            }
71            entry.text = self.convert_srt_tags_to_ass(&entry.text);
72        }
73        subtitle.format = SubtitleFormatType::Ass;
74        subtitle.metadata.original_format = SubtitleFormatType::Srt;
75        Ok(subtitle)
76    }
77
78    /// ASS to SRT conversion
79    pub(crate) fn ass_to_srt(&self, mut subtitle: Subtitle) -> crate::Result<Subtitle> {
80        for entry in &mut subtitle.entries {
81            entry.text = self.strip_ass_tags(&entry.text);
82            if self.config.preserve_styling {
83                entry.text = self.convert_ass_tags_to_srt(&entry.text);
84            }
85            entry.styling = None;
86        }
87        subtitle.format = SubtitleFormatType::Srt;
88        Ok(subtitle)
89    }
90
91    /// SRT to VTT conversion
92    pub(crate) fn srt_to_vtt(&self, mut subtitle: Subtitle) -> crate::Result<Subtitle> {
93        subtitle.metadata.title = Some("WEBVTT".to_string());
94        for entry in &mut subtitle.entries {
95            entry.text = self.convert_srt_tags_to_vtt(&entry.text);
96        }
97        subtitle.format = SubtitleFormatType::Vtt;
98        Ok(subtitle)
99    }
100
101    /// ASS to VTT conversion
102    pub(crate) fn ass_to_vtt(&self, subtitle: Subtitle) -> crate::Result<Subtitle> {
103        // First convert ASS to SRT, then to VTT
104        let subtitle = self.ass_to_srt(subtitle)?;
105        self.srt_to_vtt(subtitle)
106    }
107
108    /// VTT to SRT conversion
109    pub(crate) fn vtt_to_srt(&self, mut subtitle: Subtitle) -> crate::Result<Subtitle> {
110        // VTT can preserve or remove HTML style tags
111        for entry in &mut subtitle.entries {
112            if self.config.preserve_styling {
113                entry.text = self.convert_vtt_tags_to_srt(&entry.text);
114            } else {
115                entry.text = self.strip_vtt_tags(&entry.text);
116            }
117            entry.styling = None;
118        }
119        subtitle.format = SubtitleFormatType::Srt;
120        Ok(subtitle)
121    }
122
123    /// VTT to ASS conversion
124    pub(crate) fn vtt_to_ass(&self, subtitle: Subtitle) -> crate::Result<Subtitle> {
125        // First convert VTT to SRT, then to ASS
126        let subtitle = self.vtt_to_srt(subtitle)?;
127        self.srt_to_ass(subtitle)
128    }
129}