1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-06-03 05:59:22 +00:00
hls_m3u8/src/tags/media_segment/date_range.rs

166 lines
5.2 KiB
Rust
Raw Normal View History

2019-09-06 10:55:00 +00:00
use std::collections::BTreeMap;
use std::fmt;
use std::str::FromStr;
use std::time::Duration;
2019-09-13 14:06:52 +00:00
use crate::attribute::AttributePairs;
use crate::types::{DecimalFloatingPoint, ProtocolVersion};
use crate::utils::{quote, tag, unquote};
use crate::Error;
2019-09-06 10:55:00 +00:00
/// [4.3.2.7. EXT-X-DATERANGE]
///
/// [4.3.2.7. EXT-X-DATERANGE]: https://tools.ietf.org/html/rfc8216#section-4.3.2.7
///
/// TODO: Implement properly
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExtXDateRange {
2019-09-08 09:30:52 +00:00
pub id: String,
pub class: Option<String>,
pub start_date: String,
pub end_date: Option<String>,
2019-09-06 10:55:00 +00:00
pub duration: Option<Duration>,
pub planned_duration: Option<Duration>,
2019-09-08 09:30:52 +00:00
pub scte35_cmd: Option<String>,
pub scte35_out: Option<String>,
pub scte35_in: Option<String>,
2019-09-06 10:55:00 +00:00
pub end_on_next: bool,
pub client_attributes: BTreeMap<String, String>,
}
impl ExtXDateRange {
pub(crate) const PREFIX: &'static str = "#EXT-X-DATERANGE:";
/// Returns the protocol compatibility version that this tag requires.
2019-09-08 10:23:33 +00:00
pub const fn requires_version(&self) -> ProtocolVersion {
2019-09-06 10:55:00 +00:00
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXDateRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", Self::PREFIX)?;
2019-09-08 09:30:52 +00:00
write!(f, "ID={}", quote(&self.id))?;
2019-09-06 10:55:00 +00:00
if let Some(ref x) = self.class {
2019-09-08 09:30:52 +00:00
write!(f, ",CLASS={}", quote(x))?;
2019-09-06 10:55:00 +00:00
}
2019-09-08 09:30:52 +00:00
write!(f, ",START-DATE={}", quote(&self.start_date))?;
2019-09-06 10:55:00 +00:00
if let Some(ref x) = self.end_date {
2019-09-08 09:30:52 +00:00
write!(f, ",END-DATE={}", quote(x))?;
2019-09-06 10:55:00 +00:00
}
if let Some(x) = self.duration {
write!(f, ",DURATION={}", DecimalFloatingPoint::from_duration(x))?;
}
if let Some(x) = self.planned_duration {
write!(
f,
",PLANNED-DURATION={}",
DecimalFloatingPoint::from_duration(x)
)?;
}
if let Some(ref x) = self.scte35_cmd {
2019-09-08 09:30:52 +00:00
write!(f, ",SCTE35-CMD={}", quote(x))?;
2019-09-06 10:55:00 +00:00
}
if let Some(ref x) = self.scte35_out {
2019-09-08 09:30:52 +00:00
write!(f, ",SCTE35-OUT={}", quote(x))?;
2019-09-06 10:55:00 +00:00
}
if let Some(ref x) = self.scte35_in {
2019-09-08 09:30:52 +00:00
write!(f, ",SCTE35-IN={}", quote(x))?;
2019-09-06 10:55:00 +00:00
}
if self.end_on_next {
write!(f, ",END-ON-NEXT=YES",)?;
}
for (k, v) in &self.client_attributes {
write!(f, ",{}={}", k, v)?;
}
Ok(())
}
}
impl FromStr for ExtXDateRange {
type Err = Error;
2019-09-13 14:06:52 +00:00
fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?;
2019-09-06 10:55:00 +00:00
let mut id = None;
let mut class = None;
let mut start_date = None;
let mut end_date = None;
let mut duration = None;
let mut planned_duration = None;
let mut scte35_cmd = None;
let mut scte35_out = None;
let mut scte35_in = None;
let mut end_on_next = false;
2019-09-13 14:06:52 +00:00
2019-09-06 10:55:00 +00:00
let mut client_attributes = BTreeMap::new();
2019-09-13 14:06:52 +00:00
let attrs = AttributePairs::parse(input);
2019-09-06 10:55:00 +00:00
for attr in attrs {
2019-09-13 14:06:52 +00:00
let (key, value) = attr?;
2019-09-06 10:55:00 +00:00
match key {
2019-09-08 09:30:52 +00:00
"ID" => id = Some(unquote(value)),
"CLASS" => class = Some(unquote(value)),
"START-DATE" => start_date = Some(unquote(value)),
"END-DATE" => end_date = Some(unquote(value)),
2019-09-06 10:55:00 +00:00
"DURATION" => {
2019-09-13 14:06:52 +00:00
let seconds: DecimalFloatingPoint = (value.parse())?;
2019-09-06 10:55:00 +00:00
duration = Some(seconds.to_duration());
}
"PLANNED-DURATION" => {
2019-09-13 14:06:52 +00:00
let seconds: DecimalFloatingPoint = (value.parse())?;
2019-09-06 10:55:00 +00:00
planned_duration = Some(seconds.to_duration());
}
2019-09-08 09:30:52 +00:00
"SCTE35-CMD" => scte35_cmd = Some(unquote(value)),
"SCTE35-OUT" => scte35_out = Some(unquote(value)),
"SCTE35-IN" => scte35_in = Some(unquote(value)),
2019-09-06 10:55:00 +00:00
"END-ON-NEXT" => {
2019-09-13 14:06:52 +00:00
if value != "YES" {
return Err(Error::invalid_input());
}
2019-09-06 10:55:00 +00:00
end_on_next = true;
}
_ => {
if key.starts_with("X-") {
client_attributes.insert(key.split_at(2).1.to_owned(), value.to_owned());
} else {
// [6.3.1. General Client Responsibilities]
// > ignore any attribute/value pair with an unrecognized AttributeName.
}
}
}
}
2019-09-13 14:06:52 +00:00
let id = id.ok_or(Error::missing_value("EXT-X-ID"))?;
let start_date = start_date.ok_or(Error::missing_value("EXT-X-START-DATE"))?;
2019-09-06 10:55:00 +00:00
if end_on_next {
2019-09-13 14:06:52 +00:00
if class.is_none() {
return Err(Error::invalid_input());
}
2019-09-06 10:55:00 +00:00
}
Ok(ExtXDateRange {
id,
class,
start_date,
end_date,
duration,
planned_duration,
scte35_cmd,
scte35_out,
scte35_in,
end_on_next,
client_attributes,
})
}
}
#[cfg(test)]
mod test {
use super::*;
#[test] // TODO; write some tests
2019-09-06 11:21:05 +00:00
fn it_works() {}
2019-09-06 10:55:00 +00:00
}