Skip to content

Commit

Permalink
Add unofficial line position option for srt
Browse files Browse the repository at this point in the history
  • Loading branch information
mochi-neko committed Feb 20, 2024
1 parent f5db929 commit 2f3510b
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 1 deletion.
3 changes: 3 additions & 0 deletions examples/render_srt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ fn main() -> anyhow::Result<()> {
..Default::default()
},
text: vec!["This is the first subtitle.".to_string()],
..Default::default()
},
SrtSubtitle {
sequence: 2,
Expand All @@ -38,6 +39,7 @@ fn main() -> anyhow::Result<()> {
"This is the second subtitle.".to_string(),
"Subtitle text can span multiple lines.".to_string(),
],
..Default::default()
},
],
};
Expand All @@ -59,6 +61,7 @@ fn main() -> anyhow::Result<()> {
..Default::default()
},
text: vec!["This is the third subtitle.".to_string()],
..Default::default()
});
println!("Rendered srt:\n{}", subrip.render());

Expand Down
59 changes: 59 additions & 0 deletions src/srt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
//! milliseconds: 0,
//! },
//! text: vec!["Hello, world!".to_string()],
//! line_position: None,
//! },
//! SrtSubtitle {
//! sequence: 2,
Expand All @@ -53,6 +54,7 @@
//! "This is a sample.".to_string(),
//! "Thank you for your reading.".to_string()
//! ],
//! line_position: None,
//! },
//! ],
//! });
Expand Down Expand Up @@ -96,6 +98,7 @@ use crate::ParseResult;
/// milliseconds: 0,
/// },
/// text: vec!["Hello, world!".to_string()],
/// line_position: None,
/// }
/// ],
/// };
Expand Down Expand Up @@ -159,6 +162,7 @@ impl SubRip {
/// milliseconds: 0,
/// },
/// text: vec!["Hello, world!".to_string()],
/// line_position: None,
/// }
/// ],
/// };
Expand Down Expand Up @@ -234,6 +238,7 @@ impl Iterator for SubRip {
/// milliseconds: 0,
/// },
/// text: vec!["Hello, world!".to_string()],
/// line_position: None,
/// };
///
/// assert_eq!(
Expand All @@ -259,6 +264,7 @@ impl Iterator for SubRip {
/// ..Default::default()
/// },
/// text: vec!["Hello, world!".to_string()],
/// ..Default::default()
/// };
/// ```
#[derive(Debug, Clone, Eq, Hash)]
Expand All @@ -271,6 +277,8 @@ pub struct SrtSubtitle {
pub end: SrtTimestamp,
/// The subtitle text.
pub text: Vec<String>,
/// The unofficial line position.
pub line_position: Option<LinePosition>,
}

impl PartialEq<Self> for SrtSubtitle {
Expand Down Expand Up @@ -308,6 +316,7 @@ impl Default for SrtSubtitle {
start: SrtTimestamp::default(),
end: SrtTimestamp::default(),
text: vec![],
line_position: None,
}
}
}
Expand Down Expand Up @@ -427,6 +436,43 @@ impl Into<Duration> for SrtTimestamp {
}
}

/// Unofficial line position settings.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct LinePosition {
/// X1 of the line position.
pub x1: u32,
/// X2 of the line position.
pub x2: u32,
/// Y1 of the line position.
pub y1: u32,
/// Y2 of the line position.
pub y2: u32,
}

impl Default for LinePosition {
fn default() -> Self {
Self {
x1: 0,
x2: 0,
y1: 0,
y2: 0,
}
}
}

impl Display for LinePosition {
fn fmt(
&self,
f: &mut Formatter<'_>,
) -> std::fmt::Result {
write!(
f,
"X1:{} X2:{} Y1:{} Y2:{}",
self.x1, self.x2, self.y1, self.y2
)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -461,6 +507,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
},
SrtSubtitle {
sequence: 2,
Expand All @@ -477,6 +524,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["This is a test.".to_string()],
line_position: None,
},
],
};
Expand Down Expand Up @@ -505,6 +553,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
}],
};
let expected = r#"1
Expand All @@ -530,6 +579,7 @@ Hello, world!
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
},
SrtSubtitle {
sequence: 2,
Expand All @@ -546,6 +596,7 @@ Hello, world!
milliseconds: 0,
},
text: vec!["This is a test.".to_string()],
line_position: None,
},
],
};
Expand Down Expand Up @@ -579,6 +630,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
},
SrtSubtitle {
sequence: 2,
Expand All @@ -595,6 +647,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["This is a test.".to_string()],
line_position: None,
},
],
};
Expand All @@ -618,6 +671,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
})
);

Expand All @@ -638,6 +692,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["This is a test.".to_string()],
line_position: None,
})
);

Expand All @@ -661,6 +716,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
};
let displayed = format!("{}", subtitle);
let expected = "1\n00:00:01,000 --> 00:00:02,000\nHello, world!\n";
Expand All @@ -684,6 +740,7 @@ This is a test.
"Hello, world!".to_string(),
"This is the test.".to_string(),
],
line_position: None,
};
let displayed = format!("{}", subtitle);
let expected = "1\n00:00:01,000 --> 00:00:02,000\nHello, world!\nThis is the test.\n";
Expand All @@ -707,6 +764,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["First".to_string()],
line_position: None,
};
let subtitle2 = SrtSubtitle {
sequence: 2,
Expand All @@ -723,6 +781,7 @@ This is a test.
milliseconds: 0,
},
text: vec!["Second".to_string()],
line_position: None,
};
assert!(subtitle1 < subtitle2);
}
Expand Down
74 changes: 73 additions & 1 deletion src/str_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ peg::parser! {
use crate::srt::SrtTimestamp;
use crate::srt::SubRip;
use crate::srt::SrtSubtitle;
use crate::srt::LinePosition;

/// Whitespace.
rule whitespace() = [' ' | '\t']
Expand Down Expand Up @@ -58,13 +59,50 @@ peg::parser! {
}
}

pub(crate) rule line_position() -> LinePosition
= "X1:" x1:number() separator()+
"X2:" x2:number() separator()+
"Y1:" y1:number() separator()+
"Y2:" y2:number()
{
LinePosition {
x1,
y1,
x2,
y2,
}
}

/// Single subtitle entry.
pub(crate) rule subtitle() -> SrtSubtitle
= subtitle_with_line_position() / subtitle_without_line_position()

rule subtitle_without_line_position() -> SrtSubtitle
= sequence:number() separator()
start:timestamp() separator()* "-->" separator()* end:timestamp() separator()
text:multiline()
{
SrtSubtitle { sequence, start, end, text }
SrtSubtitle {
sequence,
start,
end,
text,
line_position: None,
}
}

rule subtitle_with_line_position() -> SrtSubtitle
= sequence:number() separator()
start:timestamp() separator()* "-->" separator()* end:timestamp() separator()+ line_position:line_position() separator()
text:multiline()
{
SrtSubtitle {
sequence,
start,
end,
text,
line_position: Some(line_position),
}
}

/// The entire SRT.
Expand Down Expand Up @@ -162,6 +200,7 @@ mod test {
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
};

assert_eq!(
Expand Down Expand Up @@ -217,6 +256,36 @@ mod test {
subtitle
);

// Allow unofficial line position setting.
assert_eq!(
srt_parser::subtitle(
"1\n00:00:00,000\n-->\n00:00:01,000 X1:1 X2:2 Y1:3 Y2:4\nHello, world!\n"
)
.unwrap(),
SrtSubtitle {
sequence: 1,
start: SrtTimestamp {
hours: 0,
minutes: 0,
seconds: 0,
milliseconds: 0,
},
end: SrtTimestamp {
hours: 0,
minutes: 0,
seconds: 1,
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: Some(LinePosition {
x1: 1,
x2: 2,
y1: 3,
y2: 4,
}),
}
);

// Prohibit spaces or new lines in header.
assert!(srt_parser::subtitle(
"\n1\n00:00:00,000 --> 00:00:01,000\nHello, world!\n"
Expand Down Expand Up @@ -260,6 +329,7 @@ mod test {
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
}],
};

Expand Down Expand Up @@ -318,6 +388,7 @@ Hello, world!
milliseconds: 0,
},
text: vec!["Hello, world!".to_string()],
line_position: None,
},
SrtSubtitle {
sequence: 2,
Expand All @@ -334,6 +405,7 @@ Hello, world!
milliseconds: 0,
},
text: vec!["This is a test.".to_string()],
line_position: None,
},
],
};
Expand Down

0 comments on commit 2f3510b

Please sign in to comment.