mirror of
https://github.com/rutgersc/m3u8-rs.git
synced 2024-06-26 07:20:32 +00:00
Merge pull request #1 from rutgersc/vaget/vagetman-nom-5.1.0-extra
Updated docs, tests to nom 5.1.0
This commit is contained in:
commit
3fee7b9983
|
@ -3,7 +3,6 @@ extern crate m3u8_rs;
|
||||||
|
|
||||||
use m3u8_rs::playlist::{Playlist};
|
use m3u8_rs::playlist::{Playlist};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use nom::IResult;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut file = std::fs::File::open("playlist.m3u8").unwrap();
|
let mut file = std::fs::File::open("playlist.m3u8").unwrap();
|
||||||
|
@ -13,9 +12,8 @@ fn main() {
|
||||||
let parsed = m3u8_rs::parse_playlist(&bytes);
|
let parsed = m3u8_rs::parse_playlist(&bytes);
|
||||||
|
|
||||||
let playlist = match parsed {
|
let playlist = match parsed {
|
||||||
IResult::Done(i, playlist) => playlist,
|
Result::Ok((i, playlist)) => playlist,
|
||||||
IResult::Error(e) => panic!("Parsing error: \n{}", e),
|
Result::Err(e) => panic!("Parsing error: \n{}", e),
|
||||||
IResult::Incomplete(e) => panic!("Parsing error: \n{:?}", e),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match playlist {
|
match playlist {
|
||||||
|
@ -32,9 +30,8 @@ fn main_alt() {
|
||||||
let parsed = m3u8_rs::parse_playlist(&bytes);
|
let parsed = m3u8_rs::parse_playlist(&bytes);
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
IResult::Done(i, Playlist::MasterPlaylist(pl)) => println!("Master playlist:\n{:?}", pl),
|
Result::Ok((i, Playlist::MasterPlaylist(pl))) => println!("Master playlist:\n{:?}", pl),
|
||||||
IResult::Done(i, Playlist::MediaPlaylist(pl)) => println!("Media playlist:\n{:?}", pl),
|
Result::Ok((i, Playlist::MediaPlaylist(pl))) => println!("Media playlist:\n{:?}", pl),
|
||||||
IResult::Error(e) => panic!("Parsing error: \n{}", e),
|
Result::Err(e) => panic!("Parsing error: \n{}", e),
|
||||||
IResult::Incomplete(e) => panic!("Parsing error: \n{:?}", e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
src/lib.rs
49
src/lib.rs
|
@ -1,7 +1,7 @@
|
||||||
//! A library to parse m3u8 playlists (HTTP Live Streaming) [link]
|
//! A library to parse m3u8 playlists (HTTP Live Streaming) [link]
|
||||||
//! (https://tools.ietf.org/html/draft-pantos-http-live-streaming-19).
|
//! (https://tools.ietf.org/html/draft-pantos-http-live-streaming-19).
|
||||||
//!
|
//!
|
||||||
//! #Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! Parsing a playlist and let the parser figure out if it's a media or master playlist.
|
//! Parsing a playlist and let the parser figure out if it's a media or master playlist.
|
||||||
//!
|
//!
|
||||||
|
@ -17,19 +17,10 @@
|
||||||
//! let mut bytes: Vec<u8> = Vec::new();
|
//! let mut bytes: Vec<u8> = Vec::new();
|
||||||
//! file.read_to_end(&mut bytes).unwrap();
|
//! file.read_to_end(&mut bytes).unwrap();
|
||||||
//!
|
//!
|
||||||
//! // Option 1: fn parse_playlist_res(input) -> Result<Playlist, _>
|
|
||||||
//! match m3u8_rs::parse_playlist_res(&bytes) {
|
|
||||||
//! Ok(Playlist::MasterPlaylist(pl)) => println!("Master playlist:\n{:?}", pl),
|
|
||||||
//! Ok(Playlist::MediaPlaylist(pl)) => println!("Media playlist:\n{:?}", pl),
|
|
||||||
//! Err(e) => println!("Error: {:?}", e)
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // Option 2: fn parse_playlist(input) -> IResult<_, Playlist, _>
|
|
||||||
//! match m3u8_rs::parse_playlist(&bytes) {
|
//! match m3u8_rs::parse_playlist(&bytes) {
|
||||||
//! IResult::Done(i, Playlist::MasterPlaylist(pl)) => println!("Master playlist:\n{:?}", pl),
|
//! Result::Ok((i, Playlist::MasterPlaylist(pl))) => println!("Master playlist:\n{:?}", pl),
|
||||||
//! IResult::Done(i, Playlist::MediaPlaylist(pl)) => println!("Media playlist:\n{:?}", pl),
|
//! Result::Ok((i, Playlist::MediaPlaylist(pl))) => println!("Media playlist:\n{:?}", pl),
|
||||||
//! IResult::Error(e) => panic!("Parsing error: \n{}", e),
|
//! Result::Err(e) => panic!("Parsing error: \n{}", e),
|
||||||
//! IResult::Incomplete(e) => panic!("Parsing error: \n{:?}", e),
|
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -47,7 +38,7 @@
|
||||||
//! let mut bytes: Vec<u8> = Vec::new();
|
//! let mut bytes: Vec<u8> = Vec::new();
|
||||||
//! file.read_to_end(&mut bytes).unwrap();
|
//! file.read_to_end(&mut bytes).unwrap();
|
||||||
//!
|
//!
|
||||||
//! if let IResult::Done(_, pl) = m3u8_rs::parse_master_playlist(&bytes) {
|
//! if let Result::Ok((_, pl)) = m3u8_rs::parse_master_playlist(&bytes) {
|
||||||
//! println!("{:?}", pl);
|
//! println!("{:?}", pl);
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
|
@ -97,7 +88,7 @@ use nom::{IResult};
|
||||||
use nom::{ delimited,none_of,peek,is_not,complete,terminated,tag,
|
use nom::{ delimited,none_of,peek,is_not,complete,terminated,tag,
|
||||||
alt,do_parse,opt,named,map,map_res,eof,many0,take,take_until,char};
|
alt,do_parse,opt,named,map,map_res,eof,many0,take,take_until,char};
|
||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
|
use nom::character::complete::{line_ending};
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::string;
|
use std::string;
|
||||||
|
@ -110,10 +101,14 @@ use playlist::*;
|
||||||
// Playlist parser
|
// Playlist parser
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Parse a m3u8 playlist.
|
/// Parse an m3u8 playlist.
|
||||||
///
|
///
|
||||||
/// #Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::Read;
|
||||||
|
/// use m3u8_rs::playlist::{Playlist};
|
||||||
|
///
|
||||||
/// let mut file = std::fs::File::open("playlist.m3u8").unwrap();
|
/// let mut file = std::fs::File::open("playlist.m3u8").unwrap();
|
||||||
/// let mut bytes: Vec<u8> = Vec::new();
|
/// let mut bytes: Vec<u8> = Vec::new();
|
||||||
/// file.read_to_end(&mut bytes).unwrap();
|
/// file.read_to_end(&mut bytes).unwrap();
|
||||||
|
@ -121,15 +116,15 @@ use playlist::*;
|
||||||
/// let parsed = m3u8_rs::parse_playlist(&bytes);
|
/// let parsed = m3u8_rs::parse_playlist(&bytes);
|
||||||
///
|
///
|
||||||
/// let playlist = match parsed {
|
/// let playlist = match parsed {
|
||||||
/// IResult::Done(i, playlist) => playlist,
|
/// Result::Ok((i, playlist)) => playlist,
|
||||||
/// IResult::Error(e) => panic!("Parsing error: \n{}", e),
|
/// Result::Err(e) => panic!("Parsing error: \n{}", e),
|
||||||
/// IResult::Incomplete(e) => panic!("Parsing error: \n{:?}", e),
|
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// match playlist {
|
/// match playlist {
|
||||||
/// Playlist::MasterPlaylist(pl) => println!("Master playlist:\n{:?}", pl),
|
/// Playlist::MasterPlaylist(pl) => println!("Master playlist:\n{:?}", pl),
|
||||||
/// Playlist::MediaPlaylist(pl) => println!("Media playlist:\n{:?}", pl),
|
/// Playlist::MediaPlaylist(pl) => println!("Media playlist:\n{:?}", pl),
|
||||||
/// }
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn parse_playlist(input: &[u8]) -> IResult<&[u8], Playlist> {
|
pub fn parse_playlist(input: &[u8]) -> IResult<&[u8], Playlist> {
|
||||||
match is_master_playlist(input) {
|
match is_master_playlist(input) {
|
||||||
true => map(parse_master_playlist, Playlist::MasterPlaylist)(input),
|
true => map(parse_master_playlist, Playlist::MasterPlaylist)(input),
|
||||||
|
@ -137,9 +132,10 @@ pub fn parse_playlist(input: &[u8]) -> IResult<&[u8], Playlist> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a m3u8 playlist just like `parse_playlist`. This returns a Result<PLaylist,_>.
|
/// Parses an m3u8 playlist just like `parse_playlist`, except that this returns an [std::result::Result](std::result::Result) instead of a [nom::IResult](https://docs.rs/nom/1.2.3/nom/enum.IResult.html).
|
||||||
///
|
/// However, since [nom::IResult](nom::IResult) is now an [alias to Result](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_5.md), this is no longer needed.
|
||||||
/// #Examples
|
///
|
||||||
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use m3u8_rs::playlist::{Playlist};
|
/// use m3u8_rs::playlist::{Playlist};
|
||||||
|
@ -517,10 +513,9 @@ named!(pub unquoted<String>,
|
||||||
|
|
||||||
named!(pub consume_line<String>,
|
named!(pub consume_line<String>,
|
||||||
do_parse!(
|
do_parse!(
|
||||||
l: map_res!(is_not!("\r\n"), from_utf8_slice)
|
line: map_res!(is_not!("\r\n"), from_utf8_slice)
|
||||||
>> take!(1)
|
>> line_ending
|
||||||
>>
|
>> (line)
|
||||||
(l)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
52
tests/lib.rs
52
tests/lib.rs
|
@ -42,7 +42,7 @@ fn print_parse_playlist_test(playlist_name: &str) -> bool {
|
||||||
println!("Parsing playlist file: {:?}", playlist_name);
|
println!("Parsing playlist file: {:?}", playlist_name);
|
||||||
let parsed = parse_playlist(input.as_bytes());
|
let parsed = parse_playlist(input.as_bytes());
|
||||||
|
|
||||||
if let IResult::Done(i,o) = parsed {
|
if let Result::Ok((i,o)) = parsed {
|
||||||
println!("{:?}", o);
|
println!("{:?}", o);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -117,9 +117,9 @@ fn playlist_types() {
|
||||||
let input = getm3u(path);
|
let input = getm3u(path);
|
||||||
let is_master = is_master_playlist(input.as_bytes());
|
let is_master = is_master_playlist(input.as_bytes());
|
||||||
|
|
||||||
assert!(path.to_lowercase().contains("master") == is_master);
|
|
||||||
|
|
||||||
println!("{:?} = {:?}", path, is_master);
|
println!("{:?} = {:?}", path, is_master);
|
||||||
|
|
||||||
|
assert!(path.to_lowercase().contains("master") == is_master);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ fn test_key_value_pairs_trailing_equals() {
|
||||||
fn test_key_value_pairs_multiple_quoted_values() {
|
fn test_key_value_pairs_multiple_quoted_values() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
key_value_pairs(b"BANDWIDTH=86000,URI=\"low/iframe.m3u8\",PROGRAM-ID=1,RESOLUTION=\"1x1\",VIDEO=1\nrest"),
|
key_value_pairs(b"BANDWIDTH=86000,URI=\"low/iframe.m3u8\",PROGRAM-ID=1,RESOLUTION=\"1x1\",VIDEO=1\nrest"),
|
||||||
IResult::Done(
|
Result::Ok((
|
||||||
"\nrest".as_bytes(),
|
"\nrest".as_bytes(),
|
||||||
vec![
|
vec![
|
||||||
("BANDWIDTH".to_string(), "86000".to_string()),
|
("BANDWIDTH".to_string(), "86000".to_string()),
|
||||||
|
@ -156,7 +156,7 @@ fn test_key_value_pairs_multiple_quoted_values() {
|
||||||
("RESOLUTION".to_string(), "1x1".to_string()),
|
("RESOLUTION".to_string(), "1x1".to_string()),
|
||||||
("VIDEO".to_string(), "1".to_string())
|
("VIDEO".to_string(), "1".to_string())
|
||||||
].into_iter().collect::<HashMap<String,String>>()
|
].into_iter().collect::<HashMap<String,String>>()
|
||||||
)
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,10 +177,10 @@ fn test_key_value_pairs() {
|
||||||
fn test_key_value_pair() {
|
fn test_key_value_pair() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
key_value_pair(b"PROGRAM-ID=1,rest"),
|
key_value_pair(b"PROGRAM-ID=1,rest"),
|
||||||
IResult::Done(
|
Result::Ok((
|
||||||
"rest".as_bytes(),
|
"rest".as_bytes(),
|
||||||
("PROGRAM-ID".to_string(), "1".to_string())
|
("PROGRAM-ID".to_string(), "1".to_string())
|
||||||
)
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ fn test_key_value_pair() {
|
||||||
fn comment() {
|
fn comment() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
comment_tag(b"#Hello\nxxx"),
|
comment_tag(b"#Hello\nxxx"),
|
||||||
IResult::Done("xxx".as_bytes(), "Hello".to_string())
|
Result::Ok(("xxx".as_bytes(), "Hello".to_string()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,21 +196,39 @@ fn comment() {
|
||||||
fn quotes() {
|
fn quotes() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
quoted(b"\"value\"rest"),
|
quoted(b"\"value\"rest"),
|
||||||
IResult::Done("rest".as_bytes(), "value".to_string())
|
Result::Ok(("rest".as_bytes(), "value".to_string()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn consume_empty_line() {
|
fn consume_line_empty() {
|
||||||
let line = consume_line(b"\r\nrest");
|
assert_eq!(
|
||||||
println!("{:?}", line);
|
consume_line(b"\r\nrest"),
|
||||||
|
Result::Err(nom::Err::Error(("\r\nrest".as_bytes(), nom::error::ErrorKind::IsNot)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn consume_line_n() {
|
||||||
|
assert_eq!(
|
||||||
|
consume_line(b"before\nrest"),
|
||||||
|
Result::Ok(("rest".as_bytes(), "before".into()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn consume_line_rn() {
|
||||||
|
assert_eq!(
|
||||||
|
consume_line(b"before\r\nrest"),
|
||||||
|
Result::Ok(("rest".as_bytes(), "before".into()))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_() {
|
fn float_() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
float(b"33.22rest"),
|
float(b"33.22rest"),
|
||||||
IResult::Done("rest".as_bytes(), 33.22f32)
|
Result::Ok(("rest".as_bytes(), 33.22f32))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +236,7 @@ fn float_() {
|
||||||
fn float_no_decimal() {
|
fn float_no_decimal() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
float(b"33rest"),
|
float(b"33rest"),
|
||||||
IResult::Done("rest".as_bytes(), 33f32)
|
Result::Ok(("rest".as_bytes(), 33f32))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +244,7 @@ fn float_no_decimal() {
|
||||||
fn float_should_ignore_trailing_dot() {
|
fn float_should_ignore_trailing_dot() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
float(b"33.rest"),
|
float(b"33.rest"),
|
||||||
IResult::Done(".rest".as_bytes(), 33f32)
|
Result::Ok((".rest".as_bytes(), 33f32))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +252,7 @@ fn float_should_ignore_trailing_dot() {
|
||||||
fn parse_duration_title() {
|
fn parse_duration_title() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
duration_title_tag(b"2.002,title\nrest"),
|
duration_title_tag(b"2.002,title\nrest"),
|
||||||
IResult::Done("rest".as_bytes(), (2.002f32, Some("title".to_string())))
|
Result::Ok(("rest".as_bytes(), (2.002f32, Some("title".to_string()))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +297,7 @@ fn create_and_parse_master_playlist_full() {
|
||||||
uri: "masterplaylist-uri".into(),
|
uri: "masterplaylist-uri".into(),
|
||||||
bandwidth: "10010010".into(),
|
bandwidth: "10010010".into(),
|
||||||
average_bandwidth: Some("10010010".into()),
|
average_bandwidth: Some("10010010".into()),
|
||||||
codecs: "TheCODEC".into(),
|
codecs: Some("TheCODEC".into()),
|
||||||
resolution: Some("1000x3000".into()),
|
resolution: Some("1000x3000".into()),
|
||||||
frame_rate: Some("60".into()),
|
frame_rate: Some("60".into()),
|
||||||
audio: Some("audio".into()),
|
audio: Some("audio".into()),
|
||||||
|
|
Loading…
Reference in a new issue