[wistia] Improve hls support
[youtube-dl] / youtube_dl / extractor / wistia.py
1 from __future__ import unicode_literals
2
3 from .common import InfoExtractor
4 from ..utils import (
5     ExtractorError,
6     int_or_none,
7 )
8
9
10 class WistiaIE(InfoExtractor):
11     _VALID_URL = r'(?:wistia:|https?://(?:fast\.)?wistia\.net/embed/iframe/)(?P<id>[a-z0-9]+)'
12     _API_URL = 'http://fast.wistia.com/embed/medias/%s.json'
13     _IFRAME_URL = 'http://fast.wistia.net/embed/iframe/%s'
14
15     _TESTS = [{
16         'url': 'http://fast.wistia.net/embed/iframe/sh7fpupwlt',
17         'md5': 'cafeb56ec0c53c18c97405eecb3133df',
18         'info_dict': {
19             'id': 'sh7fpupwlt',
20             'ext': 'mov',
21             'title': 'Being Resourceful',
22             'description': 'a Clients From Hell Video Series video from worldwidewebhosting',
23             'upload_date': '20131204',
24             'timestamp': 1386185018,
25             'duration': 117,
26         },
27     }, {
28         'url': 'wistia:sh7fpupwlt',
29         'only_matching': True,
30     }, {
31         # with hls video
32         'url': 'wistia:807fafadvk',
33         'only_matching': True,
34     }]
35
36     def _real_extract(self, url):
37         video_id = self._match_id(url)
38
39         data_json = self._download_json(
40             self._API_URL % video_id, video_id,
41             # Some videos require this.
42             headers={
43                 'Referer': url if url.startswith('http') else self._IFRAME_URL % video_id,
44             })
45
46         if data_json.get('error'):
47             raise ExtractorError(
48                 'Error while getting the playlist', expected=True)
49
50         data = data_json['media']
51         title = data['name']
52
53         formats = []
54         thumbnails = []
55         for a in data['assets']:
56             aurl = a.get('url')
57             if not aurl:
58                 continue
59             astatus = a.get('status')
60             atype = a.get('type')
61             if (astatus is not None and astatus != 2) or atype in ('preview', 'storyboard'):
62                 continue
63             elif atype in ('still', 'still_image'):
64                 thumbnails.append({
65                     'url': aurl,
66                     'width': int_or_none(a.get('width')),
67                     'height': int_or_none(a.get('height')),
68                 })
69             else:
70                 aext = a.get('ext')
71                 is_m3u8 = a.get('container') == 'm3u8' or aext == 'm3u8'
72                 formats.append({
73                     'format_id': atype,
74                     'url': aurl,
75                     'tbr': int_or_none(a.get('bitrate')),
76                     'vbr': int_or_none(a.get('opt_vbitrate')),
77                     'width': int_or_none(a.get('width')),
78                     'height': int_or_none(a.get('height')),
79                     'filesize': int_or_none(a.get('size')),
80                     'vcodec': a.get('codec'),
81                     'container': a.get('container'),
82                     'ext': 'mp4' if is_m3u8 else aext,
83                     'protocol': 'm3u8' if is_m3u8 else None,
84                     'preference': 1 if atype == 'original' else None,
85                 })
86
87         self._sort_formats(formats)
88
89         return {
90             'id': video_id,
91             'title': title,
92             'description': data.get('seoDescription'),
93             'formats': formats,
94             'thumbnails': thumbnails,
95             'duration': int_or_none(data.get('duration')),
96             'timestamp': int_or_none(data.get('createdAt')),
97         }