1use crate::{MAX_TEXT_CONTENT_BYTES, TextStyle};
4use alpha2_time::TimeRange;
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
9#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
10#[serde(deny_unknown_fields)]
11pub struct Captions {
12 #[serde(default)]
14 pub style: TextStyle,
15 pub cues: Vec<CaptionCue>,
18}
19
20#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
22#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
23#[serde(deny_unknown_fields)]
24pub struct CaptionCue {
25 pub timeline_range: TimeRange,
27 pub text: String,
30}
31
32pub const MAX_CAPTION_FONT_SIZE: f32 = 0.25;
34
35impl Captions {
36 pub(crate) fn is_valid(&self) -> bool {
37 self.style.is_valid(MAX_CAPTION_FONT_SIZE)
38 && self.cues.iter().all(|cue| {
39 !cue.timeline_range.is_empty()
40 && cue.timeline_range.start().ticks() >= 0
41 && !cue.text.is_empty()
42 && cue.text.len() <= MAX_TEXT_CONTENT_BYTES
43 })
44 && self
45 .cues
46 .windows(2)
47 .all(|pair| pair[0].timeline_range.end() <= pair[1].timeline_range.start())
48 }
49}