[Python-modules-commits] [python-m3u8] 01/05: Import python-m3u8_0.2.8.orig.tar.gz
Mattia Rizzolo
mattia at debian.org
Sun Feb 28 18:51:14 UTC 2016
This is an automated email from the git hooks/post-receive script.
mattia pushed a commit to branch master
in repository python-m3u8.
commit 096109e3bbb8c143885269aba896c663c4a0c600
Author: Ondřej Nový <novy at ondrej.org>
Date: Sun Feb 28 19:16:46 2016 +0100
Import python-m3u8_0.2.8.orig.tar.gz
---
MANIFEST.in | 1 +
PKG-INFO | 146 ++++++++
README.rst | 136 ++++++++
m3u8.egg-info/PKG-INFO | 146 ++++++++
m3u8.egg-info/SOURCES.txt | 14 +
m3u8.egg-info/dependency_links.txt | 1 +
m3u8.egg-info/not-zip-safe | 1 +
m3u8.egg-info/requires.txt | 1 +
m3u8.egg-info/top_level.txt | 1 +
m3u8/__init__.py | 75 +++++
m3u8/model.py | 674 +++++++++++++++++++++++++++++++++++++
m3u8/parser.py | 261 ++++++++++++++
m3u8/protocol.py | 22 ++
requirements.txt | 1 +
setup.cfg | 5 +
setup.py | 22 ++
16 files changed, 1507 insertions(+)
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..f9bd145
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include requirements.txt
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..e8f7ee3
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,146 @@
+Metadata-Version: 1.0
+Name: m3u8
+Version: 0.2.8
+Summary: Python m3u8 parser
+Home-page: https://github.com/globocom/m3u8
+Author: Globo.com
+Author-email: videos3 at corp.globo.com
+License: UNKNOWN
+Description: .. image:: https://travis-ci.org/globocom/m3u8.svg
+ :target: https://travis-ci.org/globocom/m3u8
+
+ .. image:: https://coveralls.io/repos/globocom/m3u8/badge.png?branch=master
+ :target: https://coveralls.io/r/globocom/m3u8?branch=master
+
+ .. image:: https://gemnasium.com/leandromoreira/m3u8.svg
+ :target: https://gemnasium.com/leandromoreira/m3u8
+
+ .. image:: https://badge.fury.io/py/m3u8.svg
+ :target: https://badge.fury.io/py/m3u8
+
+
+ m3u8
+ ====
+
+ Python `m3u8`_ parser.
+
+ Documentation
+ =============
+
+ The basic usage is to create a playlist object from uri, file path or
+ directly from a string:
+
+ ::
+
+ import m3u8
+
+ m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename
+ print m3u8_obj.segments
+ print m3u8_obj.target_duration
+
+ # if you already have the content as string, use
+
+ m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ... ')
+
+ Encryption key
+ --------------
+
+ The segments may be encrypted, in this case the ``key`` attribute will
+ be an object with all the attributes from `#EXT-X-KEY`_:
+
+ - ``method``: ex.: "AES-128"
+ - ``uri``: the key uri, ex.: "http://videoserver.com/key.bin"
+ - ``iv``: the initialization vector, if available. Otherwise ``None``.
+
+ If no ``#EXT-X-KEY`` is found, the ``key`` attribute will be ``None``.
+
+ Multiple keys are not supported yet (and has a low priority), follow
+ `issue 1`_ for updates.
+
+ Variant playlists (variable bitrates)
+ -------------------------------------
+
+ A playlist can have a list to other playlist files, this is used to
+ represent multiple bitrates videos, and it's called `variant streams`_.
+ See an `example here`_.
+
+ ::
+
+ variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...')
+ variant_m3u8.is_variant # in this case will be True
+
+ for playlist in variant_m3u8.playlists:
+ playlist.uri
+ playlist.stream_info.bandwidth
+
+ the playlist object used in the for loop above has a few attributes:
+
+ - ``uri``: the url to the stream
+ - ``stream_info``: a ``StreamInfo`` object (actually a namedtuple) with
+ all the attributes available to `#EXT-X-STREAM-INF`_
+ - ``media``: a list of related ``Media`` objects with all the attributes
+ available to `#EXT-X-MEDIA`_
+ - ``playlist_type``: the type of the playlist, which can be one of `VOD`_
+ (video on demand) or `EVENT`_
+
+ **NOTE: the following attributes are not implemented yet**, follow
+ `issue 4`_ for updates
+
+ - ``alternative_audios``: its an empty list, unless it's a playlist
+ with `Alternative audio`_, in this case it's a list with ``Media``
+ objects with all the attributes available to `#EXT-X-MEDIA`_
+ - ``alternative_videos``: same as ``alternative_audios``
+
+ A variant playlist can also have links to `I-frame playlists`_, which are used
+ to specify where the I-frames are in a video. See `Apple's documentation`_ on
+ this for more information. These I-frame playlists can be accessed in a similar
+ way to regular playlists.
+
+ ::
+
+ variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...')
+
+ for iframe_playlist in variant_m3u8.iframe_playlists:
+ iframe_playlist.uri
+ iframe_playlist.iframe_stream_info.bandwidth
+
+ The iframe_playlist object used in the for loop above has a few attributes:
+
+ - ``uri``: the url to the I-frame playlist
+ - ``base_uri``: the base uri of the variant playlist (if given)
+ - ``iframe_stream_info``: a ``StreamInfo`` object (same as a regular playlist)
+
+ Running Tests
+ =============
+
+ ::
+
+ $ ./runtests
+
+ Contributing
+ ============
+
+ All contribution is welcome, but we will merge a pull request if, and only if, it
+
+ - has tests
+ - follows the code conventions
+
+ If you plan to implement a new feature or something that will take more
+ than a few minutes, please open an issue to make sure we don't work on
+ the same thing.
+
+ .. _m3u8: http://tools.ietf.org/html/draft-pantos-http-live-streaming-09
+ .. _#EXT-X-KEY: http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.4
+ .. _issue 1: https://github.com/globocom/m3u8/issues/1
+ .. _variant streams: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-6.2.4
+ .. _example here: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.5
+ .. _#EXT-X-STREAM-INF: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.2
+ .. _issue 4: https://github.com/globocom/m3u8/issues/4
+ .. _I-frame playlists: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.3
+ .. _Apple's documentation: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-I_FRAME_PLAYLIST
+ .. _Alternative audio: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.7
+ .. _#EXT-X-MEDIA: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.1
+ .. _VOD: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-TNTAG2
+ .. _EVENT: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-EVENT_PLAYLIST
+
+Platform: UNKNOWN
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..4977d33
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,136 @@
+.. image:: https://travis-ci.org/globocom/m3u8.svg
+ :target: https://travis-ci.org/globocom/m3u8
+
+.. image:: https://coveralls.io/repos/globocom/m3u8/badge.png?branch=master
+ :target: https://coveralls.io/r/globocom/m3u8?branch=master
+
+.. image:: https://gemnasium.com/leandromoreira/m3u8.svg
+ :target: https://gemnasium.com/leandromoreira/m3u8
+
+.. image:: https://badge.fury.io/py/m3u8.svg
+ :target: https://badge.fury.io/py/m3u8
+
+
+m3u8
+====
+
+Python `m3u8`_ parser.
+
+Documentation
+=============
+
+The basic usage is to create a playlist object from uri, file path or
+directly from a string:
+
+::
+
+ import m3u8
+
+ m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename
+ print m3u8_obj.segments
+ print m3u8_obj.target_duration
+
+ # if you already have the content as string, use
+
+ m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ... ')
+
+Encryption key
+--------------
+
+The segments may be encrypted, in this case the ``key`` attribute will
+be an object with all the attributes from `#EXT-X-KEY`_:
+
+- ``method``: ex.: "AES-128"
+- ``uri``: the key uri, ex.: "http://videoserver.com/key.bin"
+- ``iv``: the initialization vector, if available. Otherwise ``None``.
+
+If no ``#EXT-X-KEY`` is found, the ``key`` attribute will be ``None``.
+
+Multiple keys are not supported yet (and has a low priority), follow
+`issue 1`_ for updates.
+
+Variant playlists (variable bitrates)
+-------------------------------------
+
+A playlist can have a list to other playlist files, this is used to
+represent multiple bitrates videos, and it's called `variant streams`_.
+See an `example here`_.
+
+::
+
+ variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...')
+ variant_m3u8.is_variant # in this case will be True
+
+ for playlist in variant_m3u8.playlists:
+ playlist.uri
+ playlist.stream_info.bandwidth
+
+the playlist object used in the for loop above has a few attributes:
+
+- ``uri``: the url to the stream
+- ``stream_info``: a ``StreamInfo`` object (actually a namedtuple) with
+ all the attributes available to `#EXT-X-STREAM-INF`_
+- ``media``: a list of related ``Media`` objects with all the attributes
+ available to `#EXT-X-MEDIA`_
+- ``playlist_type``: the type of the playlist, which can be one of `VOD`_
+ (video on demand) or `EVENT`_
+
+**NOTE: the following attributes are not implemented yet**, follow
+`issue 4`_ for updates
+
+- ``alternative_audios``: its an empty list, unless it's a playlist
+ with `Alternative audio`_, in this case it's a list with ``Media``
+ objects with all the attributes available to `#EXT-X-MEDIA`_
+- ``alternative_videos``: same as ``alternative_audios``
+
+A variant playlist can also have links to `I-frame playlists`_, which are used
+to specify where the I-frames are in a video. See `Apple's documentation`_ on
+this for more information. These I-frame playlists can be accessed in a similar
+way to regular playlists.
+
+::
+
+ variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...')
+
+ for iframe_playlist in variant_m3u8.iframe_playlists:
+ iframe_playlist.uri
+ iframe_playlist.iframe_stream_info.bandwidth
+
+The iframe_playlist object used in the for loop above has a few attributes:
+
+- ``uri``: the url to the I-frame playlist
+- ``base_uri``: the base uri of the variant playlist (if given)
+- ``iframe_stream_info``: a ``StreamInfo`` object (same as a regular playlist)
+
+Running Tests
+=============
+
+::
+
+ $ ./runtests
+
+Contributing
+============
+
+All contribution is welcome, but we will merge a pull request if, and only if, it
+
+- has tests
+- follows the code conventions
+
+If you plan to implement a new feature or something that will take more
+than a few minutes, please open an issue to make sure we don't work on
+the same thing.
+
+.. _m3u8: http://tools.ietf.org/html/draft-pantos-http-live-streaming-09
+.. _#EXT-X-KEY: http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.4
+.. _issue 1: https://github.com/globocom/m3u8/issues/1
+.. _variant streams: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-6.2.4
+.. _example here: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.5
+.. _#EXT-X-STREAM-INF: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.2
+.. _issue 4: https://github.com/globocom/m3u8/issues/4
+.. _I-frame playlists: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.3
+.. _Apple's documentation: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-I_FRAME_PLAYLIST
+.. _Alternative audio: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.7
+.. _#EXT-X-MEDIA: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.1
+.. _VOD: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-TNTAG2
+.. _EVENT: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-EVENT_PLAYLIST
diff --git a/m3u8.egg-info/PKG-INFO b/m3u8.egg-info/PKG-INFO
new file mode 100644
index 0000000..e8f7ee3
--- /dev/null
+++ b/m3u8.egg-info/PKG-INFO
@@ -0,0 +1,146 @@
+Metadata-Version: 1.0
+Name: m3u8
+Version: 0.2.8
+Summary: Python m3u8 parser
+Home-page: https://github.com/globocom/m3u8
+Author: Globo.com
+Author-email: videos3 at corp.globo.com
+License: UNKNOWN
+Description: .. image:: https://travis-ci.org/globocom/m3u8.svg
+ :target: https://travis-ci.org/globocom/m3u8
+
+ .. image:: https://coveralls.io/repos/globocom/m3u8/badge.png?branch=master
+ :target: https://coveralls.io/r/globocom/m3u8?branch=master
+
+ .. image:: https://gemnasium.com/leandromoreira/m3u8.svg
+ :target: https://gemnasium.com/leandromoreira/m3u8
+
+ .. image:: https://badge.fury.io/py/m3u8.svg
+ :target: https://badge.fury.io/py/m3u8
+
+
+ m3u8
+ ====
+
+ Python `m3u8`_ parser.
+
+ Documentation
+ =============
+
+ The basic usage is to create a playlist object from uri, file path or
+ directly from a string:
+
+ ::
+
+ import m3u8
+
+ m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename
+ print m3u8_obj.segments
+ print m3u8_obj.target_duration
+
+ # if you already have the content as string, use
+
+ m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ... ')
+
+ Encryption key
+ --------------
+
+ The segments may be encrypted, in this case the ``key`` attribute will
+ be an object with all the attributes from `#EXT-X-KEY`_:
+
+ - ``method``: ex.: "AES-128"
+ - ``uri``: the key uri, ex.: "http://videoserver.com/key.bin"
+ - ``iv``: the initialization vector, if available. Otherwise ``None``.
+
+ If no ``#EXT-X-KEY`` is found, the ``key`` attribute will be ``None``.
+
+ Multiple keys are not supported yet (and has a low priority), follow
+ `issue 1`_ for updates.
+
+ Variant playlists (variable bitrates)
+ -------------------------------------
+
+ A playlist can have a list to other playlist files, this is used to
+ represent multiple bitrates videos, and it's called `variant streams`_.
+ See an `example here`_.
+
+ ::
+
+ variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...')
+ variant_m3u8.is_variant # in this case will be True
+
+ for playlist in variant_m3u8.playlists:
+ playlist.uri
+ playlist.stream_info.bandwidth
+
+ the playlist object used in the for loop above has a few attributes:
+
+ - ``uri``: the url to the stream
+ - ``stream_info``: a ``StreamInfo`` object (actually a namedtuple) with
+ all the attributes available to `#EXT-X-STREAM-INF`_
+ - ``media``: a list of related ``Media`` objects with all the attributes
+ available to `#EXT-X-MEDIA`_
+ - ``playlist_type``: the type of the playlist, which can be one of `VOD`_
+ (video on demand) or `EVENT`_
+
+ **NOTE: the following attributes are not implemented yet**, follow
+ `issue 4`_ for updates
+
+ - ``alternative_audios``: its an empty list, unless it's a playlist
+ with `Alternative audio`_, in this case it's a list with ``Media``
+ objects with all the attributes available to `#EXT-X-MEDIA`_
+ - ``alternative_videos``: same as ``alternative_audios``
+
+ A variant playlist can also have links to `I-frame playlists`_, which are used
+ to specify where the I-frames are in a video. See `Apple's documentation`_ on
+ this for more information. These I-frame playlists can be accessed in a similar
+ way to regular playlists.
+
+ ::
+
+ variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...')
+
+ for iframe_playlist in variant_m3u8.iframe_playlists:
+ iframe_playlist.uri
+ iframe_playlist.iframe_stream_info.bandwidth
+
+ The iframe_playlist object used in the for loop above has a few attributes:
+
+ - ``uri``: the url to the I-frame playlist
+ - ``base_uri``: the base uri of the variant playlist (if given)
+ - ``iframe_stream_info``: a ``StreamInfo`` object (same as a regular playlist)
+
+ Running Tests
+ =============
+
+ ::
+
+ $ ./runtests
+
+ Contributing
+ ============
+
+ All contribution is welcome, but we will merge a pull request if, and only if, it
+
+ - has tests
+ - follows the code conventions
+
+ If you plan to implement a new feature or something that will take more
+ than a few minutes, please open an issue to make sure we don't work on
+ the same thing.
+
+ .. _m3u8: http://tools.ietf.org/html/draft-pantos-http-live-streaming-09
+ .. _#EXT-X-KEY: http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.4
+ .. _issue 1: https://github.com/globocom/m3u8/issues/1
+ .. _variant streams: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-6.2.4
+ .. _example here: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.5
+ .. _#EXT-X-STREAM-INF: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.2
+ .. _issue 4: https://github.com/globocom/m3u8/issues/4
+ .. _I-frame playlists: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.3
+ .. _Apple's documentation: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-I_FRAME_PLAYLIST
+ .. _Alternative audio: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.7
+ .. _#EXT-X-MEDIA: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.1
+ .. _VOD: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-TNTAG2
+ .. _EVENT: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-EVENT_PLAYLIST
+
+Platform: UNKNOWN
diff --git a/m3u8.egg-info/SOURCES.txt b/m3u8.egg-info/SOURCES.txt
new file mode 100644
index 0000000..09814c5
--- /dev/null
+++ b/m3u8.egg-info/SOURCES.txt
@@ -0,0 +1,14 @@
+MANIFEST.in
+README.rst
+requirements.txt
+setup.py
+m3u8/__init__.py
+m3u8/model.py
+m3u8/parser.py
+m3u8/protocol.py
+m3u8.egg-info/PKG-INFO
+m3u8.egg-info/SOURCES.txt
+m3u8.egg-info/dependency_links.txt
+m3u8.egg-info/not-zip-safe
+m3u8.egg-info/requires.txt
+m3u8.egg-info/top_level.txt
\ No newline at end of file
diff --git a/m3u8.egg-info/dependency_links.txt b/m3u8.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/m3u8.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/m3u8.egg-info/not-zip-safe b/m3u8.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/m3u8.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/m3u8.egg-info/requires.txt b/m3u8.egg-info/requires.txt
new file mode 100644
index 0000000..57c80f0
--- /dev/null
+++ b/m3u8.egg-info/requires.txt
@@ -0,0 +1 @@
+iso8601
diff --git a/m3u8.egg-info/top_level.txt b/m3u8.egg-info/top_level.txt
new file mode 100644
index 0000000..3f27023
--- /dev/null
+++ b/m3u8.egg-info/top_level.txt
@@ -0,0 +1 @@
+m3u8
diff --git a/m3u8/__init__.py b/m3u8/__init__.py
new file mode 100644
index 0000000..80a5da0
--- /dev/null
+++ b/m3u8/__init__.py
@@ -0,0 +1,75 @@
+# coding: utf-8
+# Copyright 2014 Globo.com Player authors. All rights reserved.
+# Use of this source code is governed by a MIT License
+# 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 m3u8.model import M3U8, Playlist, IFramePlaylist, Media, Segment
+from m3u8.parser import parse, is_url, ParseError
+
+__all__ = ('M3U8', 'Playlist', 'IFramePlaylist', 'Media',
+ 'Segment', 'loads', 'load', 'parse', 'ParseError')
+
+def loads(content):
+ '''
+ Given a string with a m3u8 content, returns a M3U8 object.
+ Raises ValueError if invalid content
+ '''
+ return M3U8(content)
+
+def load(uri):
+ '''
+ Retrieves the content from a given URI and returns a M3U8 object.
+ Raises ValueError if invalid content or IOError if request fails.
+ '''
+ if is_url(uri):
+ return _load_from_uri(uri)
+ else:
+ return _load_from_file(uri)
+
+# Support for python3 inspired by https://github.com/szemtiv/m3u8/
+def _load_from_uri(uri):
+ resource = urlopen(uri)
+ base_uri = _parsed_url(_url_for(uri))
+ if PYTHON_MAJOR_VERSION < (3,):
+ content = _read_python2x(resource)
+ else:
+ content = _read_python3x(resource)
+ return M3U8(content, base_uri=base_uri)
+
+def _url_for(uri):
+ return urlopen(uri).geturl()
+
+def _parsed_url(url):
+ parsed_url = url_parser.urlparse(url)
+ prefix = parsed_url.scheme + '://' + parsed_url.netloc
+ base_path = posixpath.normpath(parsed_url.path + '/..')
+ return url_parser.urljoin(prefix, base_path)
+
+def _read_python2x(resource):
+ return resource.read().strip()
+
+def _read_python3x(resource):
+ return resource.read().decode(resource.headers.get_content_charset(failobj="utf-8"))
+
+def _load_from_file(uri):
+ with open(uri) as fileobj:
+ raw_content = fileobj.read().strip()
+ base_uri = os.path.dirname(uri)
+ return M3U8(raw_content, base_uri=base_uri)
+
diff --git a/m3u8/model.py b/m3u8/model.py
new file mode 100644
index 0000000..4ca8c66
--- /dev/null
+++ b/m3u8/model.py
@@ -0,0 +1,674 @@
+# coding: utf-8
+# Copyright 2014 Globo.com Player authors. All rights reserved.
+# Use of this source code is governed by a MIT License
+# license that can be found in the LICENSE file.
+
+from collections import namedtuple
+import os
+import errno
+import math
+
+try:
+ import urlparse as url_parser
+except ImportError:
+ import urllib.parse as url_parser
+
+from m3u8 import parser
+
+
+class M3U8(object):
+ '''
+ Represents a single M3U8 playlist. Should be instantiated with
+ the content as string.
+
+ Parameters:
+
+ `content`
+ the m3u8 content as string
+
+ `base_path`
+ all urls (key and segments url) will be updated with this base_path,
+ ex.:
+ base_path = "http://videoserver.com/hls"
+
+ /foo/bar/key.bin --> http://videoserver.com/hls/key.bin
+ http://vid.com/segment1.ts --> http://videoserver.com/hls/segment1.ts
+
+ can be passed as parameter or setted as an attribute to ``M3U8`` object.
+ `base_uri`
+ uri the playlist comes from. it is propagated to SegmentList and Key
+ ex.: http://example.com/path/to
+
+ Attributes:
+
+ `key`
+ it's a `Key` object, the EXT-X-KEY from m3u8. Or None
+
+ `segments`
+ a `SegmentList` object, represents the list of `Segment`s from this playlist
+
+ `is_variant`
+ Returns true if this M3U8 is a variant playlist, with links to
+ other M3U8s with different bitrates.
+
+ If true, `playlists` is a list of the playlists available,
+ and `iframe_playlists` is a list of the i-frame playlists available.
+
+ `is_endlist`
+ Returns true if EXT-X-ENDLIST tag present in M3U8.
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.8
+
+ `playlists`
+ If this is a variant playlist (`is_variant` is True), returns a list of
+ Playlist objects
+
+ `iframe_playlists`
+ If this is a variant playlist (`is_variant` is True), returns a list of
+ IFramePlaylist objects
+
+ `playlist_type`
+ A lower-case string representing the type of the playlist, which can be
+ one of VOD (video on demand) or EVENT.
+
+ `media`
+ If this is a variant playlist (`is_variant` is True), returns a list of
+ Media objects
+
+ `target_duration`
+ Returns the EXT-X-TARGETDURATION as an integer
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.2
+
+ `media_sequence`
+ Returns the EXT-X-MEDIA-SEQUENCE as an integer
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.3
+
+ `program_date_time`
+ Returns the EXT-X-PROGRAM-DATE-TIME as a string
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.5
+
+ `version`
+ Return the EXT-X-VERSION as is
+
+ `allow_cache`
+ Return the EXT-X-ALLOW-CACHE as is
+
+ `files`
+ Returns an iterable with all files from playlist, in order. This includes
+ segments and key uri, if present.
+
+ `base_uri`
+ It is a property (getter and setter) used by
+ SegmentList and Key to have absolute URIs.
+
+ `is_i_frames_only`
+ Returns true if EXT-X-I-FRAMES-ONLY tag present in M3U8.
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.12
+
+ `is_independent_segments`
+ Returns true if EXT-X-INDEPENDENT-SEGMENTS tag present in M3U8.
+ https://tools.ietf.org/html/draft-pantos-http-live-streaming-13#section-3.4.16
+
+ '''
+
+ simple_attributes = (
+ # obj attribute # parser attribute
+ ('is_variant', 'is_variant'),
+ ('is_endlist', 'is_endlist'),
+ ('is_i_frames_only', 'is_i_frames_only'),
+ ('target_duration', 'targetduration'),
+ ('media_sequence', 'media_sequence'),
+ ('program_date_time', 'program_date_time'),
+ ('is_independent_segments', 'is_independent_segments'),
+ ('version', 'version'),
+ ('allow_cache', 'allow_cache'),
+ ('playlist_type', 'playlist_type')
+ )
+
+ def __init__(self, content=None, base_path=None, base_uri=None, strict=False):
+ if content is not None:
+ self.data = parser.parse(content, strict)
+ else:
+ self.data = {}
+ self._base_uri = base_uri
+ if self._base_uri:
+ if not self._base_uri.endswith('/'):
+ self._base_uri += '/'
+
+ self._initialize_attributes()
+ self.base_path = base_path
+
+ def _initialize_attributes(self):
+ self.key = Key(base_uri=self.base_uri, **self.data['key']) if 'key' in self.data else None
+ self.segments = SegmentList([ Segment(base_uri=self.base_uri, **params)
+ for params in self.data.get('segments', []) ])
+
+ for attr, param in self.simple_attributes:
+ setattr(self, attr, self.data.get(param))
+
+ self.files = []
+ if self.key:
+ self.files.append(self.key.uri)
+ self.files.extend(self.segments.uri)
+
+ self.media = MediaList([ Media(base_uri=self.base_uri,
+ **media)
+ for media in self.data.get('media', []) ])
+
+ self.playlists = PlaylistList([ Playlist(base_uri=self.base_uri,
+ media=self.media,
+ **playlist)
+ for playlist in self.data.get('playlists', []) ])
+
+ self.iframe_playlists = PlaylistList()
+ for ifr_pl in self.data.get('iframe_playlists', []):
+ self.iframe_playlists.append(
+ IFramePlaylist(base_uri=self.base_uri,
+ uri=ifr_pl['uri'],
+ iframe_stream_info=ifr_pl['iframe_stream_info'])
+ )
+
+ def __unicode__(self):
+ return self.dumps()
+
+ @property
+ def base_uri(self):
+ return self._base_uri
+
+ @base_uri.setter
+ def base_uri(self, new_base_uri):
+ self._base_uri = new_base_uri
+ self.media.base_uri = new_base_uri
+ self.playlists.base_uri = new_base_uri
+ self.segments.base_uri = new_base_uri
+
+ @property
+ def base_path(self):
+ return self._base_path
+
+ @base_path.setter
+ def base_path(self, newbase_path):
+ self._base_path = newbase_path
+ self._update_base_path()
+
+ def _update_base_path(self):
+ if self._base_path is None:
+ return
+ if self.key:
+ self.key.base_path = self.base_path
+ self.media.base_path = self.base_path
+ self.segments.base_path = self.base_path
+ self.playlists.base_path = self.base_path
+
+ def add_playlist(self, playlist):
+ self.is_variant = True
+ self.playlists.append(playlist)
+
+ def add_iframe_playlist(self, iframe_playlist):
+ if iframe_playlist is not None:
+ self.is_variant = True
+ self.iframe_playlists.append(iframe_playlist)
+
+ def add_media(self, media):
+ self.media.append(media)
+
+ def add_segment(self, segment):
+ self.segments.append(segment)
+
+ def dumps(self):
+ '''
+ Returns the current m3u8 as a string.
+ You could also use unicode(<this obj>) or str(<this obj>)
+ '''
+ output = ['#EXTM3U']
+ if self.is_independent_segments:
+ output.append('#EXT-X-INDEPENDENT-SEGMENTS')
+ if self.media_sequence:
+ output.append('#EXT-X-MEDIA-SEQUENCE:' + str(self.media_sequence))
+ if self.allow_cache:
+ output.append('#EXT-X-ALLOW-CACHE:' + self.allow_cache.upper())
+ if self.version:
+ output.append('#EXT-X-VERSION:' + self.version)
+ if self.key:
+ output.append(str(self.key))
+ if self.target_duration:
+ output.append('#EXT-X-TARGETDURATION:' + int_or_float_to_string(self.target_duration))
+ if self.program_date_time is not None:
+ output.append('#EXT-X-PROGRAM-DATE-TIME:' + parser.format_date_time(self.program_date_time))
+ if not (self.playlist_type is None or self.playlist_type == ''):
+ output.append(
+ '#EXT-X-PLAYLIST-TYPE:%s' % str(self.playlist_type).upper())
+ if self.is_i_frames_only:
+ output.append('#EXT-X-I-FRAMES-ONLY')
+ if self.is_variant:
+ if self.media:
+ output.append(str(self.media))
+ output.append(str(self.playlists))
+ if self.iframe_playlists:
+ output.append(str(self.iframe_playlists))
+
+ output.append(str(self.segments))
+
+ if self.is_endlist:
+ output.append('#EXT-X-ENDLIST')
+
+ return '\n'.join(output)
+
+ def dump(self, filename):
+ '''
+ Saves the current m3u8 to ``filename``
+ '''
+ self._create_sub_directories(filename)
+
+ with open(filename, 'w') as fileobj:
+ fileobj.write(self.dumps())
+
+ def _create_sub_directories(self, filename):
+ basename = os.path.dirname(filename)
+ try:
+ os.makedirs(basename)
+ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+
+class BasePathMixin(object):
+
+ @property
+ def absolute_uri(self):
+ if self.uri is None:
+ return None
+ if parser.is_url(self.uri):
+ return self.uri
+ else:
+ if self.base_uri is None:
+ raise ValueError('There can not be `absolute_uri` with no `base_uri` set')
+ return _urijoin(self.base_uri, self.uri)
+
+ @property
+ def base_path(self):
+ return os.path.dirname(self.uri)
+
+ @base_path.setter
+ def base_path(self, newbase_path):
+ if not self.base_path:
+ self.uri = "%s/%s" % (newbase_path, self.uri)
+ self.uri = self.uri.replace(self.base_path, newbase_path)
+
+class GroupedBasePathMixin(object):
+
+ def _set_base_uri(self, new_base_uri):
+ for item in self:
+ item.base_uri = new_base_uri
+
+ base_uri = property(None, _set_base_uri)
+
+ def _set_base_path(self, newbase_path):
+ for item in self:
+ item.base_path = newbase_path
+
+ base_path = property(None, _set_base_path)
+
+class Segment(BasePathMixin):
+ '''
+ A video segment from a M3U8 playlist
+
+ `uri`
+ a string with the segment uri
+
+ `title`
+ title attribute from EXTINF parameter
+
+ `program_date_time`
+ Returns the EXT-X-PROGRAM-DATE-TIME as a datetime
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.5
+
+ `discontinuity`
+ Returns a boolean indicating if a EXT-X-DISCONTINUITY tag exists
+ http://tools.ietf.org/html/draft-pantos-http-live-streaming-13#section-3.4.11
+
+ `cue_out`
+ Returns a boolean indicating if a EXT-X-CUE-OUT-CONT tag exists
+
+ `duration`
+ duration attribute from EXTINF parameter
+
+ `base_uri`
+ uri the key comes from in URI hierarchy. ex.: http://example.com/path/to
+
+ `byterange`
+ byterange attribute from EXT-X-BYTERANGE parameter
+
+ `key`
+ Key used to encrypt the segment (EXT-X-KEY)
+ '''
+
+ def __init__(self, uri, base_uri, program_date_time=None, duration=None,
+ title=None, byterange=None, cue_out=False, discontinuity=False, key=None):
+ self.uri = uri
+ self.duration = duration
+ self.title = title
+ self.base_uri = base_uri
+ self.byterange = byterange
+ self.program_date_time = program_date_time
+ self.discontinuity = discontinuity
+ self.cue_out = cue_out
+ self.key = Key(base_uri=base_uri,**key) if key else None
+
+
+ def dumps(self, last_segment):
+ output = []
+ if last_segment and self.key != last_segment.key:
+ output.append(str(self.key))
+ output.append('\n')
+
+ if self.discontinuity:
+ output.append('#EXT-X-DISCONTINUITY\n')
+ if self.program_date_time:
+ output.append('#EXT-X-PROGRAM-DATE-TIME:%s\n' % parser.format_date_time(self.program_date_time))
+ if self.cue_out:
+ output.append('#EXT-X-CUE-OUT-CONT\n')
+ output.append('#EXTINF:%s,' % int_or_float_to_string(self.duration))
+ if self.title:
+ output.append(quoted(self.title))
+
+ output.append('\n')
+
+ if self.byterange:
+ output.append('#EXT-X-BYTERANGE:%s\n' % self.byterange)
+
+ output.append(self.uri)
+
+ return ''.join(output)
+
+ def __str__(self):
+ return self.dumps(None)
+
+
+class SegmentList(list, GroupedBasePathMixin):
+
... 628 lines suppressed ...
--
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