use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ContentType { Movie, Episode, Short, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct MediaFilter { pub content_type: Option, pub genres: Vec, pub decade: Option, pub tags: Vec, pub min_duration_secs: Option, pub max_duration_secs: Option, pub collections: Vec, #[serde(default)] pub series_names: Vec, pub search_term: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum FillStrategy { BestFit, Sequential, Random, Alternating, Weighted, Marathon, } const DEFAULT_COOLDOWN_DAYS: u32 = 30; const DEFAULT_MIN_AVAILABLE_RATIO: f32 = 0.2; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RotationPolicy { pub cooldown_days: Option, pub cooldown_generations: Option, pub min_available_ratio: f32, } impl Default for RotationPolicy { fn default() -> Self { Self { cooldown_days: Some(DEFAULT_COOLDOWN_DAYS), cooldown_generations: None, min_available_ratio: DEFAULT_MIN_AVAILABLE_RATIO, } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, } impl From for Weekday { fn from(w: chrono::Weekday) -> Self { match w { chrono::Weekday::Mon => Weekday::Monday, chrono::Weekday::Tue => Weekday::Tuesday, chrono::Weekday::Wed => Weekday::Wednesday, chrono::Weekday::Thu => Weekday::Thursday, chrono::Weekday::Fri => Weekday::Friday, chrono::Weekday::Sat => Weekday::Saturday, chrono::Weekday::Sun => Weekday::Sunday, } } } impl Weekday { pub fn all() -> [Weekday; 7] { // ISO week order: Monday first. Schedule engine depends on this ordering. [ Weekday::Monday, Weekday::Tuesday, Weekday::Wednesday, Weekday::Thursday, Weekday::Friday, Weekday::Saturday, Weekday::Sunday, ] } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(rename_all = "snake_case")] pub enum MediaRole { #[default] Program, Interstitial, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InterstitialRule { pool_filter: MediaFilter, strategy: FillStrategy, min_gap_secs: u32, } impl InterstitialRule { pub fn new(pool_filter: MediaFilter, strategy: FillStrategy, min_gap_secs: u32) -> Self { Self { pool_filter, strategy, min_gap_secs, } } pub fn pool_filter(&self) -> &MediaFilter { &self.pool_filter } pub fn strategy(&self) -> &FillStrategy { &self.strategy } pub fn min_gap_secs(&self) -> u32 { self.min_gap_secs } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MidRollRule { prefer_chapters: bool, fallback_interval_mins: u32, break_duration_secs: u32, pool_filter: MediaFilter, } impl MidRollRule { pub fn new( prefer_chapters: bool, fallback_interval_mins: u32, break_duration_secs: u32, pool_filter: MediaFilter, ) -> Self { Self { prefer_chapters, fallback_interval_mins, break_duration_secs, pool_filter, } } pub fn prefer_chapters(&self) -> bool { self.prefer_chapters } pub fn fallback_interval_mins(&self) -> u32 { self.fallback_interval_mins } pub fn break_duration_secs(&self) -> u32 { self.break_duration_secs } pub fn pool_filter(&self) -> &MediaFilter { &self.pool_filter } } #[cfg(test)] #[path = "tests/scheduling.rs"] mod tests;