use crate::*;
use alux_ext::ext;
use rsynko_manager::MediaStreams;
pub trait FormatDescriptionAlg {
fn format_identity(&self) -> &str;
fn format_extension(&self) -> Option<&str>;
fn format_streams(&self) -> Option<MediaStreams>;
fn format_quality(&self) -> Option<&str>;
fn format_height(&self) -> Option<u64>;
fn format_width(&self) -> Option<u64>;
fn format_bitrate(&self) -> Option<u64>;
fn format_size(&self) -> Option<u64>;
fn format_codecs(&self) -> Option<&str>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DiscoveryState<'a> {
Unrequested,
Waiting,
Inspecting,
Described,
Failed(&'a str),
}
pub trait FormatChoiceViewAlg {
type Format;
fn discovery(&self) -> DiscoveryState<'_>;
fn described_formats(&self) -> impl Iterator<Item = &Self::Format>;
}
#[ext(name = FormatLabelExt)]
pub impl<This> This
where
This: FormatDescriptionAlg,
{
fn format_label(&self) -> String {
let described = self.format_observations();
let columns = format!(
"{:<4} {:<5} {:<13}",
self.format_identity(),
self.format_extension().unwrap_or(UNSTATED),
self.format_streams().map_or("no media streams", MediaStreams::streams_label)
);
if described.is_empty() { columns } else { format!("{columns} {described}") }
}
fn format_observations(&self) -> String {
let quality = self.format_stated_quality();
[
quality.as_deref().map(str::to_owned),
self.format_bitrate().map(|bitrate| format!("{}/s", bytes_label(bitrate / 8))),
self.format_size().map(bytes_label),
self.format_codecs().map(str::to_owned),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.join(" ")
}
fn format_stated_quality(&self) -> Option<String> {
if let Some(quality) = self.format_quality() {
return Some(quality.to_owned());
}
match (self.format_width(), self.format_height()) {
(Some(width), Some(height)) => Some(format!("{width}x{height}")),
(None, Some(height)) => Some(format!("{height}p")),
(Some(_) | None, None) => None,
}
}
}
#[ext(name = FormatRolesExt)]
pub impl<This> This
where
This: FormatChoiceViewAlg,
This::Format: FormatDescriptionAlg,
{
fn offered_streams(&self) -> Vec<MediaStreams> {
let described = self.described_formats().collect::<Vec<_>>();
if described.is_empty() {
return MediaStreams::OFFERED.to_vec();
}
let carried = described.into_iter().filter_map(FormatDescriptionAlg::format_streams).collect::<Vec<_>>();
MediaStreams::OFFERED.into_iter().filter(|role| carried.contains(role)).collect()
}
}