1use hex_color::HexColor;
2use serde::{Deserialize, Serialize};
3use serde_repr::{Deserialize_repr, Serialize_repr};
4#[derive(Debug, Serialize, Deserialize)]
5#[serde(rename = "timedtext")]
6pub struct TimedText {
9    #[serde(rename = "format")]
10    pub format: Option<String>,
11    pub head: Option<Head>,
12    pub body: Body,
13}
14impl TimedText {
15    pub fn from_str(s: &str) -> Result<Self, quick_xml::DeError> {
16        quick_xml::de::from_str(s)
17    }
18}
19
20#[derive(Debug, Serialize, Deserialize)]
21pub struct Head {
22    #[serde(rename = "pen")]
23    pub pen: Vec<Pen>,
24    #[serde(rename = "wp")]
25    pub wp: Vec<WindowPosition>,
26    #[serde(rename = "ws")]
27    pub ws: Vec<WindowStyle>,
28}
29
30#[derive(Debug, Serialize, Deserialize)]
31pub struct Pen {
44    #[serde(rename = "@id")]
46    pub id: Option<u32>,
47
48    #[serde(rename = "@b")]
50    pub bold: Option<bool>,
52
53    #[serde(rename = "@i")]
54    pub italic: Option<bool>,
56
57    #[serde(rename = "@u")]
58    pub underline: Option<bool>,
60
61    #[serde(rename = "@fc")]
63    pub foreground_color: Option<HexColor>,
64
65    #[serde(rename = "@fo")]
71    pub foreground_opacity: Option<u32>,
72
73    #[serde(rename = "@bc")]
75    pub background_color: Option<HexColor>,
76
77    #[serde(rename = "@bo")]
83    pub background_opacity: Option<u32>,
84
85    #[serde(rename = "@ec")]
87    pub edge_color: Option<HexColor>,
88
89    #[serde(rename = "@et")]
91    pub edge_type: Option<u32>,
92
93    #[serde(rename = "@sz")]
95    pub font_size: Option<u32>,
96
97    #[serde(rename = "@fs")]
98    pub font_style: Option<FontStyle>,
100
101    #[serde(rename = "@rb")]
102    pub ruby: Option<RubyPart>,
124
125    #[serde(rename = "@hg")]
126    pub packing: Option<u32>,
128}
129
130#[derive(Debug, Serialize_repr, Deserialize_repr)]
131#[repr(u32)]
132pub enum RubyPart {
133    None = 0,
134    Base = 1,
135    Parenthesis = 2,
136    BeforeText = 4,
137    AfterText = 5,
138}
139
140#[derive(Debug, Serialize_repr, Deserialize_repr)]
141#[repr(u32)]
142pub enum FontStyle {
143    CourierNew = 1,
144    TimesNewRoman = 2,
145    LucidaConsole = 3,
146    ComicSans = 5,
147    MonotypeCorsiva = 6,
148    CarriosGothic = 7,
149    #[serde(other)]
150    Roboto = 0,
151}
152
153impl Default for FontStyle {
154    fn default() -> Self {
155        FontStyle::Roboto
156    }
157}
158
159#[derive(Debug, Serialize_repr, Deserialize_repr)]
160#[repr(u32)]
161pub enum AnchorPoint {
162    TopLeft = 0,
163    TopCenter = 1,
164    TopRight = 2,
165    MiddleLeft = 3,
166    Center = 4,
167    MiddleRight = 5,
168    BottomLeft = 6,
169    BottomCenter = 7,
170    BottomRight = 8,
171}
172
173#[derive(Debug, Serialize, Deserialize)]
174#[serde(rename = "wp")]
176pub struct WindowPosition {
177    #[serde(rename = "@id")]
179    pub id: u32,
180    #[serde(rename = "@ap")]
181    pub anchor_point: Option<AnchorPoint>,
184
185    #[serde(rename = "@ah")]
187    pub anchor_horizontal: Option<i32>,
188
189    #[serde(rename = "@av")]
191    pub anchor_vertical: Option<i32>,
192}
193
194#[derive(Debug, Serialize, Deserialize)]
195#[serde(rename = "ws")]
196pub struct WindowStyle {
197    #[serde(rename = "@id")]
198    pub id: u32,
199    #[serde(rename = "@ju")]
200    pub justify: Option<u32>,
202
203    #[serde(rename = "@pd")]
206    pub pitch_direction: Option<Rotation>,
207
208    #[serde(rename = "@sd")]
210    pub skew_direction: Option<Rotation>,
211}
212
213#[derive(Debug, Serialize_repr, Deserialize_repr)]
214#[repr(u32)]
215pub enum Rotation {
216    Zero = 0,
217    Ninety = 1,
218    OneEighty = 2,
219    TwoSeventy = 3,
220}
221
222#[derive(Debug, Serialize, Deserialize)]
223pub struct Body {
224    #[serde(rename = "$value")]
226    pub elements: Vec<BodyElement>,
227}
228
229#[derive(Debug, Serialize, Deserialize)]
235pub struct Paragraph {
236    #[serde(rename = "$value")]
239    pub inner: Vec<BodyElement>,
241    #[serde(rename = "@t")]
243    pub timestamp: u64,
244    #[serde(rename = "@d")]
246    pub duration: u64,
247
248    #[serde(rename = "@wp")]
250    pub window_position: Option<u32>,
251
252    #[serde(rename = "@ws")]
254    pub window_style: Option<u32>,
255}
256
257#[derive(Debug, Serialize, Deserialize)]
260pub struct Span {
261    #[serde(rename = "$value")]
262    pub inner: Option<Vec<BodyElement>>,
263    #[serde(rename = "p")]
265    pub pen: Option<u32>,
266    }
269#[derive(Debug, Serialize, Deserialize)]
270pub struct Br;
271#[derive(Debug, Serialize, Deserialize)]
272pub struct Div {
273    #[serde(rename = "$value")]
274    pub elements: Vec<BodyElement>,
275}
276
277#[derive(Debug, Serialize, Deserialize)]
278pub enum BodyElement {
279    #[serde(rename = "$text")]
280    Text(String),
281    #[serde(rename = "p")]
282    Paragraph(Paragraph),
283    #[serde(rename = "s")]
284    Span(Span),
285    #[serde(rename = "br")]
286    Br(Br),
287    #[serde(rename = "div")]
288    Div(Vec<Self>),
289}
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294
295    #[test]
298    fn test_parse_file() {
299        let file = include_str!("../test/aishite.srv3");
300        let parse = TimedText::from_str(file).unwrap();
301
302        println!("{:#?}", parse);
303    }
304
305    #[test]
306    fn test_parse_file_unformatted() {
307        let file = include_str!("../test/mesmerizer.srv3.xml");
308        let parse = TimedText::from_str(file).unwrap();
309
310        println!("{:#?}", parse);
311    }
312}