[Python-modules-commits] [python-m3u8] 01/04: Import python-m3u8_0.3.1.orig.tar.gz
Ondřej Nový
onovy at moszumanska.debian.org
Tue Jan 24 09:41:20 UTC 2017
This is an automated email from the git hooks/post-receive script.
onovy pushed a commit to branch master
in repository python-m3u8.
commit 81937f6cea962bdb4c5a9aa0c409fd4dc5dda6e7
Author: Ondřej Nový <onovy at debian.org>
Date: Tue Jan 24 10:35:25 2017 +0100
Import python-m3u8_0.3.1.orig.tar.gz
---
m3u8/__init__.py | 44 +++++++++++++++++++++++---------------------
m3u8/model.py | 2 +-
m3u8/parser.py | 3 +--
setup.py | 2 +-
tests/playlists.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
tests/test_model.py | 10 +++++++++-
tests/test_parser.py | 22 ++++++++++++++++++++++
7 files changed, 101 insertions(+), 26 deletions(-)
diff --git a/m3u8/__init__.py b/m3u8/__init__.py
index 7393089..acd14c0 100644
--- a/m3u8/__init__.py
+++ b/m3u8/__init__.py
@@ -4,24 +4,22 @@
# license that can be found in the LICENSE file.
import sys
-PYTHON_MAJOR_VERSION = sys.version_info
-
import os
import posixpath
try:
- import urlparse as url_parser
- import urllib2
- urlopen = urllib2.urlopen
-except ImportError:
- import urllib.parse as url_parser
- from urllib.request import urlopen as url_opener
- urlopen = url_opener
-
+ from urllib.request import urlopen, Request
+ from urllib.error import HTTPError
+ from urllib.parse import urlparse, urljoin
+except ImportError: # Python 2.x
+ from urllib2 import urlopen, Request, HTTPError
+ from urlparse import urlparse, urljoin
from m3u8.model import M3U8, Playlist, IFramePlaylist, Media, Segment
from m3u8.parser import parse, is_url, ParseError
+PYTHON_MAJOR_VERSION = sys.version_info
+
__all__ = ('M3U8', 'Playlist', 'IFramePlaylist', 'Media',
'Segment', 'loads', 'load', 'parse', 'ParseError')
@@ -34,23 +32,25 @@ def loads(content):
return M3U8(content)
-def load(uri, timeout=None):
+def load(uri, timeout=None, headers={}):
'''
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
+ 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)
+ return _load_from_uri(uri, timeout, headers)
else:
return _load_from_file(uri)
# Support for python3 inspired by https://github.com/szemtiv/m3u8/
-def _load_from_uri(uri, timeout=None):
- resource = urlopen(uri, timeout=timeout)
- base_uri = _parsed_url(_url_for(uri))
+def _load_from_uri(uri, timeout=None, headers={}):
+ request = Request(uri, headers=headers)
+ resource = urlopen(request, timeout=timeout)
+ base_uri = _parsed_url(_url_for(request))
if PYTHON_MAJOR_VERSION < (3,):
content = _read_python2x(resource)
else:
@@ -58,15 +58,15 @@ def _load_from_uri(uri, timeout=None):
return M3U8(content, base_uri=base_uri)
-def _url_for(uri):
- return urlopen(uri).geturl()
+def _url_for(request):
+ return urlopen(request).geturl()
def _parsed_url(url):
- parsed_url = url_parser.urlparse(url)
+ parsed_url = urlparse(url)
prefix = parsed_url.scheme + '://' + parsed_url.netloc
base_path = posixpath.normpath(parsed_url.path + '/..')
- return url_parser.urljoin(prefix, base_path)
+ return urljoin(prefix, base_path)
def _read_python2x(resource):
@@ -74,7 +74,9 @@ def _read_python2x(resource):
def _read_python3x(resource):
- return resource.read().decode(resource.headers.get_content_charset(failobj="utf-8"))
+ return resource.read().decode(
+ resource.headers.get_content_charset(failobj="utf-8")
+ )
def _load_from_file(uri):
diff --git a/m3u8/model.py b/m3u8/model.py
index 591faa7..f39dd68 100644
--- a/m3u8/model.py
+++ b/m3u8/model.py
@@ -412,7 +412,7 @@ class Key(BasePathMixin):
'''
- def __init__(self, method, uri, base_uri, iv=None, keyformat=None, keyformatversions=None):
+ def __init__(self, method, base_uri, uri=None, iv=None, keyformat=None, keyformatversions=None):
self.method = method
self.uri = uri
self.iv = iv
diff --git a/m3u8/parser.py b/m3u8/parser.py
index 21e6207..1e472da 100644
--- a/m3u8/parser.py
+++ b/m3u8/parser.py
@@ -218,13 +218,12 @@ def _parse_attribute_list(prefix, line, atribute_parser):
return attributes
-
def _parse_stream_inf(line, data, state):
data['is_variant'] = True
data['media_sequence'] = None
atribute_parser = remove_quotes_parser('codecs', 'audio', 'video', 'subtitles')
atribute_parser["program_id"] = int
- atribute_parser["bandwidth"] = int
+ atribute_parser["bandwidth"] = lambda x: int(float(x))
atribute_parser["average_bandwidth"] = int
state['stream_info'] = _parse_attribute_list(protocol.ext_x_stream_inf, line, atribute_parser)
diff --git a/setup.py b/setup.py
index 8c727c2..c450f0f 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@ setup(
name="m3u8",
author='Globo.com',
author_email='videos3 at corp.globo.com',
- version="0.3.0",
+ version="0.3.1",
license='MIT',
zip_safe=False,
include_package_data=True,
diff --git a/tests/playlists.py b/tests/playlists.py
index bad5da0..fe405a1 100755
--- a/tests/playlists.py
+++ b/tests/playlists.py
@@ -82,6 +82,18 @@ http://example.com/hi.m3u8
http://example.com/audio-only.m3u8
'''
+VARIANT_PLAYLIST_WITH_BANDWIDTH_FLOAT = '''
+#EXTM3U
+#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1280000.0
+http://example.com/low.m3u8
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000.4
+http://example.com/mid.m3u8
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000.6
+http://example.com/hi.m3u8
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS="mp4a.40.5,avc1.42801e"
+http://example.com/audio-only.m3u8
+'''
+
VARIANT_PLAYLIST_WITH_IFRAME_PLAYLISTS = '''
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000,RESOLUTION=624x352,CODECS="avc1.4d001f, mp4a.40.5"
@@ -342,6 +354,38 @@ PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED_NONE = '''
'''
+PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED_NONE_AND_NO_URI_ATTR = '''
+#EXTM3U
+#EXT-X-MEDIA-SEQUENCE:82400
+#EXT-X-ALLOW-CACHE:NO
+#EXT-X-VERSION:2
+#EXT-X-TARGETDURATION:8
+#EXTINF:8,
+../../../../hls/streamNum82400.ts
+#EXTINF:8,
+../../../../hls/streamNum82401.ts
+#EXT-X-KEY:METHOD=AES-128,URI="/hls-key/key.bin",IV=0X10ef8f758ca555115584bb5b3c687f52
+#EXTINF:8,
+../../../../hls/streamNum82400.ts
+#EXTINF:8,
+../../../../hls/streamNum82401.ts
+#EXTINF:8,
+../../../../hls/streamNum82402.ts
+#EXTINF:8,
+../../../../hls/streamNum82403.ts
+#EXT-X-KEY:METHOD=NONE
+#EXTINF:8,
+../../../../hls/streamNum82404.ts
+#EXTINF:8,
+../../../../hls/streamNum82405.ts
+#EXT-X-KEY:METHOD=AES-128,URI="/hls-key/key2.bin",IV=0Xcafe8f758ca555115584bb5b3c687f52
+#EXTINF:8,
+../../../../hls/streamNum82404.ts
+#EXTINF:8,
+../../../../hls/streamNum82405.ts
+
+'''
+
SIMPLE_PLAYLIST_WITH_TITLE = '''
#EXTM3U
diff --git a/tests/test_model.py b/tests/test_model.py
index 02d0f1d..5672291 100755
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -507,6 +507,14 @@ def test_should_dump_complex_unencrypted_encrypted_keys():
assert expected == obj.dumps().strip()
+def test_should_dump_complex_unencrypted_encrypted_keys_no_uri_attr():
+ obj = m3u8.M3U8(playlists.PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED_NONE_AND_NO_URI_ATTR)
+ expected = playlists.PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED_NONE_AND_NO_URI_ATTR \
+ .strip()
+
+ assert expected == obj.dumps().strip()
+
+
def test_length_segments_by_key():
obj = m3u8.M3U8(playlists.PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED)
@@ -536,7 +544,7 @@ def test_replace_segment_key():
obj = m3u8.M3U8(playlists.PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED)
# Replace unencrypted segments with new key
- new_key = Key("AES-128", "/hls-key/key0.bin", None, iv="0Xcafe8f758ca555115584bb5b3c687f52")
+ new_key = Key("AES-128", None, "/hls-key/key0.bin", iv="0Xcafe8f758ca555115584bb5b3c687f52")
for segment in obj.segments.by_key(None):
segment.key = new_key
diff --git a/tests/test_parser.py b/tests/test_parser.py
index b5355bb..3e0df79 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -77,6 +77,16 @@ def test_should_add_non_key_for_multiple_keys_unencrypted_and_encrypted():
assert "AES-128" == last_segment_key['method']
assert "0Xcafe8f758ca555115584bb5b3c687f52" == last_segment_key['iv']
+def test_should_handle_key_method_none_and_no_uri_attr():
+ data = m3u8.parse(playlists.PLAYLIST_WITH_MULTIPLE_KEYS_UNENCRYPTED_AND_ENCRYPTED_NONE_AND_NO_URI_ATTR)
+ assert 'key' not in data['segments'][0]
+ assert 'key' not in data['segments'][1]
+ third_segment_key = data['segments'][2]['key']
+ assert "/hls-key/key.bin" == third_segment_key['uri']
+ assert "AES-128" == third_segment_key['method']
+ assert "0X10ef8f758ca555115584bb5b3c687f52" == third_segment_key['iv']
+ assert "NONE" == data['segments'][6]['key']['method']
+
def test_should_parse_title_from_playlist():
data = m3u8.parse(playlists.SIMPLE_PLAYLIST_WITH_TITLE)
assert 1 == len(data['segments'])
@@ -113,6 +123,18 @@ def test_should_parse_variant_playlist_with_average_bandwidth():
assert 65000 == playlists_list[3]['stream_info']['bandwidth']
assert 63005 == playlists_list[3]['stream_info']['average_bandwidth']
+# This is actually not according to specification but as for example Twitch.tv
+# is producing master playlists that have bandwidth as floats (issue 72)
+# this tests that this situation does not break the parser and will just
+# truncate to a decimal-integer according to specification
+def test_should_parse_variant_playlist_with_bandwidth_as_float():
+ data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_BANDWIDTH_FLOAT)
+ playlists_list = list(data['playlists'])
+ assert 1280000 == playlists_list[0]['stream_info']['bandwidth']
+ assert 2560000 == playlists_list[1]['stream_info']['bandwidth']
+ assert 7680000 == playlists_list[2]['stream_info']['bandwidth']
+ assert 65000 == playlists_list[3]['stream_info']['bandwidth']
+
def test_should_parse_variant_playlist_with_iframe_playlists():
data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IFRAME_PLAYLISTS)
iframe_playlists = list(data['iframe_playlists'])
--
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