[livestream] Parse SMIL (#2713)
authorPhilipp Hagemeister <phihag@phihag.de>
Fri, 25 Jul 2014 09:39:17 +0000 (11:39 +0200)
committerPhilipp Hagemeister <phihag@phihag.de>
Fri, 25 Jul 2014 09:39:17 +0000 (11:39 +0200)
youtube_dl/extractor/livestream.py
youtube_dl/utils.py

index 1ea1bbab4dc31123d8c45669315226bfe2fdda68..444771bd38ec1c8056493e1bbceeef0ff7799772 100644 (file)
@@ -5,11 +5,14 @@ import json
 
 from .common import InfoExtractor
 from ..utils import (
+    compat_str,
     compat_urllib_parse_urlparse,
     compat_urlparse,
-    xpath_with_ns,
-    compat_str,
+    ExtractorError,
+    find_xpath_attr,
+    int_or_none,
     orderedSet,
+    xpath_with_ns,
 )
 
 
@@ -24,20 +27,71 @@ class LivestreamIE(InfoExtractor):
             'ext': 'mp4',
             'title': 'Live from Webster Hall NYC',
             'upload_date': '20121012',
+            'like_count': int,
+            'view_count': int,
+            'thumbnail': 're:^http://.*\.jpg$'
         }
     }
 
     def _extract_video_info(self, video_data):
-        video_url = (
-            video_data.get('progressive_url_hd') or
-            video_data.get('progressive_url')
+        video_id = compat_str(video_data['id'])
+
+        FORMAT_KEYS = (
+            ('sd', 'progressive_url'),
+            ('hd', 'progressive_url_hd'),
         )
+        formats = [{
+            'format_id': format_id,
+            'url': video_data[key],
+            'quality': i + 1,
+        } for i, (format_id, key) in enumerate(FORMAT_KEYS)
+            if video_data.get(key)]
+
+        smil_url = video_data.get('smil_url')
+        if smil_url:
+            _SWITCH_XPATH = (
+                './/{http://www.w3.org/2001/SMIL20/Language}body/'
+                '{http://www.w3.org/2001/SMIL20/Language}switch')
+            smil_doc = self._download_xml(
+                smil_url, video_id, note='Downloading SMIL information')
+
+            title_node = find_xpath_attr(
+                smil_doc, './/{http://www.w3.org/2001/SMIL20/Language}meta',
+                'name', 'title')
+            if title_node is None:
+                self.report_warning('Cannot find SMIL id')
+                switch_node = smil_doc.find(_SWITCH_XPATH)
+            else:
+                title_id = title_node.attrib['content']
+                switch_node = find_xpath_attr(
+                    smil_doc, _SWITCH_XPATH, 'id', title_id)
+            if switch_node is None:
+                raise ExtractorError('Cannot find switch node')
+            video_nodes = switch_node.findall(
+                '{http://www.w3.org/2001/SMIL20/Language}video')
+
+            for vn in video_nodes:
+                tbr = int_or_none(vn.attrib.get('system-bitrate'))
+                furl = (
+                    'http://livestream-f.akamaihd.net/%s?v=3.0.3&fp=WIN%%2014,0,0,145&seek=%s' %
+                    (vn.attrib['src'], vn.attrib['clipBegin']))
+                formats.append({
+                    'url': furl,
+                    'format_id': 'smil_%d' % tbr,
+                    'ext': 'flv',
+                    'tbr': tbr,
+                    'preference': -1000,
+                })
+        self._sort_formats(formats)
+
         return {
-            'id': compat_str(video_data['id']),
-            'url': video_url,
+            'id': video_id,
+            'formats': formats,
             'title': video_data['caption'],
-            'thumbnail': video_data['thumbnail_url'],
+            'thumbnail': video_data.get('thumbnail_url'),
             'upload_date': video_data['updated_at'].replace('-', '')[:8],
+            'like_count': video_data.get('likes', {}).get('total'),
+            'view_count': video_data.get('views'),
         }
 
     def _real_extract(self, url):
index 3ecd798d74217011920135199ee59c76d58852c0..0d0bbe8f66e67e35eb732349e6cfd374a3bbd2b5 100644 (file)
@@ -242,8 +242,8 @@ else:
 if sys.version_info >= (2,7):
     def find_xpath_attr(node, xpath, key, val):
         """ Find the xpath xpath[@key=val] """
-        assert re.match(r'^[a-zA-Z]+$', key)
-        assert re.match(r'^[a-zA-Z0-9@\s:._]*$', val)
+        assert re.match(r'^[a-zA-Z-]+$', key)
+        assert re.match(r'^[a-zA-Z0-9@\s:._-]*$', val)
         expr = xpath + u"[@%s='%s']" % (key, val)
         return node.find(expr)
 else: