Repository: globocom/m3u8

Issue:
EXTINF tag with optional comma?
m3u8 library requires EXTINF tag to have title, but the title is optional, see https://tools.ietf.org/html/draft-pantos-http-live-streaming-09#section-3.3.2 

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/7575105/badge)](https://coveralls.io/builds/7575105)

Coverage increased (+0.6%) to 95.122% when pulling **2876d443742bc91dfeda646072a6b71235bacfa8 on ziima:73-commaless-extinf** into **651c14ab5368692fd23f321a78bfe558d2b22f33 on globocom:master**.

leandromoreira: Thanks @ziima can you fixe https://travis-ci.org/globocom/m3u8/jobs/154559924#L442 for python 3 ?
ziima: I think that's unrelated existing bug. This is just first time it's covered in tests.
ziima: The bug should be addressed in #78
leandromoreira: Thanks @ziima can you rebase it?

Patch:
diff --git a/m3u8/parser.py b/m3u8/parser.py
index f1c7590..a0b7f5d 100644
--- a/m3u8/parser.py
+++ b/m3u8/parser.py
@@ -91,7 +91,7 @@ def parse(content, strict=False):
             data['key'] = data.get('key', state['current_key'])
 
         elif line.startswith(protocol.extinf):
-            _parse_extinf(line, data, state)
+            _parse_extinf(line, data, state, lineno, strict)
             state['expect_segment'] = True
 
         elif line.startswith(protocol.ext_x_stream_inf):
@@ -145,8 +145,16 @@ def _parse_key(line):
         key[normalize_attribute(name)] = remove_quotes(value)
     return key
 
-def _parse_extinf(line, data, state):
-    duration, title = line.replace(protocol.extinf + ':', '').split(',')
+def _parse_extinf(line, data, state, lineno, strict):
+    chunks = line.replace(protocol.extinf + ':', '').split(',')
+    if len(chunks) == 2:
+        duration, title = chunks
+    elif len(chunks) == 1:
+        if strict:
+            raise ParseError(lineno, line)
+        else:
+            duration = chunks[0]
+            title = ''
     if 'segment' not in state:
         state['segment'] = {}
     state['segment']['duration'] = float(duration)


Test patch:
diff --git a/tests/playlists.py b/tests/playlists.py
index b663eba..909af78 100755
--- a/tests/playlists.py
+++ b/tests/playlists.py
@@ -287,6 +287,15 @@ JUNK
 #EXT-X-ENDLIST
 '''
 
+# Playlist with EXTINF record not ending with comma
+SIMPLE_PLAYLIST_COMMALESS_EXTINF = '''
+#EXTM3U
+#EXT-X-TARGETDURATION:5220
+#EXTINF:5220
+http://media.example.com/entire.ts
+#EXT-X-ENDLIST
+'''
+
 DISCONTINUITY_PLAYLIST_WITH_PROGRAM_DATE_TIME = '''
 #EXTM3U
 #EXT-X-MEDIA-SEQUENCE:50116
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 9c20f8d..fbbf834 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -191,3 +191,15 @@ def test_parse_simple_playlist_messy_strict():
     with pytest.raises(ParseError) as catch:
         m3u8.parse(playlists.SIMPLE_PLAYLIST_MESSY, strict=True)
     assert str(catch.value) == 'Syntax error in manifest on line 5: JUNK'
+
+def test_commaless_extinf():
+    data = m3u8.parse(playlists.SIMPLE_PLAYLIST_COMMALESS_EXTINF)
+    assert 5220 == data['targetduration']
+    assert 0 == data['media_sequence']
+    assert ['http://media.example.com/entire.ts'] == [c['uri'] for c in data['segments']]
+    assert [5220] == [c['duration'] for c in data['segments']]
+
+def test_commaless_extinf_strict():
+    with pytest.raises(ParseError) as e:
+        m3u8.parse(playlists.SIMPLE_PLAYLIST_COMMALESS_EXTINF, strict=True)
+    assert str(e.value) == 'Syntax error in manifest on line 3: #EXTINF:5220'