Skip to content

Commit

Permalink
Add basic support for custom tags
Browse files Browse the repository at this point in the history
Main parser function now receives a function that can be
used to parse the line content and save it into the data store object.
  • Loading branch information
mauricioabreu committed Jan 27, 2019
1 parent 6cbe1e5 commit 4e5675c
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 16 deletions.
20 changes: 10 additions & 10 deletions m3u8/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,44 +24,44 @@
'Segment', 'loads', 'load', 'parse', 'ParseError')


def loads(content, uri=None):
def loads(content, uri=None, custom_tags_parser=None):
'''
Given a string with a m3u8 content, returns a M3U8 object.
Optionally parses a uri to set a correct base_uri on the M3U8 object.
Raises ValueError if invalid content
'''

if uri is None:
return M3U8(content)
return M3U8(content, custom_tags_parser)
else:
base_uri = _parsed_url(uri)
return M3U8(content, base_uri=base_uri)
return M3U8(content, base_uri=base_uri, custom_tags_parser=custom_tags_parser)


def load(uri, timeout=None, headers={}):
def load(uri, timeout=None, headers={}, custom_tags_parser=None):
'''
Retrieves the content from a given URI and returns a M3U8 object.
Raises ValueError if invalid content or IOError if request fails.
Raises socket.timeout(python 2.7+) or urllib2.URLError(python 2.6) if
timeout happens when loading from uri
'''
if is_url(uri):
return _load_from_uri(uri, timeout, headers)
return _load_from_uri(uri, timeout, headers, custom_tags_parser)
else:
return _load_from_file(uri)
return _load_from_file(uri, custom_tags_parser)

# Support for python3 inspired by https://github.com/szemtiv/m3u8/


def _load_from_uri(uri, timeout=None, headers={}):
def _load_from_uri(uri, timeout=None, headers={}, custom_tags_parser=None):
request = Request(uri, headers=headers)
resource = urlopen(request, timeout=timeout)
base_uri = _parsed_url(resource.geturl())
if PYTHON_MAJOR_VERSION < (3,):
content = _read_python2x(resource)
else:
content = _read_python3x(resource)
return M3U8(content, base_uri=base_uri)
return M3U8(content, base_uri=base_uri, custom_tags_parser=custom_tags_parser)


def _parsed_url(url):
Expand All @@ -81,8 +81,8 @@ def _read_python3x(resource):
)


def _load_from_file(uri):
def _load_from_file(uri, custom_tags_parser=None):
with open(uri) as fileobj:
raw_content = fileobj.read().strip()
base_uri = os.path.dirname(uri)
return M3U8(raw_content, base_uri=base_uri)
return M3U8(raw_content, base_uri=base_uri, custom_tags_parser=custom_tags_parser)
4 changes: 2 additions & 2 deletions m3u8/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ class M3U8(object):
('discontinuity_sequence', 'discontinuity_sequence')
)

def __init__(self, content=None, base_path=None, base_uri=None, strict=False):
def __init__(self, content=None, base_path=None, base_uri=None, strict=False, custom_tags_parser=None):
if content is not None:
self.data = parse(content, strict)
self.data = parse(content, strict, custom_tags_parser)
else:
self.data = {}
self._base_uri = base_uri
Expand Down
7 changes: 3 additions & 4 deletions m3u8/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ def __str__(self):
return 'Syntax error in manifest on line %d: %s' % (self.lineno, self.line)



def parse(content, strict=False):
def parse(content, strict=False, custom_tags_parser=None):
'''
Given a M3U8 playlist content returns a dictionary with all data found
'''
Expand Down Expand Up @@ -153,8 +152,8 @@ def parse(content, strict=False):

# Comments and whitespace
elif line.startswith('#'):
# comment
pass
if callable(custom_tags_parser):
custom_tags_parser(line, data, lineno)

elif line.strip() == '':
# blank lines are legal
Expand Down
8 changes: 8 additions & 0 deletions tests/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,14 @@
#EXT-X-ENDLIST
'''

SIMPLE_PLAYLIST_WITH_CUSTOM_TAGS = '''#EXTM3U
#EXT-X-MOVIE: million dollar baby
#EXT-X-TARGETDURATION:5220
#EXTINF:5220,
http://media.example.com/entire.ts
#EXT-X-ENDLIST
'''

RELATIVE_PLAYLIST_FILENAME = abspath(join(dirname(__file__), 'playlists/relative-playlist.m3u8'))

RELATIVE_PLAYLIST_URI = TEST_HOST + '/path/to/relative-playlist.m3u8'
Expand Down
9 changes: 9 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,12 @@ def test_should_parse_start_with_precise():
def test_simple_playlist_with_discontinuity_sequence():
data = m3u8.parse(playlists.SIMPLE_PLAYLIST_WITH_DISCONTINUITY_SEQUENCE)
assert data['discontinuity_sequence'] == 123

def test_simple_playlist_with_custom_tags():
def get_movie(line, data, lineno):
custom_tag = line.split(':')
if len(custom_tag) == 2:
data['movie'] = custom_tag[1].strip()

data = m3u8.parse(playlists.SIMPLE_PLAYLIST_WITH_CUSTOM_TAGS, strict=False, custom_tags_parser=get_movie)
assert data['movie'] == 'million dollar baby'

0 comments on commit 4e5675c

Please sign in to comment.