a2379eb04c2e6744a49f315ebee2a0c9fb0170f6
[youtube-dl] / youtube_dl / extractor / rutv.py
1 # encoding: utf-8
2 from __future__ import unicode_literals
3
4 import re
5
6 from .common import InfoExtractor
7 from ..utils import (
8     ExtractorError,
9     int_or_none
10 )
11
12
13 class RUTVIE(InfoExtractor):
14     IE_DESC = 'RUTV.RU'
15     _VALID_URL = r'''(?x)
16         https?://player\.(?:rutv\.ru|vgtrk\.com)/
17             (?P<path>flash\d+v/container\.swf\?id=
18             |iframe/(?P<type>swf|video|live)/id/
19             |index/iframe/cast_id/)
20             (?P<id>\d+)'''
21
22     _TESTS = [
23         {
24             'url': 'http://player.rutv.ru/flash2v/container.swf?id=774471&sid=kultura&fbv=true&isPlay=true&ssl=false&i=560&acc_video_id=episode_id/972347/video_id/978186/brand_id/31724',
25             'info_dict': {
26                 'id': '774471',
27                 'ext': 'mp4',
28                 'title': 'Монологи на все времена',
29                 'description': 'md5:18d8b5e6a41fb1faa53819471852d5d5',
30                 'duration': 2906,
31             },
32             'params': {
33                 # m3u8 download
34                 'skip_download': True,
35             },
36         },
37         {
38             'url': 'https://player.vgtrk.com/flash2v/container.swf?id=774016&sid=russiatv&fbv=true&isPlay=true&ssl=false&i=560&acc_video_id=episode_id/972098/video_id/977760/brand_id/57638',
39             'info_dict': {
40                 'id': '774016',
41                 'ext': 'mp4',
42                 'title': 'Чужой в семье Сталина',
43                 'description': '',
44                 'duration': 2539,
45             },
46             'params': {
47                 # m3u8 download
48                 'skip_download': True,
49             },
50         },
51         {
52             'url': 'http://player.rutv.ru/iframe/swf/id/766888/sid/hitech/?acc_video_id=4000',
53             'info_dict': {
54                 'id': '766888',
55                 'ext': 'mp4',
56                 'title': 'Вести.net: интернет-гиганты начали перетягивание программных "одеял"',
57                 'description': 'md5:65ddd47f9830c4f42ed6475f8730c995',
58                 'duration': 279,
59             },
60             'params': {
61                 # m3u8 download
62                 'skip_download': True,
63             },
64         },
65         {
66             'url': 'http://player.rutv.ru/iframe/video/id/771852/start_zoom/true/showZoomBtn/false/sid/russiatv/?acc_video_id=episode_id/970443/video_id/975648/brand_id/5169',
67             'info_dict': {
68                 'id': '771852',
69                 'ext': 'mp4',
70                 'title': 'Прямой эфир. Жертвы загадочной болезни: смерть от старости в 17 лет',
71                 'description': 'md5:b81c8c55247a4bd996b43ce17395b2d8',
72                 'duration': 3096,
73             },
74             'params': {
75                 # m3u8 download
76                 'skip_download': True,
77             },
78         },
79         {
80             'url': 'http://player.rutv.ru/iframe/live/id/51499/showZoomBtn/false/isPlay/true/sid/sochi2014',
81             'info_dict': {
82                 'id': '51499',
83                 'ext': 'flv',
84                 'title': 'Сочи-2014. Биатлон. Индивидуальная гонка. Мужчины ',
85                 'description': 'md5:9e0ed5c9d2fa1efbfdfed90c9a6d179c',
86             },
87             'skip': 'Translation has finished',
88         },
89         {
90             'url': 'http://player.rutv.ru/iframe/live/id/21/showZoomBtn/false/isPlay/true/',
91             'info_dict': {
92                 'id': '21',
93                 'ext': 'mp4',
94                 'title': 're:^Россия 24. Прямой эфир [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
95                 'is_live': True,
96             },
97             'params': {
98                 # m3u8 download
99                 'skip_download': True,
100             },
101         },
102     ]
103
104     @classmethod
105     def _extract_url(cls, webpage):
106         mobj = re.search(
107             r'<iframe[^>]+?src=(["\'])(?P<url>https?://player\.(?:rutv\.ru|vgtrk\.com)/(?:iframe/(?:swf|video|live)/id|index/iframe/cast_id)/.+?)\1', webpage)
108         if mobj:
109             return mobj.group('url')
110
111         mobj = re.search(
112             r'<meta[^>]+?property=(["\'])og:video\1[^>]+?content=(["\'])(?P<url>https?://player\.(?:rutv\.ru|vgtrk\.com)/flash\d+v/container\.swf\?id=.+?\2)',
113             webpage)
114         if mobj:
115             return mobj.group('url')
116
117     def _real_extract(self, url):
118         mobj = re.match(self._VALID_URL, url)
119         video_id = mobj.group('id')
120         video_path = mobj.group('path')
121
122         if re.match(r'flash\d+v', video_path):
123             video_type = 'video'
124         elif video_path.startswith('iframe'):
125             video_type = mobj.group('type')
126             if video_type == 'swf':
127                 video_type = 'video'
128         elif video_path.startswith('index/iframe/cast_id'):
129             video_type = 'live'
130
131         is_live = video_type == 'live'
132
133         json_data = self._download_json(
134             'http://player.rutv.ru/iframe/data%s/id/%s' % ('live' if is_live else 'video', video_id),
135             video_id, 'Downloading JSON')
136
137         if json_data['errors']:
138             raise ExtractorError('%s said: %s' % (self.IE_NAME, json_data['errors']), expected=True)
139
140         playlist = json_data['data']['playlist']
141         medialist = playlist['medialist']
142         media = medialist[0]
143
144         if media['errors']:
145             raise ExtractorError('%s said: %s' % (self.IE_NAME, media['errors']), expected=True)
146
147         view_count = playlist.get('count_views')
148         priority_transport = playlist['priority_transport']
149
150         thumbnail = media['picture']
151         width = int_or_none(media['width'])
152         height = int_or_none(media['height'])
153         description = media['anons']
154         title = media['title']
155         duration = int_or_none(media.get('duration'))
156
157         formats = []
158
159         for transport, links in media['sources'].items():
160             for quality, url in links.items():
161                 preference = -1 if priority_transport == transport else -2
162                 if transport == 'rtmp':
163                     mobj = re.search(r'^(?P<url>rtmp://[^/]+/(?P<app>.+))/(?P<playpath>.+)$', url)
164                     if not mobj:
165                         continue
166                     fmt = {
167                         'url': mobj.group('url'),
168                         'play_path': mobj.group('playpath'),
169                         'app': mobj.group('app'),
170                         'page_url': 'http://player.rutv.ru',
171                         'player_url': 'http://player.rutv.ru/flash3v/osmf.swf?i=22',
172                         'rtmp_live': True,
173                         'ext': 'flv',
174                         'vbr': int(quality),
175                         'preference': preference,
176                     }
177                 elif transport == 'm3u8':
178                     formats.extend(self._extract_m3u8_formats(
179                         url, video_id, 'mp4', preference=preference, m3u8_id='hls'))
180                     continue
181                 else:
182                     fmt = {
183                         'url': url
184                     }
185                 fmt.update({
186                     'width': width,
187                     'height': height,
188                     'format_id': '%s-%s' % (transport, quality),
189                 })
190                 formats.append(fmt)
191
192         self._sort_formats(formats)
193
194         return {
195             'id': video_id,
196             'title': self._live_title(title) if is_live else title,
197             'description': description,
198             'thumbnail': thumbnail,
199             'view_count': view_count,
200             'duration': duration,
201             'formats': formats,
202             'is_live': is_live,
203         }