[Python-modules-commits] [python-m3u8] 01/03: Import python-m3u8_0.2.10.orig.tar.gz
Ondrej Koblizek
kobla-guest at moszumanska.debian.org
Fri Aug 12 11:35:51 UTC 2016
This is an automated email from the git hooks/post-receive script.
kobla-guest pushed a commit to branch master
in repository python-m3u8.
commit 5e1b18ae277fb9d3f04721a8c4536e1a08c4c5eb
Author: Ondřej Kobližek <ondrej.koblizek at firma.seznam.cz>
Date: Fri Aug 12 12:43:21 2016 +0200
Import python-m3u8_0.2.10.orig.tar.gz
---
m3u8/__init__.py | 9 +++++----
m3u8/model.py | 12 ++++++++++--
m3u8/parser.py | 12 ++++++++++++
m3u8/protocol.py | 3 +++
setup.py | 2 +-
tests/m3u8server.py | 7 +++++++
tests/playlists.py | 37 +++++++++++++++++++++++++++++++++++++
tests/test_loader.py | 7 +++++++
tests/test_model.py | 7 +++++++
tests/test_parser.py | 7 +++++++
10 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/m3u8/__init__.py b/m3u8/__init__.py
index 80a5da0..0f364fb 100644
--- a/m3u8/__init__.py
+++ b/m3u8/__init__.py
@@ -32,19 +32,20 @@ def loads(content):
'''
return M3U8(content)
-def load(uri):
+def load(uri, timeout = 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)
+ return _load_from_uri(uri, timeout)
else:
return _load_from_file(uri)
# Support for python3 inspired by https://github.com/szemtiv/m3u8/
-def _load_from_uri(uri):
- resource = urlopen(uri)
+def _load_from_uri(uri, timeout = None):
+ resource = urlopen(uri, timeout=timeout)
base_uri = _parsed_url(_url_for(uri))
if PYTHON_MAJOR_VERSION < (3,):
content = _read_python2x(resource)
diff --git a/m3u8/model.py b/m3u8/model.py
index 05850f5..8f653e9 100644
--- a/m3u8/model.py
+++ b/m3u8/model.py
@@ -328,6 +328,12 @@ class Segment(BasePathMixin):
`cue_out`
Returns a boolean indicating if a EXT-X-CUE-OUT-CONT tag exists
+ `scte35`
+ Base64 encoded SCTE35 metadata if available
+
+ `scte35_duration`
+ Planned SCTE35 duration
+
`duration`
duration attribute from EXTINF parameter
@@ -342,7 +348,8 @@ class Segment(BasePathMixin):
'''
def __init__(self, uri, base_uri, program_date_time=None, duration=None,
- title=None, byterange=None, cue_out=False, discontinuity=False, key=None):
+ title=None, byterange=None, cue_out=False, discontinuity=False, key=None,
+ scte35=None, scte35_duration=None):
self.uri = uri
self.duration = duration
self.title = title
@@ -351,6 +358,8 @@ class Segment(BasePathMixin):
self.program_date_time = program_date_time
self.discontinuity = discontinuity
self.cue_out = cue_out
+ self.scte35 = scte35
+ self.scte35_duration = scte35_duration
self.key = Key(base_uri=base_uri,**key) if key else None
@@ -382,7 +391,6 @@ class Segment(BasePathMixin):
def __str__(self):
return self.dumps(None)
-
class SegmentList(list, GroupedBasePathMixin):
def __str__(self):
diff --git a/m3u8/parser.py b/m3u8/parser.py
index 40616bf..9840d1a 100644
--- a/m3u8/parser.py
+++ b/m3u8/parser.py
@@ -82,7 +82,9 @@ def parse(content, strict=False):
state['discontinuity'] = True
elif line.startswith(protocol.ext_x_cue_out):
+ _parse_cueout(line, state)
state['cue_out'] = True
+ state['cue_start'] = True
elif line.startswith(protocol.ext_x_version):
_parse_simple_parameter(line, data)
@@ -163,6 +165,9 @@ def _parse_ts_chunk(line, data, state):
state['current_program_date_time'] += datetime.timedelta(seconds=segment['duration'])
segment['uri'] = line
segment['cue_out'] = state.pop('cue_out', False)
+ if state.get('current_cue_out_scte35'):
+ segment['scte35'] = state['current_cue_out_scte35']
+ segment['scte35_duration'] = state['current_cue_out_duration']
segment['discontinuity'] = state.pop('discontinuity', False)
if state.get('current_key'):
segment['key'] = state['current_key']
@@ -233,6 +238,13 @@ def _parse_and_set_simple_parameter_raw_value(line, data, cast_to=str, normalize
def _parse_simple_parameter(line, data, cast_to=str):
return _parse_and_set_simple_parameter_raw_value(line, data, cast_to, True)
+def _parse_cueout(line, state):
+ param, value = line.split(':', 1)
+ res = re.match('.*Duration=(.*),SCTE35=(.*)$', value)
+ if res:
+ state['current_cue_out_duration'] = res.group(1)
+ state['current_cue_out_scte35'] = res.group(2)
+
def string_to_lines(string):
return string.strip().replace('\r\n', '\n').split('\n')
diff --git a/m3u8/protocol.py b/m3u8/protocol.py
index fd0e128..bfa5992 100644
--- a/m3u8/protocol.py
+++ b/m3u8/protocol.py
@@ -20,3 +20,6 @@ ext_x_i_frame_stream_inf = '#EXT-X-I-FRAME-STREAM-INF'
ext_x_discontinuity = '#EXT-X-DISCONTINUITY'
ext_x_cue_out = '#EXT-X-CUE-OUT-CONT'
ext_is_independent_segments = '#EXT-X-INDEPENDENT-SEGMENTS'
+ext_x_scte35 = '#EXT-OATCLS-SCTE35'
+ext_x_cue_start = '#EXT-X-CUE-OUT'
+ext_x_cue_end = '#EXT-X-CUE-IN'
diff --git a/setup.py b/setup.py
index 61c2501..1315e2c 100644
--- a/setup.py
+++ b/setup.py
@@ -11,7 +11,7 @@ setup(
name="m3u8",
author='Globo.com',
author_email='videos3 at corp.globo.com',
- version="0.2.9",
+ version="0.2.10",
license='MIT',
zip_safe=False,
include_package_data=True,
diff --git a/tests/m3u8server.py b/tests/m3u8server.py
index a1068e5..247d80b 100644
--- a/tests/m3u8server.py
+++ b/tests/m3u8server.py
@@ -9,6 +9,7 @@ from os.path import dirname, abspath, join
from bottle import route, run, response, redirect
import bottle
+import time
playlists = abspath(join(dirname(__file__), 'playlists'))
@@ -21,6 +22,12 @@ def simple():
response.set_header('Content-Type', 'application/vnd.apple.mpegurl')
return m3u8_file('simple-playlist.m3u8')
+ at route('/timeout_simple.m3u8')
+def simple():
+ time.sleep(5)
+ response.set_header('Content-Type', 'application/vnd.apple.mpegurl')
+ return m3u8_file('simple-playlist.m3u8')
+
@route('/path/to/relative-playlist.m3u8')
def simple():
response.set_header('Content-Type', 'application/vnd.apple.mpegurl')
diff --git a/tests/playlists.py b/tests/playlists.py
index e17ae09..3c9c78d 100755
--- a/tests/playlists.py
+++ b/tests/playlists.py
@@ -18,8 +18,10 @@ http://media.example.com/entire.ts
SIMPLE_PLAYLIST_FILENAME = abspath(join(dirname(__file__), 'playlists/simple-playlist.m3u8'))
SIMPLE_PLAYLIST_URI = TEST_HOST + '/simple.m3u8'
+TIMEOUT_SIMPLE_PLAYLIST_URI = TEST_HOST + '/timeout_simple.m3u8'
REDIRECT_PLAYLIST_URI = TEST_HOST + '/path/to/redirect_me'
+
PLAYLIST_WITH_NON_INTEGER_DURATION = '''
#EXTM3U
#EXT-X-TARGETDURATION:5220.5
@@ -325,6 +327,41 @@ CUE_OUT_PLAYLIST = '''
'''
+CUE_OUT_WITH_SCTE35_PLAYLIST = '''
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:10
+#EXT-X-MEDIA-SEQUENCE:47224
+#EXTINF:10.000,
+master2500_47224.ts
+#EXTINF:10.000,
+master2500_47225.ts
+#EXTINF:2.040,
+master2500_47226.ts
+#EXT-OATCLS-SCTE35:/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==
+#EXT-X-CUE-OUT:50.000
+#EXTINF:7.960,
+master2500_47227.ts
+#EXT-X-CUE-OUT-CONT:ElapsedTime=7.960,Duration=50,SCTE35=/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==
+#EXTINF:10.000,
+master2500_47228.ts
+#EXT-X-CUE-OUT-CONT:ElapsedTime=17.960,Duration=50,SCTE35=/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==
+#EXTINF:10.000,
+master2500_47229.ts
+#EXT-X-CUE-OUT-CONT:ElapsedTime=27.960,Duration=50,SCTE35=/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==
+#EXTINF:10.000,
+master2500_47230.ts
+#EXT-X-CUE-OUT-CONT:ElapsedTime=37.960,Duration=50,SCTE35=/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==
+#EXTINF:10.000,
+master2500_47231.ts
+#EXT-X-CUE-OUT-CONT:ElapsedTime=47.960,Duration=50,SCTE35=/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==
+#EXTINF:2.040,
+master2500_47232.ts
+#EXT-X-CUE-IN
+#EXTINF:7.960,
+master2500_47233.ts
+'''
+
MULTI_MEDIA_PLAYLIST = '''#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA:URI="chinese/ed.ttml",TYPE=SUBTITLES,GROUP-ID="subs",LANGUAGE="zho",NAME="Chinese",AUTOSELECT=YES,FORCED=NO
diff --git a/tests/test_loader.py b/tests/test_loader.py
index 3bc6700..f53c517 100644
--- a/tests/test_loader.py
+++ b/tests/test_loader.py
@@ -101,3 +101,10 @@ def test_absolute_uri_should_handle_empty_base_uri_path():
key = m3u8.model.Key(method='AES', uri='/key.bin', base_uri='http://example.com')
assert 'http://example.com/key.bin' == key.absolute_uri
+def test_raise_timeout_exception_if_timeout_happens_when_loading_from_uri():
+ try:
+ obj = m3u8.load(playlists.TIMEOUT_SIMPLE_PLAYLIST_URI, timeout=1)
+ except:
+ assert True
+ else:
+ assert False
diff --git a/tests/test_model.py b/tests/test_model.py
index 344590d..2b68d31 100755
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -65,6 +65,13 @@ def test_segment_cue_out_attribute():
assert segments[2].cue_out == True
assert segments[3].cue_out == False
+def test_segment_scte35_attribute():
+ obj = m3u8.M3U8(playlists.CUE_OUT_WITH_SCTE35_PLAYLIST)
+ segments = obj.segments
+ assert segments[4].cue_out == True
+ assert segments[9].cue_out == False
+ assert segments[4].scte35 == '/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg=='
+
def test_key_attribute():
obj = m3u8.M3U8(playlists.SIMPLE_PLAYLIST)
data = {'key': {'method': 'AES-128',
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 9eeb50d..ef03b17 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -172,3 +172,10 @@ def test_should_parse_VERSION():
def test_should_parse_program_date_time_from_playlist():
data = m3u8.parse(playlists.SIMPLE_PLAYLIST_WITH_PROGRAM_DATE_TIME)
assert cast_date_time('2014-08-13T13:36:33+00:00') == data['program_date_time']
+
+def test_should_parse_scte35_from_playlist():
+ data = m3u8.parse(playlists.CUE_OUT_WITH_SCTE35_PLAYLIST)
+ print(data)
+ assert '/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg==' == data['segments'][4]['scte35']
+ assert '50' == data['segments'][4]['scte35_duration']
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-m3u8.git
More information about the Python-modules-commits
mailing list