use bitflags::bitflags;
use serde::{Deserialize, Serialize};
use serde_with::DefaultOnError;
use serde_with::serde_as;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoQuality {
P240 = 6,
P360 = 16,
P480 = 32,
P720 = 64,
P720_60 = 74,
P1080 = 80,
Smart = 100,
P1080Plus = 112,
P1080_60 = 116,
P4K = 120,
HDR = 125,
DolbyVision = 126,
P8K = 127,
}
impl VideoQuality {
pub fn as_u32(self) -> u32 {
self as u32
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Fnval: u32 {
const FLV = 0; const MP4 = 1; const DASH = 1 << 4;
const HDR = 1 << 6; const FOURK = 1 << 7; const DOLBY_AUDIO = 1 << 8; const DOLBY_VISION = 1 << 9; const EIGHTK = 1 << 10; const AV1 = 1 << 11;
const AI_FIX = 12240; }
}
impl Fnval {
pub fn is_fourk(&self) -> bool {
self.contains(Fnval::FOURK) || self.contains(Fnval::EIGHTK)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoCodec {
Avc = 7,
Hevc = 12,
Av1 = 13,
}
impl VideoCodec {
pub fn as_u32(self) -> u32 {
self as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AudioQuality {
K64 = 30216,
K132 = 30232,
K192 = 30280,
}
impl AudioQuality {
pub fn as_u32(self) -> u32 {
self as u32
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoStreamData {
pub quality: u32,
pub accept_quality: Vec<u32>,
pub accept_format: String,
pub accept_description: Vec<String>,
pub format: String,
pub video_codecid: u32,
#[serde(default, rename = "durls")]
pub durl: Option<Vec<Durl>>,
#[serde(default)]
pub dash: Option<DashStreams>,
pub has_paid: bool,
pub support_formats: Vec<SupportFormat>,
#[serde(default)]
pub timelength: Option<u64>,
#[serde(default)]
pub fnval: Option<u32>,
#[serde(default)]
pub is_preview: Option<u32>,
}
impl VideoStreamData {
pub fn best_format(&self) -> Option<&SupportFormat> {
self.support_formats.iter().max_by_key(|f| f.quality)
}
pub fn best_video(&self) -> Option<&DashTrack> {
self.dash.as_ref().and_then(|dash| {
dash.video.iter().max_by(|a, b| {
let res_a = a.width * a.height;
let res_b = b.width * b.height;
res_a
.cmp(&res_b)
.then_with(|| a.bandwidth.cmp(&b.bandwidth))
.then_with(|| {
let codec_priority = |c: &str| {
if c.starts_with("hev1") || c.starts_with("hvc1") {
1
} else {
0
}
};
codec_priority(&a.codecs).cmp(&codec_priority(&b.codecs))
})
})
})
}
pub fn best_audio(&self) -> Option<&DashTrack> {
self.dash.as_ref().and_then(|dash| {
dash.audio.iter().max_by(|a, b| {
a.bandwidth
.cmp(&b.bandwidth)
.then_with(|| a.size.cmp(&b.size))
})
})
}
pub fn supports_dash(&self) -> bool {
self.dash.is_some()
}
pub fn supports_direct_url(&self) -> bool {
self.durl.is_some() && !self.durl.as_ref().unwrap().is_empty()
}
pub fn duration_seconds(&self) -> Option<u64> {
self.timelength.map(|ms| ms / 1000)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Durl {
pub size: u64,
pub ahead: String,
pub length: u64,
pub vhead: String,
pub backup_url: Vec<String>,
pub url: String,
pub order: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SupportFormat {
pub display_desc: String,
pub format: String,
pub description: String,
pub quality: u32,
pub new_description: String,
pub superscript: String,
#[serde(default)]
pub codecs: Vec<String>,
pub attribute: Option<u32>,
pub has_preview: Option<bool>,
pub sub_description: Option<String>,
pub need_login: Option<bool>,
pub need_vip: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashStreams {
pub duration: u64,
pub min_buffer_time: f64,
pub video: Vec<DashTrack>,
pub audio: Vec<DashTrack>,
pub dolby: Option<DashDolby>,
pub flac: Option<DashFlac>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashFlac {
pub display_sample_rate: String,
pub audio: DashTrack,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SegmentBase {
pub initialization: String,
pub index_range: String,
}
#[serde_as]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashDolby {
#[serde_as(as = "DefaultOnError")]
pub r#type: u32,
pub audio: Vec<DashTrack>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashTrack {
pub id: u32,
pub base_url: String,
pub backup_url: Vec<String>,
pub bandwidth: u32,
pub mime_type: String,
pub codecs: String,
pub width: u32,
pub height: u32,
pub frame_rate: String,
pub sar: String,
pub start_with_sap: u32,
pub segment_base: SegmentBase,
pub codecid: u32,
pub size: u64,
pub md5: Option<String>,
}