| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  | # coding: utf-8 | 
					
						
							|  |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .common import InfoExtractor | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  | from ..compat import compat_HTTPError | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  | from ..utils import ( | 
					
						
							|  |  |  |     float_or_none, | 
					
						
							|  |  |  |     int_or_none, | 
					
						
							|  |  |  |     try_get, | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |     # unified_timestamp, | 
					
						
							|  |  |  |     ExtractorError, | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RedBullTVIE(InfoExtractor): | 
					
						
							|  |  |  |     _VALID_URL = r'https?://(?:www\.)?redbull\.tv/(?:video|film)/(?P<id>AP-\w+)' | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         # film | 
					
						
							|  |  |  |         'url': 'https://www.redbull.tv/video/AP-1Q756YYX51W11/abc-of-wrc', | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |         'md5': 'fb0445b98aa4394e504b413d98031d1f', | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'AP-1Q756YYX51W11', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'ABC of...WRC', | 
					
						
							|  |  |  |             'description': 'md5:5c7ed8f4015c8492ecf64b6ab31e7d31', | 
					
						
							|  |  |  |             'duration': 1582.04, | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |             # 'timestamp': 1488405786, | 
					
						
							|  |  |  |             # 'upload_date': '20170301', | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |         }, | 
					
						
							|  |  |  |     }, { | 
					
						
							|  |  |  |         # episode | 
					
						
							|  |  |  |         'url': 'https://www.redbull.tv/video/AP-1PMT5JCWH1W11/grime?playlist=shows:shows-playall:web', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'AP-1PMT5JCWH1W11', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'Grime - Hashtags S2 E4', | 
					
						
							|  |  |  |             'description': 'md5:334b741c8c1ce65be057eab6773c1cf5', | 
					
						
							|  |  |  |             'duration': 904.6, | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |             # 'timestamp': 1487290093, | 
					
						
							|  |  |  |             # 'upload_date': '20170217', | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |             'series': 'Hashtags', | 
					
						
							|  |  |  |             'season_number': 2, | 
					
						
							|  |  |  |             'episode_number': 4, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }, { | 
					
						
							|  |  |  |         'url': 'https://www.redbull.tv/film/AP-1MSKKF5T92111/in-motion', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         video_id = self._match_id(url) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |         session = self._download_json( | 
					
						
							|  |  |  |             'https://api-v2.redbull.tv/session', video_id, | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |             note='Downloading access token', query={ | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |                 'build': '4.370.0', | 
					
						
							|  |  |  |                 'category': 'personal_computer', | 
					
						
							|  |  |  |                 'os_version': '1.0', | 
					
						
							|  |  |  |                 'os_family': 'http', | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         if session.get('code') == 'error': | 
					
						
							|  |  |  |             raise ExtractorError('%s said: %s' % ( | 
					
						
							|  |  |  |                 self.IE_NAME, session['message'])) | 
					
						
							|  |  |  |         auth = '%s %s' % (session.get('token_type', 'Bearer'), session['access_token']) | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             info = self._download_json( | 
					
						
							|  |  |  |                 'https://api-v2.redbull.tv/content/%s' % video_id, | 
					
						
							|  |  |  |                 video_id, note='Downloading video information', | 
					
						
							|  |  |  |                 headers={'Authorization': auth} | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         except ExtractorError as e: | 
					
						
							|  |  |  |             if isinstance(e.cause, compat_HTTPError) and e.cause.code == 404: | 
					
						
							|  |  |  |                 error_message = self._parse_json( | 
					
						
							|  |  |  |                     e.cause.read().decode(), video_id)['message'] | 
					
						
							|  |  |  |                 raise ExtractorError('%s said: %s' % ( | 
					
						
							|  |  |  |                     self.IE_NAME, error_message), expected=True) | 
					
						
							|  |  |  |             raise | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         video = info['video_product'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         title = info['title'].strip() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         formats = self._extract_m3u8_formats( | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |             video['url'], video_id, 'mp4', 'm3u8_native') | 
					
						
							|  |  |  |         self._sort_formats(formats) | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         subtitles = {} | 
					
						
							|  |  |  |         for _, captions in (try_get( | 
					
						
							|  |  |  |                 video, lambda x: x['attachments']['captions'], | 
					
						
							|  |  |  |                 dict) or {}).items(): | 
					
						
							|  |  |  |             if not captions or not isinstance(captions, list): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             for caption in captions: | 
					
						
							|  |  |  |                 caption_url = caption.get('url') | 
					
						
							|  |  |  |                 if not caption_url: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |                 ext = caption.get('format') | 
					
						
							|  |  |  |                 if ext == 'xml': | 
					
						
							|  |  |  |                     ext = 'ttml' | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |                 subtitles.setdefault(caption.get('lang') or 'en', []).append({ | 
					
						
							|  |  |  |                     'url': caption_url, | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |                     'ext': ext, | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |                 }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         subheading = info.get('subheading') | 
					
						
							|  |  |  |         if subheading: | 
					
						
							|  |  |  |             title += ' - %s' % subheading | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             'id': video_id, | 
					
						
							|  |  |  |             'title': title, | 
					
						
							|  |  |  |             'description': info.get('long_description') or info.get( | 
					
						
							|  |  |  |                 'short_description'), | 
					
						
							|  |  |  |             'duration': float_or_none(video.get('duration'), scale=1000), | 
					
						
							| 
									
										
										
										
											2017-03-15 01:40:54 +01:00
										 |  |  |             # 'timestamp': unified_timestamp(info.get('published')), | 
					
						
							| 
									
										
										
										
											2017-03-04 23:25:09 +07:00
										 |  |  |             'series': info.get('show_title'), | 
					
						
							|  |  |  |             'season_number': int_or_none(info.get('season_number')), | 
					
						
							|  |  |  |             'episode_number': int_or_none(info.get('episode_number')), | 
					
						
							|  |  |  |             'formats': formats, | 
					
						
							|  |  |  |             'subtitles': subtitles, | 
					
						
							|  |  |  |         } |