# coding: utf-8 from __future__ import unicode_literals import re from .common import InfoExtractor from ..compat import ( compat_str, compat_urllib_parse_unquote, ) from ..utils import ( int_or_none, parse_iso8601, strip_or_none, try_get, unescapeHTML, urljoin, ) class KinjaEmbedIE(InfoExtractor): IENAME = 'kinja:embed' _DOMAIN_REGEX = r'''(?:[^.]+\.)? (?: avclub| clickhole| deadspin| gizmodo| jalopnik| jezebel| kinja| kotaku| lifehacker| splinternews| the(?:inventory|onion|root|takeout) )\.com''' _COMMON_REGEX = r'''/ (?: ajax/inset| embed/video )/iframe\?.*?\bid=''' _VALID_URL = r'''(?x)https?://%s%s (?P fb| imgur| instagram| jwp(?:layer)?-video| kinjavideo| mcp| megaphone| ooyala| soundcloud(?:-playlist)?| tumblr-post| twitch-stream| twitter| ustream-channel| vimeo| vine| youtube-(?:list|video) )-(?P[^&]+)''' % (_DOMAIN_REGEX, _COMMON_REGEX) _TESTS = [{ 'url': 'https://kinja.com/ajax/inset/iframe?id=fb-10103303356633621', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=kinjavideo-100313', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=megaphone-PPY1300931075', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=ooyala-xzMXhleDpopuT0u1ijt_qZj3Va-34pEX%2FZTIxYmJjZDM2NWYzZDViZGRiOWJjYzc5', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=soundcloud-128574047', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=soundcloud-playlist-317413750', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=tumblr-post-160130699814-daydreams-at-midnight', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=twitch-stream-libratus_extra', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=twitter-1068875942473404422', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=ustream-channel-10414700', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=vimeo-120153502', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=vine-5BlvV5qqPrD', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=youtube-list-BCQ3KyrPjgA/PLE6509247C270A72E', 'only_matching': True, }, { 'url': 'https://kinja.com/ajax/inset/iframe?id=youtube-video-00QyL0AgPAE', 'only_matching': True, }] _JWPLATFORM_PROVIDER = ('cdn.jwplayer.com/v2/media/', 'JWPlatform') _PROVIDER_MAP = { 'fb': ('facebook.com/video.php?v=', 'Facebook'), 'imgur': ('imgur.com/', 'Imgur'), 'instagram': ('instagram.com/p/', 'Instagram'), 'jwplayer-video': _JWPLATFORM_PROVIDER, 'jwp-video': _JWPLATFORM_PROVIDER, 'megaphone': ('player.megaphone.fm/', 'Generic'), 'ooyala': ('player.ooyala.com/player.js?embedCode=', 'Ooyala'), 'soundcloud': ('api.soundcloud.com/tracks/', 'Soundcloud'), 'soundcloud-playlist': ('api.soundcloud.com/playlists/', 'SoundcloudPlaylist'), 'tumblr-post': ('%s.tumblr.com/post/%s', 'Tumblr'), 'twitch-stream': ('twitch.tv/', 'TwitchStream'), 'twitter': ('twitter.com/i/cards/tfw/v1/', 'TwitterCard'), 'ustream-channel': ('ustream.tv/embed/', 'Ustream'), 'vimeo': ('vimeo.com/', 'Vimeo'), 'vine': ('vine.co/v/', 'Vine'), 'youtube-list': ('youtube.com/embed/%s?list=%s', 'YoutubePlaylist'), 'youtube-video': ('youtube.com/embed/', 'Youtube'), } @staticmethod def _extract_urls(webpage, url): return [urljoin(url, unescapeHTML(mobj.group('url'))) for mobj in re.finditer( r'(?x)]+?src=(?P["\'])(?P(?:(?:https?:)?//%s)?%s(?:(?!\1).)+)\1' % (KinjaEmbedIE._DOMAIN_REGEX, KinjaEmbedIE._COMMON_REGEX), webpage)] def _real_extract(self, url): video_type, video_id = re.match(self._VALID_URL, url).groups() provider = self._PROVIDER_MAP.get(video_type) if provider: video_id = compat_urllib_parse_unquote(video_id) if video_type == 'tumblr-post': video_id, blog = video_id.split('-', 1) result_url = provider[0] % (blog, video_id) elif video_type == 'youtube-list': video_id, playlist_id = video_id.split('/') result_url = provider[0] % (video_id, playlist_id) else: if video_type == 'ooyala': video_id = video_id.split('/')[0] result_url = provider[0] + video_id return self.url_result('http://' + result_url, provider[1]) if video_type == 'kinjavideo': data = self._download_json( 'https://kinja.com/api/core/video/views/videoById', video_id, query={'videoId': video_id})['data'] title = data['title'] formats = [] for k in ('signedPlaylist', 'streaming'): m3u8_url = data.get(k + 'Url') if m3u8_url: formats.extend(self._extract_m3u8_formats( m3u8_url, video_id, 'mp4', 'm3u8_native', m3u8_id='hls', fatal=False)) self._sort_formats(formats) thumbnail = None poster = data.get('poster') or {} poster_id = poster.get('id') if poster_id: thumbnail = 'https://i.kinja-img.com/gawker-media/image/upload/%s.%s' % (poster_id, poster.get('format') or 'jpg') return { 'id': video_id, 'title': title, 'description': strip_or_none(data.get('description')), 'formats': formats, 'tags': data.get('tags'), 'timestamp': int_or_none(try_get( data, lambda x: x['postInfo']['publishTimeMillis']), 1000), 'thumbnail': thumbnail, 'uploader': data.get('network'), } else: video_data = self._download_json( 'https://api.vmh.univision.com/metadata/v1/content/' + video_id, video_id)['videoMetadata'] iptc = video_data['photoVideoMetadataIPTC'] title = iptc['title']['en'] fmg = video_data.get('photoVideoMetadata_fmg') or {} tvss_domain = fmg.get('tvssDomain') or 'https://auth.univision.com' data = self._download_json( tvss_domain + '/api/v3/video-auth/url-signature-tokens', video_id, query={'mcpids': video_id})['data'][0] formats = [] rendition_url = data.get('renditionUrl') if rendition_url: formats = self._extract_m3u8_formats( rendition_url, video_id, 'mp4', 'm3u8_native', m3u8_id='hls', fatal=False) fallback_rendition_url = data.get('fallbackRenditionUrl') if fallback_rendition_url: formats.append({ 'format_id': 'fallback', 'tbr': int_or_none(self._search_regex( r'_(\d+)\.mp4', fallback_rendition_url, 'bitrate', default=None)), 'url': fallback_rendition_url, }) self._sort_formats(formats) return { 'id': video_id, 'title': title, 'thumbnail': try_get(iptc, lambda x: x['cloudinaryLink']['link'], compat_str), 'uploader': fmg.get('network'), 'duration': int_or_none(iptc.get('fileDuration')), 'formats': formats, 'description': try_get(iptc, lambda x: x['description']['en'], compat_str), 'timestamp': parse_iso8601(iptc.get('dateReleased')), }