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
//! # rsubs-lib
//!
//! This [crate](https://crates.io/crates/rsubs-lib) provides a simple way for parsing, modifying or converting
//! subtitle files such as `.srt`,`.ssa`,`.ass` and `.vtt`.
//!
//! Example usage :
//!
//! In this example we read a .srt file and add 1s(1000ms) to each line
//! Afterwards we print the result to stdout.
//!
//!   ```
//!   use std::str::FromStr;
//!   let mut srt: rsubs_lib::srt::SRTFile = rsubs_lib::Subtitle::from_str("test.srt").expect("failed parsing").into();
//!   for line in srt.lines.iter_mut() {
//!       line.line_end += 1000;
//!       line.line_start += 1000;
//!   }
//!   println!("{}", srt);
//!   ```
//!
//!

use std::str::FromStr;
use std::{fmt::Display, io::Error};

use srt::SRTFile;
use ssa::SSAFile;
use vtt::VTTFile;
pub mod srt;
pub mod ssa;
pub mod util;
pub mod vtt;

#[derive(Clone, Debug)]
pub enum Subtitle {
    SRT(Option<SRTFile>),
    VTT(Option<VTTFile>),
    SSA(Option<SSAFile>),
}

impl FromStr for Subtitle {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let sr = s.to_string();
        if sr.lines().count() > 1 {
            let first_line = sr.lines().next().unwrap();
            if first_line.contains("WEBVTT") {
                Ok(Subtitle::VTT(Some(
                    VTTFile::from_str(s).unwrap_or_default(),
                )))
            } else if first_line.contains("[Script Info]") {
                Ok(Subtitle::SSA(Some(
                    SSAFile::from_str(s).unwrap_or_default(),
                )))
            } else {
                Ok(Subtitle::SRT(Some(
                    SRTFile::from_str(s).unwrap_or_default(),
                )))
            }
        } else if sr.contains(".vtt") {
            Ok(Subtitle::VTT(Some(
                VTTFile::from_str(s).unwrap_or_default(),
            )))
        } else if sr.contains(".ass") || sr.contains(".ssa") {
            Ok(Subtitle::SSA(Some(
                SSAFile::from_str(s).unwrap_or_default(),
            )))
        } else {
            Ok(Subtitle::SRT(Some(
                SRTFile::from_str(s).unwrap_or_default(),
            )))
        }
    }
}

impl Display for Subtitle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Subtitle::SRT(Some(i)) => write!(f, "{i}"),
            Subtitle::VTT(Some(i)) => write!(f, "{i}"),
            Subtitle::SSA(Some(i)) => write!(f, "{i}"),
            _ => panic!("format error"),
        }
    }
}

impl From<Subtitle> for SSAFile {
    fn from(value: Subtitle) -> Self {
        match value {
            Subtitle::SRT(Some(i)) => i.into(),
            Subtitle::VTT(Some(i)) => i.into(),
            Subtitle::SSA(Some(i)) => i,
            _ => panic!("format error"),
        }
    }
}
impl From<Subtitle> for VTTFile {
    fn from(value: Subtitle) -> Self {
        match value {
            Subtitle::SRT(Some(i)) => i.into(),
            Subtitle::VTT(Some(i)) => i,
            Subtitle::SSA(Some(i)) => i.into(),
            _ => panic!("format error"),
        }
    }
}

impl From<Subtitle> for SRTFile {
    fn from(value: Subtitle) -> Self {
        match value {
            Subtitle::SRT(Some(i)) => i,
            Subtitle::VTT(Some(i)) => i.into(),
            Subtitle::SSA(Some(i)) => i.into(),
            _ => panic!("format error"),
        }
    }
}