code:
# coding: utf-8
from __future__ import unicode_literals

from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
    clean_html,
    ExtractorError,
    int_or_none,
    merge_dicts,
    parse_count,
    str_or_none,
    try_get,
    unified_strdate,
    urlencode_postdata,
    urljoin,
)

class HKETVIE(InfoExtractor):
    IE_NAME = 'hketv'
    IE_DESC = '香港教育局教育電視 (HKETV) Educational Television, Hong Kong Educational Bureau'
    _GEO_BYPASS = False
    _GEO_COUNTRIES = ['HK']
    _VALID_URL = r'https?://(?:www\.)?hkedcity\.net/etv/resource/(?P<id>[0-9]+)'
    _TESTS = [{
        'url': 'https://www.hkedcity.net/etv/resource/2932360618',
        'md5': 'f193712f5f7abb208ddef3c5ea6ed0b7',
        'info_dict': {
            'id': '2932360618',
            'ext': 'mp4',
            'title': '喜閱一生(共享閱讀樂) (中、英文字幕可供選擇)',
            'description': 'md5:d5286d05219ef50e0613311cbe96e560',
            'upload_date': '20181024',
            'duration': 900,
            'subtitles': 'count:2',
        },
        'skip': 'Geo restricted to HK',
    }, {
        'url': 'https://www.hkedcity.net/etv/resource/972641418',
        'md5': '1ed494c1c6cf7866a8290edad9b07dc9',
        'info_dict': {
            'id': '972641418',
            'ext': 'mp4',
            'title': '衣冠楚楚 (天使系列之一)',
            'description': 'md5:10bb3d659421e74f58e5db5691627b0f',
            'upload_date': '20070109',
            'duration': 907,
            'subtitles': {},
        },
        'params': {
            'geo_verification_proxy': '<HK proxy here>',
        },
        'skip': 'Geo restricted to HK',
    }]

    _CC_LANGS = {
        '中文（繁體中文）': 'zh-Hant',
        '中文（简体中文）': 'zh-Hans',
        'English': 'en',
        'Bahasa Indonesia': 'id',
        '\u0939\u093f\u0928\u094d\u0926\u0940': 'hi',
        '\u0928\u0947\u092a\u093e\u0932\u0940': 'ne',
        'Tagalog': 'tl',
        '\u0e44\u0e17\u0e22': 'th',
        '\u0627\u0631\u062f\u0648': 'ur',
    }
    _FORMAT_HEIGHTS = {
        'SD': 360,
        'HD': 720,
    }
    _APPS_BASE_URL = 'https://apps.hkedcity.net'

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        title = (
            self._html_search_meta(
                ('ed_title', 'search.ed_title'), webpage, default=None)
            or self._search_regex(
                r'data-favorite_title_(?:eng|chi)=(["\'])(?P<id>(?:(?!\1).)+)\1',
                webpage, 'title', default=None, group='url')
            or self._html_search_regex(
                r'<h1>([^<]+)</h1>', webpage, 'title', default=None)
            or self._og_search_title(webpage)
        )

        file_id = self._search_regex(
            r'post_var\[["\']file_id["\']\s*\]\s*=\s*(.+?);',
            webpage, 'file ID')
        curr_url = self._search_regex(
            r'post_var\[["\']curr_url["\']\s*\]\s*=\s*"(.+?)";',
            webpage, 'curr URL')
        data = {
            'action': 'get_info',
            'curr_url': curr_url,
            'file_id': file_id,
            'video_url': file_id,
        }

        response = self._download_json(
            self._APPS_BASE_URL + '/media/play/handler.php', video_id,
            data=urlencode_postdata(data),
            headers=merge_dicts({
                'Content-Type': 'application/x-www-form-urlencoded'},
                self.geo_verification_headers()))

        result = response['result']

        if not response.get('success') or not response.get('access'):
            error = clean_html(response.get('access_err_msg'))
            if 'Video streaming is not available in your country' in error:
                self.raise_geo_restricted(
                    msg=error, countries=self._GEO_COUNTRIES)
            else:
                raise ExtractorError(error, expected=True)

        formats = []

        width = int_or_none(result.get('width'))
        height = int_or_none(result.get('height'))

        playlist0 = result['playlist'][0]
        for fmt in playlist0['sources']:
            file_url = urljoin(self._APPS_BASE_URL, fmt.get('file'))
            if not file_url:
                continue
            # If we ever wanted to provide the final resolved URL that
            # does not require cookies, albeit with a shorter lifespan:
            #     urlh = self._downloader.urlopen(file_url)
            #     resolved_url = urlh.geturl()
            label = fmt.get('label')
            h = self._FORMAT_HEIGHTS.get(label)
            w = h * width // height if h and width and height else None
            formats.append({
                'format_id': label,
                'ext': fmt.get('type'),
                'url': file_url,
                'width': w,
                'height': h,
            })
        self._sort_formats(formats)

        subtitles = {}
        tracks = try_get(playlist0, lambda x: x['tracks'], list) or []
        for track in tracks:
            if not isinstance(track, dict):
                continue
            track_kind = str_or_none(track.get('kind'))
            if not track_kind or not isinstance(track_kind, compat_str):
                continue
            if track_kind.lower() not in ('captions', 'subtitles'):
                continue
            track_url = urljoin(self._APPS_BASE_URL, track.get('file'))
            if not track_url:
                continue
            track_label = track.get('label')
            subtitles.setdefault(self._CC_LANGS.get(
                track_label, track_label), []).append({
                    'url': self._proto_relative_url(track_url),
                    'ext': 'srt',
                })

        # Likes
        emotion = self._download_json(
            'https://emocounter.hkedcity.net/handler.php', video_id,
            data=urlencode_postdata({
                'action': 'get_emotion',
                'data[bucket_id]': 'etv',
                'data[identifier]': video_id,
            }),
            headers={'Content-Type': 'application/x-www-form-urlencoded'},
            fatal=False) or {}
        like_count = int_or_none(try_get(
            emotion, lambda x: x['data']['emotion_data'][0]['count']))

        return {
            'id': video_id,
            'title': title,
            'description': self._html_search_meta(
                'description', webpage, fatal=False),
            'upload_date': unified_strdate(self._html_search_meta(
                'ed_date', webpage, fatal=False), day_first=False),
            'duration': int_or_none(result.get('length')),
            'formats': formats,
            'subtitles': subtitles,
            'thumbnail': urljoin(self._APPS_BASE_URL, result.get('image')),
            'view_count': parse_count(result.get('view_count')),
            'like_count': like_count,
        }


code:
# coding: utf-8
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import (
    int_or_none,
    parse_duration,
)

class HornBunnyIE(InfoExtractor):
    _VALID_URL = r'http?://(?:www\.)?hornbunny\.com/videos/(?P<title_dash>[a-z-]+)-(?P<id>\d+)\.html'
    _TEST = {
        'url': 'http://hornbunny.com/videos/panty-slut-jerk-off-instruction-5227.html',
        'md5': 'e20fd862d1894b67564c96f180f43924',
        'info_dict': {
            'id': '5227',
            'ext': 'mp4',
            'title': 'panty slut jerk off instruction',
            'duration': 550,
            'age_limit': 18,
            'view_count': int,
            'thumbnail': r're:^https?://.*\.jpg$',
        }
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)

        webpage = self._download_webpage(url, video_id)
        title = self._og_search_title(webpage)
        info_dict = self._parse_html5_media_entries(url, webpage, video_id)[0]

        duration = parse_duration(self._search_regex(
            r'Runtime:\s*([0-9:]+)
',
            webpage, 'duration', fatal=False))
        view_count = int_or_none(self._search_regex(
            r'Views:\s*(\d+)
',
            webpage, 'view count', fatal=False))

        info_dict.update({
            'id': video_id,
            'title': title,
            'duration': duration,
            'view_count': view_count,
            'age_limit': 18,
        })

        return info_dict

repo_name: rrosajp/youtube


code:
from __future__ import unicode_literals

from .common import InfoExtractor
from ..compat import compat_b64decode
from ..utils import (
    ExtractorError,
    HEADRequest,
    sanitized_Request,
    urlencode_postdata,
)

class HotNewHipHopIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?hotnewhiphop\.com/.*\.(?P<id>.*)\.html'
    _TEST = {
        'url': 'http://www.hotnewhiphop.com/freddie-gibbs-lay-it-down-song.1435540.html',
        'md5': '2c2cd2f76ef11a9b3b581e8b232f3d96',
        'info_dict': {
            'id': '1435540',
            'ext': 'mp3',
            'title': 'Freddie Gibbs - Lay It Down'
        }
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        video_url_base64 = self._search_regex(
            r'data-path="(.*?)"', webpage, 'video URL', default=None)

        if video_url_base64 is None:
            video_url = self._search_regex(
                r'"contentUrl" content="(.*?)"', webpage, 'content URL')
            return self.url_result(video_url, ie='Youtube')

        reqdata = urlencode_postdata([
            ('mediaType', 's'),
            ('mediaId', video_id),
        ])
        r = sanitized_Request(
            'http://www.hotnewhiphop.com/ajax/media/getActions/', data=reqdata)
        r.add_header('Content-Type', 'application/x-www-form-urlencoded')
        mkd = self._download_json(
            r, video_id, note='Requesting media key',
            errnote='Could not download media key')
        if 'mediaKey' not in mkd:
            raise ExtractorError('Did not get a media key')

        redirect_url = compat_b64decode(video_url_base64).decode('utf-8')
        redirect_req = HEADRequest(redirect_url)
        req = self._request_webpage(
            redirect_req, video_id,
            note='Resolving final URL', errnote='Could not resolve final URL')
        video_url = req.geturl()
        if video_url.endswith('.html'):
            raise ExtractorError('Redirect failed')

        video_title = self._og_search_title(webpage).strip()

        return {
            'id': video_id,
            'url': video_url,
            'title': video_title,
            'thumbnail': self._og_search_thumbnail(webpage),
        }


code:
# coding: utf-8
from __future__ import unicode_literals

import hashlib
import hmac
import re
import time
import uuid

from .common import InfoExtractor
from ..compat import (
    compat_HTTPError,
    compat_str,
)
from ..utils import (
    determine_ext,
    ExtractorError,
    int_or_none,
    str_or_none,
    try_get,
    url_or_none,
)

class HotStarBaseIE(InfoExtractor):
    _AKAMAI_ENCRYPTION_KEY = b'\x05\xfc\x1a\x01\xca\xc9\x4b\xc4\x12\xfc\x53\x12\x07\x75\xf9\xee'

    def _call_api_impl(self, path, video_id, query):
        st = int(time.time())
        exp = st + 6000
        auth = 'st=%d~exp=%d~acl=/*' % (st, exp)
        auth += '~hmac=' + hmac.new(self._AKAMAI_ENCRYPTION_KEY, auth.encode(), hashlib.sha256).hexdigest()
        response = self._download_json(
            'https://api.hotstar.com/' + path, video_id, headers={
                'hotstarauth': auth,
                'x-country-code': 'IN',
                'x-platform-code': 'JIO',
            }, query=query)
        if response['statusCode'] != 'OK':
            raise ExtractorError(
                response['body']['message'], expected=True)
        return response['body']['results']

    def _call_api(self, path, video_id, query_name='contentId'):
        return self._call_api_impl(path, video_id, {
            query_name: video_id,
            'tas': 10000,
        })

    def _call_api_v2(self, path, video_id):
        return self._call_api_impl(
            '%s/in/contents/%s' % (path, video_id), video_id, {
                'desiredConfig': 'encryption:plain;ladder:phone,tv;package:hls,dash',
                'client': 'mweb',
                'clientVersion': '6.18.0',
                'deviceId': compat_str(uuid.uuid4()),
                'osName': 'Windows',
                'osVersion': '10',
            })

class HotStarIE(HotStarBaseIE):
    IE_NAME = 'hotstar'
    _VALID_URL = r'https?://(?:www\.)?hotstar\.com/(?:.+?[/-])?(?P<id>\d{10})'
    _TESTS = [{
        # contentData
        'url': 'https://www.hotstar.com/can-you-not-spread-rumours/1000076273',
        'info_dict': {
            'id': '1000076273',
            'ext': 'mp4',
            'title': 'Can You Not Spread Rumours?',
            'description': 'md5:c957d8868e9bc793ccb813691cc4c434',
            'timestamp': 1447248600,
            'upload_date': '20151111',
            'duration': 381,
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        }
    }, {
        # contentDetail
        'url': 'https://www.hotstar.com/movies/radha-gopalam/1000057157',
        'only_matching': True,
    }, {
        'url': 'http://www.hotstar.com/sports/cricket/rajitha-sizzles-on-debut-with-329/2001477583',
        'only_matching': True,
    }, {
        'url': 'http://www.hotstar.com/1000000515',
        'only_matching': True,
    }, {
        # only available via api v2
        'url': 'https://www.hotstar.com/tv/ek-bhram-sarvagun-sampanna/s-2116/janhvi-targets-suman/1000234847',
        'only_matching': True,
    }]
    _GEO_BYPASS = False

    def _real_extract(self, url):
        video_id = self._match_id(url)

        webpage = self._download_webpage(url, video_id)
        app_state = self._parse_json(self._search_regex(
            r'<script>window\.APP_STATE\s*=\s*({.+?})</script>',
            webpage, 'app state'), video_id)
        video_data = {}
        getters = list(
            lambda x, k=k: x['initialState']['content%s' % k]['content']
            for k in ('Data', 'Detail')
        )
        for v in app_state.values():
            content = try_get(v, getters, dict)
            if content and content.get('contentId') == video_id:
                video_data = content
                break

        title = video_data['title']

        if video_data.get('drmProtected'):
            raise ExtractorError('This video is DRM protected.', expected=True)

        headers = {'Referer': url}
        formats = []
        geo_restricted = False
        playback_sets = self._call_api_v2('h/v2/play', video_id)['playBackSets']
        for playback_set in playback_sets:
            if not isinstance(playback_set, dict):
                continue
            format_url = url_or_none(playback_set.get('playbackUrl'))
            if not format_url:
                continue
            format_url = re.sub(
                r'(?<=//staragvod)(\d)', r'web\1', format_url)
            tags = str_or_none(playback_set.get('tagsCombination')) or ''
            if tags and 'encryption:plain' not in tags:
                continue
            ext = determine_ext(format_url)
            try:
                if 'package:hls' in tags or ext == 'm3u8':
                    formats.extend(self._extract_m3u8_formats(
                        format_url, video_id, 'mp4',
                        entry_protocol='m3u8_native',
                        m3u8_id='hls', headers=headers))
                elif 'package:dash' in tags or ext == 'mpd':
                    formats.extend(self._extract_mpd_formats(
                        format_url, video_id, mpd_id='dash', headers=headers))
                elif ext == 'f4m':
                    # produce broken files
                    pass
                else:
                    formats.append({
                        'url': format_url,
                        'width': int_or_none(playback_set.get('width')),
                        'height': int_or_none(playback_set.get('height')),
                    })
            except ExtractorError as e:
                if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                    geo_restricted = True
                continue
        if not formats and geo_restricted:
            self.raise_geo_restricted(countries=['IN'])
        self._sort_formats(formats)

        for f in formats:
            f.setdefault('http_headers', {}).update(headers)

        return {
            'id': video_id,
            'title': title,
            'description': video_data.get('description'),
            'duration': int_or_none(video_data.get('duration')),
            'timestamp': int_or_none(video_data.get('broadcastDate') or video_data.get('startDate')),
            'formats': formats,
            'channel': video_data.get('channelName'),
            'channel_id': video_data.get('channelId'),
            'series': video_data.get('showName'),
            'season': video_data.get('seasonName'),
            'season_number': int_or_none(video_data.get('seasonNo')),
            'season_id': video_data.get('seasonId'),
            'episode': title,
            'episode_number': int_or_none(video_data.get('episodeNo')),
        }

class HotStarPlaylistIE(HotStarBaseIE):
    IE_NAME = 'hotstar:playlist'
    _VALID_URL = r'https?://(?:www\.)?hotstar\.com/tv/[^/]+/s-\w+/list/[^/]+/t-(?P<id>\w+)'
    _TESTS = [{
        'url': 'https://www.hotstar.com/tv/savdhaan-india/s-26/list/popular-clips/t-3_2_26',
        'info_dict': {
            'id': '3_2_26',
        },
        'playlist_mincount': 20,
    }, {
        'url': 'https://www.hotstar.com/tv/savdhaan-india/s-26/list/extras/t-2480',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        playlist_id = self._match_id(url)

        collection = self._call_api('o/v1/tray/find', playlist_id, 'uqId')

        entries = [
            self.url_result(
                'https://www.hotstar.com/%s' % video['contentId'],
                ie=HotStarIE.ie_key(), video_id=video['contentId'])
            for video in collection['assets']['items']
            if video.get('contentId')]

        return self.playlist_result(entries, playlist_id)


code:
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import parse_iso8601

class HowcastIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?howcast\.com/videos/(?P<id>\d+)'
    _TEST = {
        'url': 'http://www.howcast.com/videos/390161-How-to-Tie-a-Square-Knot-Properly',
        'md5': '7d45932269a288149483144f01b99789',
        'info_dict': {
            'id': '390161',
            'ext': 'mp4',
            'title': 'How to Tie a Square Knot Properly',
            'description': 'md5:dbe792e5f6f1489027027bf2eba188a3',
            'timestamp': 1276081287,
            'upload_date': '20100609',
            'duration': 56.823,
        },
        'params': {
            'skip_download': True,
        },
        'add_ie': ['Ooyala'],
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)

        webpage = self._download_webpage(url, video_id)

        embed_code = self._search_regex(
            r'<iframe[^>]+src="[^"]+\bembed_code=([^\b]+)\b',
            webpage, 'ooyala embed code')

        return {
            '_type': 'url_transparent',
            'ie_key': 'Ooyala',
            'url': 'ooyala:%s' % embed_code,
            'id': video_id,
            'timestamp': parse_iso8601(self._html_search_meta(
                'article:published_time', webpage, 'timestamp')),
        }


code:
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import (
    find_xpath_attr,
    int_or_none,
    js_to_json,
    unescapeHTML,
    determine_ext,
)

class HowStuffWorksIE(InfoExtractor):
    _VALID_URL = r'https?://[\da-z-]+\.(?:howstuffworks|stuff(?:(?:youshould|theydontwantyouto)know|toblowyourmind|momnevertoldyou)|(?:brain|car)stuffshow|fwthinking|geniusstuff)\.com/(?:[^/]+/)*(?:\d+-)?(?P<id>.+?)-video\.htm'
    _TESTS = [
        {
            'url': 'http://www.stufftoblowyourmind.com/videos/optical-illusions-video.htm',
            'md5': '76646a5acc0c92bf7cd66751ca5db94d',
            'info_dict': {
                'id': '855410',
                'ext': 'mp4',
                'title': 'Your Trickster Brain: Optical Illusions -- Science on the Web',
                'description': 'md5:e374ff9561f6833ad076a8cc0a5ab2fb',
            },
        },
        {
            'url': 'http://shows.howstuffworks.com/more-shows/why-does-balloon-stick-to-hair-video.htm',
            'only_matching': True,
        }
    ]

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)
        clip_js = self._search_regex(
            r'(?s)var clip = ({.*?});', webpage, 'clip info')
        clip_info = self._parse_json(
            clip_js, display_id, transform_source=js_to_json)

        video_id = clip_info['content_id']
        formats = []
        m3u8_url = clip_info.get('m3u8')
        if m3u8_url and determine_ext(m3u8_url) == 'm3u8':
            formats.extend(self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', format_id='hls', fatal=True))
        flv_url = clip_info.get('flv_url')
        if flv_url:
            formats.append({
                'url': flv_url,
                'format_id': 'flv',
            })
        for video in clip_info.get('mp4', []):
            formats.append({
                'url': video['src'],
                'format_id': 'mp4-%s' % video['bitrate'],
                'vbr': int_or_none(video['bitrate'].rstrip('k')),
            })

        if not formats:
            smil = self._download_xml(
                'http://services.media.howstuffworks.com/videos/%s/smil-service.smil' % video_id,
                video_id, 'Downloading video SMIL')

            http_base = find_xpath_attr(
                smil,
                './{0}head/{0}meta'.format('{http://www.w3.org/2001/SMIL20/Language}'),
                'name',
                'httpBase').get('content')

            URL_SUFFIX = '?v=2.11.3&fp=LNX 11,2,202,356&r=A&g=A'

            for video in smil.findall(
                    './{0}body/{0}switch/{0}video'.format('{http://www.w3.org/2001/SMIL20/Language}')):
                vbr = int_or_none(video.attrib['system-bitrate'], scale=1000)
                formats.append({
                    'url': '%s/%s%s' % (http_base, video.attrib['src'], URL_SUFFIX),
                    'format_id': '%dk' % vbr,
                    'vbr': vbr,
                })

        self._sort_formats(formats)

        return {
            'id': '%s' % video_id,
            'display_id': display_id,
            'title': unescapeHTML(clip_info['clip_title']),
            'description': unescapeHTML(clip_info.get('caption')),
            'thumbnail': clip_info.get('video_still_url'),
            'duration': int_or_none(clip_info.get('duration')),
            'formats': formats,
        }


code:
# coding: utf-8
from __future__ import unicode_literals

import json
import re

from .common import InfoExtractor
from ..compat import compat_HTTPError
from ..utils import (
    clean_html,
    ExtractorError,
    int_or_none,
    parse_age_limit,
    sanitized_Request,
    try_get,
)

class HRTiBaseIE(InfoExtractor):
    """
        Base Information Extractor for Croatian Radiotelevision
        video on demand site https://hrti.hrt.hr
        Reverse engineered from the JavaScript app in app.min.js
    """
    _NETRC_MACHINE = 'hrti'

    _APP_LANGUAGE = 'hr'
    _APP_VERSION = '1.1'
    _APP_PUBLICATION_ID = 'all_in_one'
    _API_URL = 'http://clientapi.hrt.hr/client_api.php/config/identify/format/json'

    def _initialize_api(self):
        init_data = {
            'application_publication_id': self._APP_PUBLICATION_ID
        }

        uuid = self._download_json(
            self._API_URL, None, note='Downloading uuid',
            errnote='Unable to download uuid',
            data=json.dumps(init_data).encode('utf-8'))['uuid']

        app_data = {
            'uuid': uuid,
            'application_publication_id': self._APP_PUBLICATION_ID,
            'application_version': self._APP_VERSION
        }

        req = sanitized_Request(self._API_URL, data=json.dumps(app_data).encode('utf-8'))
        req.get_method = lambda: 'PUT'

        resources = self._download_json(
            req, None, note='Downloading session information',
            errnote='Unable to download session information')

        self._session_id = resources['session_id']

        modules = resources['modules']

        self._search_url = modules['vod_catalog']['resources']['search']['uri'].format(
            language=self._APP_LANGUAGE,
            application_id=self._APP_PUBLICATION_ID)

        self._login_url = (modules['user']['resources']['login']['uri']
                           + '/format/json').format(session_id=self._session_id)

        self._logout_url = modules['user']['resources']['logout']['uri']

    def _login(self):
        username, password = self._get_login_info()
        # TODO: figure out authentication with cookies
        if username is None or password is None:
            self.raise_login_required()

        auth_data = {
            'username': username,
            'password': password,
        }

        try:
            auth_info = self._download_json(
                self._login_url, None, note='Logging in', errnote='Unable to log in',
                data=json.dumps(auth_data).encode('utf-8'))
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 406:
                auth_info = self._parse_json(e.cause.read().encode('utf-8'), None)
            else:
                raise

        error_message = auth_info.get('error', {}).get('message')
        if error_message:
            raise ExtractorError(
                '%s said: %s' % (self.IE_NAME, error_message),
                expected=True)

        self._token = auth_info['secure_streaming_token']

    def _real_initialize(self):
        self._initialize_api()
        self._login()

class HRTiIE(HRTiBaseIE):
    _VALID_URL = r'''(?x)
                        (?:
                            hrti:(?P<short_id>[0-9]+)|
                            https?://
                                hrti\.hrt\.hr/(?:\#/)?video/show/(?P<id>[0-9]+)/(?P<display_id>[^/]+)?
                        )
                    '''
    _TESTS = [{
        'url': 'https://hrti.hrt.hr/#/video/show/2181385/republika-dokumentarna-serija-16-hd',
        'info_dict': {
            'id': '2181385',
            'display_id': 'republika-dokumentarna-serija-16-hd',
            'ext': 'mp4',
            'title': 'REPUBLIKA, dokumentarna serija (1/6) (HD)',
            'description': 'md5:48af85f620e8e0e1df4096270568544f',
            'duration': 2922,
            'view_count': int,
            'average_rating': int,
            'episode_number': int,
            'season_number': int,
            'age_limit': 12,
        },
        'skip': 'Requires account credentials',
    }, {
        'url': 'https://hrti.hrt.hr/#/video/show/2181385/',
        'only_matching': True,
    }, {
        'url': 'hrti:2181385',
        'only_matching': True,
    }, {
        'url': 'https://hrti.hrt.hr/video/show/3873068/cuvar-dvorca-dramska-serija-14',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('short_id') or mobj.group('id')
        display_id = mobj.group('display_id') or video_id

        video = self._download_json(
            '%s/video_id/%s/format/json' % (self._search_url, video_id),
            display_id, 'Downloading video metadata JSON')['video'][0]

        title_info = video['title']
        title = title_info['title_long']

        movie = video['video_assets']['movie'][0]
        m3u8_url = movie['url'].format(TOKEN=self._token)
        formats = self._extract_m3u8_formats(
            m3u8_url, display_id, 'mp4', entry_protocol='m3u8_native',
            m3u8_id='hls')
        self._sort_formats(formats)

        description = clean_html(title_info.get('summary_long'))
        age_limit = parse_age_limit(video.get('parental_control', {}).get('rating'))
        view_count = int_or_none(video.get('views'))
        average_rating = int_or_none(video.get('user_rating'))
        duration = int_or_none(movie.get('duration'))

        return {
            'id': video_id,
            'display_id': display_id,
            'title': title,
            'description': description,
            'duration': duration,
            'view_count': view_count,
            'average_rating': average_rating,
            'age_limit': age_limit,
            'formats': formats,
        }

class HRTiPlaylistIE(HRTiBaseIE):
    _VALID_URL = r'https?://hrti\.hrt\.hr/(?:#/)?video/list/category/(?P<id>[0-9]+)/(?P<display_id>[^/]+)?'
    _TESTS = [{
        'url': 'https://hrti.hrt.hr/#/video/list/category/212/ekumena',
        'info_dict': {
            'id': '212',
            'title': 'ekumena',
        },
        'playlist_mincount': 8,
        'skip': 'Requires account credentials',
    }, {
        'url': 'https://hrti.hrt.hr/#/video/list/category/212/',
        'only_matching': True,
    }, {
        'url': 'https://hrti.hrt.hr/video/list/category/212/ekumena',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        category_id = mobj.group('id')
        display_id = mobj.group('display_id') or category_id

        response = self._download_json(
            '%s/category_id/%s/format/json' % (self._search_url, category_id),
            display_id, 'Downloading video metadata JSON')

        video_ids = try_get(
            response, lambda x: x['video_listings'][0]['alternatives'][0]['list'],
            list) or [video['id'] for video in response.get('videos', []) if video.get('id')]

        entries = [self.url_result('hrti:%s' % video_id) for video_id in video_ids]

        return self.playlist_result(entries, category_id, display_id)


code:
# coding: utf-8
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import (
    parse_duration,
    parse_iso8601,
)

class HuajiaoIE(InfoExtractor):
    IE_DESC = '花椒直播'
    _VALID_URL = r'https?://(?:www\.)?huajiao\.com/l/(?P<id>[0-9]+)'
    _TEST = {
        'url': 'http://www.huajiao.com/l/38941232',
        'md5': 'd08bf9ac98787d24d1e4c0283f2d372d',
        'info_dict': {
            'id': '38941232',
            'ext': 'mp4',
            'title': '#新人求关注#',
            'description': 're:.*',
            'duration': 2424.0,
            'thumbnail': r're:^https?://.*\.jpg$',
            'timestamp': 1475866459,
            'upload_date': '20161007',
            'uploader': 'Penny_余姿昀',
            'uploader_id': '75206005',
        }
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        feed_json = self._search_regex(
            r'var\s+feed\s*=\s*({.+})', webpage, 'feed json')
        feed = self._parse_json(feed_json, video_id)

        description = self._html_search_meta(
            'description', webpage, 'description', fatal=False)

        def get(section, field):
            return feed.get(section, {}).get(field)

        return {
            'id': video_id,
            'title': feed['feed']['formated_title'],
            'description': description,
            'duration': parse_duration(get('feed', 'duration')),
            'thumbnail': get('feed', 'image'),
            'timestamp': parse_iso8601(feed.get('creatime'), ' '),
            'uploader': get('author', 'nickname'),
            'uploader_id': get('author', 'uid'),
            'formats': self._extract_m3u8_formats(
                feed['feed']['m3u8'], video_id, 'mp4', 'm3u8_native'),
        }


code:
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import (
    determine_ext,
    parse_duration,
    unified_strdate,
)

class HuffPostIE(InfoExtractor):
    IE_DESC = 'Huffington Post'
    _VALID_URL = r'''(?x)
        https?://(embed\.)?live\.huffingtonpost\.com/
        (?:
            r/segment/[^/]+/|
            HPLEmbedPlayer/\?segmentId=
        )
        (?P<id>[0-9a-f]+)'''

    _TEST = {
        'url': 'http://live.huffingtonpost.com/r/segment/legalese-it/52dd3e4b02a7602131000677',
        'md5': '55f5e8981c1c80a64706a44b74833de8',
        'info_dict': {
            'id': '52dd3e4b02a7602131000677',
            'ext': 'mp4',
            'title': 'Legalese It! with @MikeSacksHP',
            'description': 'This week on Legalese It, Mike talks to David Bosco about his new book on the ICC, "Rough Justice," he also discusses the Virginia AG\'s historic stance on gay marriage, the execution of Edgar Tamayo, the ICC\'s delay of Kenya\'s President and more.  ',
            'duration': 1549,
            'upload_date': '20140124',
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
        'expected_warnings': ['HTTP Error 404: Not Found'],
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)

        api_url = 'http://embed.live.huffingtonpost.com/api/segments/%s.json' % video_id
        data = self._download_json(api_url, video_id)['data']

        video_title = data['title']
        duration = parse_duration(data.get('running_time'))
        upload_date = unified_strdate(
            data.get('schedule', {}).get('starts_at') or data.get('segment_start_date_time'))
        description = data.get('description')

        thumbnails = []
        for url in filter(None, data['images'].values()):
            m = re.match(r'.*-([0-9]+x[0-9]+)\.', url)
            if not m:
                continue
            thumbnails.append({
                'url': url,
                'resolution': m.group(1),
            })

        formats = []
        sources = data.get('sources', {})
        live_sources = list(sources.get('live', {}).items()) + list(sources.get('live_again', {}).items())
        for key, url in live_sources:
            ext = determine_ext(url)
            if ext == 'm3u8':
                formats.extend(self._extract_m3u8_formats(
                    url, video_id, ext='mp4', m3u8_id='hls', fatal=False))
            elif ext == 'f4m':
                formats.extend(self._extract_f4m_formats(
                    url + '?hdcore=2.9.5', video_id, f4m_id='hds', fatal=False))
            else:
                formats.append({
                    'format': key,
                    'format_id': key.replace('/', '.'),
                    'ext': 'mp4',
                    'url': url,
                    'vcodec': 'none' if key.startswith('audio/') else None,
                })

        if not formats and data.get('fivemin_id'):
            return self.url_result('5min:%s' % data['fivemin_id'])

        self._sort_formats(formats)

        return {
            'id': video_id,
            'title': video_title,
            'description': description,
            'formats': formats,
            'duration': duration,
            'upload_date': upload_date,
            'thumbnails': thumbnails,
        }


code:
# coding: utf-8
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import (
    int_or_none,
    urlencode_postdata,
)

class HungamaIE(InfoExtractor):
    _VALID_URL = r'''(?x)
                    https?://
                        (?:www\.)?hungama\.com/
                        (?:
                            (?:video|movie)/[^/]+/|
                            tv-show/(?:[^/]+/){2}\d+/episode/[^/]+/
                        )
                        (?P<id>\d+)
                    '''
    _TESTS = [{
        'url': 'http://www.hungama.com/video/krishna-chants/39349649/',
        'md5': 'a845a6d1ebd08d80c1035126d49bd6a0',
        'info_dict': {
            'id': '2931166',
            'ext': 'mp4',
            'title': 'Lucky Ali - Kitni Haseen Zindagi',
            'track': 'Kitni Haseen Zindagi',
            'artist': 'Lucky Ali',
            'album': 'Aks',
            'release_year': 2000,
        }
    }, {
        'url': 'https://www.hungama.com/movie/kahaani-2/44129919/',
        'only_matching': True,
    }, {
        'url': 'https://www.hungama.com/tv-show/padded-ki-pushup/season-1/44139461/episode/ep-02-training-sasu-pathlaag-karing/44139503/',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        webpage = self._download_webpage(url, video_id)

        info = self._search_json_ld(webpage, video_id)

        m3u8_url = self._download_json(
            'https://www.hungama.com/index.php', video_id,
            data=urlencode_postdata({'content_id': video_id}), headers={
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                'X-Requested-With': 'XMLHttpRequest',
            }, query={
                'c': 'common',
                'm': 'get_video_mdn_url',
            })['stream_url']

        formats = self._extract_m3u8_formats(
            m3u8_url, video_id, ext='mp4', entry_protocol='m3u8_native',
            m3u8_id='hls')
        self._sort_formats(formats)

        info.update({
            'id': video_id,
            'formats': formats,
        })
        return info

class HungamaSongIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?hungama\.com/song/[^/]+/(?P<id>\d+)'
    _TEST = {
        'url': 'https://www.hungama.com/song/kitni-haseen-zindagi/2931166/',
        'md5': 'a845a6d1ebd08d80c1035126d49bd6a0',
        'info_dict': {
            'id': '2931166',
            'ext': 'mp4',
            'title': 'Lucky Ali - Kitni Haseen Zindagi',
            'track': 'Kitni Haseen Zindagi',
            'artist': 'Lucky Ali',
            'album': 'Aks',
            'release_year': 2000,
        }
    }

    def _real_extract(self, url):
        audio_id = self._match_id(url)

        data = self._download_json(
            'https://www.hungama.com/audio-player-data/track/%s' % audio_id,
            audio_id, query={'_country': 'IN'})[0]

        track = data['song_name']
        artist = data.get('singer_name')

        m3u8_url = self._download_json(
            data.get('file') or data['preview_link'],
            audio_id)['response']['media_url']

        formats = self._extract_m3u8_formats(
            m3u8_url, audio_id, ext='mp4', entry_protocol='m3u8_native',
            m3u8_id='hls')
        self._sort_formats(formats)

        title = '%s - %s' % (artist, track) if artist else track
        thumbnail = data.get('img_src') or data.get('album_image')

        return {
            'id': audio_id,
            'title': title,
            'thumbnail': thumbnail,
            'track': track,
            'artist': artist,
            'album': data.get('album_name'),
            'release_year': int_or_none(data.get('date')),
            'formats': formats,
        }


code:
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import int_or_none

class HypemIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?hypem\.com/track/(?P<id>[0-9a-z]{5})'
    _TEST = {
        'url': 'http://hypem.com/track/1v6ga/BODYWORK+-+TAME',
        'md5': 'b9cc91b5af8995e9f0c1cee04c575828',
        'info_dict': {
            'id': '1v6ga',
            'ext': 'mp3',
            'title': 'Tame',
            'uploader': 'BODYWORK',
            'timestamp': 1371810457,
            'upload_date': '20130621',
        }
    }

    def _real_extract(self, url):
        track_id = self._match_id(url)

        response = self._download_webpage(url, track_id)

        track = self._parse_json(self._html_search_regex(
            r'(?s)<script\s+type="application/json"\s+id="displayList-data">(.+?)</script>',
            response, 'tracks'), track_id)['tracks'][0]

        track_id = track['id']
        title = track['song']

        final_url = self._download_json(
            'http://hypem.com/serve/source/%s/%s' % (track_id, track['key']),
            track_id, 'Downloading metadata', headers={
                'Content-Type': 'application/json'
            })['url']

        return {
            'id': track_id,
            'url': final_url,
            'ext': 'mp3',
            'title': title,
            'uploader': track.get('artist'),
            'duration': int_or_none(track.get('time')),
            'timestamp': int_or_none(track.get('ts')),
            'track': title,
        }


code:
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import (
    int_or_none,
    parse_iso8601,
)

class IGNIE(InfoExtractor):
    """
    Extractor for some of the IGN sites, like www.ign.com, es.ign.com de.ign.com.
    Some videos of it.ign.com are also supported
    """

    _VALID_URL = r'https?://.+?\.ign\.com/(?:[^/]+/)?(?P<type>videos|show_videos|articles|feature|(?:[^/]+/\d+/video))(/.+)?/(?P<name_or_id>.+)'
    IE_NAME = 'ign.com'

    _API_URL_TEMPLATE = 'http://apis.ign.com/video/v3/videos/%s'
    _EMBED_RE = r'<iframe[^>]+?["\']((?:https?:)?//.+?\.ign\.com.+?/embed.+?)["\']'

    _TESTS = [
        {
            'url': 'http://www.ign.com/videos/2013/06/05/the-last-of-us-review',
            'md5': 'febda82c4bafecd2d44b6e1a18a595f8',
            'info_dict': {
                'id': '8f862beef863986b2785559b9e1aa599',
                'ext': 'mp4',
                'title': 'The Last of Us Review',
                'description': 'md5:c8946d4260a4d43a00d5ae8ed998870c',
                'timestamp': 1370440800,
                'upload_date': '20130605',
                'uploader_id': 'cberidon@ign.com',
            }
        },
        {
            'url': 'http://me.ign.com/en/feature/15775/100-little-things-in-gta-5-that-will-blow-your-mind',
            'info_dict': {
                'id': '100-little-things-in-gta-5-that-will-blow-your-mind',
            },
            'playlist': [
                {
                    'info_dict': {
                        'id': '5ebbd138523268b93c9141af17bec937',
                        'ext': 'mp4',
                        'title': 'GTA 5 Video Review',
                        'description': 'Rockstar drops the mic on this generation of games. Watch our review of the masterly Grand Theft Auto V.',
                        'timestamp': 1379339880,
                        'upload_date': '20130916',
                        'uploader_id': 'danieljkrupa@gmail.com',
                    },
                },
                {
                    'info_dict': {
                        'id': '638672ee848ae4ff108df2a296418ee2',
                        'ext': 'mp4',
                        'title': '26 Twisted Moments from GTA 5 in Slow Motion',
                        'description': 'The twisted beauty of GTA 5 in stunning slow motion.',
                        'timestamp': 1386878820,
                        'upload_date': '20131212',
                        'uploader_id': 'togilvie@ign.com',
                    },
                },
            ],
            'params': {
                'skip_download': True,
            },
        },
        {
            'url': 'http://www.ign.com/articles/2014/08/15/rewind-theater-wild-trailer-gamescom-2014?watch',
            'md5': '618fedb9c901fd086f6f093564ef8558',
            'info_dict': {
                'id': '078fdd005f6d3c02f63d795faa1b984f',
                'ext': 'mp4',
                'title': 'Rewind Theater - Wild Trailer Gamescom 2014',
                'description': 'Brian and Jared explore Michel Ancel\'s captivating new preview.',
                'timestamp': 1408047180,
                'upload_date': '20140814',
                'uploader_id': 'jamesduggan1990@gmail.com',
            },
        },
        {
            'url': 'http://me.ign.com/en/videos/112203/video/how-hitman-aims-to-be-different-than-every-other-s',
            'only_matching': True,
        },
        {
            'url': 'http://me.ign.com/ar/angry-birds-2/106533/video/lrd-ldyy-lwl-lfylm-angry-birds',
            'only_matching': True,
        },
        {
            # videoId pattern
            'url': 'http://www.ign.com/articles/2017/06/08/new-ducktales-short-donalds-birthday-doesnt-go-as-planned',
            'only_matching': True,
        },
    ]

    def _find_video_id(self, webpage):
        res_id = [
            r'"video_id"\s*:\s*"(.*?)"',
            r'class="hero-poster[^"]*?"[^>]*id="(.+?)"',
            r'data-video-id="(.+?)"',
            r'<object id="vid_(.+?)"',
            r'<meta name="og:image" content=".*/(.+?)-(.+?)/.+.jpg"',
            r'videoId"\s*:\s*"(.+?)"',
            r'videoId["\']\s*:\s*["\']([^"\']+?)["\']',
        ]
        return self._search_regex(res_id, webpage, 'video id', default=None)

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        name_or_id = mobj.group('name_or_id')
        page_type = mobj.group('type')
        webpage = self._download_webpage(url, name_or_id)
        if page_type != 'video':
            multiple_urls = re.findall(
                r'<param name="flashvars"[^>]*value="[^"]*?url=(https?://www\.ign\.com/videos/.*?)["&]',
                webpage)
            if multiple_urls:
                entries = [self.url_result(u, ie='IGN') for u in multiple_urls]
                return {
                    '_type': 'playlist',
                    'id': name_or_id,
                    'entries': entries,
                }

        video_id = self._find_video_id(webpage)
        if not video_id:
            return self.url_result(self._search_regex(
                self._EMBED_RE, webpage, 'embed url'))
        return self._get_video_info(video_id)

    def _get_video_info(self, video_id):
        api_data = self._download_json(
            self._API_URL_TEMPLATE % video_id, video_id)

        formats = []
        m3u8_url = api_data['refs'].get('m3uUrl')
        if m3u8_url:
            formats.extend(self._extract_m3u8_formats(
                m3u8_url, video_id, 'mp4', 'm3u8_native',
                m3u8_id='hls', fatal=False))
        f4m_url = api_data['refs'].get('f4mUrl')
        if f4m_url:
            formats.extend(self._extract_f4m_formats(
                f4m_url, video_id, f4m_id='hds', fatal=False))
        for asset in api_data['assets']:
            formats.append({
                'url': asset['url'],
                'tbr': asset.get('actual_bitrate_kbps'),
                'fps': asset.get('frame_rate'),
                'height': int_or_none(asset.get('height')),
                'width': int_or_none(asset.get('width')),
            })
        self._sort_formats(formats)

        thumbnails = [{
            'url': thumbnail['url']
        } for thumbnail in api_data.get('thumbnails', [])]

        metadata = api_data['metadata']

        return {
            'id': api_data.get('videoId') or video_id,
            'title': metadata.get('longTitle') or metadata.get('name') or metadata.get['title'],
            'description': metadata.get('description'),
            'timestamp': parse_iso8601(metadata.get('publishDate')),
            'duration': int_or_none(metadata.get('duration')),
            'display_id': metadata.get('slug') or video_id,
            'uploader_id': metadata.get('creator'),
            'thumbnails': thumbnails,
            'formats': formats,
        }

class OneUPIE(IGNIE):
    _VALID_URL = r'https?://gamevideos\.1up\.com/(?P<type>video)/id/(?P<name_or_id>.+)\.html'
    IE_NAME = '1up.com'

    _TESTS = [{
        'url': 'http://gamevideos.1up.com/video/id/34976.html',
        'md5': 'c9cc69e07acb675c31a16719f909e347',
        'info_dict': {
            'id': '34976',
            'ext': 'mp4',
            'title': 'Sniper Elite V2 - Trailer',
            'description': 'md5:bf0516c5ee32a3217aa703e9b1bc7826',
            'timestamp': 1313099220,
            'upload_date': '20110811',
            'uploader_id': 'IGN',
        }
    }]

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        result = super(OneUPIE, self)._real_extract(url)
        result['id'] = mobj.group('name_or_id')
        return result

class PCMagIE(IGNIE):
    _VALID_URL = r'https?://(?:www\.)?pcmag\.com/(?P<type>videos|article2)(/.+)?/(?P<name_or_id>.+)'
    IE_NAME = 'pcmag'

    _EMBED_RE = r'iframe\.setAttribute\("src",\s*__util.objToUrlString\("http://widgets\.ign\.com/video/embed/content\.html?[^"]*url=([^"]+)["&]'

    _TESTS = [{
        'url': 'http://www.pcmag.com/videos/2015/01/06/010615-whats-new-now-is-gogo-snooping-on-your-data',
        'md5': '212d6154fd0361a2781075f1febbe9ad',
        'info_dict': {
            'id': 'ee10d774b508c9b8ec07e763b9125b91',
            'ext': 'mp4',
            'title': '010615_What\'s New Now: Is GoGo Snooping on Your Data?',
            'description': 'md5:a7071ae64d2f68cc821c729d4ded6bb3',
            'timestamp': 1420571160,
            'upload_date': '20150106',
            'uploader_id': 'cozzipix@gmail.com',
        }
    }, {
        'url': 'http://www.pcmag.com/article2/0,2817,2470156,00.asp',
        'md5': '94130c1ca07ba0adb6088350681f16c1',
        'info_dict': {
            'id': '042e560ba94823d43afcb12ddf7142ca',
            'ext': 'mp4',
            'title': 'HTC\'s Weird New Re Camera - What\'s New Now',
            'description': 'md5:53433c45df96d2ea5d0fda18be2ca908',
            'timestamp': 1412953920,
            'upload_date': '20141010',
            'uploader_id': 'chris_snyder@pcmag.com',
        }
    }]


code:
from __future__ import unicode_literals

import base64
import json
import re

from .common import InfoExtractor
from ..utils import (
    determine_ext,
    mimetype2ext,
    parse_duration,
    qualities,
    try_get,
    url_or_none,
)

class ImdbIE(InfoExtractor):
    IE_NAME = 'imdb'
    IE_DESC = 'Internet Movie Database trailers'
    _VALID_URL = r'https?://(?:www|m)\.imdb\.com/(?:video|title|list).*?[/-]vi(?P<id>\d+)'

    _TESTS = [{
        'url': 'http://www.imdb.com/video/imdb/vi2524815897',
        'info_dict': {
            'id': '2524815897',
            'ext': 'mp4',
            'title': 'No. 2',
            'description': 'md5:87bd0bdc61e351f21f20d2d7441cb4e7',
            'duration': 152,
        }
    }, {
        'url': 'http://www.imdb.com/video/_/vi2524815897',
        'only_matching': True,
    }, {
        'url': 'http://www.imdb.com/title/tt1667889/?ref_=ext_shr_eml_vi#lb-vi2524815897',
        'only_matching': True,
    }, {
        'url': 'http://www.imdb.com/title/tt1667889/#lb-vi2524815897',
        'only_matching': True,
    }, {
        'url': 'http://www.imdb.com/videoplayer/vi1562949145',
        'only_matching': True,
    }, {
        'url': 'http://www.imdb.com/title/tt4218696/videoplayer/vi2608641561',
        'only_matching': True,
    }, {
        'url': 'https://www.imdb.com/list/ls009921623/videoplayer/vi260482329',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        data = self._download_json(
            'https://www.imdb.com/ve/data/VIDEO_PLAYBACK_DATA', video_id,
            query={
                'key': base64.b64encode(json.dumps({
                    'type': 'VIDEO_PLAYER',
                    'subType': 'FORCE_LEGACY',
                    'id': 'vi%s' % video_id,
                }).encode()).decode(),
            })[0]

        quality = qualities(('SD', '480p', '720p', '1080p'))
        formats = []
        for encoding in data['videoLegacyEncodings']:
            if not encoding or not isinstance(encoding, dict):
                continue
            video_url = url_or_none(encoding.get('url'))
            if not video_url:
                continue
            ext = mimetype2ext(encoding.get(
                'mimeType')) or determine_ext(video_url)
            if ext == 'm3u8':
                formats.extend(self._extract_m3u8_formats(
                    video_url, video_id, 'mp4', entry_protocol='m3u8_native',
                    preference=1, m3u8_id='hls', fatal=False))
                continue
            format_id = encoding.get('definition')
            formats.append({
                'format_id': format_id,
                'url': video_url,
                'ext': ext,
                'quality': quality(format_id),
            })
        self._sort_formats(formats)

        webpage = self._download_webpage(
            'https://www.imdb.com/video/vi' + video_id, video_id)
        video_metadata = self._parse_json(self._search_regex(
            r'args\.push\(\s*({.+?})\s*\)\s*;', webpage,
            'video metadata'), video_id)

        video_info = video_metadata.get('VIDEO_INFO')
        if video_info and isinstance(video_info, dict):
            info = try_get(
                video_info, lambda x: x[list(video_info.keys())[0]][0], dict)
        else:
            info = {}

        title = self._html_search_meta(
            ['og:title', 'twitter:title'], webpage) or self._html_search_regex(
            r'<title>(.+?)</title>', webpage, 'title',
            default=None) or info['videoTitle']

        return {
            'id': video_id,
            'title': title,
            'alt_title': info.get('videoSubTitle'),
            'formats': formats,
            'description': info.get('videoDescription'),
            'thumbnail': url_or_none(try_get(
                video_metadata, lambda x: x['videoSlate']['source'])),
            'duration': parse_duration(info.get('videoRuntime')),
        }

class ImdbListIE(InfoExtractor):
    IE_NAME = 'imdb:list'
    IE_DESC = 'Internet Movie Database lists'
    _VALID_URL = r'https?://(?:www\.)?imdb\.com/list/ls(?P<id>\d{9})(?!/videoplayer/vi\d+)'
    _TEST = {
        'url': 'https://www.imdb.com/list/ls009921623/',
        'info_dict': {
            'id': '009921623',
            'title': 'The Bourne Legacy',
            'description': 'A list of trailers, clips, and more from The Bourne Legacy, starring Jeremy Renner and Rachel Weisz.',
        },
        'playlist_count': 8,
    }

    def _real_extract(self, url):
        list_id = self._match_id(url)
        webpage = self._download_webpage(url, list_id)
        entries = [
            self.url_result('http://www.imdb.com' + m, 'Imdb')
            for m in re.findall(r'href="(/list/ls%s/videoplayer/vi[^"]+)"' % list_id, webpage)]

        list_title = self._html_search_regex(
            r'
]+class="[^"]*header[^"]*"[^>]*>(.*?)
',
            webpage, 'list title')
        list_description = self._html_search_regex(
            r'
]+class="[^"]*list-description[^"]*"[^>]*>
(.*?)
',
            webpage, 'list description')

        return self.playlist_result(entries, list_id, list_title, list_description)


code:
# coding: utf-8
from __future__ import unicode_literals

import json
import re

from .common import InfoExtractor
from ..compat import compat_HTTPError
from ..utils import (
    ExtractorError,
    int_or_none,
    str_or_none,
    try_get,
)

class ImgGamingBaseIE(InfoExtractor):
    _API_BASE = 'https://dce-frontoffice.imggaming.com/api/v2/'
    _API_KEY = '857a1e5d-e35e-4fdf-805b-a87b6f8364bf'
    _HEADERS = None
    _MANIFEST_HEADERS = {'Accept-Encoding': 'identity'}
    _REALM = None
    _VALID_URL_TEMPL = r'https?://(?P<domain>%s)/(?P<type>live|playlist|video)/(?P<id>\d+)(?:\?.*?\bplaylistId=(?P<playlist_id>\d+))?'

    def _real_initialize(self):
        self._HEADERS = {
            'Realm': 'dce.' + self._REALM,
            'x-api-key': self._API_KEY,
        }

        email, password = self._get_login_info()
        if email is None:
            self.raise_login_required()

        p_headers = self._HEADERS.copy()
        p_headers['Content-Type'] = 'application/json'
        self._HEADERS['Authorization'] = 'Bearer ' + self._download_json(
            self._API_BASE + 'login',
            None, 'Logging in', data=json.dumps({
                'id': email,
                'secret': password,
            }).encode(), headers=p_headers)['authorisationToken']

    def _call_api(self, path, media_id):
        return self._download_json(
            self._API_BASE + path + media_id, media_id, headers=self._HEADERS)

    def _extract_dve_api_url(self, media_id, media_type):
        stream_path = 'stream'
        if media_type == 'video':
            stream_path += '/vod/'
        else:
            stream_path += '?eventId='
        try:
            return self._call_api(
                stream_path, media_id)['playerUrlCallback']
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                raise ExtractorError(
                    self._parse_json(e.cause.read().decode(), media_id)['messages'][0],
                    expected=True)
            raise

    def _real_extract(self, url):
        domain, media_type, media_id, playlist_id = re.match(self._VALID_URL, url).groups()

        if playlist_id:
            if self._downloader.params.get('noplaylist'):
                self.to_screen('Downloading just video %s because of --no-playlist' % media_id)
            else:
                self.to_screen('Downloading playlist %s - add --no-playlist to just download video' % playlist_id)
                media_type, media_id = 'playlist', playlist_id

        if media_type == 'playlist':
            playlist = self._call_api('vod/playlist/', media_id)
            entries = []
            for video in try_get(playlist, lambda x: x['videos']['vods']) or []:
                video_id = str_or_none(video.get('id'))
                if not video_id:
                    continue
                entries.append(self.url_result(
                    'https://%s/video/%s' % (domain, video_id),
                    self.ie_key(), video_id))
            return self.playlist_result(
                entries, media_id, playlist.get('title'),
                playlist.get('description'))

        dve_api_url = self._extract_dve_api_url(media_id, media_type)
        video_data = self._download_json(dve_api_url, media_id)
        is_live = media_type == 'live'
        if is_live:
            title = self._live_title(self._call_api('event/', media_id)['title'])
        else:
            title = video_data['name']

        formats = []
        for proto in ('hls', 'dash'):
            media_url = video_data.get(proto + 'Url') or try_get(video_data, lambda x: x[proto]['url'])
            if not media_url:
                continue
            if proto == 'hls':
                m3u8_formats = self._extract_m3u8_formats(
                    media_url, media_id, 'mp4', 'm3u8' if is_live else 'm3u8_native',
                    m3u8_id='hls', fatal=False, headers=self._MANIFEST_HEADERS)
                for f in m3u8_formats:
                    f.setdefault('http_headers', {}).update(self._MANIFEST_HEADERS)
                    formats.append(f)
            else:
                formats.extend(self._extract_mpd_formats(
                    media_url, media_id, mpd_id='dash', fatal=False,
                    headers=self._MANIFEST_HEADERS))
        self._sort_formats(formats)

        subtitles = {}
        for subtitle in video_data.get('subtitles', []):
            subtitle_url = subtitle.get('url')
            if not subtitle_url:
                continue
            subtitles.setdefault(subtitle.get('lang', 'en_US'), []).append({
                'url': subtitle_url,
            })

        return {
            'id': media_id,
            'title': title,
            'formats': formats,
            'thumbnail': video_data.get('thumbnailUrl'),
            'description': video_data.get('description'),
            'duration': int_or_none(video_data.get('duration')),
            'tags': video_data.get('tags'),
            'is_live': is_live,
            'subtitles': subtitles,
        }


code:
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import (
    int_or_none,
    js_to_json,
    mimetype2ext,
    ExtractorError,
)

class ImgurIE(InfoExtractor):
    _VALID_URL = r'https?://(?:i\.)?imgur\.com/(?!(?:a|gallery|(?:t(?:opic)?|r)/[^/]+)/)(?P<id>[a-zA-Z0-9]+)'

    _TESTS = [{
        'url': 'https://i.imgur.com/A61SaA1.gifv',
        'info_dict': {
            'id': 'A61SaA1',
            'ext': 'mp4',
            'title': 're:Imgur GIF$|MRW gifv is up and running without any bugs$',
        },
    }, {
        'url': 'https://imgur.com/A61SaA1',
        'only_matching': True,
    }, {
        'url': 'https://i.imgur.com/crGpqCV.mp4',
        'only_matching': True,
    }, {
        # no title
        'url': 'https://i.imgur.com/jxBXAMC.gifv',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(
            'https://i.imgur.com/{id}.gifv'.format(id=video_id), video_id)

        width = int_or_none(self._og_search_property(
            'video:width', webpage, default=None))
        height = int_or_none(self._og_search_property(
            'video:height', webpage, default=None))

        video_elements = self._search_regex(
            r'(?s)
(.*?)
',
            webpage, 'video elements', default=None)
        if not video_elements:
            raise ExtractorError(
                'No sources found for video %s. Maybe an image?' % video_id,
                expected=True)

        formats = []
        for m in re.finditer(r'<source\s+src="(?P<src>[^"]+)"\s+type="(?P<type>[^"]+)"', video_elements):
            formats.append({
                'format_id': m.group('type').partition('/')[2],
                'url': self._proto_relative_url(m.group('src')),
                'ext': mimetype2ext(m.group('type')),
                'width': width,
                'height': height,
                'http_headers': {
                    'User-Agent': 'youtube-dl (like wget)',
                },
            })

        gif_json = self._search_regex(
            r'(?s)var\s+videoItem\s*=\s*(\{.*?\})',
            webpage, 'GIF code', fatal=False)
        if gif_json:
            gifd = self._parse_json(
                gif_json, video_id, transform_source=js_to_json)
            formats.append({
                'format_id': 'gif',
                'preference': -10,
                'width': width,
                'height': height,
                'ext': 'gif',
                'acodec': 'none',
                'vcodec': 'gif',
                'container': 'gif',
                'url': self._proto_relative_url(gifd['gifUrl']),
                'filesize': gifd.get('size'),
                'http_headers': {
                    'User-Agent': 'youtube-dl (like wget)',
                },
            })

        self._sort_formats(formats)

        return {
            'id': video_id,
            'formats': formats,
            'title': self._og_search_title(webpage, default=video_id),
        }

class ImgurGalleryIE(InfoExtractor):
    IE_NAME = 'imgur:gallery'
    _VALID_URL = r'https?://(?:i\.)?imgur\.com/(?:gallery|(?:t(?:opic)?|r)/[^/]+)/(?P<id>[a-zA-Z0-9]+)'

    _TESTS = [{
        'url': 'http://imgur.com/gallery/Q95ko',
        'info_dict': {
            'id': 'Q95ko',
            'title': 'Adding faces make every GIF better',
        },
        'playlist_count': 25,
    }, {
        'url': 'http://imgur.com/topic/Aww/ll5Vk',
        'only_matching': True,
    }, {
        'url': 'https://imgur.com/gallery/YcAQlkx',
        'info_dict': {
            'id': 'YcAQlkx',
            'ext': 'mp4',
            'title': 'Classic Steve Carell gif...cracks me up everytime....damn the repost downvotes....',
        }
    }, {
        'url': 'http://imgur.com/topic/Funny/N8rOudd',
        'only_matching': True,
    }, {
        'url': 'http://imgur.com/r/aww/VQcQPhM',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        gallery_id = self._match_id(url)

        data = self._download_json(
            'https://imgur.com/gallery/%s.json' % gallery_id,
            gallery_id)['data']['image']

        if data.get('is_album'):
            entries = [
                self.url_result('http://imgur.com/%s' % image['hash'], ImgurIE.ie_key(), image['hash'])
                for image in data['album_images']['images'] if image.get('hash')]
            return self.playlist_result(entries, gallery_id, data.get('title'), data.get('description'))

        return self.url_result('http://imgur.com/%s' % gallery_id, ImgurIE.ie_key(), gallery_id)

class ImgurAlbumIE(ImgurGalleryIE):
    IE_NAME = 'imgur:album'
    _VALID_URL = r'https?://(?:i\.)?imgur\.com/a/(?P<id>[a-zA-Z0-9]+)'

    _TESTS = [{
        'url': 'http://imgur.com/a/j6Orj',
        'info_dict': {
            'id': 'j6Orj',
            'title': 'A Literary Analysis of "Star Wars: The Force Awakens"',
        },
        'playlist_count': 12,
    }]


code:
# coding: utf-8
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import (
    determine_ext,
    int_or_none,
    strip_or_none,
    xpath_attr,
    xpath_text,
)

class InaIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?ina\.fr/(?:video|audio)/(?P<id>[A-Z0-9_]+)'
    _TESTS = [{
        'url': 'http://www.ina.fr/video/I12055569/francois-hollande-je-crois-que-c-est-clair-video.html',
        'md5': 'a667021bf2b41f8dc6049479d9bb38a3',
        'info_dict': {
            'id': 'I12055569',
            'ext': 'mp4',
            'title': 'François Hollande "Je crois que c\'est clair"',
            'description': 'md5:3f09eb072a06cb286b8f7e4f77109663',
        }
    }, {
        'url': 'https://www.ina.fr/video/S806544_001/don-d-organes-des-avancees-mais-d-importants-besoins-video.html',
        'only_matching': True,
    }, {
        'url': 'https://www.ina.fr/audio/P16173408',
        'only_matching': True,
    }, {
        'url': 'https://www.ina.fr/video/P16173408-video.html',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        info_doc = self._download_xml(
            'http://player.ina.fr/notices/%s.mrss' % video_id, video_id)
        item = info_doc.find('channel/item')
        title = xpath_text(item, 'title', fatal=True)
        media_ns_xpath = lambda x: self._xpath_ns(x, 'http://search.yahoo.com/mrss/')
        content = item.find(media_ns_xpath('content'))

        get_furl = lambda x: xpath_attr(content, media_ns_xpath(x), 'url')
        formats = []
        for q, w, h in (('bq', 400, 300), ('mq', 512, 384), ('hq', 768, 576)):
            q_url = get_furl(q)
            if not q_url:
                continue
            formats.append({
                'format_id': q,
                'url': q_url,
                'width': w,
                'height': h,
            })
        if not formats:
            furl = get_furl('player') or content.attrib['url']
            ext = determine_ext(furl)
            formats = [{
                'url': furl,
                'vcodec': 'none' if ext == 'mp3' else None,
                'ext': ext,
            }]

        thumbnails = []
        for thumbnail in content.findall(media_ns_xpath('thumbnail')):
            thumbnail_url = thumbnail.get('url')
            if not thumbnail_url:
                continue
            thumbnails.append({
                'url': thumbnail_url,
                'height': int_or_none(thumbnail.get('height')),
                'width': int_or_none(thumbnail.get('width')),
            })

        return {
            'id': video_id,
            'formats': formats,
            'title': title,
            'description': strip_or_none(xpath_text(item, 'description')),
            'thumbnails': thumbnails,
        }


code:
from __future__ import unicode_literals

from .common import InfoExtractor
from .kaltura import KalturaIE

class IncIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?inc\.com/(?:[^/]+/)+(?P<id>[^.]+).html'
    _TESTS = [{
        'url': 'http://www.inc.com/tip-sheet/bill-gates-says-these-5-books-will-make-you-smarter.html',
        'md5': '7416739c9c16438c09fa35619d6ba5cb',
        'info_dict': {
            'id': '1_wqig47aq',
            'ext': 'mov',
            'title': 'Bill Gates Says These 5 Books Will Make You Smarter',
            'description': 'md5:bea7ff6cce100886fc1995acb743237e',
            'timestamp': 1474414430,
            'upload_date': '20160920',
            'uploader_id': 'video@inc.com',
        },
        'params': {
            'skip_download': True,
        },
    }, {
        # div with id=kaltura_player_1_kqs38cgm
        'url': 'https://www.inc.com/oscar-raymundo/richard-branson-young-entrepeneurs.html',
        'info_dict': {
            'id': '1_kqs38cgm',
            'ext': 'mp4',
            'title': 'Branson: "In the end, you have to say, Screw it. Just do it."',
            'description': 'md5:21b832d034f9af5191ca5959da5e9cb6',
            'timestamp': 1364403232,
            'upload_date': '20130327',
            'uploader_id': 'incdigital@inc.com',
        },
        'params': {
            'skip_download': True,
        },
    }, {
        'url': 'http://www.inc.com/video/david-whitford/founders-forum-tripadvisor-steve-kaufer-most-enjoyable-moment-for-entrepreneur.html',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)

        partner_id = self._search_regex(
            r'var\s+_?bizo_data_partner_id\s*=\s*["\'](\d+)', webpage,
            'partner id', default='1034971')

        kaltura_id = self._search_regex(
            r'id=(["\'])kaltura_player_(?P<id>.+?)\1', webpage, 'kaltura id',
            default=None, group='id') or self._parse_json(self._search_regex(
                r'pageInfo\.videos\s*=\s*\[(.+)\];', webpage, 'kaltura id'),
            display_id)['vid_kaltura_id']

        return self.url_result(
            'kaltura:%s:%s' % (partner_id, kaltura_id), KalturaIE.ie_key())


code:
# coding: utf-8
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
    int_or_none,
    parse_age_limit,
    parse_iso8601,
    update_url_query,
)

class IndavideoEmbedIE(InfoExtractor):
    _VALID_URL = r'https?://(?:(?:embed\.)?indavideo\.hu/player/video/|assets\.indavideo\.hu/swf/player\.swf\?.*\b(?:v(?:ID|id))=)(?P<id>[\da-f]+)'
    _TESTS = [{
        'url': 'http://indavideo.hu/player/video/1bdc3c6d80/',
        'md5': 'c8a507a1c7410685f83a06eaeeaafeab',
        'info_dict': {
            'id': '1837039',
            'ext': 'mp4',
            'title': 'Cicatánc',
            'description': '',
            'thumbnail': r're:^https?://.*\.jpg$',
            'uploader': 'cukiajanlo',
            'uploader_id': '83729',
            'timestamp': 1439193826,
            'upload_date': '20150810',
            'duration': 72,
            'age_limit': 0,
            'tags': ['tánc', 'cica', 'cuki', 'cukiajanlo', 'newsroom'],
        },
    }, {
        'url': 'http://embed.indavideo.hu/player/video/1bdc3c6d80?autostart=1&hide=1',
        'only_matching': True,
    }, {
        'url': 'http://assets.indavideo.hu/swf/player.swf?v=fe25e500&vID=1bdc3c6d80&autostart=1&hide=1&i=1',
        'only_matching': True,
    }]

    # Some example URLs covered by generic extractor:
    #   http://indavideo.hu/video/Vicces_cica_1
    #   http://index.indavideo.hu/video/2015_0728_beregszasz
    #   http://auto.indavideo.hu/video/Sajat_utanfutoban_a_kis_tacsko
    #   http://erotika.indavideo.hu/video/Amator_tini_punci
    #   http://film.indavideo.hu/video/f_hrom_nagymamm_volt
    #   http://palyazat.indavideo.hu/video/Embertelen_dal_Dodgem_egyuttes

    @staticmethod
    def _extract_urls(webpage):
        return re.findall(
            r'<iframe[^>]+\bsrc=["\'](?P<url>(?:https?:)?//embed\.indavideo\.hu/player/video/[\da-f]+)',
            webpage)

    def _real_extract(self, url):
        video_id = self._match_id(url)

        video = self._download_json(
            'https://amfphp.indavideo.hu/SYm0json.php/player.playerHandler.getVideoData/%s' % video_id,
            video_id)['data']

        title = video['title']

        video_urls = []

        video_files = video.get('video_files')
        if isinstance(video_files, list):
            video_urls.extend(video_files)
        elif isinstance(video_files, dict):
            video_urls.extend(video_files.values())

        video_file = video.get('video_file')
        if video:
            video_urls.append(video_file)
        video_urls = list(set(video_urls))

        video_prefix = video_urls[0].rsplit('/', 1)[0]

        for flv_file in video.get('flv_files', []):
            flv_url = '%s/%s' % (video_prefix, flv_file)
            if flv_url not in video_urls:
                video_urls.append(flv_url)

        filesh = video.get('filesh')

        formats = []
        for video_url in video_urls:
            height = int_or_none(self._search_regex(
                r'\.(\d{3,4})\.mp4(?:\?|$)', video_url, 'height', default=None))
            if filesh:
                if not height:
                    continue
                token = filesh.get(compat_str(height))
                if token is None:
                    continue
                video_url = update_url_query(video_url, {'token': token})
            formats.append({
                'url': video_url,
                'height': height,
            })
        self._sort_formats(formats)

        timestamp = video.get('date')
        if timestamp:
            # upload date is in CEST
            timestamp = parse_iso8601(timestamp + ' +0200', ' ')

        thumbnails = [{
            'url': self._proto_relative_url(thumbnail)
        } for thumbnail in video.get('thumbnails', [])]

        tags = [tag['title'] for tag in video.get('tags') or []]

        return {
            'id': video.get('id') or video_id,
            'title': title,
            'description': video.get('description'),
            'thumbnails': thumbnails,
            'uploader': video.get('user_name'),
            'uploader_id': video.get('user_id'),
            'timestamp': timestamp,
            'duration': int_or_none(video.get('length')),
            'age_limit': parse_age_limit(video.get('age_limit')),
            'tags': tags,
            'formats': formats,
        }


code:
# coding: utf-8

from __future__ import unicode_literals

from ..compat import (
    compat_b64decode,
    compat_urllib_parse_unquote,
    compat_urlparse,
)
from ..utils import (
    determine_ext,
    update_url_query,
)
from .bokecc import BokeCCBaseIE

class InfoQIE(BokeCCBaseIE):
    _VALID_URL = r'https?://(?:www\.)?infoq\.com/(?:[^/]+/)+(?P<id>[^/]+)'

    _TESTS = [{
        'url': 'http://www.infoq.com/presentations/A-Few-of-My-Favorite-Python-Things',
        'md5': 'b5ca0e0a8c1fed93b0e65e48e462f9a2',
        'info_dict': {
            'id': 'A-Few-of-My-Favorite-Python-Things',
            'ext': 'mp4',
            'description': 'Mike Pirnat presents some tips and tricks, standard libraries and third party packages that make programming in Python a richer experience.',
            'title': 'A Few of My Favorite [Python] Things',
        },
    }, {
        'url': 'http://www.infoq.com/fr/presentations/changez-avis-sur-javascript',
        'only_matching': True,
    }, {
        'url': 'http://www.infoq.com/cn/presentations/openstack-continued-delivery',
        'md5': '4918d0cca1497f2244572caf626687ef',
        'info_dict': {
            'id': 'openstack-continued-delivery',
            'title': 'OpenStack持续交付之路',
            'ext': 'flv',
            'description': 'md5:308d981fb28fa42f49f9568322c683ff',
        },
    }, {
        'url': 'https://www.infoq.com/presentations/Simple-Made-Easy',
        'md5': '0e34642d4d9ef44bf86f66f6399672db',
        'info_dict': {
            'id': 'Simple-Made-Easy',
            'title': 'Simple Made Easy',
            'ext': 'mp3',
            'description': 'md5:3e0e213a8bbd074796ef89ea35ada25b',
        },
        'params': {
            'format': 'bestaudio',
        },
    }]

    def _extract_rtmp_video(self, webpage):
        # The server URL is hardcoded
        video_url = 'rtmpe://video.infoq.com/cfx/st/'

        # Extract video URL
        encoded_id = self._search_regex(
            r"jsclassref\s*=\s*'([^']*)'", webpage, 'encoded id', default=None)

        real_id = compat_urllib_parse_unquote(compat_b64decode(encoded_id).decode('utf-8'))
        playpath = 'mp4:' + real_id

        return [{
            'format_id': 'rtmp_video',
            'url': video_url,
            'ext': determine_ext(playpath),
            'play_path': playpath,
        }]

    def _extract_cf_auth(self, webpage):
        policy = self._search_regex(r'InfoQConstants\.scp\s*=\s*\'([^\']+)\'', webpage, 'policy')
        signature = self._search_regex(r'InfoQConstants\.scs\s*=\s*\'([^\']+)\'', webpage, 'signature')
        key_pair_id = self._search_regex(r'InfoQConstants\.sck\s*=\s*\'([^\']+)\'', webpage, 'key-pair-id')
        return {
            'Policy': policy,
            'Signature': signature,
            'Key-Pair-Id': key_pair_id,
        }

    def _extract_http_video(self, webpage):
        http_video_url = self._search_regex(r'P\.s\s*=\s*\'([^\']+)\'', webpage, 'video URL')
        http_video_url = update_url_query(http_video_url, self._extract_cf_auth(webpage))
        return [{
            'format_id': 'http_video',
            'url': http_video_url,
        }]

    def _extract_http_audio(self, webpage, video_id):
        fields = self._hidden_inputs(webpage)
        http_audio_url = fields.get('filename')
        if not http_audio_url:
            return []

        # base URL is found in the Location header in the response returned by
        # GET https://www.infoq.com/mp3download.action?filename=... when logged in.
        http_audio_url = compat_urlparse.urljoin('http://res.infoq.com/downloads/mp3downloads/', http_audio_url)
        http_audio_url = update_url_query(http_audio_url, self._extract_cf_auth(webpage))

        # audio file seem to be missing some times even if there is a download link
        # so probe URL to make sure
        if not self._is_valid_url(http_audio_url, video_id):
            return []

        return [{
            'format_id': 'http_audio',
            'url': http_audio_url,
            'vcodec': 'none',
        }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        video_title = self._html_search_regex(r'<title>(.*?)</title>', webpage, 'title')
        video_description = self._html_search_meta('description', webpage, 'description')

        if '/cn/' in url:
            # for China videos, HTTP video URL exists but always fails with 403
            formats = self._extract_bokecc_formats(webpage, video_id)
        else:
            formats = (
                self._extract_rtmp_video(webpage)
                + self._extract_http_video(webpage)
                + self._extract_http_audio(webpage, video_id))

        self._sort_formats(formats)

        return {
            'id': video_id,
            'title': video_title,
            'description': video_description,
            'formats': formats,
        }


code:
from __future__ import unicode_literals

import itertools
import hashlib
import json
import re

from .common import InfoExtractor
from ..compat import (
    compat_str,
    compat_HTTPError,
)
from ..utils import (
    ExtractorError,
    get_element_by_attribute,
    int_or_none,
    lowercase_escape,
    std_headers,
    try_get,
    url_or_none,
)

class InstagramIE(InfoExtractor):
    _VALID_URL = r'(?P<url>https?://(?:www\.)?instagram\.com/(?:p|tv)/(?P<id>[^/?#&]+))'
    _TESTS = [{
        'url': 'https://instagram.com/p/aye83DjauH/?foo=bar#abc',
        'md5': '0d2da106a9d2631273e192b372806516',
        'info_dict': {
            'id': 'aye83DjauH',
            'ext': 'mp4',
            'title': 'Video by naomipq',
            'description': 'md5:1f17f0ab29bd6fe2bfad705f58de3cb8',
            'thumbnail': r're:^https?://.*\.jpg',
            'timestamp': 1371748545,
            'upload_date': '20130620',
            'uploader_id': 'naomipq',
            'uploader': 'Naomi Leonor Phan-Quang',
            'like_count': int,
            'comment_count': int,
            'comments': list,
        },
    }, {
        # missing description
        'url': 'https://www.instagram.com/p/BA-pQFBG8HZ/?taken-by=britneyspears',
        'info_dict': {
            'id': 'BA-pQFBG8HZ',
            'ext': 'mp4',
            'title': 'Video by britneyspears',
            'thumbnail': r're:^https?://.*\.jpg',
            'timestamp': 1453760977,
            'upload_date': '20160125',
            'uploader_id': 'britneyspears',
            'uploader': 'Britney Spears',
            'like_count': int,
            'comment_count': int,
            'comments': list,
        },
        'params': {
            'skip_download': True,
        },
    }, {
        # multi video post
        'url': 'https://www.instagram.com/p/BQ0eAlwhDrw/',
        'playlist': [{
            'info_dict': {
                'id': 'BQ0dSaohpPW',
                'ext': 'mp4',
                'title': 'Video 1',
            },
        }, {
            'info_dict': {
                'id': 'BQ0dTpOhuHT',
                'ext': 'mp4',
                'title': 'Video 2',
            },
        }, {
            'info_dict': {
                'id': 'BQ0dT7RBFeF',
                'ext': 'mp4',
                'title': 'Video 3',
            },
        }],
        'info_dict': {
            'id': 'BQ0eAlwhDrw',
            'title': 'Post by instagram',
            'description': 'md5:0f9203fc6a2ce4d228da5754bcf54957',
        },
    }, {
        'url': 'https://instagram.com/p/-Cmh1cukG2/',
        'only_matching': True,
    }, {
        'url': 'http://instagram.com/p/9o6LshA7zy/embed/',
        'only_matching': True,
    }, {
        'url': 'https://www.instagram.com/tv/aye83DjauH/',
        'only_matching': True,
    }]

    @staticmethod
    def _extract_embed_url(webpage):
        mobj = re.search(
            r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//(?:www\.)?instagram\.com/p/[^/]+/embed.*?)\1',
            webpage)
        if mobj:
            return mobj.group('url')

        blockquote_el = get_element_by_attribute(
            'class', 'instagram-media', webpage)
        if blockquote_el is None:
            return

        mobj = re.search(
            r'<a[^>]+href=([\'"])(?P<link>[^\'"]+)\1', blockquote_el)
        if mobj:
            return mobj.group('link')

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('id')
        url = mobj.group('url')

        webpage = self._download_webpage(url, video_id)

        (video_url, description, thumbnail, timestamp, uploader,
         uploader_id, like_count, comment_count, comments, height,
         width) = [None] * 11

        shared_data = self._parse_json(
            self._search_regex(
                r'window\._sharedData\s*=\s*({.+?});',
                webpage, 'shared data', default='{}'),
            video_id, fatal=False)
        if shared_data:
            media = try_get(
                shared_data,
                (lambda x: x['entry_data']['PostPage'][0]['graphql']['shortcode_media'],
                 lambda x: x['entry_data']['PostPage'][0]['media']),
                dict)
            if media:
                video_url = media.get('video_url')
                height = int_or_none(media.get('dimensions', {}).get('height'))
                width = int_or_none(media.get('dimensions', {}).get('width'))
                description = try_get(
                    media, lambda x: x['edge_media_to_caption']['edges'][0]['node']['text'],
                    compat_str) or media.get('caption')
                thumbnail = media.get('display_src')
                timestamp = int_or_none(media.get('taken_at_timestamp') or media.get('date'))
                uploader = media.get('owner', {}).get('full_name')
                uploader_id = media.get('owner', {}).get('username')

                def get_count(key, kind):
                    return int_or_none(try_get(
                        media, (lambda x: x['edge_media_%s' % key]['count'],
                                lambda x: x['%ss' % kind]['count'])))
                like_count = get_count('preview_like', 'like')
                comment_count = get_count('to_comment', 'comment')

                comments = [{
                    'author': comment.get('user', {}).get('username'),
                    'author_id': comment.get('user', {}).get('id'),
                    'id': comment.get('id'),
                    'text': comment.get('text'),
                    'timestamp': int_or_none(comment.get('created_at')),
                } for comment in media.get(
                    'comments', {}).get('nodes', []) if comment.get('text')]
                if not video_url:
                    edges = try_get(
                        media, lambda x: x['edge_sidecar_to_children']['edges'],
                        list) or []
                    if edges:
                        entries = []
                        for edge_num, edge in enumerate(edges, start=1):
                            node = try_get(edge, lambda x: x['node'], dict)
                            if not node:
                                continue
                            node_video_url = url_or_none(node.get('video_url'))
                            if not node_video_url:
                                continue
                            entries.append({
                                'id': node.get('shortcode') or node['id'],
                                'title': 'Video %d' % edge_num,
                                'url': node_video_url,
                                'thumbnail': node.get('display_url'),
                                'width': int_or_none(try_get(node, lambda x: x['dimensions']['width'])),
                                'height': int_or_none(try_get(node, lambda x: x['dimensions']['height'])),
                                'view_count': int_or_none(node.get('video_view_count')),
                            })
                        return self.playlist_result(
                            entries, video_id,
                            'Post by %s' % uploader_id if uploader_id else None,
                            description)

        if not video_url:
            video_url = self._og_search_video_url(webpage, secure=False)

        formats = [{
            'url': video_url,
            'width': width,
            'height': height,
        }]

        if not uploader_id:
            uploader_id = self._search_regex(
                r'"owner"\s*:\s*{\s*"username"\s*:\s*"(.+?)"',
                webpage, 'uploader id', fatal=False)

        if not description:
            description = self._search_regex(
                r'"caption"\s*:\s*"(.+?)"', webpage, 'description', default=None)
            if description is not None:
                description = lowercase_escape(description)

        if not thumbnail:
            thumbnail = self._og_search_thumbnail(webpage)

        return {
            'id': video_id,
            'formats': formats,
            'ext': 'mp4',
            'title': 'Video by %s' % uploader_id,
            'description': description,
            'thumbnail': thumbnail,
            'timestamp': timestamp,
            'uploader_id': uploader_id,
            'uploader': uploader,
            'like_count': like_count,
            'comment_count': comment_count,
            'comments': comments,
        }

class InstagramPlaylistIE(InfoExtractor):
    # A superclass for handling any kind of query based on GraphQL which
    # results in a playlist.

    _gis_tmpl = None  # used to cache GIS request type

    def _parse_graphql(self, webpage, item_id):
        # Reads a webpage and returns its GraphQL data.
        return self._parse_json(
            self._search_regex(
                r'sharedData\s*=\s*({.+?})\s*;\s*[<\n]', webpage, 'data'),
            item_id)

    def _extract_graphql(self, data, url):
        # Parses GraphQL queries containing videos and generates a playlist.
        def get_count(suffix):
            return int_or_none(try_get(
                node, lambda x: x['edge_media_' + suffix]['count']))

        uploader_id = self._match_id(url)
        csrf_token = data['config']['csrf_token']
        rhx_gis = data.get('rhx_gis') or '3c7ca9dcefcf966d11dacf1f151335e8'

        cursor = ''
        for page_num in itertools.count(1):
            variables = {
                'first': 12,
                'after': cursor,
            }
            variables.update(self._query_vars_for(data))
            variables = json.dumps(variables)

            if self._gis_tmpl:
                gis_tmpls = [self._gis_tmpl]
            else:
                gis_tmpls = [
                    '%s' % rhx_gis,
                    '',
                    '%s:%s' % (rhx_gis, csrf_token),
                    '%s:%s:%s' % (rhx_gis, csrf_token, std_headers['User-Agent']),
                ]

            # try all of the ways to generate a GIS query, and not only use the
            # first one that works, but cache it for future requests
            for gis_tmpl in gis_tmpls:
                try:
                    json_data = self._download_json(
                        'https://www.instagram.com/graphql/query/', uploader_id,
                        'Downloading JSON page %d' % page_num, headers={
                            'X-Requested-With': 'XMLHttpRequest',
                            'X-Instagram-GIS': hashlib.md5(
                                ('%s:%s' % (gis_tmpl, variables)).encode('utf-8')).hexdigest(),
                        }, query={
                            'query_hash': self._QUERY_HASH,
                            'variables': variables,
                        })
                    media = self._parse_timeline_from(json_data)
                    self._gis_tmpl = gis_tmpl
                    break
                except ExtractorError as e:
                    # if it's an error caused by a bad query, and there are
                    # more GIS templates to try, ignore it and keep trying
                    if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                        if gis_tmpl != gis_tmpls[-1]:
                            continue
                    raise

            edges = media.get('edges')
            if not edges or not isinstance(edges, list):
                break

            for edge in edges:
                node = edge.get('node')
                if not node or not isinstance(node, dict):
                    continue
                if node.get('__typename') != 'GraphVideo' and node.get('is_video') is not True:
                    continue
                video_id = node.get('shortcode')
                if not video_id:
                    continue

                info = self.url_result(
                    'https://instagram.com/p/%s/' % video_id,
                    ie=InstagramIE.ie_key(), video_id=video_id)

                description = try_get(
                    node, lambda x: x['edge_media_to_caption']['edges'][0]['node']['text'],
                    compat_str)
                thumbnail = node.get('thumbnail_src') or node.get('display_src')
                timestamp = int_or_none(node.get('taken_at_timestamp'))

                comment_count = get_count('to_comment')
                like_count = get_count('preview_like')
                view_count = int_or_none(node.get('video_view_count'))

                info.update({
                    'description': description,
                    'thumbnail': thumbnail,
                    'timestamp': timestamp,
                    'comment_count': comment_count,
                    'like_count': like_count,
                    'view_count': view_count,
                })

                yield info

            page_info = media.get('page_info')
            if not page_info or not isinstance(page_info, dict):
                break

            has_next_page = page_info.get('has_next_page')
            if not has_next_page:
                break

            cursor = page_info.get('end_cursor')
            if not cursor or not isinstance(cursor, compat_str):
                break

    def _real_extract(self, url):
        user_or_tag = self._match_id(url)
        webpage = self._download_webpage(url, user_or_tag)
        data = self._parse_graphql(webpage, user_or_tag)

        self._set_cookie('instagram.com', 'ig_pr', '1')

        return self.playlist_result(
            self._extract_graphql(data, url), user_or_tag, user_or_tag)

class InstagramUserIE(InstagramPlaylistIE):
    _VALID_URL = r'https?://(?:www\.)?instagram\.com/(?P<id>[^/]{2,})/?(?:$|[?#])'
    IE_DESC = 'Instagram user profile'
    IE_NAME = 'instagram:user'
    _TEST = {
        'url': 'https://instagram.com/porsche',
        'info_dict': {
            'id': 'porsche',
            'title': 'porsche',
        },
        'playlist_count': 5,
        'params': {
            'extract_flat': True,
            'skip_download': True,
            'playlistend': 5,
        }
    }

    _QUERY_HASH = '42323d64886122307be10013ad2dcc44',

    @staticmethod
    def _parse_timeline_from(data):
        # extracts the media timeline data from a GraphQL result
        return data['data']['user']['edge_owner_to_timeline_media']

    @staticmethod
    def _query_vars_for(data):
        # returns a dictionary of variables to add to the timeline query based
        # on the GraphQL of the original page
        return {
            'id': data['entry_data']['ProfilePage'][0]['graphql']['user']['id']
        }

class InstagramTagIE(InstagramPlaylistIE):
    _VALID_URL = r'https?://(?:www\.)?instagram\.com/explore/tags/(?P<id>[^/]+)'
    IE_DESC = 'Instagram hashtag search'
    IE_NAME = 'instagram:tag'
    _TEST = {
        'url': 'https://instagram.com/explore/tags/lolcats',
        'info_dict': {
            'id': 'lolcats',
            'title': 'lolcats',
        },
        'playlist_count': 50,
        'params': {
            'extract_flat': True,
            'skip_download': True,
            'playlistend': 50,
        }
    }

    _QUERY_HASH = 'f92f56d47dc7a55b606908374b43a314',

    @staticmethod
    def _parse_timeline_from(data):
        # extracts the media timeline data from a GraphQL result
        return data['data']['hashtag']['edge_hashtag_to_media']

    @staticmethod
    def _query_vars_for(data):
        # returns a dictionary of variables to add to the timeline query based
        # on the GraphQL of the original page
        return {
            'tag_name':
                data['entry_data']['TagPage'][0]['graphql']['hashtag']['name']
        }


code:
# coding: utf-8
from __future__ import unicode_literals

from .common import InfoExtractor
from ..utils import unified_timestamp

class InternazionaleIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?internazionale\.it/video/(?:[^/]+/)*(?P<id>[^/?#&]+)'
    _TESTS = [{
        'url': 'https://www.internazionale.it/video/2015/02/19/richard-linklater-racconta-una-scena-di-boyhood',
        'md5': '3e39d32b66882c1218e305acbf8348ca',
        'info_dict': {
            'id': '265968',
            'display_id': 'richard-linklater-racconta-una-scena-di-boyhood',
            'ext': 'mp4',
            'title': 'Richard Linklater racconta una scena di Boyhood',
            'description': 'md5:efb7e5bbfb1a54ae2ed5a4a015f0e665',
            'timestamp': 1424354635,
            'upload_date': '20150219',
            'thumbnail': r're:^https?://.*\.jpg$',
        },
        'params': {
            'format': 'bestvideo',
        },
    }, {
        'url': 'https://www.internazionale.it/video/2018/08/29/telefono-stare-con-noi-stessi',
        'md5': '9db8663704cab73eb972d1cee0082c79',
        'info_dict': {
            'id': '761344',
            'display_id': 'telefono-stare-con-noi-stessi',
            'ext': 'mp4',
            'title': 'Usiamo il telefono per evitare di stare con noi stessi',
            'description': 'md5:75ccfb0d6bcefc6e7428c68b4aa1fe44',
            'timestamp': 1535528954,
            'upload_date': '20180829',
            'thumbnail': r're:^https?://.*\.jpg$',
        },
        'params': {
            'format': 'bestvideo',
        },
    }]

    def _real_extract(self, url):
        display_id = self._match_id(url)

        webpage = self._download_webpage(url, display_id)

        DATA_RE = r'data-%s=(["\'])(?P<value>(?:(?!\1).)+)\1'

        title = self._search_regex(
            DATA_RE % 'video-title', webpage, 'title', default=None,
            group='value') or self._og_search_title(webpage)

        video_id = self._search_regex(
            DATA_RE % 'job-id', webpage, 'video id', group='value')
        video_path = self._search_regex(
            DATA_RE % 'video-path', webpage, 'video path', group='value')
        video_available_abroad = self._search_regex(
            DATA_RE % 'video-available_abroad', webpage,
            'video available aboard', default='1', group='value')
        video_available_abroad = video_available_abroad == '1'

        video_base = 'https://video%s.internazionale.it/%s/%s.' % \
            ('' if video_available_abroad else '-ita', video_path, video_id)

        formats = self._extract_m3u8_formats(
            video_base + 'm3u8', display_id, 'mp4',
            entry_protocol='m3u8_native', m3u8_id='hls', fatal=False)
        formats.extend(self._extract_mpd_formats(
            video_base + 'mpd', display_id, mpd_id='dash', fatal=False))
        self._sort_formats(formats)

        timestamp = unified_timestamp(self._html_search_meta(
            'article:published_time', webpage, 'timestamp'))

        return {
            'id': video_id,
            'display_id': display_id,
            'title': title,
            'thumbnail': self._og_search_thumbnail(webpage),
            'description': self._og_search_description(webpage),
            'timestamp': timestamp,
            'formats': formats,
        }