1use serde::Deserialize;
7use serde::Serialize;
8
9use std::fmt::Display;
10use std::str;
11use time::format_description::BorrowedFormatItem;
12use time::macros::format_description;
13
14use crate::error;
15use time::Time;
16
17use super::ssa::SSA;
18use super::strip_bom;
19use super::vtt::{VTTLine, VTT};
20
21const TIME_FORMAT: &[BorrowedFormatItem] =
22 format_description!("[hour]:[minute]:[second],[subsecond digits:3]");
23
24#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
37pub struct SRT {
38 pub lines: Vec<SRTLine>,
39}
40
41#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
45pub struct SRTLine {
46 pub sequence_number: u32,
47 pub start: Time,
48 pub end: Time,
49 pub text: String,
50}
51
52impl SRT {
53 pub fn parse<S: AsRef<str>>(content: S) -> Result<SRT, SRTError> {
55 let mut line_num = 0;
56
57 let mut blocks = vec![vec![]];
58 for line in strip_bom(&content).lines() {
59 if line.trim().is_empty() {
60 if !blocks.last().unwrap().is_empty() {
61 blocks.push(vec![])
62 }
63 } else {
64 blocks.last_mut().unwrap().push(line)
65 }
66 }
67 if blocks.last().is_some_and(|b| b.is_empty()) {
68 blocks.remove(blocks.len() - 1);
69 }
70
71 let mut lines = vec![];
72 for block in blocks {
73 line_num += 1;
74
75 let mut block_lines = block.into_iter();
76
77 let sequence_number = block_lines
79 .next()
80 .ok_or(SRTError::new(
81 SRTErrorKind::Parse("invalid sequence number".to_string()),
82 line_num,
83 ))?
84 .trim()
85 .parse::<u32>()
86 .map_err(|e| SRTError::new(SRTErrorKind::Parse(e.to_string()), line_num))?;
87 line_num += 1;
88 let (start, end) = {
90 let (start, end) = block_lines
91 .next()
92 .ok_or(SRTError::new(
93 SRTErrorKind::Parse("invalid time range".to_string()),
94 line_num,
95 ))?
96 .split_once("-->")
97 .ok_or(SRTError::new(
98 SRTErrorKind::Parse("invalid time range".to_string()),
99 line_num,
100 ))?;
101 let start_time = Time::parse(start.trim(), TIME_FORMAT)
102 .map_err(|e| SRTError::new(SRTErrorKind::Parse(e.to_string()), line_num))?;
103 let end_time = Time::parse(end.trim(), TIME_FORMAT)
104 .map_err(|e| SRTError::new(SRTErrorKind::Parse(e.to_string()), line_num))?;
105 (start_time, end_time)
106 };
107 line_num += 1;
108 line_num += block_lines.len();
109 let text = block_lines.collect::<Vec<&str>>().join("\r\n");
111
112 lines.push(SRTLine {
113 sequence_number,
114 start,
115 end,
116 text,
117 })
118 }
119
120 Ok(SRT { lines })
121 }
122
123 pub fn to_ssa(&self) -> SSA {
125 self.to_vtt().to_ssa()
126 }
127 pub fn to_vtt(&self) -> VTT {
129 VTT {
130 regions: vec![],
131 styles: vec![],
132 lines: self
133 .lines
134 .iter()
135 .map(|l| VTTLine {
136 identifier: Some(l.sequence_number.to_string()),
137 start: l.start,
138 end: l.end,
139 text: l.text.replace("\r\n", "\n"),
140 ..Default::default()
141 })
142 .collect(),
143 }
144 }
145}
146
147impl Display for SRT {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 let mut blocks = vec![];
150
151 for line in &self.lines {
152 let mut block = vec![];
153
154 block.push(line.sequence_number.to_string());
155 block.push(format!(
156 "{} --> {}",
157 line.start.format(TIME_FORMAT).unwrap(),
158 line.end.format(TIME_FORMAT).unwrap()
159 ));
160 block.push(line.text.clone());
161
162 blocks.push(block)
163 }
164
165 write!(
166 f,
167 "{}",
168 blocks
169 .into_iter()
170 .map(|b| b.join("\r\n"))
171 .collect::<Vec<String>>()
172 .join("\r\n\r\n")
173 )
174 }
175}
176
177error! {
178 SRTError => SRTErrorKind {
179 Parse(String),
180 }
181}