use std::{
borrow::Cow,
fmt::Display,
fs::File,
io::{BufWriter, Write},
path::Path,
str::FromStr,
};
use encoding_rs::Encoding;
use crate::{errors::Error, Moment, TimeDelta};
pub trait Subtitle: Display + FromStr {
type Event;
fn from_path(path: impl AsRef<Path>) -> Result<Self, Error> {
Self::from_path_with_encoding(path, None)
}
fn from_path_with_encoding(
path: impl AsRef<Path>,
encoding: Option<&'static Encoding>,
) -> Result<Self, Error>;
fn events(&self) -> &[Self::Event];
fn events_mut(&mut self) -> &mut [Self::Event];
fn event(&self, index: usize) -> Option<&Self::Event> {
self.events().get(index)
}
fn event_mut(&mut self, index: usize) -> Option<&mut Self::Event> {
self.events_mut().get_mut(index)
}
fn export(&self, path: impl AsRef<Path>) -> Result<(), Error> {
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
Ok(write!(writer, "{self}")?)
}
}
pub trait TextSubtitle: Subtitle
where
Self::Event: TextEvent,
{
fn strip_formatting(&mut self) {
for event in self.events_mut() {
event.strip_formatting();
}
}
}
pub trait TimedSubtitle: Subtitle
where
Self::Event: TimedEvent,
{
fn shift(&mut self, delta: TimeDelta)
where
<Self as Subtitle>::Event: TimedEvent,
{
for event in self.events_mut() {
event.shift(delta);
}
}
}
pub trait TextEvent: TextEventInterface {
fn strip_formatting(&mut self) {
self.set_text(self.unformatted_text().into_owned());
}
fn unformatted_text(&self) -> Cow<'_, String>;
fn as_plaintext(&self) -> Cow<'_, String> {
self.unformatted_text()
}
}
pub trait TextEventInterface {
fn text(&self) -> String;
fn set_text(&mut self, text: String);
}
pub trait TimedEvent: TimedEventInterface {
fn shift(&mut self, delta: TimeDelta) {
self.set_start(self.start() + delta);
self.set_end(self.end() + delta);
}
fn duration(&self) -> TimeDelta {
self.end() - self.start()
}
}
pub trait TimedEventInterface {
fn start(&self) -> Moment;
fn end(&self) -> Moment;
fn set_start(&mut self, moment: Moment);
fn set_end(&mut self, moment: Moment);
}