mirror of
https://github.com/v0l/m3u8-rs.git
synced 2025-06-22 19:18:07 +00:00
Allow unknown tags at the master playlist level
This commit is contained in:
@ -276,6 +276,7 @@ pub enum MasterPlaylistTag {
|
|||||||
IndependentSegments,
|
IndependentSegments,
|
||||||
Comment(String),
|
Comment(String),
|
||||||
Uri(String),
|
Uri(String),
|
||||||
|
Unknown(ExtTag),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn master_playlist_tag(input: &[u8]) -> IResult<&[u8], MasterPlaylistTag> {
|
pub fn master_playlist_tag(input: &[u8]) -> IResult<&[u8], MasterPlaylistTag> {
|
||||||
@ -291,6 +292,8 @@ pub fn master_playlist_tag(input: &[u8]) -> IResult<&[u8], MasterPlaylistTag> {
|
|||||||
| map!(start_tag, MasterPlaylistTag::Start)
|
| map!(start_tag, MasterPlaylistTag::Start)
|
||||||
| map!(tag!("#EXT-X-INDEPENDENT-SEGMENTS"), |_| MasterPlaylistTag::IndependentSegments)
|
| map!(tag!("#EXT-X-INDEPENDENT-SEGMENTS"), |_| MasterPlaylistTag::IndependentSegments)
|
||||||
|
|
||||||
|
| map!(ext_tag, MasterPlaylistTag::Unknown)
|
||||||
|
|
||||||
| map!(comment_tag, MasterPlaylistTag::Comment)
|
| map!(comment_tag, MasterPlaylistTag::Comment)
|
||||||
|
|
||||||
| map!(consume_line, MasterPlaylistTag::Uri)
|
| map!(consume_line, MasterPlaylistTag::Uri)
|
||||||
@ -328,6 +331,9 @@ pub fn master_playlist_from_tags(mut tags: Vec<MasterPlaylistTag>) -> MasterPlay
|
|||||||
MasterPlaylistTag::IndependentSegments => {
|
MasterPlaylistTag::IndependentSegments => {
|
||||||
master_playlist.independent_segments = true;
|
master_playlist.independent_segments = true;
|
||||||
}
|
}
|
||||||
|
MasterPlaylistTag::Unknown(unknown) => {
|
||||||
|
master_playlist.unknown_tags.push(unknown);
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use std::collections::HashMap;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
macro_rules! write_some_attribute_quoted {
|
macro_rules! write_some_attribute_quoted {
|
||||||
($w:expr, $tag:expr, $o:expr) => (
|
($w:expr, $tag:expr, $o:expr) => (
|
||||||
@ -69,6 +70,7 @@ pub struct MasterPlaylist {
|
|||||||
pub start: Option<Start>,
|
pub start: Option<Start>,
|
||||||
pub independent_segments: bool,
|
pub independent_segments: bool,
|
||||||
pub alternatives: Vec<AlternativeMedia>, // EXT-X-MEDIA tags
|
pub alternatives: Vec<AlternativeMedia>, // EXT-X-MEDIA tags
|
||||||
|
pub unknown_tags: Vec<ExtTag>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MasterPlaylist {
|
impl MasterPlaylist {
|
||||||
@ -100,6 +102,9 @@ impl MasterPlaylist {
|
|||||||
if self.independent_segments {
|
if self.independent_segments {
|
||||||
writeln!(w, "#EXT-X-INDEPENDENT-SEGMENTS")?;
|
writeln!(w, "#EXT-X-INDEPENDENT-SEGMENTS")?;
|
||||||
}
|
}
|
||||||
|
for unknown_tag in &self.unknown_tags {
|
||||||
|
writeln!(w, "{}", unknown_tag)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -528,11 +533,7 @@ impl MediaSegment {
|
|||||||
writeln!(w, "#EXT-X-DATERANGE:{}", v)?;
|
writeln!(w, "#EXT-X-DATERANGE:{}", v)?;
|
||||||
}
|
}
|
||||||
for unknown_tag in &self.unknown_tags {
|
for unknown_tag in &self.unknown_tags {
|
||||||
write!(w, "#EXT-{}", unknown_tag.tag)?;
|
writeln!(w, "{}", unknown_tag)?;
|
||||||
if let Some(v) = &unknown_tag.rest {
|
|
||||||
writeln!(w, ":{}", v)?;
|
|
||||||
}
|
|
||||||
write!(w, "\n")?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(w, "#EXTINF:{},", self.duration)?;
|
write!(w, "#EXTINF:{},", self.duration)?;
|
||||||
@ -692,3 +693,43 @@ pub struct ExtTag {
|
|||||||
pub rest: Option<String>,
|
pub rest: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ExtTag {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "#EXT-{}", self.tag)?;
|
||||||
|
if let Some(v) = &self.rest {
|
||||||
|
write!(f, ":{}", v)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ext_tag_with_value_is_printable() {
|
||||||
|
let cue_out_tag = ExtTag {
|
||||||
|
tag: "X-CUE-OUT".into(),
|
||||||
|
rest: Some("DURATION=30".into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut output = Vec::new();
|
||||||
|
write!(output, "{}", cue_out_tag);
|
||||||
|
|
||||||
|
assert_eq!(std::str::from_utf8(output.as_slice()).unwrap(), "#EXT-X-CUE-OUT:DURATION=30")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ext_tag_without_value_is_printable() {
|
||||||
|
let cue_in_tag = ExtTag {
|
||||||
|
tag: "X-CUE-IN".into(),
|
||||||
|
rest: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut output = Vec::new();
|
||||||
|
write!(output, "{}", cue_in_tag);
|
||||||
|
|
||||||
|
assert_eq!(std::str::from_utf8(output.as_slice()).unwrap(), "#EXT-X-CUE-IN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -390,6 +390,7 @@ fn create_and_parse_master_playlist_full() {
|
|||||||
precise: Some("YES".into()),
|
precise: Some("YES".into()),
|
||||||
}),
|
}),
|
||||||
independent_segments: true,
|
independent_segments: true,
|
||||||
|
unknown_tags: vec![],
|
||||||
});
|
});
|
||||||
let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
|
let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
|
||||||
assert_eq!(playlist_original, playlist_parsed);
|
assert_eq!(playlist_original, playlist_parsed);
|
||||||
|
Reference in New Issue
Block a user