#[cfg(feature = "rocket")] use rocket::{FromForm, FromFormField, UriDisplayQuery}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Deserialize, Serialize)] #[cfg_attr(feature = "rocket", derive(FromForm, UriDisplayQuery))] pub struct StreamSpec { pub tracks: Vec, pub format: StreamFormat, pub webm: Option, pub abr: Option, pub vbr: Option, pub index: Option, } #[rustfmt::skip] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] #[cfg_attr(feature = "rocket", derive(FromFormField, UriDisplayQuery))] pub enum StreamFormat { #[cfg_attr(feature = "rocket", field(value = "original"))] Original, #[cfg_attr(feature = "rocket", field(value = "matroska"))] Matroska, #[cfg_attr(feature = "rocket", field(value = "hls"))] Hls, #[cfg_attr(feature = "rocket", field(value = "jhls"))] Jhls, #[cfg_attr(feature = "rocket", field(value = "hlsseg"))] Segment, } impl Default for StreamSpec { fn default() -> Self { Self { tracks: Vec::new(), format: StreamFormat::Matroska, webm: Some(true), abr: None, vbr: None, index: None, } } } impl StreamSpec { pub fn to_query(&self) -> String { use std::fmt::Write; let mut u = String::new(); writeln!(u, "format={}", self.format.ident()).unwrap(); if !self.tracks.is_empty() { writeln!( u, "&tracks={}", self.tracks .iter() .map(|s| s.to_string()) .collect::>() .join(",") ) .unwrap(); } if let Some(abr) = self.abr { writeln!(u, "&abr={abr}").unwrap(); } if let Some(vbr) = self.vbr { writeln!(u, "&vbr={vbr}").unwrap(); } if let Some(index) = self.index { writeln!(u, "&index={index}").unwrap(); } if let Some(webm) = self.webm { writeln!(u, "&webmm={webm}").unwrap(); } u } } impl StreamFormat { pub fn ident(&self) -> &'static str { match self { StreamFormat::Original => "original", StreamFormat::Matroska => "matroska", StreamFormat::Hls => "hls", StreamFormat::Jhls => "jhls", StreamFormat::Segment => "hlsseg", } } }