1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
pub mod common;
pub mod idx;
pub mod microdvd;
pub mod srt;
pub mod ssa;
pub mod vobsub;
use encoding_rs::Encoding;
use errors::*;
use SubtitleFile;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SubtitleFormat {
SubRip,
SubStationAlpha,
VobSubIdx,
VobSubSub,
MicroDVD,
}
impl SubtitleFormat {
pub fn get_name(&self) -> &'static str {
match *self {
SubtitleFormat::SubRip => ".srt (SubRip)",
SubtitleFormat::SubStationAlpha => ".ssa (SubStation Alpha)",
SubtitleFormat::VobSubIdx => ".idx (VobSub)",
SubtitleFormat::VobSubSub => ".sub (VobSub)",
SubtitleFormat::MicroDVD => ".sub (MicroDVD)",
}
}
}
pub fn get_subtitle_format_by_ending(ending: &str) -> Option<SubtitleFormat> {
if ending.ends_with(".srt") {
Some(SubtitleFormat::SubRip)
} else if ending.ends_with(".ssa") || ending.ends_with(".ass") {
Some(SubtitleFormat::SubStationAlpha)
} else if ending.ends_with(".idx") {
Some(SubtitleFormat::VobSubIdx)
} else {
None
}
}
pub fn get_subtitle_format_by_ending_err(ending: &str) -> Result<SubtitleFormat> {
get_subtitle_format_by_ending(ending).ok_or_else(|| ErrorKind::UnknownFileFormat.into())
}
pub fn get_subtitle_format(ending: &str, content: &[u8]) -> Option<SubtitleFormat> {
if ending.ends_with(".sub") {
if content.iter().take(4).cloned().eq([0x00, 0x00, 0x01, 0xba].iter().cloned()) {
Some(SubtitleFormat::VobSubSub)
} else {
Some(SubtitleFormat::MicroDVD)
}
} else {
get_subtitle_format_by_ending(ending)
}
}
pub fn get_subtitle_format_err(ending: &str, content: &[u8]) -> Result<SubtitleFormat> {
get_subtitle_format(ending, content).ok_or_else(|| ErrorKind::UnknownFileFormat.into())
}
pub trait ClonableSubtitleFile: SubtitleFile + Send + Sync {
fn clone_box(&self) -> Box<ClonableSubtitleFile>;
}
impl<T> ClonableSubtitleFile for T
where
T: SubtitleFile + Clone + Send + Sync + 'static,
{
fn clone_box(&self) -> Box<ClonableSubtitleFile> {
Box::new(Clone::clone(self))
}
}
impl Clone for Box<ClonableSubtitleFile> {
fn clone(&self) -> Box<ClonableSubtitleFile> {
self.clone_box()
}
}
pub fn parse_str(format: SubtitleFormat, content: &str, fps: f64) -> Result<Box<ClonableSubtitleFile>> {
match format {
SubtitleFormat::SubRip => Ok(Box::new(srt::SrtFile::parse(content)?)),
SubtitleFormat::SubStationAlpha => Ok(Box::new(ssa::SsaFile::parse(content)?)),
SubtitleFormat::VobSubIdx => Ok(Box::new(idx::IdxFile::parse(content)?)),
SubtitleFormat::VobSubSub => Err(ErrorKind::TextFormatOnly.into()),
SubtitleFormat::MicroDVD => Ok(Box::new(microdvd::MdvdFile::parse(content, fps)?)),
}
}
fn decode_bytes_to_string(content: &[u8], encoding: &'static Encoding) -> Result<String> {
let (decoded, _, replaced) = encoding.decode(content);
if replaced {
Err(Error::from(ErrorKind::DecodingError))
} else {
Ok(decoded.into_owned())
}
}
pub fn parse_bytes(format: SubtitleFormat, content: &[u8], encoding: &'static Encoding, fps: f64) -> Result<Box<ClonableSubtitleFile>> {
match format {
SubtitleFormat::SubRip => Ok(Box::new(srt::SrtFile::parse(&decode_bytes_to_string(content, encoding)?)?)),
SubtitleFormat::SubStationAlpha => Ok(Box::new(ssa::SsaFile::parse(&decode_bytes_to_string(content, encoding)?)?)),
SubtitleFormat::VobSubIdx => Ok(Box::new(idx::IdxFile::parse(&decode_bytes_to_string(content, encoding)?)?)),
SubtitleFormat::VobSubSub => Ok(Box::new(vobsub::VobFile::parse(content)?)),
SubtitleFormat::MicroDVD => Ok(Box::new(microdvd::MdvdFile::parse(&decode_bytes_to_string(content, encoding)?, fps)?)),
}
}