mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-30 22:25:19 +00:00 
			
		
		
		
	[generic] Try parsing JWPlayer embedded videos (closes #12030)
This commit is contained in:
		| @@ -1,3 +1,9 @@ | |||||||
|  | version <unreleased> | ||||||
|  |  | ||||||
|  | Extractors | ||||||
|  | + [generic] Support complex JWPlayer embedded videos (#12030) | ||||||
|  |  | ||||||
|  |  | ||||||
| version 2017.02.16 | version 2017.02.16 | ||||||
|  |  | ||||||
| Core | Core | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     unified_strdate, |     unified_strdate, | ||||||
|     clean_html, |     clean_html, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class ArchiveOrgIE(JWPlatformBaseIE): | class ArchiveOrgIE(InfoExtractor): | ||||||
|     IE_NAME = 'archive.org' |     IE_NAME = 'archive.org' | ||||||
|     IE_DESC = 'archive.org videos' |     IE_DESC = 'archive.org videos' | ||||||
|     _VALID_URL = r'https?://(?:www\.)?archive\.org/(?:details|embed)/(?P<id>[^/?#]+)(?:[?].*)?$' |     _VALID_URL = r'https?://(?:www\.)?archive\.org/(?:details|embed)/(?P<id>[^/?#]+)(?:[?].*)?$' | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ from ..utils import ( | |||||||
|     fix_xml_ampersands, |     fix_xml_ampersands, | ||||||
|     float_or_none, |     float_or_none, | ||||||
|     int_or_none, |     int_or_none, | ||||||
|  |     js_to_json, | ||||||
|     parse_iso8601, |     parse_iso8601, | ||||||
|     RegexNotFoundError, |     RegexNotFoundError, | ||||||
|     sanitize_filename, |     sanitize_filename, | ||||||
| @@ -2073,6 +2074,123 @@ class InfoExtractor(object): | |||||||
|                     }) |                     }) | ||||||
|         return formats |         return formats | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def _find_jwplayer_data(webpage): | ||||||
|  |         mobj = re.search( | ||||||
|  |             r'jwplayer\((?P<quote>[\'"])[^\'" ]+(?P=quote)\)\.setup\s*\((?P<options>[^)]+)\)', | ||||||
|  |             webpage) | ||||||
|  |         if mobj: | ||||||
|  |             return mobj.group('options') | ||||||
|  |  | ||||||
|  |     def _extract_jwplayer_data(self, webpage, video_id, *args, **kwargs): | ||||||
|  |         jwplayer_data = self._parse_json( | ||||||
|  |             self._find_jwplayer_data(webpage), video_id, | ||||||
|  |             transform_source=js_to_json) | ||||||
|  |         return self._parse_jwplayer_data( | ||||||
|  |             jwplayer_data, video_id, *args, **kwargs) | ||||||
|  |  | ||||||
|  |     def _parse_jwplayer_data(self, jwplayer_data, video_id=None, require_title=True, | ||||||
|  |                              m3u8_id=None, mpd_id=None, rtmp_params=None, base_url=None): | ||||||
|  |         # JWPlayer backward compatibility: flattened playlists | ||||||
|  |         # https://github.com/jwplayer/jwplayer/blob/v7.4.3/src/js/api/config.js#L81-L96 | ||||||
|  |         if 'playlist' not in jwplayer_data: | ||||||
|  |             jwplayer_data = {'playlist': [jwplayer_data]} | ||||||
|  |  | ||||||
|  |         entries = [] | ||||||
|  |  | ||||||
|  |         # JWPlayer backward compatibility: single playlist item | ||||||
|  |         # https://github.com/jwplayer/jwplayer/blob/v7.7.0/src/js/playlist/playlist.js#L10 | ||||||
|  |         if not isinstance(jwplayer_data['playlist'], list): | ||||||
|  |             jwplayer_data['playlist'] = [jwplayer_data['playlist']] | ||||||
|  |  | ||||||
|  |         for video_data in jwplayer_data['playlist']: | ||||||
|  |             # JWPlayer backward compatibility: flattened sources | ||||||
|  |             # https://github.com/jwplayer/jwplayer/blob/v7.4.3/src/js/playlist/item.js#L29-L35 | ||||||
|  |             if 'sources' not in video_data: | ||||||
|  |                 video_data['sources'] = [video_data] | ||||||
|  |  | ||||||
|  |             this_video_id = video_id or video_data['mediaid'] | ||||||
|  |  | ||||||
|  |             formats = [] | ||||||
|  |             for source in video_data['sources']: | ||||||
|  |                 source_url = self._proto_relative_url(source['file']) | ||||||
|  |                 if base_url: | ||||||
|  |                     source_url = compat_urlparse.urljoin(base_url, source_url) | ||||||
|  |                 source_type = source.get('type') or '' | ||||||
|  |                 ext = mimetype2ext(source_type) or determine_ext(source_url) | ||||||
|  |                 if source_type == 'hls' or ext == 'm3u8': | ||||||
|  |                     formats.extend(self._extract_m3u8_formats( | ||||||
|  |                         source_url, this_video_id, 'mp4', 'm3u8_native', m3u8_id=m3u8_id, fatal=False)) | ||||||
|  |                 elif ext == 'mpd': | ||||||
|  |                     formats.extend(self._extract_mpd_formats( | ||||||
|  |                         source_url, this_video_id, mpd_id=mpd_id, fatal=False)) | ||||||
|  |                 # https://github.com/jwplayer/jwplayer/blob/master/src/js/providers/default.js#L67 | ||||||
|  |                 elif source_type.startswith('audio') or ext in ('oga', 'aac', 'mp3', 'mpeg', 'vorbis'): | ||||||
|  |                     formats.append({ | ||||||
|  |                         'url': source_url, | ||||||
|  |                         'vcodec': 'none', | ||||||
|  |                         'ext': ext, | ||||||
|  |                     }) | ||||||
|  |                 else: | ||||||
|  |                     height = int_or_none(source.get('height')) | ||||||
|  |                     if height is None: | ||||||
|  |                         # Often no height is provided but there is a label in | ||||||
|  |                         # format like 1080p. | ||||||
|  |                         height = int_or_none(self._search_regex( | ||||||
|  |                             r'^(\d{3,})[pP]$', source.get('label') or '', | ||||||
|  |                             'height', default=None)) | ||||||
|  |                     a_format = { | ||||||
|  |                         'url': source_url, | ||||||
|  |                         'width': int_or_none(source.get('width')), | ||||||
|  |                         'height': height, | ||||||
|  |                         'ext': ext, | ||||||
|  |                     } | ||||||
|  |                     if source_url.startswith('rtmp'): | ||||||
|  |                         a_format['ext'] = 'flv' | ||||||
|  |  | ||||||
|  |                         # See com/longtailvideo/jwplayer/media/RTMPMediaProvider.as | ||||||
|  |                         # of jwplayer.flash.swf | ||||||
|  |                         rtmp_url_parts = re.split( | ||||||
|  |                             r'((?:mp4|mp3|flv):)', source_url, 1) | ||||||
|  |                         if len(rtmp_url_parts) == 3: | ||||||
|  |                             rtmp_url, prefix, play_path = rtmp_url_parts | ||||||
|  |                             a_format.update({ | ||||||
|  |                                 'url': rtmp_url, | ||||||
|  |                                 'play_path': prefix + play_path, | ||||||
|  |                             }) | ||||||
|  |                         if rtmp_params: | ||||||
|  |                             a_format.update(rtmp_params) | ||||||
|  |                     formats.append(a_format) | ||||||
|  |             self._sort_formats(formats) | ||||||
|  |  | ||||||
|  |             subtitles = {} | ||||||
|  |             tracks = video_data.get('tracks') | ||||||
|  |             if tracks and isinstance(tracks, list): | ||||||
|  |                 for track in tracks: | ||||||
|  |                     if track.get('kind') != 'captions': | ||||||
|  |                         continue | ||||||
|  |                     track_url = urljoin(base_url, track.get('file')) | ||||||
|  |                     if not track_url: | ||||||
|  |                         continue | ||||||
|  |                     subtitles.setdefault(track.get('label') or 'en', []).append({ | ||||||
|  |                         'url': self._proto_relative_url(track_url) | ||||||
|  |                     }) | ||||||
|  |  | ||||||
|  |             entries.append({ | ||||||
|  |                 'id': this_video_id, | ||||||
|  |                 'title': video_data['title'] if require_title else video_data.get('title'), | ||||||
|  |                 'description': video_data.get('description'), | ||||||
|  |                 'thumbnail': self._proto_relative_url(video_data.get('image')), | ||||||
|  |                 'timestamp': int_or_none(video_data.get('pubdate')), | ||||||
|  |                 'duration': float_or_none(jwplayer_data.get('duration') or video_data.get('duration')), | ||||||
|  |                 'subtitles': subtitles, | ||||||
|  |                 'formats': formats, | ||||||
|  |             }) | ||||||
|  |         if len(entries) == 1: | ||||||
|  |             return entries[0] | ||||||
|  |         else: | ||||||
|  |             return self.playlist_result(entries) | ||||||
|  |  | ||||||
|     def _live_title(self, name): |     def _live_title(self, name): | ||||||
|         """ Generate the title for a live video """ |         """ Generate the title for a live video """ | ||||||
|         now = datetime.datetime.now() |         now = datetime.datetime.now() | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ from ..utils import ( | |||||||
|     float_or_none, |     float_or_none, | ||||||
|     HEADRequest, |     HEADRequest, | ||||||
|     is_html, |     is_html, | ||||||
|  |     js_to_json, | ||||||
|     orderedSet, |     orderedSet, | ||||||
|     sanitized_Request, |     sanitized_Request, | ||||||
|     smuggle_url, |     smuggle_url, | ||||||
| @@ -961,6 +962,16 @@ class GenericIE(InfoExtractor): | |||||||
|                 'skip_download': True, |                 'skip_download': True, | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         # Complex jwplayer | ||||||
|  |         { | ||||||
|  |             'url': 'http://www.indiedb.com/games/king-machine/videos', | ||||||
|  |             'info_dict': { | ||||||
|  |                 'id': 'videos', | ||||||
|  |                 'ext': 'mp4', | ||||||
|  |                 'title': 'king machine trailer 1', | ||||||
|  |                 'thumbnail': r're:^https?://.*\.jpg$', | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|         # rtl.nl embed |         # rtl.nl embed | ||||||
|         { |         { | ||||||
|             'url': 'http://www.rtlnieuws.nl/nieuws/buitenland/aanslagen-kopenhagen', |             'url': 'http://www.rtlnieuws.nl/nieuws/buitenland/aanslagen-kopenhagen', | ||||||
| @@ -2488,6 +2499,15 @@ class GenericIE(InfoExtractor): | |||||||
|                 self._sort_formats(entry['formats']) |                 self._sort_formats(entry['formats']) | ||||||
|             return self.playlist_result(entries) |             return self.playlist_result(entries) | ||||||
|  |  | ||||||
|  |         jwplayer_data_str = self._find_jwplayer_data(webpage) | ||||||
|  |         if jwplayer_data_str: | ||||||
|  |             try: | ||||||
|  |                 jwplayer_data = self._parse_json( | ||||||
|  |                     jwplayer_data_str, video_id, transform_source=js_to_json) | ||||||
|  |                 return self._parse_jwplayer_data(jwplayer_data, video_id) | ||||||
|  |             except ExtractorError: | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|         def check_video(vurl): |         def check_video(vurl): | ||||||
|             if YoutubeIE.suitable(vurl): |             if YoutubeIE.suitable(vurl): | ||||||
|                 return True |                 return True | ||||||
|   | |||||||
| @@ -4,139 +4,9 @@ from __future__ import unicode_literals | |||||||
| import re | import re | ||||||
|  |  | ||||||
| from .common import InfoExtractor | from .common import InfoExtractor | ||||||
| from ..compat import compat_urlparse |  | ||||||
| from ..utils import ( |  | ||||||
|     determine_ext, |  | ||||||
|     float_or_none, |  | ||||||
|     int_or_none, |  | ||||||
|     js_to_json, |  | ||||||
|     mimetype2ext, |  | ||||||
|     urljoin, |  | ||||||
| ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class JWPlatformBaseIE(InfoExtractor): | class JWPlatformIE(InfoExtractor): | ||||||
|     @staticmethod |  | ||||||
|     def _find_jwplayer_data(webpage): |  | ||||||
|         # TODO: Merge this with JWPlayer-related codes in generic.py |  | ||||||
|  |  | ||||||
|         mobj = re.search( |  | ||||||
|             r'jwplayer\((?P<quote>[\'"])[^\'" ]+(?P=quote)\)\.setup\s*\((?P<options>[^)]+)\)', |  | ||||||
|             webpage) |  | ||||||
|         if mobj: |  | ||||||
|             return mobj.group('options') |  | ||||||
|  |  | ||||||
|     def _extract_jwplayer_data(self, webpage, video_id, *args, **kwargs): |  | ||||||
|         jwplayer_data = self._parse_json( |  | ||||||
|             self._find_jwplayer_data(webpage), video_id, |  | ||||||
|             transform_source=js_to_json) |  | ||||||
|         return self._parse_jwplayer_data( |  | ||||||
|             jwplayer_data, video_id, *args, **kwargs) |  | ||||||
|  |  | ||||||
|     def _parse_jwplayer_data(self, jwplayer_data, video_id=None, require_title=True, |  | ||||||
|                              m3u8_id=None, mpd_id=None, rtmp_params=None, base_url=None): |  | ||||||
|         # JWPlayer backward compatibility: flattened playlists |  | ||||||
|         # https://github.com/jwplayer/jwplayer/blob/v7.4.3/src/js/api/config.js#L81-L96 |  | ||||||
|         if 'playlist' not in jwplayer_data: |  | ||||||
|             jwplayer_data = {'playlist': [jwplayer_data]} |  | ||||||
|  |  | ||||||
|         entries = [] |  | ||||||
|  |  | ||||||
|         # JWPlayer backward compatibility: single playlist item |  | ||||||
|         # https://github.com/jwplayer/jwplayer/blob/v7.7.0/src/js/playlist/playlist.js#L10 |  | ||||||
|         if not isinstance(jwplayer_data['playlist'], list): |  | ||||||
|             jwplayer_data['playlist'] = [jwplayer_data['playlist']] |  | ||||||
|  |  | ||||||
|         for video_data in jwplayer_data['playlist']: |  | ||||||
|             # JWPlayer backward compatibility: flattened sources |  | ||||||
|             # https://github.com/jwplayer/jwplayer/blob/v7.4.3/src/js/playlist/item.js#L29-L35 |  | ||||||
|             if 'sources' not in video_data: |  | ||||||
|                 video_data['sources'] = [video_data] |  | ||||||
|  |  | ||||||
|             this_video_id = video_id or video_data['mediaid'] |  | ||||||
|  |  | ||||||
|             formats = [] |  | ||||||
|             for source in video_data['sources']: |  | ||||||
|                 source_url = self._proto_relative_url(source['file']) |  | ||||||
|                 if base_url: |  | ||||||
|                     source_url = compat_urlparse.urljoin(base_url, source_url) |  | ||||||
|                 source_type = source.get('type') or '' |  | ||||||
|                 ext = mimetype2ext(source_type) or determine_ext(source_url) |  | ||||||
|                 if source_type == 'hls' or ext == 'm3u8': |  | ||||||
|                     formats.extend(self._extract_m3u8_formats( |  | ||||||
|                         source_url, this_video_id, 'mp4', 'm3u8_native', m3u8_id=m3u8_id, fatal=False)) |  | ||||||
|                 elif ext == 'mpd': |  | ||||||
|                     formats.extend(self._extract_mpd_formats( |  | ||||||
|                         source_url, this_video_id, mpd_id=mpd_id, fatal=False)) |  | ||||||
|                 # https://github.com/jwplayer/jwplayer/blob/master/src/js/providers/default.js#L67 |  | ||||||
|                 elif source_type.startswith('audio') or ext in ('oga', 'aac', 'mp3', 'mpeg', 'vorbis'): |  | ||||||
|                     formats.append({ |  | ||||||
|                         'url': source_url, |  | ||||||
|                         'vcodec': 'none', |  | ||||||
|                         'ext': ext, |  | ||||||
|                     }) |  | ||||||
|                 else: |  | ||||||
|                     height = int_or_none(source.get('height')) |  | ||||||
|                     if height is None: |  | ||||||
|                         # Often no height is provided but there is a label in |  | ||||||
|                         # format like 1080p. |  | ||||||
|                         height = int_or_none(self._search_regex( |  | ||||||
|                             r'^(\d{3,})[pP]$', source.get('label') or '', |  | ||||||
|                             'height', default=None)) |  | ||||||
|                     a_format = { |  | ||||||
|                         'url': source_url, |  | ||||||
|                         'width': int_or_none(source.get('width')), |  | ||||||
|                         'height': height, |  | ||||||
|                         'ext': ext, |  | ||||||
|                     } |  | ||||||
|                     if source_url.startswith('rtmp'): |  | ||||||
|                         a_format['ext'] = 'flv' |  | ||||||
|  |  | ||||||
|                         # See com/longtailvideo/jwplayer/media/RTMPMediaProvider.as |  | ||||||
|                         # of jwplayer.flash.swf |  | ||||||
|                         rtmp_url_parts = re.split( |  | ||||||
|                             r'((?:mp4|mp3|flv):)', source_url, 1) |  | ||||||
|                         if len(rtmp_url_parts) == 3: |  | ||||||
|                             rtmp_url, prefix, play_path = rtmp_url_parts |  | ||||||
|                             a_format.update({ |  | ||||||
|                                 'url': rtmp_url, |  | ||||||
|                                 'play_path': prefix + play_path, |  | ||||||
|                             }) |  | ||||||
|                         if rtmp_params: |  | ||||||
|                             a_format.update(rtmp_params) |  | ||||||
|                     formats.append(a_format) |  | ||||||
|             self._sort_formats(formats) |  | ||||||
|  |  | ||||||
|             subtitles = {} |  | ||||||
|             tracks = video_data.get('tracks') |  | ||||||
|             if tracks and isinstance(tracks, list): |  | ||||||
|                 for track in tracks: |  | ||||||
|                     if track.get('kind') != 'captions': |  | ||||||
|                         continue |  | ||||||
|                     track_url = urljoin(base_url, track.get('file')) |  | ||||||
|                     if not track_url: |  | ||||||
|                         continue |  | ||||||
|                     subtitles.setdefault(track.get('label') or 'en', []).append({ |  | ||||||
|                         'url': self._proto_relative_url(track_url) |  | ||||||
|                     }) |  | ||||||
|  |  | ||||||
|             entries.append({ |  | ||||||
|                 'id': this_video_id, |  | ||||||
|                 'title': video_data['title'] if require_title else video_data.get('title'), |  | ||||||
|                 'description': video_data.get('description'), |  | ||||||
|                 'thumbnail': self._proto_relative_url(video_data.get('image')), |  | ||||||
|                 'timestamp': int_or_none(video_data.get('pubdate')), |  | ||||||
|                 'duration': float_or_none(jwplayer_data.get('duration') or video_data.get('duration')), |  | ||||||
|                 'subtitles': subtitles, |  | ||||||
|                 'formats': formats, |  | ||||||
|             }) |  | ||||||
|         if len(entries) == 1: |  | ||||||
|             return entries[0] |  | ||||||
|         else: |  | ||||||
|             return self.playlist_result(entries) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class JWPlatformIE(JWPlatformBaseIE): |  | ||||||
|     _VALID_URL = r'(?:https?://content\.jwplatform\.com/(?:feeds|players|jw6)/|jwplatform:)(?P<id>[a-zA-Z0-9]{8})' |     _VALID_URL = r'(?:https?://content\.jwplatform\.com/(?:feeds|players|jw6)/|jwplatform:)(?P<id>[a-zA-Z0-9]{8})' | ||||||
|     _TEST = { |     _TEST = { | ||||||
|         'url': 'http://content.jwplatform.com/players/nPripu9l-ALJ3XQCI.js', |         'url': 'http://content.jwplatform.com/players/nPripu9l-ALJ3XQCI.js', | ||||||
|   | |||||||
| @@ -1,14 +1,14 @@ | |||||||
| # coding: utf-8 | # coding: utf-8 | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     ExtractorError, |     ExtractorError, | ||||||
|     js_to_json, |     js_to_json, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class OnDemandKoreaIE(JWPlatformBaseIE): | class OnDemandKoreaIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://(?:www\.)?ondemandkorea\.com/(?P<id>[^/]+)\.html' |     _VALID_URL = r'https?://(?:www\.)?ondemandkorea\.com/(?P<id>[^/]+)\.html' | ||||||
|     _TEST = { |     _TEST = { | ||||||
|         'url': 'http://www.ondemandkorea.com/ask-us-anything-e43.html', |         'url': 'http://www.ondemandkorea.com/ask-us-anything-e43.html', | ||||||
|   | |||||||
| @@ -169,50 +169,6 @@ class PornHubIE(InfoExtractor): | |||||||
|         comment_count = self._extract_count( |         comment_count = self._extract_count( | ||||||
|             r'All Comments\s*<span>\(([\d,.]+)\)', webpage, 'comment') |             r'All Comments\s*<span>\(([\d,.]+)\)', webpage, 'comment') | ||||||
|  |  | ||||||
|         """ |  | ||||||
|         video_variables = {} |  | ||||||
|         for video_variablename, quote, video_variable in re.findall( |  | ||||||
|                 r'(player_quality_[0-9]{3,4}p\w+)\s*=\s*(["\'])(.+?)\2;', webpage): |  | ||||||
|             video_variables[video_variablename] = video_variable |  | ||||||
|  |  | ||||||
|         video_urls = [] |  | ||||||
|         for encoded_video_url in re.findall( |  | ||||||
|                 r'player_quality_[0-9]{3,4}p\s*=(.+?);', webpage): |  | ||||||
|             for varname, varval in video_variables.items(): |  | ||||||
|                 encoded_video_url = encoded_video_url.replace(varname, varval) |  | ||||||
|             video_urls.append(re.sub(r'[\s+]', '', encoded_video_url)) |  | ||||||
|  |  | ||||||
|         if webpage.find('"encrypted":true') != -1: |  | ||||||
|             password = compat_urllib_parse_unquote_plus( |  | ||||||
|                 self._search_regex(r'"video_title":"([^"]+)', webpage, 'password')) |  | ||||||
|             video_urls = list(map(lambda s: aes_decrypt_text(s, password, 32).decode('utf-8'), video_urls)) |  | ||||||
|  |  | ||||||
|         formats = [] |  | ||||||
|         for video_url in video_urls: |  | ||||||
|             path = compat_urllib_parse_urlparse(video_url).path |  | ||||||
|             extension = os.path.splitext(path)[1][1:] |  | ||||||
|             format = path.split('/')[5].split('_')[:2] |  | ||||||
|             format = '-'.join(format) |  | ||||||
|  |  | ||||||
|             m = re.match(r'^(?P<height>[0-9]+)[pP]-(?P<tbr>[0-9]+)[kK]$', format) |  | ||||||
|             if m is None: |  | ||||||
|                 height = None |  | ||||||
|                 tbr = None |  | ||||||
|             else: |  | ||||||
|                 height = int(m.group('height')) |  | ||||||
|                 tbr = int(m.group('tbr')) |  | ||||||
|  |  | ||||||
|             formats.append({ |  | ||||||
|                 'url': video_url, |  | ||||||
|                 'ext': extension, |  | ||||||
|                 'format': format, |  | ||||||
|                 'format_id': format, |  | ||||||
|                 'tbr': tbr, |  | ||||||
|                 'height': height, |  | ||||||
|             }) |  | ||||||
|         self._sort_formats(formats) |  | ||||||
|         """ |  | ||||||
|  |  | ||||||
|         page_params = self._parse_json(self._search_regex( |         page_params = self._parse_json(self._search_regex( | ||||||
|             r'page_params\.zoneDetails\[([\'"])[^\'"]+\1\]\s*=\s*(?P<data>{[^}]+})', |             r'page_params\.zoneDetails\[([\'"])[^\'"]+\1\]\s*=\s*(?P<data>{[^}]+})', | ||||||
|             webpage, 'page parameters', group='data', default='{}'), |             webpage, 'page parameters', group='data', default='{}'), | ||||||
|   | |||||||
| @@ -2,13 +2,13 @@ from __future__ import unicode_literals | |||||||
|  |  | ||||||
| import re | import re | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     str_to_int, |     str_to_int, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class PornoXOIE(JWPlatformBaseIE): | class PornoXOIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://(?:www\.)?pornoxo\.com/videos/(?P<id>\d+)/(?P<display_id>[^/]+)\.html' |     _VALID_URL = r'https?://(?:www\.)?pornoxo\.com/videos/(?P<id>\d+)/(?P<display_id>[^/]+)\.html' | ||||||
|     _TEST = { |     _TEST = { | ||||||
|         'url': 'http://www.pornoxo.com/videos/7564/striptease-from-sexy-secretary.html', |         'url': 'http://www.pornoxo.com/videos/7564/striptease-from-sexy-secretary.html', | ||||||
|   | |||||||
| @@ -2,11 +2,10 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| from .common import InfoExtractor | from .common import InfoExtractor | ||||||
| from .jwplatform import JWPlatformBaseIE |  | ||||||
| from ..compat import compat_str | from ..compat import compat_str | ||||||
|  |  | ||||||
|  |  | ||||||
| class RENTVIE(JWPlatformBaseIE): | class RENTVIE(InfoExtractor): | ||||||
|     _VALID_URL = r'(?:rentv:|https?://(?:www\.)?ren\.tv/(?:player|video/epizod)/)(?P<id>\d+)' |     _VALID_URL = r'(?:rentv:|https?://(?:www\.)?ren\.tv/(?:player|video/epizod)/)(?P<id>\d+)' | ||||||
|     _TESTS = [{ |     _TESTS = [{ | ||||||
|         'url': 'http://ren.tv/video/epizod/118577', |         'url': 'http://ren.tv/video/epizod/118577', | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ from __future__ import unicode_literals | |||||||
|  |  | ||||||
| import re | import re | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     js_to_json, |     js_to_json, | ||||||
|     get_element_by_class, |     get_element_by_class, | ||||||
| @@ -11,7 +11,7 @@ from ..utils import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class RudoIE(JWPlatformBaseIE): | class RudoIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://rudo\.video/vod/(?P<id>[0-9a-zA-Z]+)' |     _VALID_URL = r'https?://rudo\.video/vod/(?P<id>[0-9a-zA-Z]+)' | ||||||
|  |  | ||||||
|     _TEST = { |     _TEST = { | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| # coding: utf-8 | # coding: utf-8 | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import js_to_json | from ..utils import js_to_json | ||||||
|  |  | ||||||
|  |  | ||||||
| class ScreencastOMaticIE(JWPlatformBaseIE): | class ScreencastOMaticIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://screencast-o-matic\.com/watch/(?P<id>[0-9a-zA-Z]+)' |     _VALID_URL = r'https?://screencast-o-matic\.com/watch/(?P<id>[0-9a-zA-Z]+)' | ||||||
|     _TEST = { |     _TEST = { | ||||||
|         'url': 'http://screencast-o-matic.com/watch/c2lD3BeOPl', |         'url': 'http://screencast-o-matic.com/watch/c2lD3BeOPl', | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ from __future__ import unicode_literals | |||||||
|  |  | ||||||
| import re | import re | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     float_or_none, |     float_or_none, | ||||||
|     parse_iso8601, |     parse_iso8601, | ||||||
| @@ -14,7 +14,7 @@ from ..utils import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class SendtoNewsIE(JWPlatformBaseIE): | class SendtoNewsIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://embed\.sendtonews\.com/player2/embedplayer\.php\?.*\bSC=(?P<id>[0-9A-Za-z-]+)' |     _VALID_URL = r'https?://embed\.sendtonews\.com/player2/embedplayer\.php\?.*\bSC=(?P<id>[0-9A-Za-z-]+)' | ||||||
|  |  | ||||||
|     _TEST = { |     _TEST = { | ||||||
|   | |||||||
| @@ -3,11 +3,11 @@ from __future__ import unicode_literals | |||||||
|  |  | ||||||
| import re | import re | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import remove_end | from ..utils import remove_end | ||||||
|  |  | ||||||
|  |  | ||||||
| class ThisAVIE(JWPlatformBaseIE): | class ThisAVIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://(?:www\.)?thisav\.com/video/(?P<id>[0-9]+)/.*' |     _VALID_URL = r'https?://(?:www\.)?thisav\.com/video/(?P<id>[0-9]+)/.*' | ||||||
|     _TESTS = [{ |     _TESTS = [{ | ||||||
|         'url': 'http://www.thisav.com/video/47734/%98%26sup1%3B%83%9E%83%82---just-fit.html', |         'url': 'http://www.thisav.com/video/47734/%98%26sup1%3B%83%9E%83%82---just-fit.html', | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| # coding: utf-8 | # coding: utf-8 | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     clean_html, |     clean_html, | ||||||
|     get_element_by_class, |     get_element_by_class, | ||||||
| @@ -9,7 +9,7 @@ from ..utils import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TVNoeIE(JWPlatformBaseIE): | class TVNoeIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://(?:www\.)?tvnoe\.cz/video/(?P<id>[0-9]+)' |     _VALID_URL = r'https?://(?:www\.)?tvnoe\.cz/video/(?P<id>[0-9]+)' | ||||||
|     _TEST = { |     _TEST = { | ||||||
|         'url': 'http://www.tvnoe.cz/video/10362', |         'url': 'http://www.tvnoe.cz/video/10362', | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ from __future__ import unicode_literals | |||||||
|  |  | ||||||
| import re | import re | ||||||
|  |  | ||||||
| from .jwplatform import JWPlatformBaseIE | from .common import InfoExtractor | ||||||
| from ..utils import ( | from ..utils import ( | ||||||
|     decode_packed_codes, |     decode_packed_codes, | ||||||
|     js_to_json, |     js_to_json, | ||||||
| @@ -12,7 +12,7 @@ from ..utils import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class VidziIE(JWPlatformBaseIE): | class VidziIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://(?:www\.)?vidzi\.tv/(?:embed-)?(?P<id>[0-9a-zA-Z]+)' |     _VALID_URL = r'https?://(?:www\.)?vidzi\.tv/(?:embed-)?(?P<id>[0-9a-zA-Z]+)' | ||||||
|     _TESTS = [{ |     _TESTS = [{ | ||||||
|         'url': 'http://vidzi.tv/cghql9yq6emu.html', |         'url': 'http://vidzi.tv/cghql9yq6emu.html', | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
|  | from .common import InfoExtractor | ||||||
| from .youtube import YoutubeIE | from .youtube import YoutubeIE | ||||||
| from .jwplatform import JWPlatformBaseIE |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class WimpIE(JWPlatformBaseIE): | class WimpIE(InfoExtractor): | ||||||
|     _VALID_URL = r'https?://(?:www\.)?wimp\.com/(?P<id>[^/]+)' |     _VALID_URL = r'https?://(?:www\.)?wimp\.com/(?P<id>[^/]+)' | ||||||
|     _TESTS = [{ |     _TESTS = [{ | ||||||
|         'url': 'http://www.wimp.com/maru-is-exhausted/', |         'url': 'http://www.wimp.com/maru-is-exhausted/', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Yen Chi Hsuan
					Yen Chi Hsuan