1pub mod common;
6pub mod idx;
7pub mod microdvd;
8pub mod srt;
9pub mod ssa;
10pub mod vobsub;
11
12use crate::errors::*;
13use crate::SubtitleEntry;
14use crate::SubtitleFileInterface;
15use encoding_rs::Encoding;
16use std::ffi::OsStr;
17use chardet::{charset2encoding, detect};
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum SubtitleFormat {
22 SubRip,
24
25 SubStationAlpha,
27
28 VobSubIdx,
30
31 VobSubSub,
33
34 MicroDVD,
36}
37
38#[derive(Clone, Debug)]
39pub enum SubtitleFile {
41 SubRipFile(srt::SrtFile),
43
44 SubStationAlpha(ssa::SsaFile),
46
47 VobSubIdxFile(idx::IdxFile),
49
50 VobSubSubFile(vobsub::VobFile),
52
53 MicroDVDFile(microdvd::MdvdFile),
55}
56
57impl SubtitleFile {
58 pub fn get_subtitle_entries(&self) -> Result<Vec<SubtitleEntry>> {
60 match self {
61 SubtitleFile::SubRipFile(f) => f.get_subtitle_entries(),
62 SubtitleFile::SubStationAlpha(f) => f.get_subtitle_entries(),
63 SubtitleFile::VobSubIdxFile(f) => f.get_subtitle_entries(),
64 SubtitleFile::VobSubSubFile(f) => f.get_subtitle_entries(),
65 SubtitleFile::MicroDVDFile(f) => f.get_subtitle_entries(),
66 }
67 }
68
69 pub fn update_subtitle_entries(&mut self, i: &[SubtitleEntry]) -> Result<()> {
81 match self {
82 SubtitleFile::SubRipFile(f) => f.update_subtitle_entries(i),
83 SubtitleFile::SubStationAlpha(f) => f.update_subtitle_entries(i),
84 SubtitleFile::VobSubIdxFile(f) => f.update_subtitle_entries(i),
85 SubtitleFile::VobSubSubFile(f) => f.update_subtitle_entries(i),
86 SubtitleFile::MicroDVDFile(f) => f.update_subtitle_entries(i),
87 }
88 }
89
90 pub fn to_data(&self) -> Result<Vec<u8>> {
93 match self {
94 SubtitleFile::SubRipFile(f) => f.to_data(),
95 SubtitleFile::SubStationAlpha(f) => f.to_data(),
96 SubtitleFile::VobSubIdxFile(f) => f.to_data(),
97 SubtitleFile::VobSubSubFile(f) => f.to_data(),
98 SubtitleFile::MicroDVDFile(f) => f.to_data(),
99 }
100 }
101}
102
103impl From<srt::SrtFile> for SubtitleFile {
104 fn from(f: srt::SrtFile) -> SubtitleFile {
105 SubtitleFile::SubRipFile(f)
106 }
107}
108
109impl From<ssa::SsaFile> for SubtitleFile {
110 fn from(f: ssa::SsaFile) -> SubtitleFile {
111 SubtitleFile::SubStationAlpha(f)
112 }
113}
114
115impl From<idx::IdxFile> for SubtitleFile {
116 fn from(f: idx::IdxFile) -> SubtitleFile {
117 SubtitleFile::VobSubIdxFile(f)
118 }
119}
120
121impl From<vobsub::VobFile> for SubtitleFile {
122 fn from(f: vobsub::VobFile) -> SubtitleFile {
123 SubtitleFile::VobSubSubFile(f)
124 }
125}
126
127impl From<microdvd::MdvdFile> for SubtitleFile {
128 fn from(f: microdvd::MdvdFile) -> SubtitleFile {
129 SubtitleFile::MicroDVDFile(f)
130 }
131}
132
133impl SubtitleFormat {
134 pub fn get_name(&self) -> &'static str {
136 match *self {
137 SubtitleFormat::SubRip => ".srt (SubRip)",
138 SubtitleFormat::SubStationAlpha => ".ssa (SubStation Alpha)",
139 SubtitleFormat::VobSubIdx => ".idx (VobSub)",
140 SubtitleFormat::VobSubSub => ".sub (VobSub)",
141 SubtitleFormat::MicroDVD => ".sub (MicroDVD)",
142 }
143 }
144}
145
146#[test]
147fn test_subtitle_format_by_extension() {
148 assert_eq!(get_subtitle_format_by_extension(Some(OsStr::new("srt"))), Some(SubtitleFormat::SubRip));
150}
151
152pub fn get_subtitle_format_by_extension(extension: Option<&OsStr>) -> Option<SubtitleFormat> {
163 let _ext_opt: Option<&OsStr> = extension.into();
164
165 if _ext_opt == Some(OsStr::new("srt")) {
166 Some(SubtitleFormat::SubRip)
167 } else if _ext_opt == Some(OsStr::new("ssa")) || _ext_opt == Some(OsStr::new("ass")) {
168 Some(SubtitleFormat::SubStationAlpha)
169 } else if _ext_opt == Some(OsStr::new("idx")) {
170 Some(SubtitleFormat::VobSubIdx)
171 } else {
172 None
173 }
174}
175
176pub fn is_valid_extension_for_subtitle_format(extension: Option<&OsStr>, format: SubtitleFormat) -> bool {
180 match format {
181 SubtitleFormat::SubRip => extension == Some(OsStr::new("srt")),
182 SubtitleFormat::SubStationAlpha => extension == Some(OsStr::new("ssa")) || extension == Some(OsStr::new("ass")),
183 SubtitleFormat::VobSubIdx => extension == Some(OsStr::new("idx")),
184 SubtitleFormat::VobSubSub => extension == Some(OsStr::new("sub")),
185 SubtitleFormat::MicroDVD => extension == Some(OsStr::new("sub")),
186 }
187}
188
189pub fn get_subtitle_format_by_extension_err(extension: Option<&OsStr>) -> Result<SubtitleFormat> {
196 get_subtitle_format_by_extension(extension).ok_or_else(|| ErrorKind::UnknownFileFormat.into())
197}
198
199pub fn get_subtitle_format(extension: Option<&OsStr>, content: &[u8]) -> Option<SubtitleFormat> {
209 if extension == Some(OsStr::new("sub")) {
210 if content.iter().take(4).cloned().eq([0x00, 0x00, 0x01, 0xba].iter().cloned()) {
212 Some(SubtitleFormat::VobSubSub)
213 } else {
214 Some(SubtitleFormat::MicroDVD)
215 }
216 } else {
217 get_subtitle_format_by_extension(extension)
218 }
219}
220
221pub fn get_subtitle_format_err(extension: Option<&OsStr>, content: &[u8]) -> Result<SubtitleFormat> {
226 get_subtitle_format(extension, content).ok_or_else(|| ErrorKind::UnknownFileFormat.into())
227}
228
229pub fn parse_str(format: SubtitleFormat, content: &str, fps: f64) -> Result<SubtitleFile> {
237 match format {
238 SubtitleFormat::SubRip => Ok(srt::SrtFile::parse(content)?.into()),
239 SubtitleFormat::SubStationAlpha => Ok(ssa::SsaFile::parse(content)?.into()),
240 SubtitleFormat::VobSubIdx => Ok(idx::IdxFile::parse(content)?.into()),
241 SubtitleFormat::VobSubSub => Err(ErrorKind::TextFormatOnly.into()),
242 SubtitleFormat::MicroDVD => Ok(microdvd::MdvdFile::parse(content, fps)?.into()),
243 }
244}
245
246fn decode_bytes_to_string(content: &[u8], encoding: Option<&'static Encoding>) -> Result<String> {
248 let det_encoding = match encoding {
249 Some(encoding) => encoding,
250 None => {
251 let (charset, _, _) = detect(content);
252 let encoding_name = charset2encoding(&charset);
253 Encoding::for_label_no_replacement(encoding_name.as_bytes()).ok_or(ErrorKind::EncodingDetectionError)?
254 }
255 };
256
257 let (decoded, _, replaced) = det_encoding.decode(content);
258 if replaced {
259 Err(Error::from(ErrorKind::DecodingError))
260 } else {
261 Ok(decoded.into_owned())
262 }
263}
264
265pub fn parse_bytes(format: SubtitleFormat, content: &[u8], encoding: Option<&'static Encoding>, fps: f64) -> Result<SubtitleFile> {
280 match format {
281 SubtitleFormat::SubRip => Ok(srt::SrtFile::parse(&decode_bytes_to_string(content, encoding)?)?.into()),
282 SubtitleFormat::SubStationAlpha => Ok(ssa::SsaFile::parse(&decode_bytes_to_string(content, encoding)?)?.into()),
283 SubtitleFormat::VobSubIdx => Ok(idx::IdxFile::parse(&decode_bytes_to_string(content, encoding)?)?.into()),
284 SubtitleFormat::VobSubSub => Ok(vobsub::VobFile::parse(content)?.into()),
285 SubtitleFormat::MicroDVD => Ok(microdvd::MdvdFile::parse(&decode_bytes_to_string(content, encoding)?, fps)?.into()),
286 }
287}