subtitle_translator_cli/
subtitle_file.rs

1use std::error::Error;
2
3pub trait SubtitleFile {
4    fn split_contents(&self, contents: &String) -> Result<Vec<String>, Box<dyn Error>>;
5    fn merge_contents(
6        &self,
7        contents: &String,
8        translated_contents: Vec<String>,
9    ) -> Result<String, Box<dyn Error>>;
10}
11
12pub struct SrtFile {}
13
14impl SubtitleFile for SrtFile {
15    fn split_contents(&self, contents: &String) -> Result<Vec<String>, Box<dyn Error>> {
16        let segments = contents.split("\r\n").collect::<Vec<&str>>();
17        let extracted_contents = extract_contents(&segments);
18
19        let extracted_strings: Vec<String> = extracted_contents
20            .into_iter()
21            .map(|s| s.to_string())
22            .collect();
23        Ok(extracted_strings)
24    }
25
26    fn merge_contents(
27        &self,
28        contents: &String,
29        translated_contents: Vec<String>,
30    ) -> Result<String, Box<dyn Error>> {
31        let mut merged_contents = String::new();
32        let mut translated_contents = translated_contents.into_iter();
33        for line in contents.lines() {
34            if is_number(line) || is_timeline(line) || is_empty_line(line) {
35                merged_contents.push_str(format!("{}\n", line).as_str());
36                continue;
37            }
38            // add original content
39            merged_contents.push_str(format!("{}\n", line).as_str());
40            // add translated content
41            match translated_contents.next() {
42                Some(translated_line) => {
43                    merged_contents.push_str(format!("{}\n", translated_line).as_str());
44                }
45                None => {
46                    merged_contents.push_str(format!("{}\n", line).as_str());
47                }
48            }
49        }
50        Ok(merged_contents)
51    }
52}
53
54fn extract_contents(segments: &[&str]) -> Vec<String> {
55    let mut extracted_contents = Vec::new();
56    for &segment in segments {
57        if is_number(segment) || is_timeline(segment) || is_empty_line(segment) {
58            continue;
59        }
60        extracted_contents.push(segment.to_string());
61    }
62    extracted_contents
63}
64
65fn is_number(s: &str) -> bool {
66    s.chars().all(char::is_numeric)
67}
68
69fn is_timeline(s: &str) -> bool {
70    s.contains("-->")
71}
72
73fn is_empty_line(s: &str) -> bool {
74    s.is_empty()
75}