| 
									
										
										
										
											2014-07-28 13:40:58 -05:00
										 |  |  | # encoding: utf-8 | 
					
						
							|  |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .common import InfoExtractor | 
					
						
							|  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |     js_to_json, | 
					
						
							| 
									
										
										
										
											2014-07-28 13:40:58 -05:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PatreonIE(InfoExtractor): | 
					
						
							| 
									
										
										
										
											2015-02-19 00:38:05 +01:00
										 |  |  |     _VALID_URL = r'https?://(?:www\.)?patreon\.com/creation\?hid=(?P<id>[^&#]+)' | 
					
						
							| 
									
										
										
										
											2014-07-28 13:40:58 -05:00
										 |  |  |     _TESTS = [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             'url': 'http://www.patreon.com/creation?hid=743933', | 
					
						
							|  |  |  |             'md5': 'e25505eec1053a6e6813b8ed369875cc', | 
					
						
							|  |  |  |             'info_dict': { | 
					
						
							|  |  |  |                 'id': '743933', | 
					
						
							|  |  |  |                 'ext': 'mp3', | 
					
						
							|  |  |  |                 'title': 'Episode 166: David Smalley of Dogma Debate', | 
					
						
							|  |  |  |                 'uploader': 'Cognitive Dissonance Podcast', | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |                 'thumbnail': 're:^https?://.*$', | 
					
						
							| 
									
										
										
										
											2014-07-28 13:40:58 -05:00
										 |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2014-08-05 00:26:23 -05:00
										 |  |  |         { | 
					
						
							|  |  |  |             'url': 'http://www.patreon.com/creation?hid=754133', | 
					
						
							|  |  |  |             'md5': '3eb09345bf44bf60451b8b0b81759d0a', | 
					
						
							|  |  |  |             'info_dict': { | 
					
						
							|  |  |  |                 'id': '754133', | 
					
						
							|  |  |  |                 'ext': 'mp3', | 
					
						
							|  |  |  |                 'title': 'CD 167 Extra', | 
					
						
							|  |  |  |                 'uploader': 'Cognitive Dissonance Podcast', | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |                 'thumbnail': 're:^https?://.*$', | 
					
						
							| 
									
										
										
										
											2014-08-05 00:26:23 -05:00
										 |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2015-02-19 01:04:19 +01:00
										 |  |  |         { | 
					
						
							|  |  |  |             'url': 'https://www.patreon.com/creation?hid=1682498', | 
					
						
							|  |  |  |             'info_dict': { | 
					
						
							|  |  |  |                 'id': 'SU4fj_aEMVw', | 
					
						
							|  |  |  |                 'ext': 'mp4', | 
					
						
							|  |  |  |                 'title': 'I\'m on Patreon!', | 
					
						
							|  |  |  |                 'uploader': 'TraciJHines', | 
					
						
							|  |  |  |                 'thumbnail': 're:^https?://.*$', | 
					
						
							|  |  |  |                 'upload_date': '20150211', | 
					
						
							|  |  |  |                 'description': 'md5:c5a706b1f687817a3de09db1eb93acd4', | 
					
						
							|  |  |  |                 'uploader_id': 'TraciJHines', | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             'params': { | 
					
						
							|  |  |  |                 'noplaylist': True, | 
					
						
							|  |  |  |                 'skip_download': True, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-07-28 13:40:58 -05:00
										 |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Currently Patreon exposes download URL via hidden CSS, so login is not | 
					
						
							|  |  |  |     # needed. Keeping this commented for when this inevitably changes. | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     def _login(self): | 
					
						
							|  |  |  |         (username, password) = self._get_login_info() | 
					
						
							|  |  |  |         if username is None: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         login_form = { | 
					
						
							|  |  |  |             'redirectUrl': 'http://www.patreon.com/', | 
					
						
							|  |  |  |             'email': username, | 
					
						
							|  |  |  |             'password': password, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         request = compat_urllib_request.Request( | 
					
						
							|  |  |  |             'https://www.patreon.com/processLogin', | 
					
						
							|  |  |  |             compat_urllib_parse.urlencode(login_form).encode('utf-8') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         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() | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							| 
									
										
										
										
											2015-02-19 00:38:05 +01:00
										 |  |  |         video_id = self._match_id(url) | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |         webpage = self._download_webpage(url, video_id) | 
					
						
							|  |  |  |         title = self._og_search_title(webpage).strip() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         attach_fn = self._html_search_regex( | 
					
						
							|  |  |  |             r'<div class="attach"><a target="_blank" href="([^"]+)">', | 
					
						
							|  |  |  |             webpage, 'attachment URL', default=None) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:04:19 +01:00
										 |  |  |         embed = self._html_search_regex( | 
					
						
							| 
									
										
										
										
											2015-06-01 00:04:36 +06:00
										 |  |  |             r'<div[^>]+id="watchCreation"[^>]*>\s*<iframe[^>]+src="([^"]+)"', | 
					
						
							| 
									
										
										
										
											2015-02-19 01:04:19 +01:00
										 |  |  |             webpage, 'embedded URL', default=None) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |         if attach_fn is not None: | 
					
						
							|  |  |  |             video_url = 'http://www.patreon.com' + attach_fn | 
					
						
							|  |  |  |             thumbnail = self._og_search_thumbnail(webpage) | 
					
						
							|  |  |  |             uploader = self._html_search_regex( | 
					
						
							|  |  |  |                 r'<strong>(.*?)</strong> is creating', webpage, 'uploader') | 
					
						
							| 
									
										
										
										
											2015-02-19 01:04:19 +01:00
										 |  |  |         elif embed is not None: | 
					
						
							|  |  |  |             return self.url_result(embed) | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2015-02-19 00:38:05 +01:00
										 |  |  |             playlist = self._parse_json(self._search_regex( | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |                 r'(?s)new\s+jPlayerPlaylist\(\s*\{\s*[^}]*},\s*(\[.*?,?\s*\])', | 
					
						
							| 
									
										
										
										
											2015-02-19 00:38:05 +01:00
										 |  |  |                 webpage, 'playlist JSON'), | 
					
						
							|  |  |  |                 video_id, transform_source=js_to_json) | 
					
						
							| 
									
										
										
										
											2014-08-22 02:33:29 +02:00
										 |  |  |             data = playlist[0] | 
					
						
							|  |  |  |             video_url = self._proto_relative_url(data['mp3']) | 
					
						
							|  |  |  |             thumbnail = self._proto_relative_url(data.get('cover')) | 
					
						
							|  |  |  |             uploader = data.get('artist') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             'id': video_id, | 
					
						
							|  |  |  |             'url': video_url, | 
					
						
							|  |  |  |             'ext': 'mp3', | 
					
						
							|  |  |  |             'title': title, | 
					
						
							|  |  |  |             'uploader': uploader, | 
					
						
							|  |  |  |             'thumbnail': thumbnail, | 
					
						
							|  |  |  |         } |