| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 23:32:22 +06:00
										 |  |  | import itertools | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  | from .common import InfoExtractor | 
					
						
							|  |  |  | from ..compat import compat_HTTPError | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |     ExtractorError, | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |     int_or_none, | 
					
						
							|  |  |  |     float_or_none, | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |     parse_iso8601, | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VidmeIE(InfoExtractor): | 
					
						
							| 
									
										
										
										
											2016-02-05 23:58:26 +06:00
										 |  |  |     IE_NAME = 'vidme' | 
					
						
							| 
									
										
										
										
											2016-02-05 23:32:22 +06:00
										 |  |  |     _VALID_URL = r'https?://vid\.me/(?:e/)?(?P<id>[\da-zA-Z]{,5})(?:[^\da-zA-Z]|$)' | 
					
						
							| 
									
										
										
										
											2015-06-03 10:21:03 +08:00
										 |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |         'url': 'https://vid.me/QNB', | 
					
						
							| 
									
										
										
										
											2015-10-20 20:18:23 +06:00
										 |  |  |         'md5': 'f42d05e7149aeaec5c037b17e5d3dc82', | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'QNB', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'Fishing for piranha - the easy way', | 
					
						
							|  |  |  |             'description': 'source: https://www.facebook.com/photo.php?v=312276045600871', | 
					
						
							| 
									
										
										
										
											2017-01-02 20:08:07 +08:00
										 |  |  |             'thumbnail': r're:^https?://.*\.jpg', | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |             'timestamp': 1406313244, | 
					
						
							|  |  |  |             'upload_date': '20140725', | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |             'age_limit': 0, | 
					
						
							|  |  |  |             'duration': 119.92, | 
					
						
							| 
									
										
										
										
											2015-08-01 04:03:52 +06:00
										 |  |  |             'view_count': int, | 
					
						
							|  |  |  |             'like_count': int, | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |             'comment_count': int, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }, { | 
					
						
							|  |  |  |         'url': 'https://vid.me/Gc6M', | 
					
						
							|  |  |  |         'md5': 'f42d05e7149aeaec5c037b17e5d3dc82', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'Gc6M', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'O Mere Dil ke chain - Arnav and Khushi VM', | 
					
						
							| 
									
										
										
										
											2017-01-02 20:08:07 +08:00
										 |  |  |             'thumbnail': r're:^https?://.*\.jpg', | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |             'timestamp': 1441211642, | 
					
						
							|  |  |  |             'upload_date': '20150902', | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |             'uploader': 'SunshineM', | 
					
						
							|  |  |  |             'uploader_id': '3552827', | 
					
						
							|  |  |  |             'age_limit': 0, | 
					
						
							|  |  |  |             'duration': 223.72, | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |             'view_count': int, | 
					
						
							|  |  |  |             'like_count': int, | 
					
						
							|  |  |  |             'comment_count': int, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         'params': { | 
					
						
							|  |  |  |             'skip_download': True, | 
					
						
							| 
									
										
										
										
											2015-08-01 04:03:52 +06:00
										 |  |  |         }, | 
					
						
							|  |  |  |     }, { | 
					
						
							|  |  |  |         # tests uploader field | 
					
						
							|  |  |  |         'url': 'https://vid.me/4Iib', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': '4Iib', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'The Carver', | 
					
						
							|  |  |  |             'description': 'md5:e9c24870018ae8113be936645b93ba3c', | 
					
						
							| 
									
										
										
										
											2017-01-02 20:08:07 +08:00
										 |  |  |             'thumbnail': r're:^https?://.*\.jpg', | 
					
						
							| 
									
										
										
										
											2015-08-01 04:03:52 +06:00
										 |  |  |             'timestamp': 1433203629, | 
					
						
							|  |  |  |             'upload_date': '20150602', | 
					
						
							|  |  |  |             'uploader': 'Thomas', | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |             'uploader_id': '109747', | 
					
						
							|  |  |  |             'age_limit': 0, | 
					
						
							|  |  |  |             'duration': 97.859999999999999, | 
					
						
							| 
									
										
										
										
											2015-08-01 04:03:52 +06:00
										 |  |  |             'view_count': int, | 
					
						
							|  |  |  |             'like_count': int, | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |             'comment_count': int, | 
					
						
							| 
									
										
										
										
											2015-08-01 04:03:52 +06:00
										 |  |  |         }, | 
					
						
							|  |  |  |         'params': { | 
					
						
							|  |  |  |             'skip_download': True, | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2015-06-03 10:21:03 +08:00
										 |  |  |     }, { | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         # nsfw test from http://naked-yogi.tumblr.com/post/118312946248/naked-smoking-stretching | 
					
						
							| 
									
										
										
										
											2015-06-03 10:21:03 +08:00
										 |  |  |         'url': 'https://vid.me/e/Wmur', | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'Wmur', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'naked smoking & stretching', | 
					
						
							| 
									
										
										
										
											2017-01-02 20:08:07 +08:00
										 |  |  |             'thumbnail': r're:^https?://.*\.jpg', | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |             'timestamp': 1430931613, | 
					
						
							|  |  |  |             'upload_date': '20150506', | 
					
						
							|  |  |  |             'uploader': 'naked-yogi', | 
					
						
							|  |  |  |             'uploader_id': '1638622', | 
					
						
							|  |  |  |             'age_limit': 18, | 
					
						
							|  |  |  |             'duration': 653.26999999999998, | 
					
						
							|  |  |  |             'view_count': int, | 
					
						
							|  |  |  |             'like_count': int, | 
					
						
							|  |  |  |             'comment_count': int, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         'params': { | 
					
						
							|  |  |  |             'skip_download': True, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2015-10-17 23:01:24 +06:00
										 |  |  |     }, { | 
					
						
							|  |  |  |         # nsfw, user-disabled | 
					
						
							|  |  |  |         'url': 'https://vid.me/dzGJ', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							| 
									
										
										
										
											2015-10-19 20:53:27 +02:00
										 |  |  |     }, { | 
					
						
							|  |  |  |         # suspended | 
					
						
							|  |  |  |         'url': 'https://vid.me/Ox3G', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							| 
									
										
										
										
											2015-10-26 14:42:17 +01:00
										 |  |  |     }, { | 
					
						
							|  |  |  |         # deleted | 
					
						
							|  |  |  |         'url': 'https://vid.me/KTPm', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							| 
									
										
										
										
											2015-10-19 20:53:27 +02:00
										 |  |  |     }, { | 
					
						
							|  |  |  |         # no formats in the API response | 
					
						
							|  |  |  |         'url': 'https://vid.me/e5g', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'e5g', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							| 
									
										
										
										
											2015-10-20 20:17:54 +06:00
										 |  |  |             'title': 'Video upload (e5g)', | 
					
						
							| 
									
										
										
										
											2017-01-02 20:08:07 +08:00
										 |  |  |             'thumbnail': r're:^https?://.*\.jpg', | 
					
						
							| 
									
										
										
										
											2015-10-19 20:53:27 +02:00
										 |  |  |             'timestamp': 1401480195, | 
					
						
							|  |  |  |             'upload_date': '20140530', | 
					
						
							|  |  |  |             'uploader': None, | 
					
						
							|  |  |  |             'uploader_id': None, | 
					
						
							|  |  |  |             'age_limit': 0, | 
					
						
							|  |  |  |             'duration': 483, | 
					
						
							|  |  |  |             'view_count': int, | 
					
						
							|  |  |  |             'like_count': int, | 
					
						
							|  |  |  |             'comment_count': int, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         'params': { | 
					
						
							|  |  |  |             'skip_download': True, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2015-06-03 10:21:03 +08:00
										 |  |  |     }] | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							| 
									
										
										
										
											2015-03-05 22:34:56 +01:00
										 |  |  |         video_id = self._match_id(url) | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         try: | 
					
						
							|  |  |  |             response = self._download_json( | 
					
						
							|  |  |  |                 'https://api.vid.me/videoByUrl/%s' % video_id, video_id) | 
					
						
							|  |  |  |         except ExtractorError as e: | 
					
						
							|  |  |  |             if isinstance(e.cause, compat_HTTPError) and e.cause.code == 400: | 
					
						
							|  |  |  |                 response = self._parse_json(e.cause.read(), video_id) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         error = response.get('error') | 
					
						
							|  |  |  |         if error: | 
					
						
							|  |  |  |             raise ExtractorError( | 
					
						
							|  |  |  |                 '%s returned error: %s' % (self.IE_NAME, error), expected=True) | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         video = response['video'] | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 14:42:17 +01:00
										 |  |  |         if video.get('state') == 'deleted': | 
					
						
							|  |  |  |             raise ExtractorError( | 
					
						
							|  |  |  |                 'Vidme said: Sorry, this video has been deleted.', | 
					
						
							|  |  |  |                 expected=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-19 20:53:27 +02:00
										 |  |  |         if video.get('state') in ('user-disabled', 'suspended'): | 
					
						
							| 
									
										
										
										
											2015-10-17 18:52:25 +02:00
										 |  |  |             raise ExtractorError( | 
					
						
							|  |  |  |                 'Vidme said: This video has been suspended either due to a copyright claim, ' | 
					
						
							|  |  |  |                 'or for violating the terms of use.', | 
					
						
							|  |  |  |                 expected=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |         formats = [{ | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |             'format_id': f.get('type'), | 
					
						
							|  |  |  |             'url': f['uri'], | 
					
						
							|  |  |  |             'width': int_or_none(f.get('width')), | 
					
						
							|  |  |  |             'height': int_or_none(f.get('height')), | 
					
						
							| 
									
										
										
										
											2015-09-24 23:38:53 +06:00
										 |  |  |             'preference': 0 if f.get('type', '').endswith('clip') else 1, | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         } for f in video.get('formats', []) if f.get('uri')] | 
					
						
							| 
									
										
										
										
											2015-10-19 20:53:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if not formats and video.get('complete_url'): | 
					
						
							|  |  |  |             formats.append({ | 
					
						
							|  |  |  |                 'url': video.get('complete_url'), | 
					
						
							|  |  |  |                 'width': int_or_none(video.get('width')), | 
					
						
							|  |  |  |                 'height': int_or_none(video.get('height')), | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |         self._sort_formats(formats) | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |         title = video['title'] | 
					
						
							|  |  |  |         description = video.get('description') | 
					
						
							|  |  |  |         thumbnail = video.get('thumbnail_url') | 
					
						
							|  |  |  |         timestamp = parse_iso8601(video.get('date_created'), ' ') | 
					
						
							|  |  |  |         uploader = video.get('user', {}).get('username') | 
					
						
							|  |  |  |         uploader_id = video.get('user', {}).get('user_id') | 
					
						
							|  |  |  |         age_limit = 18 if video.get('nsfw') is True else 0 | 
					
						
							|  |  |  |         duration = float_or_none(video.get('duration')) | 
					
						
							|  |  |  |         view_count = int_or_none(video.get('view_count')) | 
					
						
							|  |  |  |         like_count = int_or_none(video.get('likes_count')) | 
					
						
							|  |  |  |         comment_count = int_or_none(video.get('comment_count')) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |         return { | 
					
						
							|  |  |  |             'id': video_id, | 
					
						
							| 
									
										
										
										
											2015-10-20 20:17:54 +06:00
										 |  |  |             'title': title or 'Video upload (%s)' % video_id, | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |             'description': description, | 
					
						
							|  |  |  |             'thumbnail': thumbnail, | 
					
						
							| 
									
										
										
										
											2015-09-09 22:04:05 +06:00
										 |  |  |             'uploader': uploader, | 
					
						
							|  |  |  |             'uploader_id': uploader_id, | 
					
						
							|  |  |  |             'age_limit': age_limit, | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |             'timestamp': timestamp, | 
					
						
							|  |  |  |             'duration': duration, | 
					
						
							|  |  |  |             'view_count': view_count, | 
					
						
							|  |  |  |             'like_count': like_count, | 
					
						
							| 
									
										
										
										
											2015-09-09 17:02:28 +02:00
										 |  |  |             'comment_count': comment_count, | 
					
						
							|  |  |  |             'formats': formats, | 
					
						
							| 
									
										
										
										
											2014-07-31 20:26:52 +07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-02-05 23:32:22 +06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 23:57:35 +06:00
										 |  |  | class VidmeListBaseIE(InfoExtractor): | 
					
						
							| 
									
										
										
										
											2016-02-05 23:32:22 +06:00
										 |  |  |     # Max possible limit according to https://docs.vid.me/#api-Videos-List | 
					
						
							|  |  |  |     _LIMIT = 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _entries(self, user_id, user_name): | 
					
						
							|  |  |  |         for page_num in itertools.count(1): | 
					
						
							|  |  |  |             page = self._download_json( | 
					
						
							| 
									
										
										
										
											2016-02-05 23:57:35 +06:00
										 |  |  |                 'https://api.vid.me/videos/%s?user=%s&limit=%d&offset=%d' | 
					
						
							|  |  |  |                 % (self._API_ITEM, user_id, self._LIMIT, (page_num - 1) * self._LIMIT), | 
					
						
							|  |  |  |                 user_name, 'Downloading user %s page %d' % (self._API_ITEM, page_num)) | 
					
						
							| 
									
										
										
										
											2016-02-05 23:32:22 +06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             videos = page.get('videos', []) | 
					
						
							|  |  |  |             if not videos: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for video in videos: | 
					
						
							|  |  |  |                 video_url = video.get('full_url') or video.get('embed_url') | 
					
						
							|  |  |  |                 if video_url: | 
					
						
							|  |  |  |                     yield self.url_result(video_url, VidmeIE.ie_key()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             total = int_or_none(page.get('page', {}).get('total')) | 
					
						
							|  |  |  |             if total and self._LIMIT * page_num >= total: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         user_name = self._match_id(url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         user_id = self._download_json( | 
					
						
							|  |  |  |             'https://api.vid.me/userByUsername?username=%s' % user_name, | 
					
						
							|  |  |  |             user_name)['user']['user_id'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 23:57:35 +06:00
										 |  |  |         return self.playlist_result( | 
					
						
							|  |  |  |             self._entries(user_id, user_name), user_id, | 
					
						
							|  |  |  |             '%s - %s' % (user_name, self._TITLE)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VidmeUserIE(VidmeListBaseIE): | 
					
						
							| 
									
										
										
										
											2016-02-05 23:58:26 +06:00
										 |  |  |     IE_NAME = 'vidme:user' | 
					
						
							| 
									
										
										
										
											2016-02-05 23:57:35 +06:00
										 |  |  |     _VALID_URL = r'https?://vid\.me/(?:e/)?(?P<id>[\da-zA-Z]{6,})(?!/likes)(?:[^\da-zA-Z]|$)' | 
					
						
							|  |  |  |     _API_ITEM = 'list' | 
					
						
							|  |  |  |     _TITLE = 'Videos' | 
					
						
							|  |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://vid.me/EFARCHIVE', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': '3834632', | 
					
						
							|  |  |  |             'title': 'EFARCHIVE - %s' % _TITLE, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         'playlist_mincount': 238, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VidmeUserLikesIE(VidmeListBaseIE): | 
					
						
							| 
									
										
										
										
											2016-02-05 23:58:26 +06:00
										 |  |  |     IE_NAME = 'vidme:user:likes' | 
					
						
							| 
									
										
										
										
											2016-02-05 23:57:35 +06:00
										 |  |  |     _VALID_URL = r'https?://vid\.me/(?:e/)?(?P<id>[\da-zA-Z]{6,})/likes' | 
					
						
							|  |  |  |     _API_ITEM = 'likes' | 
					
						
							|  |  |  |     _TITLE = 'Likes' | 
					
						
							|  |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://vid.me/ErinAlexis/likes', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': '6483530', | 
					
						
							|  |  |  |             'title': 'ErinAlexis - %s' % _TITLE, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         'playlist_mincount': 415, | 
					
						
							|  |  |  |     } |