2 from __future__
import unicode_literals
6 from .common
import InfoExtractor
8 compat_etree_fromstring
,
10 compat_urllib_parse_unquote
,
11 compat_urllib_parse_urlparse
,
24 class OdnoklassnikiIE(InfoExtractor
):
27 (?:(?:www|m|mobile)\.)?
28 (?:odnoklassniki|ok)\.ru/
31 web-api/video/moviePlayer/|
39 'url': 'http://ok.ru/video/20079905452',
40 'md5': '0b62089b479e06681abaaca9d204f152',
44 'title': 'Культура меняет нас (прекрасный ролик!))',
46 'upload_date': '20141207',
47 'uploader_id': '330537914540',
48 'uploader': 'Виталий Добровольский',
54 'url': 'http://ok.ru/video/63567059965189-0?fromTime=5',
55 'md5': '6ff470ea2dd51d5d18c295a355b0b6bc',
57 'id': '63567059965189-0',
59 'title': 'Девушка без комплексов ...',
61 'upload_date': '20150518',
62 'uploader_id': '534380003155',
63 'uploader': '☭ Андрей Мещанинов ☭',
69 # YouTube embed (metadataUrl, provider == USER_YOUTUBE)
70 'url': 'http://ok.ru/video/64211978996595-1',
71 'md5': '2f206894ffb5dbfcce2c5a14b909eea5',
75 'title': 'Космическая среда от 26 августа 2015',
76 'description': 'md5:848eb8b85e5e3471a3a803dae1343ed0',
78 'upload_date': '20150826',
79 'uploader_id': 'tvroscosmos',
80 'uploader': 'Телестудия Роскосмоса',
84 # YouTube embed (metadata, provider == USER_YOUTUBE, no metadata.movie.title field)
85 'url': 'http://ok.ru/video/62036049272859-0',
87 'id': '62036049272859-0',
89 'title': 'МУЗЫКА ДОЖДЯ .',
90 'description': 'md5:6f1867132bd96e33bf53eda1091e8ed0',
91 'upload_date': '20120106',
92 'uploader_id': '473534735899',
93 'uploader': 'МARINA D',
97 'skip_download': True,
99 'skip': 'Video has not been found',
101 'note': 'Only available in mobile webpage',
102 'url': 'https://m.ok.ru/video/2361249957145',
104 'id': '2361249957145',
105 'title': 'Быковское крещение',
106 'duration': 3038.181,
109 'url': 'http://ok.ru/web-api/video/moviePlayer/20079905452',
110 'only_matching': True,
112 'url': 'http://www.ok.ru/video/20648036891',
113 'only_matching': True,
115 'url': 'http://www.ok.ru/videoembed/20648036891',
116 'only_matching': True,
118 'url': 'http://m.ok.ru/video/20079905452',
119 'only_matching': True,
121 'url': 'http://mobile.ok.ru/video/20079905452',
122 'only_matching': True,
124 'url': 'https://www.ok.ru/live/484531969818',
125 'only_matching': True,
127 'url': 'https://m.ok.ru/dk?st.cmd=movieLayer&st.discId=863789452017&st.retLoc=friend&st.rtu=%2Fdk%3Fst.cmd%3DfriendMovies%26st.mode%3Down%26st.mrkId%3D%257B%2522uploadedMovieMarker%2522%253A%257B%2522marker%2522%253A%25221519410114503%2522%252C%2522hasMore%2522%253Atrue%257D%252C%2522sharedMovieMarker%2522%253A%257B%2522marker%2522%253Anull%252C%2522hasMore%2522%253Afalse%257D%257D%26st.friendId%3D561722190321%26st.frwd%3Don%26_prevCmd%3DfriendMovies%26tkn%3D7257&st.discType=MOVIE&st.mvId=863789452017&_prevCmd=friendMovies&tkn=3648#lst#',
128 'only_matching': True,
131 'url': 'https://ok.ru/video/954886983203',
132 'only_matching': True,
136 def _extract_url(webpage
):
138 r
'<iframe[^>]+src=(["\'])(?P
<url
>(?
:https?
:)?
//(?
:odnoklassniki|ok
)\
.ru
/videoembed
/.+?
)\
1', webpage)
140 return mobj.group('url
')
142 def _real_extract(self, url):
144 return self._extract_desktop(url)
145 except ExtractorError as e:
147 return self._extract_mobile(url)
148 except ExtractorError:
149 # error message of desktop webpage is in English
152 def _extract_desktop(self, url):
153 start_time = int_or_none(compat_parse_qs(
154 compat_urllib_parse_urlparse(url).query).get('fromTime
', [None])[0])
156 video_id = self._match_id(url)
158 webpage = self._download_webpage(
159 'http
://ok
.ru
/video
/%s' % video_id, video_id,
160 note='Downloading desktop webpage
')
162 error = self._search_regex(
163 r'[^
>]+class="vp_video_stub_txt"[^
>]*>([^
<]+)<',
164 webpage, 'error
', default=None)
166 raise ExtractorError(error, expected=True)
168 player = self._parse_json(
169 unescapeHTML(self._search_regex(
170 r'data
-options
=(?P
<quote
>["\'])(?P<player>{.+?%s.+?})(?P=quote)' % video_id,
171 webpage, 'player', group='player')),
174 flashvars = player['flashvars']
176 metadata = flashvars.get('metadata')
178 metadata = self._parse_json(metadata, video_id)
181 st_location = flashvars.get('location')
183 data['st.location'] = st_location
184 metadata = self._download_json(
185 compat_urllib_parse_unquote(flashvars['metadataUrl']),
186 video_id, 'Downloading metadata JSON',
187 data=urlencode_postdata(data))
189 movie = metadata['movie']
191 # Some embedded videos may not contain title in movie dict (e.g.
192 # http://ok.ru/video/62036049272859-0) thus we allow missing title
193 # here and it's going to be extracted later by an extractor that
194 # will process the actual embed.
195 provider = metadata.get('provider')
196 title = movie['title'] if provider == 'UPLOADED_ODKL' else movie.get('title')
198 thumbnail = movie.get('poster')
199 duration = int_or_none(movie.get('duration'))
201 author = metadata.get('author', {})
202 uploader_id = author.get('id')
203 uploader = author.get('name')
205 upload_date = unified_strdate(self._html_search_meta(
206 'ya:ovs:upload_date', webpage, 'upload date', default=None))
209 adult = self._html_search_meta(
210 'ya:ovs:adult', webpage, 'age limit', default=None)
212 age_limit = 18 if adult == 'true' else 0
214 like_count = int_or_none(metadata.get('likeCount'))
219 'thumbnail': thumbnail,
220 'duration': duration,
221 'upload_date': upload_date,
222 'uploader': uploader,
223 'uploader_id': uploader_id,
224 'like_count': like_count,
225 'age_limit': age_limit,
226 'start_time': start_time,
229 if provider == 'USER_YOUTUBE':
231 '_type': 'url_transparent',
232 'url': movie['contentId'],
237 if provider == 'LIVE_TV_APP':
238 info['title'] = self._live_title(title)
240 quality = qualities(('4', '0', '1', '2', '3', '5'))
245 'format_id': f['name'],
246 } for f in metadata['videos']]
248 m3u8_url = metadata.get('hlsManifestUrl')
250 formats.extend(self._extract_m3u8_formats(
251 m3u8_url, video_id, 'mp4', 'm3u8_native',
252 m3u8_id='hls', fatal=False))
254 dash_manifest = metadata.get('metadataEmbedded')
256 formats.extend(self._parse_mpd_formats(
257 compat_etree_fromstring(dash_manifest), 'mpd'))
260 fmt_type = self._search_regex(
261 r'\btype[/=](\d)', fmt['url'],
262 'format type', default=None)
264 fmt['quality'] = quality(fmt_type)
267 m3u8_url = metadata.get('hlsMasterPlaylistUrl')
269 formats.extend(self._extract_m3u8_formats(
270 m3u8_url, video_id, 'mp4', m3u8_id='hls', fatal=False))
271 rtmp_url = metadata.get('rtmpUrl')
280 payment_info = metadata.get('paymentInfo')
282 self.raise_no_formats('This video is paid, subscribe to download it', expected=True)
284 self._sort_formats(formats)
286 info['formats'] = formats
289 def _extract_mobile(self, url):
290 video_id = self._match_id(url)
292 webpage = self._download_webpage(
293 'http://m.ok.ru/video/%s' % video_id, video_id,
294 note='Downloading mobile webpage')
296 error = self._search_regex(
297 r'видео</a>\s*<div\s+class="empty
">(.+?)</div>',
298 webpage, 'error', default=None)
300 raise ExtractorError(error, expected=True)
302 json_data = self._search_regex(
303 r'data-video="(.+?
)"', webpage, 'json data')
304 json_data = self._parse_json(unescapeHTML(json_data), video_id) or {}
308 'title': json_data.get('videoName'),
309 'duration': float_or_none(json_data.get('videoDuration'), scale=1000),
310 'thumbnail': json_data.get('videoPosterSrc'),
312 'format_id': 'mobile',
313 'url': json_data.get('videoSrc'),