| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | # encoding: utf-8 | 
					
						
							| 
									
										
										
										
											2014-01-21 17:32:03 +01:00
										 |  |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | import re | 
					
						
							|  |  |  |  | import json | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | from .common import InfoExtractor | 
					
						
							| 
									
										
										
										
											2014-12-13 12:24:42 +01:00
										 |  |  |  | from ..compat import ( | 
					
						
							|  |  |  |  |     compat_str, | 
					
						
							|  |  |  |  |     compat_urllib_parse, | 
					
						
							|  |  |  |  |     compat_urllib_request, | 
					
						
							|  |  |  |  | ) | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |     ExtractorError, | 
					
						
							| 
									
										
										
										
											2014-12-13 12:24:42 +01:00
										 |  |  |  |     orderedSet, | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |     unescapeHTML, | 
					
						
							| 
									
										
										
										
											2014-11-21 23:16:12 +00:00
										 |  |  |  |     unified_strdate, | 
					
						
							| 
									
										
										
										
											2014-12-13 12:24:42 +01:00
										 |  |  |  | ) | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class VKIE(InfoExtractor): | 
					
						
							| 
									
										
										
										
											2014-01-21 17:32:03 +01:00
										 |  |  |  |     IE_NAME = 'vk.com' | 
					
						
							| 
									
										
										
										
											2014-11-17 17:52:00 -05:00
										 |  |  |  |     _VALID_URL = r'https?://(?:m\.)?vk\.com/(?:video_ext\.php\?.*?\boid=(?P<oid>-?\d+).*?\bid=(?P<id>\d+)|(?:.+?\?.*?z=)?video(?P<videoid>[^s].*?)(?:\?|%2F|$))' | 
					
						
							| 
									
										
										
										
											2014-02-17 02:17:10 +07:00
										 |  |  |  |     _NETRC_MACHINE = 'vk' | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |     _TESTS = [ | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             'url': 'http://vk.com/videos-77521?z=video-77521_162222515%2Fclub77521', | 
					
						
							|  |  |  |  |             'md5': '0deae91935c54e00003c2a00646315f0', | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '162222515', | 
					
						
							|  |  |  |  |                 'ext': 'flv', | 
					
						
							|  |  |  |  |                 'title': 'ProtivoGunz - Хуёвая песня', | 
					
						
							| 
									
										
										
										
											2014-06-29 04:51:47 +07:00
										 |  |  |  |                 'uploader': 're:Noize MC.*', | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |                 'duration': 195, | 
					
						
							| 
									
										
										
										
											2014-11-21 22:23:39 +00:00
										 |  |  |  |                 'upload_date': '20120212', | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2014-11-21 22:52:01 +00:00
										 |  |  |  |             'url': 'http://vk.com/video205387401_165548505', | 
					
						
							|  |  |  |  |             'md5': '6c0aeb2e90396ba97035b9cbde548700', | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |             'info_dict': { | 
					
						
							| 
									
										
										
										
											2014-11-21 22:52:01 +00:00
										 |  |  |  |                 'id': '165548505', | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |                 'ext': 'mp4', | 
					
						
							| 
									
										
										
										
											2014-11-21 22:52:01 +00:00
										 |  |  |  |                 'uploader': 'Tom Cruise', | 
					
						
							|  |  |  |  |                 'title': 'No name', | 
					
						
							|  |  |  |  |                 'duration': 9, | 
					
						
							|  |  |  |  |                 'upload_date': '20130721' | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-02-28 23:51:54 +07:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |             'note': 'Embedded video', | 
					
						
							|  |  |  |  |             'url': 'http://vk.com/video_ext.php?oid=32194266&id=162925554&hash=7d8c2e0d5e05aeaa&hd=1', | 
					
						
							|  |  |  |  |             'md5': 'c7ce8f1f87bec05b3de07fdeafe21a0a', | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '162925554', | 
					
						
							|  |  |  |  |                 'ext': 'mp4', | 
					
						
							|  |  |  |  |                 'uploader': 'Vladimir Gavrin', | 
					
						
							|  |  |  |  |                 'title': 'Lin Dan', | 
					
						
							|  |  |  |  |                 'duration': 101, | 
					
						
							| 
									
										
										
										
											2014-11-21 22:23:39 +00:00
										 |  |  |  |                 'upload_date': '20120730', | 
					
						
							| 
									
										
										
										
											2014-02-28 23:51:54 +07:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2014-11-21 22:52:01 +00:00
										 |  |  |  |             # VIDEO NOW REMOVED | 
					
						
							|  |  |  |  |             # please update if you find a video whose URL follows the same pattern | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |             'url': 'http://vk.com/video-8871596_164049491', | 
					
						
							|  |  |  |  |             'md5': 'a590bcaf3d543576c9bd162812387666', | 
					
						
							|  |  |  |  |             'note': 'Only available for registered users', | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '164049491', | 
					
						
							|  |  |  |  |                 'ext': 'mp4', | 
					
						
							|  |  |  |  |                 'uploader': 'Триллеры', | 
					
						
							| 
									
										
										
										
											2014-06-29 19:33:39 +07:00
										 |  |  |  |                 'title': '► Бойцовский клуб / Fight Club 1999 [HD 720]', | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |                 'duration': 8352, | 
					
						
							| 
									
										
										
										
											2014-11-21 22:52:01 +00:00
										 |  |  |  |                 'upload_date': '20121218' | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |             }, | 
					
						
							|  |  |  |  |             'skip': 'Requires vk account credentials', | 
					
						
							| 
									
										
										
										
											2014-02-28 23:51:54 +07:00
										 |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-06-29 19:33:39 +07:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |             'url': 'http://vk.com/hd_kino_mania?z=video-43215063_168067957%2F15c66b9b533119788d', | 
					
						
							|  |  |  |  |             'md5': '4d7a5ef8cf114dfa09577e57b2993202', | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '168067957', | 
					
						
							|  |  |  |  |                 'ext': 'mp4', | 
					
						
							|  |  |  |  |                 'uploader': 'Киномания - лучшее из мира кино', | 
					
						
							|  |  |  |  |                 'title': ' ', | 
					
						
							|  |  |  |  |                 'duration': 7291, | 
					
						
							| 
									
										
										
										
											2014-11-21 22:23:39 +00:00
										 |  |  |  |                 'upload_date': '20140328', | 
					
						
							| 
									
										
										
										
											2014-06-29 19:33:39 +07:00
										 |  |  |  |             }, | 
					
						
							|  |  |  |  |             'skip': 'Requires vk account credentials', | 
					
						
							|  |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-06-29 20:07:59 +07:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |             'url': 'http://m.vk.com/video-43215063_169084319?list=125c627d1aa1cebb83&from=wall-43215063_2566540', | 
					
						
							|  |  |  |  |             'md5': '0c45586baa71b7cb1d0784ee3f4e00a6', | 
					
						
							|  |  |  |  |             'note': 'ivi.ru embed', | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '60690', | 
					
						
							|  |  |  |  |                 'ext': 'mp4', | 
					
						
							|  |  |  |  |                 'title': 'Книга Илая', | 
					
						
							|  |  |  |  |                 'duration': 6771, | 
					
						
							| 
									
										
										
										
											2014-11-21 22:23:39 +00:00
										 |  |  |  |                 'upload_date': '20140626', | 
					
						
							| 
									
										
										
										
											2014-06-29 20:07:59 +07:00
										 |  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2014-06-30 03:16:31 +07:00
										 |  |  |  |             'skip': 'Only works from Russia', | 
					
						
							| 
									
										
										
										
											2014-06-29 20:07:59 +07:00
										 |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-11-23 10:11:04 +01:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |             # removed video, just testing that we match the pattern | 
					
						
							|  |  |  |  |             'url': 'http://vk.com/feed?z=video-43215063_166094326%2Fbb50cacd3177146d7a', | 
					
						
							|  |  |  |  |             'only_matching': True, | 
					
						
							|  |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |     ] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def _login(self): | 
					
						
							|  |  |  |  |         (username, password) = self._get_login_info() | 
					
						
							|  |  |  |  |         if username is None: | 
					
						
							|  |  |  |  |             return | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         login_form = { | 
					
						
							|  |  |  |  |             'act': 'login', | 
					
						
							|  |  |  |  |             'role': 'al_frame', | 
					
						
							|  |  |  |  |             'expire': '1', | 
					
						
							|  |  |  |  |             'email': username, | 
					
						
							|  |  |  |  |             'pass': password, | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         request = compat_urllib_request.Request('https://login.vk.com/?act=login', | 
					
						
							| 
									
										
										
										
											2014-11-23 21:39:15 +01:00
										 |  |  |  |                                                 compat_urllib_parse.urlencode(login_form).encode('utf-8')) | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  |         login_page = self._download_webpage(request, None, note='Logging in as %s' % username) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if re.search(r'onLoginFailed', login_page): | 
					
						
							|  |  |  |  |             raise ExtractorError('Unable to login, incorrect username and/or password', expected=True) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def _real_initialize(self): | 
					
						
							|  |  |  |  |         self._login() | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |  |         mobj = re.match(self._VALID_URL, url) | 
					
						
							| 
									
										
										
										
											2014-02-28 23:51:54 +07:00
										 |  |  |  |         video_id = mobj.group('videoid') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if not video_id: | 
					
						
							|  |  |  |  |             video_id = '%s_%s' % (mobj.group('oid'), mobj.group('id')) | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |         info_url = 'http://vk.com/al_video.php?act=show&al=1&video=%s' % video_id | 
					
						
							|  |  |  |  |         info_page = self._download_webpage(info_url, video_id) | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 21:35:25 +07:00
										 |  |  |  |         ERRORS = { | 
					
						
							|  |  |  |  |             r'>Видеозапись .*? была изъята из публичного доступа в связи с обращением правообладателя.<': | 
					
						
							| 
									
										
										
										
											2014-11-23 22:14:27 +01:00
										 |  |  |  |             'Video %s has been removed from public access due to rightholder complaint.', | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 21:35:25 +07:00
										 |  |  |  |             r'<!>Please log in or <': | 
					
						
							| 
									
										
										
										
											2014-11-23 22:14:27 +01:00
										 |  |  |  |             'Video %s is only available for registered users, ' | 
					
						
							|  |  |  |  |             'use --username and --password options to provide account credentials.', | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             r'<!>Unknown error': | 
					
						
							|  |  |  |  |             'Video %s does not exist.' | 
					
						
							| 
									
										
										
										
											2014-10-28 21:35:25 +07:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-02-17 02:05:15 +07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 21:35:25 +07:00
										 |  |  |  |         for error_re, error_msg in ERRORS.items(): | 
					
						
							|  |  |  |  |             if re.search(error_re, info_page): | 
					
						
							|  |  |  |  |                 raise ExtractorError(error_msg % video_id, expected=True) | 
					
						
							| 
									
										
										
										
											2014-10-28 21:06:07 +07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |         m_yt = re.search(r'src="(http://www.youtube.com/.*?)"', info_page) | 
					
						
							|  |  |  |  |         if m_yt is not None: | 
					
						
							| 
									
										
										
										
											2014-05-11 16:43:59 +07:00
										 |  |  |  |             self.to_screen('Youtube video detected') | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |             return self.url_result(m_yt.group(1), 'Youtube') | 
					
						
							| 
									
										
										
										
											2014-06-29 20:07:59 +07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         m_opts = re.search(r'(?s)var\s+opts\s*=\s*({.*?});', info_page) | 
					
						
							|  |  |  |  |         if m_opts: | 
					
						
							|  |  |  |  |             m_opts_url = re.search(r"url\s*:\s*'([^']+)", m_opts.group(1)) | 
					
						
							|  |  |  |  |             if m_opts_url: | 
					
						
							|  |  |  |  |                 opts_url = m_opts_url.group(1) | 
					
						
							|  |  |  |  |                 if opts_url.startswith('//'): | 
					
						
							|  |  |  |  |                     opts_url = 'http:' + opts_url | 
					
						
							|  |  |  |  |                 return self.url_result(opts_url) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-21 17:32:03 +01:00
										 |  |  |  |         data_json = self._search_regex(r'var vars = ({.*?});', info_page, 'vars') | 
					
						
							| 
									
										
										
										
											2014-01-21 17:29:04 +01:00
										 |  |  |  |         data = json.loads(data_json) | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 20:19:56 +00:00
										 |  |  |  |         # Extract upload date | 
					
						
							|  |  |  |  |         upload_date = None | 
					
						
							|  |  |  |  |         mobj = re.search(r'id="mv_date_wrap".*?Added ([a-zA-Z]+ [0-9]+), ([0-9]+) at', info_page) | 
					
						
							|  |  |  |  |         if mobj is not None: | 
					
						
							| 
									
										
										
										
											2014-11-23 21:39:15 +01:00
										 |  |  |  |             mobj.group(1) + ' ' + mobj.group(2) | 
					
						
							| 
									
										
										
										
											2014-11-18 20:19:56 +00:00
										 |  |  |  |             upload_date = unified_strdate(mobj.group(1) + ' ' + mobj.group(2)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-21 18:21:44 +01:00
										 |  |  |  |         formats = [{ | 
					
						
							|  |  |  |  |             'format_id': k, | 
					
						
							|  |  |  |  |             'url': v, | 
					
						
							|  |  |  |  |             'width': int(k[len('url'):]), | 
					
						
							|  |  |  |  |         } for k, v in data.items() | 
					
						
							|  |  |  |  |             if k.startswith('url')] | 
					
						
							|  |  |  |  |         self._sort_formats(formats) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |         return { | 
					
						
							| 
									
										
										
										
											2014-01-21 17:29:04 +01:00
										 |  |  |  |             'id': compat_str(data['vid']), | 
					
						
							| 
									
										
										
										
											2014-01-21 18:21:44 +01:00
										 |  |  |  |             'formats': formats, | 
					
						
							| 
									
										
										
										
											2014-01-21 17:29:04 +01:00
										 |  |  |  |             'title': unescapeHTML(data['md_title']), | 
					
						
							| 
									
										
										
										
											2014-01-21 18:21:44 +01:00
										 |  |  |  |             'thumbnail': data.get('jpg'), | 
					
						
							|  |  |  |  |             'uploader': data.get('md_author'), | 
					
						
							| 
									
										
										
										
											2014-11-18 20:19:56 +00:00
										 |  |  |  |             'duration': data.get('duration'), | 
					
						
							|  |  |  |  |             'upload_date': upload_date, | 
					
						
							| 
									
										
										
										
											2013-11-01 22:28:51 +01:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-11-17 17:52:00 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class VKUserVideosIE(InfoExtractor): | 
					
						
							|  |  |  |  |     IE_NAME = 'vk.com:user-videos' | 
					
						
							| 
									
										
										
										
											2014-11-21 22:54:11 +00:00
										 |  |  |  |     IE_DESC = 'vk.com:All of a user\'s videos' | 
					
						
							| 
									
										
										
										
											2014-11-21 23:03:31 +00:00
										 |  |  |  |     _VALID_URL = r'https?://vk\.com/videos(?P<id>[0-9]+)(?:m\?.*)?' | 
					
						
							| 
									
										
										
										
											2014-11-17 17:52:00 -05:00
										 |  |  |  |     _TEMPLATE_URL = 'https://vk.com/videos' | 
					
						
							|  |  |  |  |     _TEST = { | 
					
						
							|  |  |  |  |         'url': 'http://vk.com/videos205387401', | 
					
						
							|  |  |  |  |         'playlist_mincount': 4, | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def _real_extract(self, url): | 
					
						
							| 
									
										
										
										
											2014-11-21 23:21:03 +00:00
										 |  |  |  |         page_id = self._match_id(url) | 
					
						
							| 
									
										
										
										
											2014-11-17 17:52:00 -05:00
										 |  |  |  |         page = self._download_webpage(url, page_id) | 
					
						
							| 
									
										
										
										
											2014-11-23 10:11:52 +01:00
										 |  |  |  |         video_ids = orderedSet( | 
					
						
							|  |  |  |  |             m.group(1) for m in re.finditer(r'href="/video([0-9_]+)"', page)) | 
					
						
							|  |  |  |  |         url_entries = [ | 
					
						
							|  |  |  |  |             self.url_result( | 
					
						
							|  |  |  |  |                 'http://vk.com/video' + video_id, 'VK', video_id=video_id) | 
					
						
							|  |  |  |  |             for video_id in video_ids] | 
					
						
							| 
									
										
										
										
											2014-11-21 23:25:05 +00:00
										 |  |  |  |         return self.playlist_result(url_entries, page_id) |