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

from .adobepass import AdobePassIE
from ..utils import (
    extract_attributes,
    int_or_none,
    parse_age_limit,
    smuggle_url,
    update_url_query,
)

class FXNetworksIE(AdobePassIE):
    _VALID_URL = r'https?://(?:www\.)?(?:fxnetworks|simpsonsworld)\.com/video/(?P<id>\d+)'
    _TESTS = [{
        'url': 'http://www.fxnetworks.com/video/1032565827847',
        'md5': '8d99b97b4aa7a202f55b6ed47ea7e703',
        'info_dict': {
            'id': 'dRzwHC_MMqIv',
            'ext': 'mp4',
            'title': 'First Look: Better Things - Season 2',
            'description': 'Because real life is like a fart. Watch this FIRST LOOK to see what inspired the new season of Better Things.',
            'age_limit': 14,
            'uploader': 'NEWA-FNG-FX',
            'upload_date': '20170825',
            'timestamp': 1503686274,
            'episode_number': 0,
            'season_number': 2,
            'series': 'Better Things',
        },
        'add_ie': ['ThePlatform'],
    }, {
        'url': 'http://www.simpsonsworld.com/video/716094019682',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        if 'The content you are trying to access is not available in your region.' in webpage:
            self.raise_geo_restricted()
        video_data = extract_attributes(self._search_regex(
            r'(<a.+?rel="https?://link\.theplatform\.com/s/.+?</a>)', webpage, 'video data'))
        player_type = self._search_regex(r'playerType\s*=\s*[\'"]([^\'"]+)', webpage, 'player type', default=None)
        release_url = video_data['rel']
        title = video_data['data-title']
        rating = video_data.get('data-rating')
        query = {
            'mbr': 'true',
        }
        if player_type == 'movies':
            query.update({
                'manifest': 'm3u',
            })
        else:
            query.update({
                'switch': 'http',
            })
        if video_data.get('data-req-auth') == '1':
            resource = self._get_mvpd_resource(
                video_data['data-channel'], title,
                video_data.get('data-guid'), rating)
            query['auth'] = self._extract_mvpd_auth(url, video_id, 'fx', resource)

        return {
            '_type': 'url_transparent',
            'id': video_id,
            'title': title,
            'url': smuggle_url(update_url_query(release_url, query), {'force_smil_url': True}),
            'series': video_data.get('data-show-title'),
            'episode_number': int_or_none(video_data.get('data-episode')),
            'season_number': int_or_none(video_data.get('data-season')),
            'thumbnail': video_data.get('data-large-thumb'),
            'age_limit': parse_age_limit(rating),
            'ie_key': 'ThePlatform',
        }


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

import re

from .common import InfoExtractor
from ..compat import (
    compat_str,
    compat_urllib_parse_unquote,
)
from ..utils import (
    ExtractorError,
    int_or_none,
    str_or_none,
    strip_or_none,
    try_get,
    urlencode_postdata,
)

class GaiaIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?gaia\.com/video/(?P<id>[^/?]+).*?\bfullplayer=(?P<type>feature|preview)'
    _TESTS = [{
        'url': 'https://www.gaia.com/video/connecting-universal-consciousness?fullplayer=feature',
        'info_dict': {
            'id': '89356',
            'ext': 'mp4',
            'title': 'Connecting with Universal Consciousness',
            'description': 'md5:844e209ad31b7d31345f5ed689e3df6f',
            'upload_date': '20151116',
            'timestamp': 1447707266,
            'duration': 936,
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }, {
        'url': 'https://www.gaia.com/video/connecting-universal-consciousness?fullplayer=preview',
        'info_dict': {
            'id': '89351',
            'ext': 'mp4',
            'title': 'Connecting with Universal Consciousness',
            'description': 'md5:844e209ad31b7d31345f5ed689e3df6f',
            'upload_date': '20151116',
            'timestamp': 1447707266,
            'duration': 53,
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }]
    _NETRC_MACHINE = 'gaia'
    _jwt = None

    def _real_initialize(self):
        auth = self._get_cookies('https://www.gaia.com/').get('auth')
        if auth:
            auth = self._parse_json(
                compat_urllib_parse_unquote(auth.value),
                None, fatal=False)
        if not auth:
            username, password = self._get_login_info()
            if username is None:
                return
            auth = self._download_json(
                'https://auth.gaia.com/v1/login',
                None, data=urlencode_postdata({
                    'username': username,
                    'password': password
                }))
            if auth.get('success') is False:
                raise ExtractorError(', '.join(auth['messages']), expected=True)
        if auth:
            self._jwt = auth.get('jwt')

    def _real_extract(self, url):
        display_id, vtype = re.search(self._VALID_URL, url).groups()
        node_id = self._download_json(
            'https://brooklyn.gaia.com/pathinfo', display_id, query={
                'path': 'video/' + display_id,
            })['id']
        node = self._download_json(
            'https://brooklyn.gaia.com/node/%d' % node_id, node_id)
        vdata = node[vtype]
        media_id = compat_str(vdata['nid'])
        title = node['title']

        headers = None
        if self._jwt:
            headers = {'Authorization': 'Bearer ' + self._jwt}
        media = self._download_json(
            'https://brooklyn.gaia.com/media/' + media_id,
            media_id, headers=headers)
        formats = self._extract_m3u8_formats(
            media['mediaUrls']['bcHLS'], media_id, 'mp4')
        self._sort_formats(formats)

        subtitles = {}
        text_tracks = media.get('textTracks', {})
        for key in ('captions', 'subtitles'):
            for lang, sub_url in text_tracks.get(key, {}).items():
                subtitles.setdefault(lang, []).append({
                    'url': sub_url,
                })

        fivestar = node.get('fivestar', {})
        fields = node.get('fields', {})

        def get_field_value(key, value_key='value'):
            return try_get(fields, lambda x: x[key][0][value_key])

        return {
            'id': media_id,
            'display_id': display_id,
            'title': title,
            'formats': formats,
            'description': strip_or_none(get_field_value('body') or get_field_value('teaser')),
            'timestamp': int_or_none(node.get('created')),
            'subtitles': subtitles,
            'duration': int_or_none(vdata.get('duration')),
            'like_count': int_or_none(try_get(fivestar, lambda x: x['up_count']['value'])),
            'dislike_count': int_or_none(try_get(fivestar, lambda x: x['down_count']['value'])),
            'comment_count': int_or_none(node.get('comment_count')),
            'series': try_get(node, lambda x: x['series']['title'], compat_str),
            'season_number': int_or_none(get_field_value('season')),
            'season_id': str_or_none(get_field_value('series_nid', 'nid')),
            'episode_number': int_or_none(get_field_value('episode')),
        }

repo_name: rrosajp/youtube


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

from .brightcove import BrightcoveNewIE
from .common import InfoExtractor
from ..utils import (
    clean_html,
    get_element_by_class,
    get_element_by_id,
)

class GameInformerIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?gameinformer\.com/(?:[^/]+/)*(?P<id>[^.?&#]+)'
    _TESTS = [{
        # normal Brightcove embed code extracted with BrightcoveNewIE._extract_url
        'url': 'http://www.gameinformer.com/b/features/archive/2015/09/26/replay-animal-crossing.aspx',
        'md5': '292f26da1ab4beb4c9099f1304d2b071',
        'info_dict': {
            'id': '4515472681001',
            'ext': 'mp4',
            'title': 'Replay - Animal Crossing',
            'description': 'md5:2e211891b215c85d061adc7a4dd2d930',
            'timestamp': 1443457610,
            'upload_date': '20150928',
            'uploader_id': '694940074001',
        },
    }, {
        # Brightcove id inside unique element with field--name-field-brightcove-video-id class
        'url': 'https://www.gameinformer.com/video-feature/new-gameplay-today/2019/07/09/new-gameplay-today-streets-of-rogue',
        'info_dict': {
            'id': '6057111913001',
            'ext': 'mp4',
            'title': 'New Gameplay Today – Streets Of Rogue',
            'timestamp': 1562699001,
            'upload_date': '20190709',
            'uploader_id': '694940074001',

        },
    }]
    BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/694940074001/default_default/index.html?videoId=%s'

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(
            url, display_id, headers=self.geo_verification_headers())
        brightcove_id = clean_html(get_element_by_class('field--name-field-brightcove-video-id', webpage) or get_element_by_id('video-source-content', webpage))
        brightcove_url = self.BRIGHTCOVE_URL_TEMPLATE % brightcove_id if brightcove_id else BrightcoveNewIE._extract_url(self, webpage)
        return self.url_result(brightcove_url, 'BrightcoveNew', brightcove_id)


code:
from __future__ import unicode_literals

import re

from .once import OnceIE
from ..compat import (
    compat_urllib_parse_unquote,
)
from ..utils import (
    unescapeHTML,
    url_basename,
    dict_get,
)

class GameSpotIE(OnceIE):
    _VALID_URL = r'https?://(?:www\.)?gamespot\.com/(?:video|article|review)s/(?:[^/]+/\d+-|embed/)(?P<id>\d+)'
    _TESTS = [{
        'url': 'http://www.gamespot.com/videos/arma-3-community-guide-sitrep-i/2300-6410818/',
        'md5': 'b2a30deaa8654fcccd43713a6b6a4825',
        'info_dict': {
            'id': 'gs-2300-6410818',
            'ext': 'mp4',
            'title': 'Arma 3 - Community Guide: SITREP I',
            'description': 'Check out this video where some of the basics of Arma 3 is explained.',
        },
    }, {
        'url': 'http://www.gamespot.com/videos/the-witcher-3-wild-hunt-xbox-one-now-playing/2300-6424837/',
        'info_dict': {
            'id': 'gs-2300-6424837',
            'ext': 'mp4',
            'title': 'Now Playing - The Witcher 3: Wild Hunt',
            'description': 'Join us as we take a look at the early hours of The Witcher 3: Wild Hunt and more.',
        },
        'params': {
            'skip_download': True,  # m3u8 downloads
        },
    }, {
        'url': 'https://www.gamespot.com/videos/embed/6439218/',
        'only_matching': True,
    }, {
        'url': 'https://www.gamespot.com/articles/the-last-of-us-2-receives-new-ps4-trailer/1100-6454469/',
        'only_matching': True,
    }, {
        'url': 'https://www.gamespot.com/reviews/gears-of-war-review/1900-6161188/',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        page_id = self._match_id(url)
        webpage = self._download_webpage(url, page_id)
        data_video_json = self._search_regex(
            r'data-video=["\'](.*?)["\']', webpage, 'data video')
        data_video = self._parse_json(unescapeHTML(data_video_json), page_id)
        streams = data_video['videoStreams']

        manifest_url = None
        formats = []
        f4m_url = streams.get('f4m_stream')
        if f4m_url:
            manifest_url = f4m_url
            formats.extend(self._extract_f4m_formats(
                f4m_url + '?hdcore=3.7.0', page_id, f4m_id='hds', fatal=False))
        m3u8_url = dict_get(streams, ('m3u8_stream', 'adaptive_stream'))
        if m3u8_url:
            manifest_url = m3u8_url
            m3u8_formats = self._extract_m3u8_formats(
                m3u8_url, page_id, 'mp4', 'm3u8_native',
                m3u8_id='hls', fatal=False)
            formats.extend(m3u8_formats)
        progressive_url = dict_get(
            streams, ('progressive_hd', 'progressive_high', 'progressive_low', 'other_lr'))
        if progressive_url and manifest_url:
            qualities_basename = self._search_regex(
                r'/([^/]+)\.csmil/',
                manifest_url, 'qualities basename', default=None)
            if qualities_basename:
                QUALITIES_RE = r'((,\d+)+,?)'
                qualities = self._search_regex(
                    QUALITIES_RE, qualities_basename,
                    'qualities', default=None)
                if qualities:
                    qualities = list(map(lambda q: int(q), qualities.strip(',').split(',')))
                    qualities.sort()
                    http_template = re.sub(QUALITIES_RE, r'%d', qualities_basename)
                    http_url_basename = url_basename(progressive_url)
                    if m3u8_formats:
                        self._sort_formats(m3u8_formats)
                        m3u8_formats = list(filter(
                            lambda f: f.get('vcodec') != 'none', m3u8_formats))
                    if len(qualities) == len(m3u8_formats):
                        for q, m3u8_format in zip(qualities, m3u8_formats):
                            f = m3u8_format.copy()
                            f.update({
                                'url': progressive_url.replace(
                                    http_url_basename, http_template % q),
                                'format_id': f['format_id'].replace('hls', 'http'),
                                'protocol': 'http',
                            })
                            formats.append(f)
                    else:
                        for q in qualities:
                            formats.append({
                                'url': progressive_url.replace(
                                    http_url_basename, http_template % q),
                                'ext': 'mp4',
                                'format_id': 'http-%d' % q,
                                'tbr': q,
                            })

        onceux_json = self._search_regex(
            r'data-onceux-options=["\'](.*?)["\']', webpage, 'data video', default=None)
        if onceux_json:
            onceux_url = self._parse_json(unescapeHTML(onceux_json), page_id).get('metadataUri')
            if onceux_url:
                formats.extend(self._extract_once_formats(re.sub(
                    r'https?://[^/]+', 'http://once.unicornmedia.com', onceux_url),
                    http_formats_preference=-1))

        if not formats:
            for quality in ['sd', 'hd']:
                # It's actually a link to a flv file
                flv_url = streams.get('f4m_{0}'.format(quality))
                if flv_url is not None:
                    formats.append({
                        'url': flv_url,
                        'ext': 'flv',
                        'format_id': quality,
                    })
        self._sort_formats(formats)

        return {
            'id': data_video['guid'],
            'display_id': page_id,
            'title': compat_urllib_parse_unquote(data_video['title']),
            'formats': formats,
            'description': self._html_search_meta('description', webpage),
            'thumbnail': self._og_search_thumbnail(webpage),
        }


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

import re

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

class GameStarIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?game(?P<site>pro|star)\.de/videos/.*,(?P<id>[0-9]+)\.html'
    _TESTS = [{
        'url': 'http://www.gamestar.de/videos/trailer,3/hobbit-3-die-schlacht-der-fuenf-heere,76110.html',
        'md5': 'ee782f1f8050448c95c5cacd63bc851c',
        'info_dict': {
            'id': '76110',
            'ext': 'mp4',
            'title': 'Hobbit 3: Die Schlacht der Fünf Heere - Teaser-Trailer zum dritten Teil',
            'description': 'Der Teaser-Trailer zu Hobbit 3: Die Schlacht der Fünf Heere zeigt einige Szenen aus dem dritten Teil der Saga und kündigt den...',
            'thumbnail': r're:^https?://.*\.jpg$',
            'timestamp': 1406542380,
            'upload_date': '20140728',
            'duration': 17,
        }
    }, {
        'url': 'http://www.gamepro.de/videos/top-10-indie-spiele-fuer-nintendo-switch-video-tolle-nindies-games-zum-download,95316.html',
        'only_matching': True,
    }, {
        'url': 'http://www.gamestar.de/videos/top-10-indie-spiele-fuer-nintendo-switch-video-tolle-nindies-games-zum-download,95316.html',
        'only_matching': True,
    }]

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

        webpage = self._download_webpage(url, video_id)

        # TODO: there are multiple ld+json objects in the webpage,
        # while _search_json_ld finds only the first one
        json_ld = self._parse_json(self._search_regex(
            r'(?s)',
            webpage, 'JSON-LD', group='json_ld'), video_id)
        info_dict = self._json_ld(json_ld, video_id)
        info_dict['title'] = remove_end(
            info_dict['title'], ' - Game%s' % site.title())

        view_count = int_or_none(json_ld.get('interactionCount'))
        comment_count = int_or_none(self._html_search_regex(
            r'Kommentare\s*]+class=["\']count[^>]+>\s*\(\s*([0-9]+)',
            webpage, 'comment count', fatal=False))

        info_dict.update({
            'id': video_id,
            'url': 'http://gamestar.de/_misc/videos/portal/getVideoUrl.cfm?premium=0&videoId=' + video_id,
            'ext': 'mp4',
            'view_count': view_count,
            'comment_count': comment_count
        })

        return info_dict


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

import re
from .common import InfoExtractor
from ..utils import (
    float_or_none,
    int_or_none,
    unified_strdate,
)

class GaskrankIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?gaskrank\.tv/tv/(?P<categories>[^/]+)/(?P<id>[^/]+)\.htm'
    _TESTS = [{
        'url': 'http://www.gaskrank.tv/tv/motorrad-fun/strike-einparken-durch-anfaenger-crash-mit-groesserem-flurschaden.htm',
        'md5': '1ae88dbac97887d85ebd1157a95fc4f9',
        'info_dict': {
            'id': '201601/26955',
            'ext': 'mp4',
            'title': 'Strike! Einparken können nur Männer - Flurschaden hält sich in Grenzen *lol*',
            'thumbnail': r're:^https?://.*\.jpg$',
            'categories': ['motorrad-fun'],
            'display_id': 'strike-einparken-durch-anfaenger-crash-mit-groesserem-flurschaden',
            'uploader_id': 'Bikefun',
            'upload_date': '20170110',
            'uploader_url': None,
        }
    }, {
        'url': 'http://www.gaskrank.tv/tv/racing/isle-of-man-tt-2011-michael-du-15920.htm',
        'md5': 'c33ee32c711bc6c8224bfcbe62b23095',
        'info_dict': {
            'id': '201106/15920',
            'ext': 'mp4',
            'title': 'Isle of Man - Michael Dunlop vs Guy Martin - schwindelig kucken',
            'thumbnail': r're:^https?://.*\.jpg$',
            'categories': ['racing'],
            'display_id': 'isle-of-man-tt-2011-michael-du-15920',
            'uploader_id': 'IOM',
            'upload_date': '20170523',
            'uploader_url': 'www.iomtt.com',
        }
    }]

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

        webpage = self._download_webpage(url, display_id)

        title = self._og_search_title(
            webpage, default=None) or self._html_search_meta(
            'title', webpage, fatal=True)

        categories = [re.match(self._VALID_URL, url).group('categories')]

        mobj = re.search(
            r'Video von:\s*(?P<uploader_id>[^|]*?)\s*\|\s*vom:\s*(?P<upload_date>[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9][0-9][0-9])',
            webpage)
        if mobj is not None:
            uploader_id = mobj.groupdict().get('uploader_id')
            upload_date = unified_strdate(mobj.groupdict().get('upload_date'))

        uploader_url = self._search_regex(
            r'Homepage:\s*<[^>]*>(?P<uploader_url>[^<]*)',
            webpage, 'uploader_url', default=None)
        tags = re.findall(
            r'/tv/tags/[^/]+/"\s*>(?P<tag>[^<]*?)<',
            webpage)

        view_count = self._search_regex(
            r'class\s*=\s*"gkRight"(?:[^>]*>\s*<[^>]*)*icon-eye-open(?:[^>]*>\s*<[^>]*)*>\s*(?P<view_count>[0-9\.]*)',
            webpage, 'view_count', default=None)
        if view_count:
            view_count = int_or_none(view_count.replace('.', ''))

        average_rating = self._search_regex(
            r'itemprop\s*=\s*"ratingValue"[^>]*>\s*(?P<average_rating>[0-9,]+)',
            webpage, 'average_rating')
        if average_rating:
            average_rating = float_or_none(average_rating.replace(',', '.'))

        video_id = self._search_regex(
            r'https?://movies\.gaskrank\.tv/([^-]*?)(-[^\.]*)?\.mp4',
            webpage, 'video id', default=display_id)

        entry = self._parse_html5_media_entries(url, webpage, video_id)[0]
        entry.update({
            'id': video_id,
            'title': title,
            'categories': categories,
            'display_id': display_id,
            'uploader_id': uploader_id,
            'upload_date': upload_date,
            'uploader_url': uploader_url,
            'tags': tags,
            'view_count': view_count,
            'average_rating': average_rating,
        })
        self._sort_formats(entry['formats'])

        return entry


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

import re

from .common import InfoExtractor

class GazetaIE(InfoExtractor):
    _VALID_URL = r'(?P<url>https?://(?:www\.)?gazeta\.ru/(?:[^/]+/)?video/(?:main/)*(?:\d{4}/\d{2}/\d{2}/)?(?P<id>[A-Za-z0-9-_.]+)\.s?html)'
    _TESTS = [{
        'url': 'http://www.gazeta.ru/video/main/zadaite_vopros_vladislavu_yurevichu.shtml',
        'md5': 'd49c9bdc6e5a7888f27475dc215ee789',
        'info_dict': {
            'id': '205566',
            'ext': 'mp4',
            'title': '«70–80 процентов гражданских в Донецке на грани голода»',
            'description': 'md5:38617526050bd17b234728e7f9620a71',
            'thumbnail': r're:^https?://.*\.jpg',
        },
        'skip': 'video not found',
    }, {
        'url': 'http://www.gazeta.ru/lifestyle/video/2015/03/08/master-klass_krasivoi_byt._delaem_vesennii_makiyazh.shtml',
        'only_matching': True,
    }, {
        'url': 'http://www.gazeta.ru/video/main/main/2015/06/22/platit_ili_ne_platit_po_isku_yukosa.shtml',
        'md5': '37f19f78355eb2f4256ee1688359f24c',
        'info_dict': {
            'id': '252048',
            'ext': 'mp4',
            'title': '"Если по иску ЮКОСа придется платить, это будет большой удар по бюджету"',
        },
        'add_ie': ['EaglePlatform'],
    }]

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)

        display_id = mobj.group('id')
        embed_url = '%s?p=embed' % mobj.group('url')
        embed_page = self._download_webpage(
            embed_url, display_id, 'Downloading embed page')

        video_id = self._search_regex(
            r'<div[^>]*?class="eagleplayer"[^>]*?data-id="([^"]+)"', embed_page, 'video id')

        return self.url_result(
            'eagleplatform:gazeta.media.eagleplatform.com:%s' % video_id, 'EaglePlatform')


code:
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from .kaltura import KalturaIE
from ..utils import (
    HEADRequest,
    sanitized_Request,
    smuggle_url,
    urlencode_postdata,
)

class GDCVaultIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?gdcvault\.com/play/(?P<id>\d+)(?:/(?P<name>[\w-]+))?'
    _NETRC_MACHINE = 'gdcvault'
    _TESTS = [
        {
            'url': 'http://www.gdcvault.com/play/1019721/Doki-Doki-Universe-Sweet-Simple',
            'md5': '7ce8388f544c88b7ac11c7ab1b593704',
            'info_dict': {
                'id': '201311826596_AWNY',
                'display_id': 'Doki-Doki-Universe-Sweet-Simple',
                'ext': 'mp4',
                'title': 'Doki-Doki Universe: Sweet, Simple and Genuine (GDC Next 10)'
            }
        },
        {
            'url': 'http://www.gdcvault.com/play/1015683/Embracing-the-Dark-Art-of',
            'info_dict': {
                'id': '201203272_1330951438328RSXR',
                'display_id': 'Embracing-the-Dark-Art-of',
                'ext': 'flv',
                'title': 'Embracing the Dark Art of Mathematical Modeling in AI'
            },
            'params': {
                'skip_download': True,  # Requires rtmpdump
            }
        },
        {
            'url': 'http://www.gdcvault.com/play/1015301/Thexder-Meets-Windows-95-or',
            'md5': 'a5eb77996ef82118afbbe8e48731b98e',
            'info_dict': {
                'id': '1015301',
                'display_id': 'Thexder-Meets-Windows-95-or',
                'ext': 'flv',
                'title': 'Thexder Meets Windows 95, or Writing Great Games in the Windows 95 Environment',
            },
            'skip': 'Requires login',
        },
        {
            'url': 'http://gdcvault.com/play/1020791/',
            'only_matching': True,
        },
        {
            # Hard-coded hostname
            'url': 'http://gdcvault.com/play/1023460/Tenacious-Design-and-The-Interface',
            'md5': 'a8efb6c31ed06ca8739294960b2dbabd',
            'info_dict': {
                'id': '840376_BQRC',
                'ext': 'mp4',
                'display_id': 'Tenacious-Design-and-The-Interface',
                'title': 'Tenacious Design and The Interface of \'Destiny\'',
            },
        },
        {
            # Multiple audios
            'url': 'http://www.gdcvault.com/play/1014631/Classic-Game-Postmortem-PAC',
            'info_dict': {
                'id': '12396_1299111843500GMPX',
                'ext': 'mp4',
                'title': 'How to Create a Good Game - From My Experience of Designing Pac-Man',
            },
            # 'params': {
            #     'skip_download': True,  # Requires rtmpdump
            #     'format': 'jp',  # The japanese audio
            # }
        },
        {
            # gdc-player.html
            'url': 'http://www.gdcvault.com/play/1435/An-American-engine-in-Tokyo',
            'info_dict': {
                'id': '9350_1238021887562UHXB',
                'display_id': 'An-American-engine-in-Tokyo',
                'ext': 'mp4',
                'title': 'An American Engine in Tokyo:/nThe collaboration of Epic Games and Square Enix/nFor THE LAST REMINANT',
            },
        },
        {
            # Kaltura Embed
            'url': 'https://www.gdcvault.com/play/1026180/Mastering-the-Apex-of-Scaling',
            'info_dict': {
                'id': '0_h1fg8j3p',
                'ext': 'mp4',
                'title': 'Mastering the Apex of Scaling Game Servers (Presented by Multiplay)',
                'timestamp': 1554401811,
                'upload_date': '20190404',
                'uploader_id': 'joe@blazestreaming.com',
            },
            'params': {
                'format': 'mp4-408',
            },
        },
    ]

    def _login(self, webpage_url, display_id):
        username, password = self._get_login_info()
        if username is None or password is None:
            self.report_warning('It looks like ' + webpage_url + ' requires a login. Try specifying a username and password and try again.')
            return None

        mobj = re.match(r'(?P<root_url>https?://.*?/).*', webpage_url)
        login_url = mobj.group('root_url') + 'api/login.php'
        logout_url = mobj.group('root_url') + 'logout'

        login_form = {
            'email': username,
            'password': password,
        }

        request = sanitized_Request(login_url, urlencode_postdata(login_form))
        request.add_header('Content-Type', 'application/x-www-form-urlencoded')
        self._download_webpage(request, display_id, 'Logging in')
        start_page = self._download_webpage(webpage_url, display_id, 'Getting authenticated video page')
        self._download_webpage(logout_url, display_id, 'Logging out')

        return start_page

    def _real_extract(self, url):
        video_id, name = re.match(self._VALID_URL, url).groups()
        display_id = name or video_id

        webpage_url = 'http://www.gdcvault.com/play/' + video_id
        start_page = self._download_webpage(webpage_url, display_id)

        direct_url = self._search_regex(
            r's1\.addVariable\("file",\s*encodeURIComponent\("(/[^"]+)"\)\);',
            start_page, 'url', default=None)
        if direct_url:
            title = self._html_search_regex(
                r'Session Name:?	\s*(.*?)	',
                start_page, 'title')
            video_url = 'http://www.gdcvault.com' + direct_url
            # resolve the url so that we can detect the correct extension
            video_url = self._request_webpage(
                HEADRequest(video_url), video_id).geturl()

            return {
                'id': video_id,
                'display_id': display_id,
                'url': video_url,
                'title': title,
            }

        embed_url = KalturaIE._extract_url(start_page)
        if embed_url:
            embed_url = smuggle_url(embed_url, {'source_url': url})
            ie_key = 'Kaltura'
        else:
            PLAYER_REGEX = r'<iframe src="(?P<xml_root>.+?)/(?:gdc-)?player.*?\.html.*?".*?'

            xml_root = self._html_search_regex(
                PLAYER_REGEX, start_page, 'xml root', default=None)
            if xml_root is None:
                # Probably need to authenticate
                login_res = self._login(webpage_url, display_id)
                if login_res is None:
                    self.report_warning('Could not login.')
                else:
                    start_page = login_res
                    # Grab the url from the authenticated page
                    xml_root = self._html_search_regex(
                        PLAYER_REGEX, start_page, 'xml root')

            xml_name = self._html_search_regex(
                r'<iframe src=".*?\?xml(?:=|URL=xml/)(.+?\.xml).*?".*?',
                start_page, 'xml filename')
            embed_url = '%s/xml/%s' % (xml_root, xml_name)
            ie_key = 'DigitallySpeaking'

        return {
            '_type': 'url_transparent',
            'id': video_id,
            'display_id': display_id,
            'url': embed_url,
            'ie_key': ie_key,
        }