use crate::{FORMAT_EXTENSION, FORMAT_HAS_AUDIO, FORMAT_HAS_VIDEO, MediaSorts};
use alux_ext::ext;
use ambassador::delegatable_trait;
#[delegatable_trait]
pub trait FormatPredicateAlg: MediaSorts {
fn any_format(&self) -> Self::Predicate;
fn format_id(&self, id: impl Into<String>) -> Self::Predicate;
fn observed_format(&self, key: impl Into<String>) -> Self::Predicate;
fn text_format(&self, key: impl Into<String>, value: impl Into<String>) -> Self::Predicate;
fn flag_format(&self, key: impl Into<String>, value: bool) -> Self::Predicate;
fn number_format(&self, key: impl Into<String>, comparison: FormatComparison, value: f64) -> Self::Predicate;
fn all_formats(&self, left: Self::Predicate, right: Self::Predicate) -> Self::Predicate;
fn not_format(&self, predicate: Self::Predicate) -> Self::Predicate;
}
#[delegatable_trait]
pub trait FormatSelectionAlg: MediaSorts {
fn best_format(&self, predicate: Self::Predicate) -> Self::Selection;
fn worst_format(&self, predicate: Self::Predicate) -> Self::Selection;
fn merge_formats(&self, selections: impl IntoIterator<Item = Self::Selection>) -> Self::Selection;
fn fallback_formats(&self, selections: impl IntoIterator<Item = Self::Selection>) -> Self::Selection;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FormatComparison {
AtMost,
Exactly,
AtLeast,
}
#[delegatable_trait]
pub trait FormatPredicateMatchAlg: MediaSorts {
fn format_matches(&self, predicate: &Self::Predicate, format: &Self::Format) -> bool;
}
#[delegatable_trait]
pub trait FormatSelectionApplyAlg: MediaSorts {
fn select_formats<'a>(
&self,
formats: &'a [Self::Format],
selection: &Self::Selection,
) -> Option<Vec<&'a Self::Format>>;
}
#[ext(name = FormatPredicateExt)]
pub impl<This> This
where
This: FormatPredicateAlg,
{
fn has_audio(&self) -> This::Predicate {
self.flag_format(FORMAT_HAS_AUDIO, true)
}
fn has_video(&self) -> This::Predicate {
self.flag_format(FORMAT_HAS_VIDEO, true)
}
fn format_extension(&self, extension: impl Into<String>) -> This::Predicate {
self.text_format(FORMAT_EXTENSION, extension)
}
fn at_most(&self, key: impl Into<String>, value: f64) -> This::Predicate {
self.number_format(key, FormatComparison::AtMost, value)
}
fn at_least(&self, key: impl Into<String>, value: f64) -> This::Predicate {
self.number_format(key, FormatComparison::AtLeast, value)
}
fn exactly(&self, key: impl Into<String>, value: f64) -> This::Predicate {
self.number_format(key, FormatComparison::Exactly, value)
}
fn less_than(&self, key: impl Into<String>, value: f64) -> This::Predicate {
self.not_format(self.at_least(key, value))
}
fn greater_than(&self, key: impl Into<String>, value: f64) -> This::Predicate {
self.not_format(self.at_most(key, value))
}
fn progressive_format(&self) -> This::Predicate {
self.all_formats(self.has_audio(), self.has_video())
}
fn audio_only_format(&self) -> This::Predicate {
self.all_formats(self.has_audio(), self.not_format(self.has_video()))
}
fn video_only_format(&self) -> This::Predicate {
self.all_formats(self.has_video(), self.not_format(self.has_audio()))
}
}
#[ext(name = FormatSelectionProgramExt)]
pub impl<This, Predicate> This
where
This: FormatPredicateAlg<Predicate = Predicate> + FormatSelectionAlg<Predicate = Predicate>,
{
fn best_progressive_format(&self) -> This::Selection {
self.best_format(self.progressive_format())
}
fn preferred_progressive_format(&self, id: impl Into<String>) -> This::Selection {
self.fallback_formats([self.best_format(self.format_id(id)), self.best_progressive_format()])
}
}