use crate::{Format, InfoValue, MediaSyntax, predicate_accepts};
use rsynko_manager::{MediaStreams, MediaStreamsExt, Performer};
use rsynko_rsync::SyncProfile;
use rsynko_ui::FormatDescriptionAlg;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DownloadOptions {
pub(crate) media_streams: Option<MediaStreams>,
pub(crate) format: FormatChoice,
pub(crate) profile: Option<SyncProfile>,
pub(crate) dry_run: Option<bool>,
}
impl DownloadOptions {
#[must_use]
pub const fn progressive() -> Self {
Self {
media_streams: Some(MediaStreams::AudioVideo),
format: FormatChoice::Best,
profile: None,
dry_run: None,
}
}
#[must_use]
pub const fn audio() -> Self {
Self {
media_streams: Some(MediaStreams::Audio),
format: FormatChoice::Best,
profile: None,
dry_run: None,
}
}
#[must_use]
pub const fn video() -> Self {
Self {
media_streams: Some(MediaStreams::Video),
format: FormatChoice::Best,
profile: None,
dry_run: None,
}
}
#[must_use]
pub const fn transfer() -> Self {
Self {
media_streams: None,
format: FormatChoice::Best,
profile: Some(SyncProfile::Copy),
dry_run: Some(true),
}
}
#[must_use]
pub const fn profile(&self) -> Option<SyncProfile> {
self.profile
}
#[must_use]
pub const fn performer(&self) -> Performer {
if self.profile.is_some() {
Performer::Program
} else {
Performer::Retrieval
}
}
#[must_use]
pub const fn with_profile(mut self, profile: SyncProfile) -> Self {
if self.profile.is_some() {
self.profile = Some(profile);
}
self
}
#[must_use]
pub const fn rehearsing(mut self) -> Self {
if self.dry_run.is_some() {
self.dry_run = Some(true);
}
self
}
#[must_use]
pub const fn dry_run(&self) -> Option<bool> {
self.dry_run
}
pub const fn set_dry_run(&mut self, dry_run: bool) {
if self.dry_run.is_some() {
self.dry_run = Some(dry_run);
}
}
#[must_use]
pub const fn media_streams(&self) -> Option<MediaStreams> {
self.media_streams
}
#[must_use]
pub const fn format(&self) -> &FormatChoice {
&self.format
}
#[must_use]
pub fn with_media_streams(mut self, media_streams: MediaStreams) -> Self {
self.media_streams = Some(media_streams);
self.format = FormatChoice::Best;
self
}
#[must_use]
pub fn with_format(mut self, format: FormatChoice) -> Self {
self.format = format;
self
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FormatChoice {
Best,
Id(String),
}
#[derive(Clone, Debug, PartialEq)]
pub enum FormatCatalog {
Unknown,
Waiting,
Inspecting,
Available(Vec<Format>),
Failed(String),
}
impl FormatCatalog {
#[must_use]
pub fn available(&self) -> Option<&[Format]> {
match self {
Self::Available(formats) => Some(formats),
Self::Unknown | Self::Waiting | Self::Inspecting | Self::Failed(_) => None,
}
}
}
#[must_use]
pub fn role_accepts(streams: MediaStreams, format: &Format) -> bool {
predicate_accepts(&MediaSyntax.stream_role_format(streams), format)
}
impl FormatDescriptionAlg for Format {
fn format_identity(&self) -> &str {
&self.id
}
fn format_extension(&self) -> Option<&str> {
self.extension()
}
fn format_streams(&self) -> Option<MediaStreams> {
match (self.has_audio(), self.has_video()) {
(true, true) => Some(MediaStreams::AudioVideo),
(true, false) => Some(MediaStreams::Audio),
(false, true) => Some(MediaStreams::Video),
(false, false) => None,
}
}
fn format_quality(&self) -> Option<&str> {
self.text("quality")
}
fn format_height(&self) -> Option<u64> {
format_count(self, "height")
}
fn format_width(&self) -> Option<u64> {
format_count(self, "width")
}
fn format_bitrate(&self) -> Option<u64> {
format_count(self, "bitrate")
}
fn format_size(&self) -> Option<u64> {
format_count(self, "content_length")
}
fn format_codecs(&self) -> Option<&str> {
self.text("codecs")
}
}
fn format_count(format: &Format, key: &str) -> Option<u64> {
match format.observe(key) {
Some(InfoValue::Integer(value)) => u64::try_from(*value).ok(),
Some(
InfoValue::Null
| InfoValue::Bool(_)
| InfoValue::Float(_)
| InfoValue::String(_)
| InfoValue::List(_)
| InfoValue::Record(_),
)
| None => None,
}
}