mirror of
https://github.com/rutgersc/m3u8-rs.git
synced 2024-12-22 22:46:37 +00:00
Fixed a bug where the parser fails when the playlist does not end with a newline.
This commit is contained in:
parent
fe2ceb87dd
commit
d7c452fe78
5 changed files with 73 additions and 34 deletions
16
sample-playlists/master-not-ending-in-newline.m3u8
Normal file
16
sample-playlists/master-not-ending-in-newline.m3u8
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#EXTM3U
|
||||||
|
#EXT-X-VERSION:4
|
||||||
|
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="Audio1",NAME="mp4a.40.2_96K_Spanish",LANGUAGE="spa",DEFAULT=YES,AUTOSELECT=YES,URI="A1.m3u8"
|
||||||
|
A1.m3u8
|
||||||
|
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=395000,CODECS="avc1.4d001f,mp4a.40.2",AUDIO="Audio1",RESOLUTION=320x240
|
||||||
|
01.m3u8
|
||||||
|
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=394000,CODECS="avc1.4d001f,mp4a.40.2",URI="01_iframe_index.m3u8"
|
||||||
|
01_iframe_index.m3u8
|
||||||
|
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=963000,CODECS="avc1.4d001f,mp4a.40.2",AUDIO="Audio1",RESOLUTION=448x336
|
||||||
|
02.m3u8
|
||||||
|
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=962000,CODECS="avc1.4d001f,mp4a.40.2",URI="02_iframe_index.m3u8"
|
||||||
|
02_iframe_index.m3u8
|
||||||
|
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1695000,CODECS="avc1.4d001f,mp4a.40.2",AUDIO="Audio1",RESOLUTION=640x480
|
||||||
|
03.m3u8
|
||||||
|
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=1694000,CODECS="avc1.4d001f,mp4a.40.2",URI="03_iframe_index.m3u8"
|
||||||
|
03_iframe_index.m3u8
|
|
@ -1,20 +0,0 @@
|
||||||
#EXTM3U
|
|
||||||
#EXT-X-TWITCH-INFO:NODE="video47.lhr02",MANIFEST-NODE="video47.lhr02",SERVER-TIME="1463829370.34",USER-IP="145.87.245.122",CLUSTER="lhr02",STREAM-TIME="39299.3432069",MANIFEST-CLUSTER="lhr02"
|
|
||||||
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="Source",AUTOSELECT=YES,DEFAULT=YES
|
|
||||||
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3960281,RESOLUTION=1280x720,CODECS="avc1.4D4029,mp4a.40.2",VIDEO="chunked"
|
|
||||||
http://video47.lhr02.hls.ttvnw.net/hls32/itmejp_21425103760_456233939/chunked/index-live.m3u8?token=id=1079441765470438139,bid=21425103760,exp=1463915770,node=video47-1.lhr02.hls.justin.tv,nname=video47.lhr02,fmt=chunked&sig=2491212c28bdc97e74c8755d6cc18f8bdd971f30
|
|
||||||
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="high",NAME="High",AUTOSELECT=YES,DEFAULT=YES
|
|
||||||
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1760000,RESOLUTION=1280x720,CODECS="avc1.66.31,mp4a.40.2",VIDEO="high"
|
|
||||||
http://video47.lhr02.hls.ttvnw.net/hls32/itmejp_21425103760_456233939/high/index-live.m3u8?token=id=1079441765470438139,bid=21425103760,exp=1463915770,node=video47-1.lhr02.hls.justin.tv,nname=video47.lhr02,fmt=high&sig=be34da4d70ab7cabe773f12a37d863565efe2b46
|
|
||||||
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="medium",NAME="Medium",AUTOSELECT=YES,DEFAULT=YES
|
|
||||||
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=928000,RESOLUTION=852x480,CODECS="avc1.66.31,mp4a.40.2",VIDEO="medium"
|
|
||||||
http://video47.lhr02.hls.ttvnw.net/hls32/itmejp_21425103760_456233939/medium/index-live.m3u8?token=id=1079441765470438139,bid=21425103760,exp=1463915770,node=video47-1.lhr02.hls.justin.tv,nname=video47.lhr02,fmt=medium&sig=88ee9e7c5416096599e0b46017d7de82f876b8ae
|
|
||||||
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Low",AUTOSELECT=YES,DEFAULT=YES
|
|
||||||
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=596000,RESOLUTION=640x360,CODECS="avc1.66.31,mp4a.40.2",VIDEO="low"
|
|
||||||
http://video47.lhr02.hls.ttvnw.net/hls32/itmejp_21425103760_456233939/low/index-live.m3u8?token=id=1079441765470438139,bid=21425103760,exp=1463915770,node=video47-1.lhr02.hls.justin.tv,nname=video47.lhr02,fmt=low&sig=79398c8f2e8636720d59aa2310e19eff6ab42d46
|
|
||||||
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mobile",NAME="Mobile",AUTOSELECT=YES,DEFAULT=YES
|
|
||||||
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=164000,RESOLUTION=400x226,CODECS="avc1.66.31,mp4a.40.2",VIDEO="mobile"
|
|
||||||
http://video47.lhr02.hls.ttvnw.net/hls32/itmejp_21425103760_456233939/mobile/index-live.m3u8?token=id=1079441765470438139,bid=21425103760,exp=1463915770,node=video47-1.lhr02.hls.justin.tv,nname=video47.lhr02,fmt=mobile&sig=cc9f889823f25969c8b8d911ea9193dc33ce41dc
|
|
||||||
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="audio_only",NAME="Audio Only",AUTOSELECT=NO,DEFAULT=NO
|
|
||||||
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000,CODECS="mp4a.40.2",VIDEO="audio_only"
|
|
||||||
http://video47.lhr02.hls.ttvnw.net/hls32/itmejp_21425103760_456233939/audio_only/index-live.m3u8?token=id=1079441765470438139,bid=21425103760,exp=1463915770,node=video47-1.lhr02.hls.justin.tv,nname=video47.lhr02,fmt=audio_only&sig=e3179b7cacb9530df951f8d683ff02a493100849
|
|
35
sample-playlists/media-not-ending-in-newline.m3u8
Normal file
35
sample-playlists/media-not-ending-in-newline.m3u8
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#EXTM3U
|
||||||
|
#EXT-X-VERSION:4
|
||||||
|
#EXT-X-TARGETDURATION:3
|
||||||
|
#EXT-X-MEDIA-SEQUENCE:338559
|
||||||
|
#EXT-X-KEY:METHOD=AES-128,URI="https://secure.domain.com",IV=0xb059217aa2649ce170b734
|
||||||
|
#EXTINF:2.002,338559
|
||||||
|
20140311T113819-01-338559live.ts
|
||||||
|
#EXTINF:2.002,338560
|
||||||
|
20140311T113819-01-338560live.ts
|
||||||
|
#EXTINF:2.002,338561
|
||||||
|
20140311T113819-01-338561live.ts
|
||||||
|
#EXTINF:2.002,338562
|
||||||
|
20140311T113819-01-338562live.ts
|
||||||
|
#EXTINF:2.002,338563
|
||||||
|
20140311T113819-01-338563live.ts
|
||||||
|
#EXTINF:2.002,338564
|
||||||
|
20140311T113819-01-338564live.ts
|
||||||
|
#EXTINF:2.002,338565
|
||||||
|
20140311T113819-01-338565live.ts
|
||||||
|
#EXTINF:2.002,338566
|
||||||
|
20140311T113819-01-338566live.ts
|
||||||
|
#EXTINF:2.002,338567
|
||||||
|
20140311T113819-01-338567live.ts
|
||||||
|
#EXTINF:2.002,338568
|
||||||
|
20140311T113819-01-338568live.ts
|
||||||
|
#EXTINF:2.002,338569
|
||||||
|
20140311T113819-01-338569live.ts
|
||||||
|
#EXTINF:2.002,338570
|
||||||
|
20140311T113819-01-338570live.ts
|
||||||
|
#EXTINF:2.002,338571
|
||||||
|
20140311T113819-01-338571live.ts
|
||||||
|
#EXTINF:2.002,338572
|
||||||
|
20140311T113819-01-338572live.ts
|
||||||
|
#EXTINF:2.002,338573
|
||||||
|
20140311T113819-01-338573live.ts
|
|
@ -201,7 +201,7 @@ named!(pub is_master_playlist_tag_line(&[u8]) -> Option<(bool, String)>,
|
||||||
|
|
||||||
pub fn parse_master_playlist_tags(input: &[u8]) -> IResult<&[u8], Vec<MasterPlaylistTag>> {
|
pub fn parse_master_playlist_tags(input: &[u8]) -> IResult<&[u8], Vec<MasterPlaylistTag>> {
|
||||||
chain!(input,
|
chain!(input,
|
||||||
mut tags: many0!(chain!(m:master_playlist_tag ~ multispace?, || m)) ~ eof,
|
mut tags: many0!(chain!(m:master_playlist_tag ~ multispace?, || m)) ~ eof?,
|
||||||
|| { tags.reverse(); tags }
|
|| { tags.reverse(); tags }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ named!(pub session_key_tag<SessionKey>,
|
||||||
|
|
||||||
pub fn parse_media_playlist_tags(input: &[u8]) -> IResult<&[u8], Vec<MediaPlaylistTag>> {
|
pub fn parse_media_playlist_tags(input: &[u8]) -> IResult<&[u8], Vec<MediaPlaylistTag>> {
|
||||||
chain!(input,
|
chain!(input,
|
||||||
mut tags: many0!(chain!(m:media_playlist_tag ~ multispace?, || m)) ~ eof,
|
mut tags: many0!(chain!(m:media_playlist_tag ~ multispace?, || m)) ~ eof?,
|
||||||
|| { tags.reverse(); tags }
|
|| { tags.reverse(); tags }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
32
tests/lib.rs
32
tests/lib.rs
|
@ -48,11 +48,6 @@ fn print_parse_playlist_test(playlist_name: &str) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn playlis_master_usher_result() {
|
|
||||||
assert!(print_parse_playlist_test("master-usher_result.m3u8"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn playlist_master_with_alternatives() {
|
fn playlist_master_with_alternatives() {
|
||||||
assert!(print_parse_playlist_test("master-with-alternatives.m3u8"));
|
assert!(print_parse_playlist_test("master-with-alternatives.m3u8"));
|
||||||
|
@ -80,6 +75,19 @@ fn playlist_media_without_segments() {
|
||||||
assert!(print_parse_playlist_test("media-playlist-without-segments.m3u8"));
|
assert!(print_parse_playlist_test("media-playlist-without-segments.m3u8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------
|
||||||
|
// Playlist with no newline end
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn playlist_not_ending_in_newline_master() {
|
||||||
|
assert!(print_parse_playlist_test("master-not-ending-in-newline.m3u8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn playlist_not_ending_in_newline_media() {
|
||||||
|
assert!(print_parse_playlist_test("media-not-ending-in-newline.m3u8"));
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
// Playlist type detection tests
|
// Playlist type detection tests
|
||||||
|
|
||||||
|
@ -90,13 +98,13 @@ fn playlist_type_is_master() {
|
||||||
assert_eq!(true, result);
|
assert_eq!(true, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn playlist_type_with_unkown_tag() {
|
// fn playlist_type_with_unkown_tag() {
|
||||||
let input = get_sample_playlist("master-usher_result.m3u8");
|
// let input = get_sample_playlist("!!");
|
||||||
let result = is_master_playlist(input.as_bytes());
|
// let result = is_master_playlist(input.as_bytes());
|
||||||
println!("Playlist_type_with_unkown_tag is master playlist: {:?}", result);
|
// println!("Playlist_type_with_unkown_tag is master playlist: {:?}", result);
|
||||||
assert_eq!(true, result);
|
// assert_eq!(true, result);
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn playlist_types() {
|
fn playlist_types() {
|
||||||
|
|
Loading…
Reference in a new issue