Repository: globocom/m3u8

Issue:
Error parsing line #EXT-X-MAP:URI="main.mp4",BYTERANGE="812@0"
Apple 'Advanced stream (HEVC/H.264)' reference has #EXT-X-MAP:URI="main.mp4",BYTERANGE="812@0" attribute. This attribute parses as segment_map_uri with incorrect value 'main.mp4",BYTERANGE="812@0'. But should be parsed as separate 'uri' and 'byterange'.

Link to m3u8:
https://tungsten.aaplimg.com/VOD/bipbop_adv_example_hevc/tp10/iframe_index.m3u8

Link to examples:
https://developer.apple.com/streaming/examples/

Discussion:

Patch:
diff --git a/m3u8/model.py b/m3u8/model.py
index 0b13349..5ca29d5 100644
--- a/m3u8/model.py
+++ b/m3u8/model.py
@@ -176,7 +176,7 @@ class M3U8(object):
                                          uri=ifr_pl['uri'],
                                          iframe_stream_info=ifr_pl['iframe_stream_info'])
                                         )
-        self.segment_map_uri = self.data.get('segment_map_uri')
+        self.segment_map = self.data.get('segment_map')
 
     def __unicode__(self):
         return self.dumps()
diff --git a/m3u8/parser.py b/m3u8/parser.py
index 5aa117e..f28fd07 100644
--- a/m3u8/parser.py
+++ b/m3u8/parser.py
@@ -137,7 +137,9 @@ def parse(content, strict=False):
             data['is_endlist'] = True
 
         elif line.startswith(protocol.ext_x_map):
-            data['segment_map_uri'] = _parse_segment_map_uri(line)
+            quoted_parser = remove_quotes_parser('uri')
+            segment_map_info = _parse_attribute_list(protocol.ext_x_map, line, quoted_parser)
+            data['segment_map'] = segment_map_info
 
         # Comments and whitespace
         elif line.startswith('#'):
@@ -310,14 +312,6 @@ def _parse_cueout_start(line, state, prevline):
         state['current_cue_out_duration'] = _cueout_state[1]
 
 
-def _parse_segment_map_uri(line):
-    """
-    :param line: '#EXT-X-MAP:URI="fileSequence0.mp4"'
-    :rtype: str 
-    """
-    return remove_quotes(line.replace(protocol.ext_x_map+':', '').split('=', 1)[1])
-
-
 def string_to_lines(string):
     return string.strip().replace('\r\n', '\n').split('\n')
 


Test patch:
diff --git a/tests/playlists.py b/tests/playlists.py
index 8bb85be..8f06a0b 100755
--- a/tests/playlists.py
+++ b/tests/playlists.py
@@ -607,6 +607,15 @@ MAP_URI_PLAYLIST = '''#EXTM3U
 #EXT-X-MAP:URI="fileSequence0.mp4"
 '''
 
+MAP_URI_PLAYLIST_WITH_BYTERANGE = '''#EXTM3U
+#EXT-X-TARGETDURATION:2
+#EXT-X-VERSION:7
+#EXT-X-MEDIA-SEQUENCE:1
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXT-X-INDEPENDENT-SEGMENTS
+#EXT-X-MAP:URI="main.mp4",BYTERANGE="812@0"
+'''
+
 RELATIVE_PLAYLIST_FILENAME = abspath(join(dirname(__file__), 'playlists/relative-playlist.m3u8'))
 
 RELATIVE_PLAYLIST_URI = TEST_HOST + '/path/to/relative-playlist.m3u8'
diff --git a/tests/test_model.py b/tests/test_model.py
index f4e985a..502144c 100755
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -692,11 +692,16 @@ def test_m3u8_should_propagate_base_uri_to_key():
 
 def test_segment_map_uri_attribute():
     obj = m3u8.M3U8(playlists.MAP_URI_PLAYLIST)
-    assert obj.segment_map_uri == "fileSequence0.mp4"
+    assert obj.segment_map['uri'] == "fileSequence0.mp4"
 
 
+def test_segment_map_uri_attribute_with_byterange():
+    obj = m3u8.M3U8(playlists.MAP_URI_PLAYLIST_WITH_BYTERANGE)
+    assert obj.segment_map['uri'] == "main.mp4"
+
 # custom asserts
 
+
 def assert_file_content(filename, expected):
     with open(filename) as fileobj:
         content = fileobj.read().strip()
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 7a77ecb..47676f9 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -255,4 +255,9 @@ def test_commaless_extinf_strict():
 
 def test_should_parse_segment_map_uri():
     data = m3u8.parse(playlists.MAP_URI_PLAYLIST)
-    assert data['segment_map_uri'] == "fileSequence0.mp4"
+    assert data['segment_map']['uri'] == "fileSequence0.mp4"
+
+
+def test_should_parse_segment_map_uri_with_byterange():
+    data = m3u8.parse(playlists.MAP_URI_PLAYLIST_WITH_BYTERANGE)
+    assert data['segment_map']['uri'] == "main.mp4"