fb0a4b24ef5bf65ff13ca2288395f09540e71d48
[youtube-dl] / youtube_dl / extractor / svt.py
1 # coding: utf-8
2 from __future__ import unicode_literals
3
4 import re
5
6 from .common import InfoExtractor
7 from ..utils import (
8     determine_ext,
9     dict_get,
10     int_or_none,
11     try_get,
12 )
13
14
15 class SVTBaseIE(InfoExtractor):
16     def _extract_video(self, video_info, video_id):
17         formats = []
18         for vr in video_info['videoReferences']:
19             player_type = vr.get('playerType') or vr.get('format')
20             vurl = vr['url']
21             ext = determine_ext(vurl)
22             if ext == 'm3u8':
23                 formats.extend(self._extract_m3u8_formats(
24                     vurl, video_id,
25                     ext='mp4', entry_protocol='m3u8_native',
26                     m3u8_id=player_type, fatal=False))
27             elif ext == 'f4m':
28                 formats.extend(self._extract_f4m_formats(
29                     vurl + '?hdcore=3.3.0', video_id,
30                     f4m_id=player_type, fatal=False))
31             elif ext == 'mpd':
32                 if player_type == 'dashhbbtv':
33                     formats.extend(self._extract_mpd_formats(
34                         vurl, video_id, mpd_id=player_type, fatal=False))
35             else:
36                 formats.append({
37                     'format_id': player_type,
38                     'url': vurl,
39                 })
40         if not formats and video_info.get('rights', {}).get('geoBlockedSweden'):
41             self.raise_geo_restricted('This video is only available in Sweden')
42         self._sort_formats(formats)
43
44         subtitles = {}
45         subtitle_references = dict_get(video_info, ('subtitles', 'subtitleReferences'))
46         if isinstance(subtitle_references, list):
47             for sr in subtitle_references:
48                 subtitle_url = sr.get('url')
49                 subtitle_lang = sr.get('language', 'sv')
50                 if subtitle_url:
51                     if determine_ext(subtitle_url) == 'm3u8':
52                         # TODO(yan12125): handle WebVTT in m3u8 manifests
53                         continue
54
55                     subtitles.setdefault(subtitle_lang, []).append({'url': subtitle_url})
56
57         title = video_info.get('title')
58
59         series = video_info.get('programTitle')
60         season_number = int_or_none(video_info.get('season'))
61         episode = video_info.get('episodeTitle')
62         episode_number = int_or_none(video_info.get('episodeNumber'))
63
64         duration = int_or_none(dict_get(video_info, ('materialLength', 'contentDuration')))
65         age_limit = None
66         adult = dict_get(
67             video_info, ('inappropriateForChildren', 'blockedForChildren'),
68             skip_false_values=False)
69         if adult is not None:
70             age_limit = 18 if adult else 0
71
72         return {
73             'id': video_id,
74             'title': title,
75             'formats': formats,
76             'subtitles': subtitles,
77             'duration': duration,
78             'age_limit': age_limit,
79             'series': series,
80             'season_number': season_number,
81             'episode': episode,
82             'episode_number': episode_number,
83         }
84
85
86 class SVTIE(SVTBaseIE):
87     _VALID_URL = r'https?://(?:www\.)?svt\.se/wd\?(?:.*?&)?widgetId=(?P<widget_id>\d+)&.*?\barticleId=(?P<id>\d+)'
88     _TEST = {
89         'url': 'http://www.svt.se/wd?widgetId=23991&sectionId=541&articleId=2900353&type=embed&contextSectionId=123&autostart=false',
90         'md5': '33e9a5d8f646523ce0868ecfb0eed77d',
91         'info_dict': {
92             'id': '2900353',
93             'ext': 'mp4',
94             'title': 'Stjärnorna skojar till det - under SVT-intervjun',
95             'duration': 27,
96             'age_limit': 0,
97         },
98     }
99
100     @staticmethod
101     def _extract_url(webpage):
102         mobj = re.search(
103             r'(?:<iframe src|href)="(?P<url>%s[^"]*)"' % SVTIE._VALID_URL, webpage)
104         if mobj:
105             return mobj.group('url')
106
107     def _real_extract(self, url):
108         mobj = re.match(self._VALID_URL, url)
109         widget_id = mobj.group('widget_id')
110         article_id = mobj.group('id')
111
112         info = self._download_json(
113             'http://www.svt.se/wd?widgetId=%s&articleId=%s&format=json&type=embed&output=json' % (widget_id, article_id),
114             article_id)
115
116         info_dict = self._extract_video(info['video'], article_id)
117         info_dict['title'] = info['context']['title']
118         return info_dict
119
120
121 class SVTPlayIE(SVTBaseIE):
122     IE_DESC = 'SVT Play and Öppet arkiv'
123     _VALID_URL = r'https?://(?:www\.)?(?:svtplay|oppetarkiv)\.se/(?:video|klipp)/(?P<id>[0-9]+)'
124     _TESTS = [{
125         'url': 'http://www.svtplay.se/video/5996901/flygplan-till-haile-selassie/flygplan-till-haile-selassie-2',
126         'md5': '2b6704fe4a28801e1a098bbf3c5ac611',
127         'info_dict': {
128             'id': '5996901',
129             'ext': 'mp4',
130             'title': 'Flygplan till Haile Selassie',
131             'duration': 3527,
132             'thumbnail': 're:^https?://.*[\.-]jpg$',
133             'age_limit': 0,
134             'subtitles': {
135                 'sv': [{
136                     'ext': 'wsrt',
137                 }]
138             },
139         },
140     }, {
141         # geo restricted to Sweden
142         'url': 'http://www.oppetarkiv.se/video/5219710/trollflojten',
143         'only_matching': True,
144     }, {
145         'url': 'http://www.svtplay.se/klipp/9023742/stopptid-om-bjorn-borg',
146         'only_matching': True,
147     }]
148
149     def _real_extract(self, url):
150         video_id = self._match_id(url)
151
152         webpage = self._download_webpage(url, video_id)
153
154         data = self._parse_json(
155             self._search_regex(
156                 r'root\["__svtplay"\]\s*=\s*([^;]+);',
157                 webpage, 'embedded data', default='{}'),
158             video_id, fatal=False)
159
160         thumbnail = self._og_search_thumbnail(webpage)
161
162         if data:
163             video_info = try_get(
164                 data, lambda x: x['context']['dispatcher']['stores']['VideoTitlePageStore']['data']['video'],
165                 dict)
166             if video_info:
167                 info_dict = self._extract_video(video_info, video_id)
168                 info_dict.update({
169                     'title': data['context']['dispatcher']['stores']['MetaStore']['title'],
170                     'thumbnail': thumbnail,
171                 })
172                 return info_dict
173
174         video_id = self._search_regex(
175             r'<video[^>]+data-video-id=["\']([\da-zA-Z-]+)',
176             webpage, 'video id', default=None)
177
178         if video_id:
179             data = self._download_json(
180                 'http://www.svt.se/videoplayer-api/video/%s' % video_id, video_id)
181             info_dict = self._extract_video(data, video_id)
182             if not info_dict.get('title'):
183                 info_dict['title'] = re.sub(
184                     r'\s*\|\s*.+?$', '',
185                     info_dict.get('episode') or self._og_search_title(webpage))
186             return info_dict