use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Clip {
pub source: PathBuf,
pub in_point: Option<Duration>,
pub out_point: Option<Duration>,
pub timeline_offset: Duration,
pub metadata: HashMap<String, String>,
}
impl Clip {
pub fn new(source: impl AsRef<Path>) -> Self {
Self {
source: source.as_ref().to_path_buf(),
in_point: None,
out_point: None,
timeline_offset: Duration::ZERO,
metadata: HashMap::new(),
}
}
#[must_use]
pub fn trim(self, in_point: Duration, out_point: Duration) -> Self {
Self {
in_point: Some(in_point),
out_point: Some(out_point),
..self
}
}
#[must_use]
pub fn offset(self, timeline_offset: Duration) -> Self {
Self {
timeline_offset,
..self
}
}
pub fn duration(&self) -> Option<Duration> {
match (self.in_point, self.out_point) {
(Some(in_pt), Some(out_pt)) => out_pt.checked_sub(in_pt),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clip_new_should_have_zero_offset() {
let clip = Clip::new("video.mp4");
assert_eq!(clip.timeline_offset, Duration::ZERO);
assert!(clip.in_point.is_none());
assert!(clip.out_point.is_none());
assert!(clip.metadata.is_empty());
}
#[test]
fn clip_trim_should_set_in_out_points() {
let clip = Clip::new("video.mp4").trim(Duration::from_secs(3), Duration::from_secs(9));
assert_eq!(clip.in_point, Some(Duration::from_secs(3)));
assert_eq!(clip.out_point, Some(Duration::from_secs(9)));
}
#[test]
fn clip_duration_should_return_none_when_out_point_unset() {
let clip = Clip::new("video.mp4");
assert!(clip.duration().is_none());
}
#[test]
fn clip_duration_should_return_difference_when_both_points_set() {
let clip = Clip::new("video.mp4").trim(Duration::from_secs(2), Duration::from_secs(10));
assert_eq!(clip.duration(), Some(Duration::from_secs(8)));
}
}