Merge remote-tracking branch 'naglis/wistia'
[youtube-dl] / youtube_dl / extractor / theplatform.py
1 from __future__ import unicode_literals
2
3 import re
4 import json
5
6 from .common import InfoExtractor
7 from ..utils import (
8     compat_str,
9     ExtractorError,
10     xpath_with_ns,
11 )
12
13 _x = lambda p: xpath_with_ns(p, {'smil': 'http://www.w3.org/2005/SMIL21/Language'})
14
15
16 class ThePlatformIE(InfoExtractor):
17     _VALID_URL = r'''(?x)
18         (?:https?://(?:link|player)\.theplatform\.com/[sp]/[^/]+/
19            (?P<config>(?:[^/\?]+/(?:swf|config)|onsite)/select/)?
20          |theplatform:)(?P<id>[^/\?&]+)'''
21
22     _TEST = {
23         # from http://www.metacafe.com/watch/cb-e9I_cZgTgIPd/blackberrys_big_bold_z30/
24         'url': 'http://link.theplatform.com/s/dJ5BDC/e9I_cZgTgIPd/meta.smil?format=smil&Tracking=true&mbr=true',
25         'info_dict': {
26             'id': 'e9I_cZgTgIPd',
27             'ext': 'flv',
28             'title': 'Blackberry\'s big, bold Z30',
29             'description': 'The Z30 is Blackberry\'s biggest, baddest mobile messaging device yet.',
30             'duration': 247,
31         },
32         'params': {
33             # rtmp download
34             'skip_download': True,
35         },
36     }
37
38     def _get_info(self, video_id, smil_url):
39         meta = self._download_xml(smil_url, video_id)
40
41         try:
42             error_msg = next(
43                 n.attrib['abstract']
44                 for n in meta.findall(_x('.//smil:ref'))
45                 if n.attrib.get('title') == 'Geographic Restriction')
46         except StopIteration:
47             pass
48         else:
49             raise ExtractorError(error_msg, expected=True)
50
51         info_url = 'http://link.theplatform.com/s/dJ5BDC/{0}?format=preview'.format(video_id)
52         info_json = self._download_webpage(info_url, video_id)
53         info = json.loads(info_json)
54
55         head = meta.find(_x('smil:head'))
56         body = meta.find(_x('smil:body'))
57
58         f4m_node = body.find(_x('smil:seq//smil:video'))
59         if f4m_node is not None and '.f4m' in f4m_node.attrib['src']:
60             f4m_url = f4m_node.attrib['src']
61             if 'manifest.f4m?' not in f4m_url:
62                 f4m_url += '?'
63             # the parameters are from syfy.com, other sites may use others,
64             # they also work for nbc.com
65             f4m_url += '&g=UXWGVKRWHFSP&hdcore=3.0.3'
66             formats = self._extract_f4m_formats(f4m_url, video_id)
67         else:
68             formats = []
69             switch = body.find(_x('smil:switch'))
70             if switch is not None:
71                 base_url = head.find(_x('smil:meta')).attrib['base']
72                 for f in switch.findall(_x('smil:video')):
73                     attr = f.attrib
74                     width = int(attr['width'])
75                     height = int(attr['height'])
76                     vbr = int(attr['system-bitrate']) // 1000
77                     format_id = '%dx%d_%dk' % (width, height, vbr)
78                     formats.append({
79                         'format_id': format_id,
80                         'url': base_url,
81                         'play_path': 'mp4:' + attr['src'],
82                         'ext': 'flv',
83                         'width': width,
84                         'height': height,
85                         'vbr': vbr,
86                     })
87             else:
88                 switch = body.find(_x('smil:seq//smil:switch'))
89                 for f in switch.findall(_x('smil:video')):
90                     attr = f.attrib
91                     vbr = int(attr['system-bitrate']) // 1000
92                     formats.append({
93                         'format_id': compat_str(vbr),
94                         'url': attr['src'],
95                         'vbr': vbr,
96                     })
97             self._sort_formats(formats)
98
99         return {
100             'id': video_id,
101             'title': info['title'],
102             'formats': formats,
103             'description': info['description'],
104             'thumbnail': info['defaultThumbnailUrl'],
105             'duration': info['duration']//1000,
106         }
107         
108     def _real_extract(self, url):
109         mobj = re.match(self._VALID_URL, url)
110         video_id = mobj.group('id')
111         if mobj.group('config'):
112             config_url = url+ '&form=json'
113             config_url = config_url.replace('swf/', 'config/')
114             config_url = config_url.replace('onsite/', 'onsite/config/')
115             config = self._download_json(config_url, video_id, 'Downloading config')
116             smil_url = config['releaseUrl'] + '&format=SMIL&formats=MPEG4&manifest=f4m'
117         else:
118             smil_url = ('http://link.theplatform.com/s/dJ5BDC/{0}/meta.smil?'
119                 'format=smil&mbr=true'.format(video_id))
120         return self._get_info(video_id, smil_url)