| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  | import re | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  | from .common import InfoExtractor | 
					
						
							|  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2017-12-16 12:55:20 +01:00
										 |  |  |     determine_ext, | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  |     extract_attributes, | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  |     ExtractorError, | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  |     int_or_none, | 
					
						
							|  |  |  |     parse_age_limit, | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  |     remove_end, | 
					
						
							|  |  |  |     unescapeHTML, | 
					
						
							| 
									
										
										
										
											2018-07-21 19:08:28 +07:00
										 |  |  |     url_or_none, | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  | class DiscoveryGoBaseIE(InfoExtractor): | 
					
						
							|  |  |  |     _VALID_URL_TEMPLATE = r'''(?x)https?://(?:www\.)?(?:
 | 
					
						
							| 
									
										
										
										
											2016-08-17 11:03:09 +01:00
										 |  |  |             discovery| | 
					
						
							|  |  |  |             investigationdiscovery| | 
					
						
							|  |  |  |             discoverylife| | 
					
						
							|  |  |  |             animalplanet| | 
					
						
							|  |  |  |             ahctv| | 
					
						
							|  |  |  |             destinationamerica| | 
					
						
							|  |  |  |             sciencechannel| | 
					
						
							|  |  |  |             tlc| | 
					
						
							|  |  |  |             velocitychannel | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  |         )go\.com/%s(?P<id>[^/?#&]+)''' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-12 10:33:03 +01:00
										 |  |  |     def _extract_video_info(self, video, stream, display_id): | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  |         title = video['name'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-25 09:11:23 +01:00
										 |  |  |         if not stream: | 
					
						
							| 
									
										
										
										
											2016-08-25 09:55:23 +01:00
										 |  |  |             if video.get('authenticated') is True: | 
					
						
							|  |  |  |                 raise ExtractorError( | 
					
						
							|  |  |  |                     'This video is only available via cable service provider subscription that' | 
					
						
							|  |  |  |                     ' is not currently supported. You may want to use --cookies.', expected=True) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise ExtractorError('Unable to find stream') | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  |         STREAM_URL_SUFFIX = 'streamUrl' | 
					
						
							|  |  |  |         formats = [] | 
					
						
							|  |  |  |         for stream_kind in ('', 'hds'): | 
					
						
							|  |  |  |             suffix = STREAM_URL_SUFFIX.capitalize() if stream_kind else STREAM_URL_SUFFIX | 
					
						
							|  |  |  |             stream_url = stream.get('%s%s' % (stream_kind, suffix)) | 
					
						
							|  |  |  |             if not stream_url: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if stream_kind == '': | 
					
						
							|  |  |  |                 formats.extend(self._extract_m3u8_formats( | 
					
						
							|  |  |  |                     stream_url, display_id, 'mp4', entry_protocol='m3u8_native', | 
					
						
							|  |  |  |                     m3u8_id='hls', fatal=False)) | 
					
						
							|  |  |  |             elif stream_kind == 'hds': | 
					
						
							|  |  |  |                 formats.extend(self._extract_f4m_formats( | 
					
						
							|  |  |  |                     stream_url, display_id, f4m_id=stream_kind, fatal=False)) | 
					
						
							|  |  |  |         self._sort_formats(formats) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         video_id = video.get('id') or display_id | 
					
						
							|  |  |  |         description = video.get('description', {}).get('detailed') | 
					
						
							|  |  |  |         duration = int_or_none(video.get('duration')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         series = video.get('show', {}).get('name') | 
					
						
							|  |  |  |         season_number = int_or_none(video.get('season', {}).get('number')) | 
					
						
							|  |  |  |         episode_number = int_or_none(video.get('episodeNumber')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         tags = video.get('tags') | 
					
						
							|  |  |  |         age_limit = parse_age_limit(video.get('parental', {}).get('rating')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         subtitles = {} | 
					
						
							|  |  |  |         captions = stream.get('captions') | 
					
						
							|  |  |  |         if isinstance(captions, list): | 
					
						
							|  |  |  |             for caption in captions: | 
					
						
							| 
									
										
										
										
											2018-07-21 19:08:28 +07:00
										 |  |  |                 subtitle_url = url_or_none(caption.get('fileUrl')) | 
					
						
							|  |  |  |                 if not subtitle_url or not subtitle_url.startswith('http'): | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  |                     continue | 
					
						
							|  |  |  |                 lang = caption.get('fileLang', 'en') | 
					
						
							| 
									
										
										
										
											2017-12-16 12:55:20 +01:00
										 |  |  |                 ext = determine_ext(subtitle_url) | 
					
						
							|  |  |  |                 subtitles.setdefault(lang, []).append({ | 
					
						
							|  |  |  |                     'url': subtitle_url, | 
					
						
							|  |  |  |                     'ext': 'ttml' if ext == 'xml' else ext, | 
					
						
							|  |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2016-08-07 20:57:05 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             'id': video_id, | 
					
						
							|  |  |  |             'display_id': display_id, | 
					
						
							|  |  |  |             'title': title, | 
					
						
							|  |  |  |             'description': description, | 
					
						
							|  |  |  |             'duration': duration, | 
					
						
							|  |  |  |             'series': series, | 
					
						
							|  |  |  |             'season_number': season_number, | 
					
						
							|  |  |  |             'episode_number': episode_number, | 
					
						
							|  |  |  |             'tags': tags, | 
					
						
							|  |  |  |             'age_limit': age_limit, | 
					
						
							|  |  |  |             'formats': formats, | 
					
						
							|  |  |  |             'subtitles': subtitles, | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-12 10:33:03 +01:00
										 |  |  | class DiscoveryGoIE(DiscoveryGoBaseIE): | 
					
						
							|  |  |  |     _VALID_URL = DiscoveryGoBaseIE._VALID_URL_TEMPLATE % r'(?:[^/]+/)+' | 
					
						
							|  |  |  |     _GEO_COUNTRIES = ['US'] | 
					
						
							|  |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://www.discoverygo.com/bering-sea-gold/reaper-madness/', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': '58c167d86b66d12f2addeb01', | 
					
						
							|  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |             'title': 'Reaper Madness', | 
					
						
							|  |  |  |             'description': 'md5:09f2c625c99afb8946ed4fb7865f6e78', | 
					
						
							|  |  |  |             'duration': 2519, | 
					
						
							|  |  |  |             'series': 'Bering Sea Gold', | 
					
						
							|  |  |  |             'season_number': 8, | 
					
						
							|  |  |  |             'episode_number': 6, | 
					
						
							|  |  |  |             'age_limit': 14, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         display_id = self._match_id(url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         webpage = self._download_webpage(url, display_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         container = extract_attributes( | 
					
						
							|  |  |  |             self._search_regex( | 
					
						
							|  |  |  |                 r'(<div[^>]+class=["\']video-player-container[^>]+>)', | 
					
						
							|  |  |  |                 webpage, 'video container')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         video = self._parse_json( | 
					
						
							|  |  |  |             container.get('data-video') or container.get('data-json'), | 
					
						
							|  |  |  |             display_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stream = video.get('stream') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._extract_video_info(video, stream, display_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 23:16:51 +07:00
										 |  |  | class DiscoveryGoPlaylistIE(DiscoveryGoBaseIE): | 
					
						
							|  |  |  |     _VALID_URL = DiscoveryGoBaseIE._VALID_URL_TEMPLATE % '' | 
					
						
							|  |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://www.discoverygo.com/bering-sea-gold/', | 
					
						
							|  |  |  |         'info_dict': { | 
					
						
							|  |  |  |             'id': 'bering-sea-gold', | 
					
						
							|  |  |  |             'title': 'Bering Sea Gold', | 
					
						
							|  |  |  |             'description': 'md5:cc5c6489835949043c0cc3ad66c2fa0e', | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         'playlist_mincount': 6, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def suitable(cls, url): | 
					
						
							|  |  |  |         return False if DiscoveryGoIE.suitable(url) else super( | 
					
						
							|  |  |  |             DiscoveryGoPlaylistIE, cls).suitable(url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         display_id = self._match_id(url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         webpage = self._download_webpage(url, display_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         entries = [] | 
					
						
							|  |  |  |         for mobj in re.finditer(r'data-json=(["\'])(?P<json>{.+?})\1', webpage): | 
					
						
							|  |  |  |             data = self._parse_json( | 
					
						
							|  |  |  |                 mobj.group('json'), display_id, | 
					
						
							|  |  |  |                 transform_source=unescapeHTML, fatal=False) | 
					
						
							|  |  |  |             if not isinstance(data, dict) or data.get('type') != 'episode': | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             episode_url = data.get('socialUrl') | 
					
						
							|  |  |  |             if not episode_url: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             entries.append(self.url_result( | 
					
						
							|  |  |  |                 episode_url, ie=DiscoveryGoIE.ie_key(), | 
					
						
							|  |  |  |                 video_id=data.get('id'))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self.playlist_result( | 
					
						
							|  |  |  |             entries, display_id, | 
					
						
							|  |  |  |             remove_end(self._og_search_title( | 
					
						
							|  |  |  |                 webpage, fatal=False), ' | Discovery GO'), | 
					
						
							|  |  |  |             self._og_search_description(webpage)) |