pub mod common;
pub mod idx;
pub mod microdvd;
pub mod srt;
pub mod ssa;
pub mod vobsub;
use crate::errors::*;
use crate::SubtitleEntry;
use crate::SubtitleFileInterface;
use encoding_rs::Encoding;
use std::ffi::OsStr;
use chardet::{charset2encoding, detect};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SubtitleFormat {
SubRip,
SubStationAlpha,
VobSubIdx,
VobSubSub,
MicroDVD,
}
#[derive(Clone, Debug)]
pub enum SubtitleFile {
SubRipFile(srt::SrtFile),
SubStationAlpha(ssa::SsaFile),
VobSubIdxFile(idx::IdxFile),
VobSubSubFile(vobsub::VobFile),
MicroDVDFile(microdvd::MdvdFile),
}
impl SubtitleFile {
pub fn get_subtitle_entries(&self) -> Result<Vec<SubtitleEntry>> {
match self {
SubtitleFile::SubRipFile(f) => f.get_subtitle_entries(),
SubtitleFile::SubStationAlpha(f) => f.get_subtitle_entries(),
SubtitleFile::VobSubIdxFile(f) => f.get_subtitle_entries(),
SubtitleFile::VobSubSubFile(f) => f.get_subtitle_entries(),
SubtitleFile::MicroDVDFile(f) => f.get_subtitle_entries(),
}
}
pub fn update_subtitle_entries(&mut self, i: &[SubtitleEntry]) -> Result<()> {
match self {
SubtitleFile::SubRipFile(f) => f.update_subtitle_entries(i),
SubtitleFile::SubStationAlpha(f) => f.update_subtitle_entries(i),
SubtitleFile::VobSubIdxFile(f) => f.update_subtitle_entries(i),
SubtitleFile::VobSubSubFile(f) => f.update_subtitle_entries(i),
SubtitleFile::MicroDVDFile(f) => f.update_subtitle_entries(i),
}
}
pub fn to_data(&self) -> Result<Vec<u8>> {
match self {
SubtitleFile::SubRipFile(f) => f.to_data(),
SubtitleFile::SubStationAlpha(f) => f.to_data(),
SubtitleFile::VobSubIdxFile(f) => f.to_data(),
SubtitleFile::VobSubSubFile(f) => f.to_data(),
SubtitleFile::MicroDVDFile(f) => f.to_data(),
}
}
}
impl From<srt::SrtFile> for SubtitleFile {
fn from(f: srt::SrtFile) -> SubtitleFile {
SubtitleFile::SubRipFile(f)
}
}
impl From<ssa::SsaFile> for SubtitleFile {
fn from(f: ssa::SsaFile) -> SubtitleFile {
SubtitleFile::SubStationAlpha(f)
}
}
impl From<idx::IdxFile> for SubtitleFile {
fn from(f: idx::IdxFile) -> SubtitleFile {
SubtitleFile::VobSubIdxFile(f)
}
}
impl From<vobsub::VobFile> for SubtitleFile {
fn from(f: vobsub::VobFile) -> SubtitleFile {
SubtitleFile::VobSubSubFile(f)
}
}
impl From<microdvd::MdvdFile> for SubtitleFile {
fn from(f: microdvd::MdvdFile) -> SubtitleFile {
SubtitleFile::MicroDVDFile(f)
}
}
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)",
}
}
}
#[test]
fn test_subtitle_format_by_extension() {
assert_eq!(get_subtitle_format_by_extension(Some(OsStr::new("srt"))), Some(SubtitleFormat::SubRip));
}
pub fn get_subtitle_format_by_extension(extension: Option<&OsStr>) -> Option<SubtitleFormat> {
let _ext_opt: Option<&OsStr> = extension.into();
if _ext_opt == Some(OsStr::new("srt")) {
Some(SubtitleFormat::SubRip)
} else if _ext_opt == Some(OsStr::new("ssa")) || _ext_opt == Some(OsStr::new("ass")) {
Some(SubtitleFormat::SubStationAlpha)
} else if _ext_opt == Some(OsStr::new("idx")) {
Some(SubtitleFormat::VobSubIdx)
} else {
None
}
}
pub fn is_valid_extension_for_subtitle_format(extension: Option<&OsStr>, format: SubtitleFormat) -> bool {
match format {
SubtitleFormat::SubRip => extension == Some(OsStr::new("srt")),
SubtitleFormat::SubStationAlpha => extension == Some(OsStr::new("ssa")) || extension == Some(OsStr::new("ass")),
SubtitleFormat::VobSubIdx => extension == Some(OsStr::new("idx")),
SubtitleFormat::VobSubSub => extension == Some(OsStr::new("sub")),
SubtitleFormat::MicroDVD => extension == Some(OsStr::new("sub")),
}
}
pub fn get_subtitle_format_by_extension_err(extension: Option<&OsStr>) -> Result<SubtitleFormat> {
get_subtitle_format_by_extension(extension).ok_or_else(|| ErrorKind::UnknownFileFormat.into())
}
pub fn get_subtitle_format(extension: Option<&OsStr>, content: &[u8]) -> Option<SubtitleFormat> {
if extension == Some(OsStr::new("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_extension(extension)
}
}
pub fn get_subtitle_format_err(extension: Option<&OsStr>, content: &[u8]) -> Result<SubtitleFormat> {
get_subtitle_format(extension, content).ok_or_else(|| ErrorKind::UnknownFileFormat.into())
}
pub fn parse_str(format: SubtitleFormat, content: &str, fps: f64) -> Result<SubtitleFile> {
match format {
SubtitleFormat::SubRip => Ok(srt::SrtFile::parse(content)?.into()),
SubtitleFormat::SubStationAlpha => Ok(ssa::SsaFile::parse(content)?.into()),
SubtitleFormat::VobSubIdx => Ok(idx::IdxFile::parse(content)?.into()),
SubtitleFormat::VobSubSub => Err(ErrorKind::TextFormatOnly.into()),
SubtitleFormat::MicroDVD => Ok(microdvd::MdvdFile::parse(content, fps)?.into()),
}
}
fn decode_bytes_to_string(content: &[u8], encoding: Option<&'static Encoding>) -> Result<String> {
let det_encoding = match encoding {
Some(encoding) => encoding,
None => {
let (charset, _, _) = detect(content);
let encoding_name = charset2encoding(&charset);
Encoding::for_label_no_replacement(encoding_name.as_bytes()).ok_or(ErrorKind::EncodingDetectionError)?
}
};
let (decoded, _, replaced) = det_encoding.decode(content);
if replaced {
Err(Error::from(ErrorKind::DecodingError))
} else {
Ok(decoded.into_owned())
}
}
pub fn parse_bytes(format: SubtitleFormat, content: &[u8], encoding: Option<&'static Encoding>, fps: f64) -> Result<SubtitleFile> {
match format {
SubtitleFormat::SubRip => Ok(srt::SrtFile::parse(&decode_bytes_to_string(content, encoding)?)?.into()),
SubtitleFormat::SubStationAlpha => Ok(ssa::SsaFile::parse(&decode_bytes_to_string(content, encoding)?)?.into()),
SubtitleFormat::VobSubIdx => Ok(idx::IdxFile::parse(&decode_bytes_to_string(content, encoding)?)?.into()),
SubtitleFormat::VobSubSub => Ok(vobsub::VobFile::parse(content)?.into()),
SubtitleFormat::MicroDVD => Ok(microdvd::MdvdFile::parse(&decode_bytes_to_string(content, encoding)?, fps)?.into()),
}
}