Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic support for custom tags #130

Merged
merged 1 commit into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
13 changes: 13 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,16 @@ 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'
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']]