rsynko_media/
selection.rs1use crate::{FORMAT_EXTENSION, FORMAT_HAS_AUDIO, FORMAT_HAS_VIDEO, MediaSorts};
2use alux_ext::ext;
3use ambassador::delegatable_trait;
4
5#[delegatable_trait]
7pub trait FormatPredicateAlg: MediaSorts {
8 fn any_format(&self) -> Self::Predicate;
10 fn format_id(&self, id: impl Into<String>) -> Self::Predicate;
12 fn observed_format(&self, key: impl Into<String>) -> Self::Predicate;
14 fn text_format(&self, key: impl Into<String>, value: impl Into<String>) -> Self::Predicate;
16 fn flag_format(&self, key: impl Into<String>, value: bool) -> Self::Predicate;
18 fn number_format(&self, key: impl Into<String>, comparison: FormatComparison, value: f64) -> Self::Predicate;
20 fn all_formats(&self, left: Self::Predicate, right: Self::Predicate) -> Self::Predicate;
22 fn not_format(&self, predicate: Self::Predicate) -> Self::Predicate;
24}
25
26#[delegatable_trait]
28pub trait FormatSelectionAlg: MediaSorts {
29 fn best_format(&self, predicate: Self::Predicate) -> Self::Selection;
31 fn worst_format(&self, predicate: Self::Predicate) -> Self::Selection;
33 fn merge_formats(&self, selections: impl IntoIterator<Item = Self::Selection>) -> Self::Selection;
35 fn fallback_formats(&self, selections: impl IntoIterator<Item = Self::Selection>) -> Self::Selection;
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum FormatComparison {
42 AtMost,
44 Exactly,
46 AtLeast,
48}
49
50#[delegatable_trait]
55pub trait FormatPredicateMatchAlg: MediaSorts {
56 fn format_matches(&self, predicate: &Self::Predicate, format: &Self::Format) -> bool;
58}
59
60#[delegatable_trait]
65pub trait FormatSelectionApplyAlg: MediaSorts {
66 fn select_formats<'a>(
68 &self,
69 formats: &'a [Self::Format],
70 selection: &Self::Selection,
71 ) -> Option<Vec<&'a Self::Format>>;
72}
73
74#[ext(name = FormatPredicateExt)]
76pub impl<This> This
77where
78 This: FormatPredicateAlg,
79{
80 fn has_audio(&self) -> This::Predicate {
82 self.flag_format(FORMAT_HAS_AUDIO, true)
83 }
84
85 fn has_video(&self) -> This::Predicate {
87 self.flag_format(FORMAT_HAS_VIDEO, true)
88 }
89
90 fn format_extension(&self, extension: impl Into<String>) -> This::Predicate {
92 self.text_format(FORMAT_EXTENSION, extension)
93 }
94
95 fn at_most(&self, key: impl Into<String>, value: f64) -> This::Predicate {
97 self.number_format(key, FormatComparison::AtMost, value)
98 }
99
100 fn at_least(&self, key: impl Into<String>, value: f64) -> This::Predicate {
102 self.number_format(key, FormatComparison::AtLeast, value)
103 }
104
105 fn exactly(&self, key: impl Into<String>, value: f64) -> This::Predicate {
107 self.number_format(key, FormatComparison::Exactly, value)
108 }
109
110 fn less_than(&self, key: impl Into<String>, value: f64) -> This::Predicate {
112 self.not_format(self.at_least(key, value))
113 }
114
115 fn greater_than(&self, key: impl Into<String>, value: f64) -> This::Predicate {
117 self.not_format(self.at_most(key, value))
118 }
119
120 fn progressive_format(&self) -> This::Predicate {
122 self.all_formats(self.has_audio(), self.has_video())
123 }
124
125 fn audio_only_format(&self) -> This::Predicate {
127 self.all_formats(self.has_audio(), self.not_format(self.has_video()))
128 }
129
130 fn video_only_format(&self) -> This::Predicate {
132 self.all_formats(self.has_video(), self.not_format(self.has_audio()))
133 }
134}
135
136#[ext(name = FormatSelectionProgramExt)]
138pub impl<This, Predicate> This
139where
140 This: FormatPredicateAlg<Predicate = Predicate> + FormatSelectionAlg<Predicate = Predicate>,
141{
142 fn best_progressive_format(&self) -> This::Selection {
144 self.best_format(self.progressive_format())
145 }
146
147 fn preferred_progressive_format(&self, id: impl Into<String>) -> This::Selection {
149 self.fallback_formats([self.best_format(self.format_id(id)), self.best_progressive_format()])
150 }
151}