[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