code:
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import (
    decode_packed_codes,
    ExtractorError,
    urlencode_postdata,
)

class SCTEBaseIE(InfoExtractor):
    _LOGIN_URL = 'https://www.scte.org/SCTE/Sign_In.aspx'
    _NETRC_MACHINE = 'scte'

    def _real_initialize(self):
        self._login()

    def _login(self):
        username, password = self._get_login_info()
        if username is None:
            return

        login_popup = self._download_webpage(
            self._LOGIN_URL, None, 'Downloading login popup')

        def is_logged(webpage):
            return any(re.search(p, webpage) for p in (
                r'class=["\']welcome\b', r'>Sign Out<'))

        # already logged in
        if is_logged(login_popup):
            return

        login_form = self._hidden_inputs(login_popup)

        login_form.update({
            'ctl01$TemplateBody$WebPartManager1$gwpciNewContactSignInCommon$ciNewContactSignInCommon$signInUserName': username,
            'ctl01$TemplateBody$WebPartManager1$gwpciNewContactSignInCommon$ciNewContactSignInCommon$signInPassword': password,
            'ctl01$TemplateBody$WebPartManager1$gwpciNewContactSignInCommon$ciNewContactSignInCommon$RememberMe': 'on',
        })

        response = self._download_webpage(
            self._LOGIN_URL, None, 'Logging in',
            data=urlencode_postdata(login_form))

        if '|pageRedirect|' not in response and not is_logged(response):
            error = self._html_search_regex(
                r'(?s)<[^>]+class=["\']AsiError["\'][^>]*>(.+?)</',
                response, 'error message', default=None)
            if error:
                raise ExtractorError('Unable to login: %s' % error, expected=True)
            raise ExtractorError('Unable to log in')

class SCTEIE(SCTEBaseIE):
    _VALID_URL = r'https?://learning\.scte\.org/mod/scorm/view\.php?.*?\bid=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://learning.scte.org/mod/scorm/view.php?id=31484',
        'info_dict': {
            'title': 'Introduction to DOCSIS Engineering Professional',
            'id': '31484',
        },
        'playlist_count': 5,
        'skip': 'Requires account credentials',
    }]

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

        webpage = self._download_webpage(url, video_id)

        title = self._search_regex(r'
(.+?)
', webpage, 'title')

        context_id = self._search_regex(r'context-(\d+)', webpage, video_id)
        content_base = 'https://learning.scte.org/pluginfile.php/%s/mod_scorm/content/8/' % context_id
        context = decode_packed_codes(self._download_webpage(
            '%smobile/data.js' % content_base, video_id))

        data = self._parse_xml(
            self._search_regex(
                r'CreateData\(\s*"(.+?)"', context, 'data').replace(r"\'", "'"),
            video_id)

        entries = []
        for asset in data.findall('.//asset'):
            asset_url = asset.get('url')
            if not asset_url or not asset_url.endswith('.mp4'):
                continue
            asset_id = self._search_regex(
                r'video_([^_]+)_', asset_url, 'asset id', default=None)
            if not asset_id:
                continue
            entries.append({
                'id': asset_id,
                'title': title,
                'url': content_base + asset_url,
            })

        return self.playlist_result(entries, video_id, title)

class SCTECourseIE(SCTEBaseIE):
    _VALID_URL = r'https?://learning\.scte\.org/(?:mod/sub)?course/view\.php?.*?\bid=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://learning.scte.org/mod/subcourse/view.php?id=31491',
        'only_matching': True,
    }, {
        'url': 'https://learning.scte.org/course/view.php?id=3639',
        'only_matching': True,
    }, {
        'url': 'https://learning.scte.org/course/view.php?id=3073',
        'only_matching': True,
    }]

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

        webpage = self._download_webpage(url, course_id)

        title = self._search_regex(
            r'
(.+?)
', webpage, 'title', default=None)

        entries = []
        for mobj in re.finditer(
                r'''(?x)
                    ]+
                        href=(["\'])
                        (?P<url>
                            https?://learning\.scte\.org/mod/
                            (?P<kind>scorm|subcourse)/view\.php?(?:(?!\1).)*?
                            \bid=\d+
                        )
                    ''',
                webpage):
            item_url = mobj.group('url')
            if item_url == url:
                continue
            ie = (SCTEIE.ie_key() if mobj.group('kind') == 'scorm'
                  else SCTECourseIE.ie_key())
            entries.append(self.url_result(item_url, ie=ie))

        return self.playlist_result(entries, course_id, title)


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

import re

from .common import InfoExtractor
from ..utils import (
    get_element_by_class,
    strip_or_none,
)

class SeekerIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?seeker\.com/(?P<display_id>.*)-(?P<article_id>\d+)\.html'
    _TESTS = [{
        'url': 'http://www.seeker.com/should-trump-be-required-to-release-his-tax-returns-1833805621.html',
        'md5': '897d44bbe0d8986a2ead96de565a92db',
        'info_dict': {
            'id': 'Elrn3gnY',
            'ext': 'mp4',
            'title': 'Should Trump Be Required To Release His Tax Returns?',
            'description': 'md5:41efa8cfa8d627841045eec7b018eb45',
            'timestamp': 1490090165,
            'upload_date': '20170321',
        }
    }, {
        'url': 'http://www.seeker.com/changes-expected-at-zoos-following-recent-gorilla-lion-shootings-1834116536.html',
        'playlist': [
            {
                'md5': '0497b9f20495174be73ae136949707d2',
                'info_dict': {
                    'id': 'FihYQ8AE',
                    'ext': 'mp4',
                    'title': 'The Pros & Cons Of Zoos',
                    'description': 'md5:d88f99a8ea8e7d25e6ff77f271b1271c',
                    'timestamp': 1490039133,
                    'upload_date': '20170320',
                },
            }
        ],
        'info_dict': {
            'id': '1834116536',
            'title': 'After Gorilla Killing, Changes Ahead for Zoos',
            'description': 'The largest association of zoos and others are hoping to learn from recent incidents that led to the shooting deaths of a gorilla and two lions.',
        },
    }]

    def _real_extract(self, url):
        display_id, article_id = re.match(self._VALID_URL, url).groups()
        webpage = self._download_webpage(url, display_id)
        entries = []
        for jwp_id in re.findall(r'data-video-id="([a-zA-Z0-9]{8})"', webpage):
            entries.append(self.url_result(
                'jwplatform:' + jwp_id, 'JWPlatform', jwp_id))
        return self.playlist_result(
            entries, article_id,
            self._og_search_title(webpage),
            strip_or_none(get_element_by_class('subtitle__text', webpage)) or self._og_search_description(webpage))

repo_name: rrosajp/youtube


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

import re
from .common import InfoExtractor
from ..utils import (
    ExtractorError,
    unsmuggle_url,
)
from ..compat import (
    compat_parse_qs,
    compat_urlparse,
)

class SenateISVPIE(InfoExtractor):
    _COMM_MAP = [
        ['ag', '76440', 'http://ag-f.akamaihd.net'],
        ['aging', '76442', 'http://aging-f.akamaihd.net'],
        ['approps', '76441', 'http://approps-f.akamaihd.net'],
        ['armed', '76445', 'http://armed-f.akamaihd.net'],
        ['banking', '76446', 'http://banking-f.akamaihd.net'],
        ['budget', '76447', 'http://budget-f.akamaihd.net'],
        ['cecc', '76486', 'http://srs-f.akamaihd.net'],
        ['commerce', '80177', 'http://commerce1-f.akamaihd.net'],
        ['csce', '75229', 'http://srs-f.akamaihd.net'],
        ['dpc', '76590', 'http://dpc-f.akamaihd.net'],
        ['energy', '76448', 'http://energy-f.akamaihd.net'],
        ['epw', '76478', 'http://epw-f.akamaihd.net'],
        ['ethics', '76449', 'http://ethics-f.akamaihd.net'],
        ['finance', '76450', 'http://finance-f.akamaihd.net'],
        ['foreign', '76451', 'http://foreign-f.akamaihd.net'],
        ['govtaff', '76453', 'http://govtaff-f.akamaihd.net'],
        ['help', '76452', 'http://help-f.akamaihd.net'],
        ['indian', '76455', 'http://indian-f.akamaihd.net'],
        ['intel', '76456', 'http://intel-f.akamaihd.net'],
        ['intlnarc', '76457', 'http://intlnarc-f.akamaihd.net'],
        ['jccic', '85180', 'http://jccic-f.akamaihd.net'],
        ['jec', '76458', 'http://jec-f.akamaihd.net'],
        ['judiciary', '76459', 'http://judiciary-f.akamaihd.net'],
        ['rpc', '76591', 'http://rpc-f.akamaihd.net'],
        ['rules', '76460', 'http://rules-f.akamaihd.net'],
        ['saa', '76489', 'http://srs-f.akamaihd.net'],
        ['smbiz', '76461', 'http://smbiz-f.akamaihd.net'],
        ['srs', '75229', 'http://srs-f.akamaihd.net'],
        ['uscc', '76487', 'http://srs-f.akamaihd.net'],
        ['vetaff', '76462', 'http://vetaff-f.akamaihd.net'],
        ['arch', '', 'http://ussenate-f.akamaihd.net/']
    ]
    _IE_NAME = 'senate.gov'
    _VALID_URL = r'https?://(?:www\.)?senate\.gov/isvp/?\?(?P<qs>.+)'
    _TESTS = [{
        'url': 'http://www.senate.gov/isvp/?comm=judiciary&type=live&stt=&filename=judiciary031715&auto_play=false&wmode=transparent&poster=http%3A%2F%2Fwww.judiciary.senate.gov%2Fthemes%2Fjudiciary%2Fimages%2Fvideo-poster-flash-fit.png',
        'info_dict': {
            'id': 'judiciary031715',
            'ext': 'mp4',
            'title': 'Integrated Senate Video Player',
            'thumbnail': r're:^https?://.*\.(?:jpg|png)$',
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }, {
        'url': 'http://www.senate.gov/isvp/?type=live&comm=commerce&filename=commerce011514.mp4&auto_play=false',
        'info_dict': {
            'id': 'commerce011514',
            'ext': 'mp4',
            'title': 'Integrated Senate Video Player'
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }, {
        'url': 'http://www.senate.gov/isvp/?type=arch&comm=intel&filename=intel090613&hc_location=ufi',
        # checksum differs each time
        'info_dict': {
            'id': 'intel090613',
            'ext': 'mp4',
            'title': 'Integrated Senate Video Player'
        }
    }, {
        # From http://www.c-span.org/video/?96791-1
        'url': 'http://www.senate.gov/isvp?type=live&comm=banking&filename=banking012715',
        'only_matching': True,
    }]

    @staticmethod
    def _search_iframe_url(webpage):
        mobj = re.search(
            r"<iframe[^>]+src=['\"](?P<url>https?://www\.senate\.gov/isvp/?\?[^'\"]+)['\"]",
            webpage)
        if mobj:
            return mobj.group('url')

    def _get_info_for_comm(self, committee):
        for entry in self._COMM_MAP:
            if entry[0] == committee:
                return entry[1:]

    def _real_extract(self, url):
        url, smuggled_data = unsmuggle_url(url, {})

        qs = compat_parse_qs(re.match(self._VALID_URL, url).group('qs'))
        if not qs.get('filename') or not qs.get('type') or not qs.get('comm'):
            raise ExtractorError('Invalid URL', expected=True)

        video_id = re.sub(r'.mp4$', '', qs['filename'][0])

        webpage = self._download_webpage(url, video_id)

        if smuggled_data.get('force_title'):
            title = smuggled_data['force_title']
        else:
            title = self._html_search_regex(r'<title>([^<]+)</title>', webpage, video_id)
        poster = qs.get('poster')
        thumbnail = poster[0] if poster else None

        video_type = qs['type'][0]
        committee = video_type if video_type == 'arch' else qs['comm'][0]
        stream_num, domain = self._get_info_for_comm(committee)

        formats = []
        if video_type == 'arch':
            filename = video_id if '.' in video_id else video_id + '.mp4'
            formats = [{
                # All parameters in the query string are necessary to prevent a 403 error
                'url': compat_urlparse.urljoin(domain, filename) + '?v=3.1.0&fp=&r=&g=',
            }]
        else:
            hdcore_sign = 'hdcore=3.1.0'
            url_params = (domain, video_id, stream_num)
            f4m_url = '%s/z/%s_1@%s/manifest.f4m?' % url_params + hdcore_sign
            m3u8_url = '%s/i/%s_1@%s/master.m3u8' % url_params
            for entry in self._extract_f4m_formats(f4m_url, video_id, f4m_id='f4m'):
                # URLs without the extra param induce an 404 error
                entry.update({'extra_param_to_segment_url': hdcore_sign})
                formats.append(entry)
            for entry in self._extract_m3u8_formats(m3u8_url, video_id, ext='mp4', m3u8_id='m3u8'):
                mobj = re.search(r'(?P<tag>(?:-p|-b)).m3u8', entry['url'])
                if mobj:
                    entry['format_id'] += mobj.group('tag')
                formats.append(entry)

            self._sort_formats(formats)

        return {
            'id': video_id,
            'title': title,
            'formats': formats,
            'thumbnail': thumbnail,
        }


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

import re

from .common import InfoExtractor
from ..utils import (
    float_or_none,
    parse_iso8601,
    update_url_query,
    int_or_none,
    determine_protocol,
    unescapeHTML,
)

class SendtoNewsIE(InfoExtractor):
    _VALID_URL = r'https?://embed\.sendtonews\.com/player2/embedplayer\.php\?.*\bSC=(?P<id>[0-9A-Za-z-]+)'

    _TEST = {
        # From http://cleveland.cbslocal.com/2016/05/16/indians-score-season-high-15-runs-in-blowout-win-over-reds-rapid-reaction/
        'url': 'http://embed.sendtonews.com/player2/embedplayer.php?SC=GxfCe0Zo7D-175909-5588&type=single&autoplay=on&sound=YES',
        'info_dict': {
            'id': 'GxfCe0Zo7D-175909-5588'
        },
        'playlist_count': 8,
        # test the first video only to prevent lengthy tests
        'playlist': [{
            'info_dict': {
                'id': '240385',
                'ext': 'mp4',
                'title': 'Indians introduce Encarnacion',
                'description': 'Indians president of baseball operations Chris Antonetti and Edwin Encarnacion discuss the slugger\'s three-year contract with Cleveland',
                'duration': 137.898,
                'thumbnail': r're:https?://.*\.jpg$',
                'upload_date': '20170105',
                'timestamp': 1483649762,
            },
        }],
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }

    _URL_TEMPLATE = '//embed.sendtonews.com/player2/embedplayer.php?SC=%s'

    @classmethod
    def _extract_url(cls, webpage):
        mobj = re.search(r'''(?x)<script[^>]+src=([\'"])
            (?:https?:)?//embed\.sendtonews\.com/player/responsiveembed\.php\?
                .*\bSC=(?P<SC>[0-9a-zA-Z-]+).*
            \1>''', webpage)
        if mobj:
            sc = mobj.group('SC')
            return cls._URL_TEMPLATE % sc

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

        data_url = update_url_query(
            url.replace('embedplayer.php', 'data_read.php'),
            {'cmd': 'loadInitial'})
        playlist_data = self._download_json(data_url, playlist_id)

        entries = []
        for video in playlist_data['playlistData'][0]:
            info_dict = self._parse_jwplayer_data(
                video['jwconfiguration'],
                require_title=False, m3u8_id='hls', rtmp_params={'no_resume': True})

            for f in info_dict['formats']:
                if f.get('tbr'):
                    continue
                tbr = int_or_none(self._search_regex(
                    r'/(\d+)k/', f['url'], 'bitrate', default=None))
                if not tbr:
                    continue
                f.update({
                    'format_id': '%s-%d' % (determine_protocol(f), tbr),
                    'tbr': tbr,
                })
            self._sort_formats(info_dict['formats'], ('tbr', 'height', 'width', 'format_id'))

            thumbnails = []
            if video.get('thumbnailUrl'):
                thumbnails.append({
                    'id': 'normal',
                    'url': video['thumbnailUrl'],
                })
            if video.get('smThumbnailUrl'):
                thumbnails.append({
                    'id': 'small',
                    'url': video['smThumbnailUrl'],
                })
            info_dict.update({
                'title': video['S_headLine'].strip(),
                'description': unescapeHTML(video.get('S_fullStory')),
                'thumbnails': thumbnails,
                'duration': float_or_none(video.get('SM_length')),
                'timestamp': parse_iso8601(video.get('S_sysDate'), delimiter=' '),
            })
            entries.append(info_dict)

        return self.playlist_result(entries, playlist_id)


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

import re

from .common import InfoExtractor

class ServusIE(InfoExtractor):
    _VALID_URL = r'''(?x)
                    https?://
                        (?:www\.)?
                        (?:
                            servus\.com/(?:(?:at|de)/p/[^/]+|tv/videos)|
                            servustv\.com/videos
                        )
                        /(?P<id>[aA]{2}-\w+|\d+-\d+)
                    '''
    _TESTS = [{
        # new URL schema
        'url': 'https://www.servustv.com/videos/aa-1t6vbu5pw1w12/',
        'md5': '3e1dd16775aa8d5cbef23628cfffc1f4',
        'info_dict': {
            'id': 'AA-1T6VBU5PW1W12',
            'ext': 'mp4',
            'title': 'Die Grünen aus Sicht des Volkes',
            'description': 'md5:1247204d85783afe3682644398ff2ec4',
            'thumbnail': r're:^https?://.*\.jpg',
        }
    }, {
        # old URL schema
        'url': 'https://www.servus.com/de/p/Die-Gr%C3%BCnen-aus-Sicht-des-Volkes/AA-1T6VBU5PW1W12/',
        'only_matching': True,
    }, {
        'url': 'https://www.servus.com/at/p/Wie-das-Leben-beginnt/1309984137314-381415152/',
        'only_matching': True,
    }, {
        'url': 'https://www.servus.com/tv/videos/aa-1t6vbu5pw1w12/',
        'only_matching': True,
    }, {
        'url': 'https://www.servus.com/tv/videos/1380889096408-1235196658/',
        'only_matching': True,
    }]

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

        title = self._search_regex(
            (r'videoLabel\s*=\s*(["\'])(?P<title>(?:(?!\1).)+)\1',
             r'<h\d+[^>]+\bclass=["\']heading--(?:one|two)["\'][^>]*>(?P<title>[^<]+)'),
            webpage, 'title', default=None,
            group='title') or self._og_search_title(webpage)
        title = re.sub(r'\s*-\s*Servus TV\s*$', '', title)
        description = self._og_search_description(webpage)
        thumbnail = self._og_search_thumbnail(webpage)

        formats = self._extract_m3u8_formats(
            'https://stv.rbmbtnx.net/api/v1/manifests/%s.m3u8' % video_id,
            video_id, 'mp4', entry_protocol='m3u8_native', m3u8_id='hls')
        self._sort_formats(formats)

        return {
            'id': video_id,
            'title': title,
            'description': description,
            'thumbnail': thumbnail,
            'formats': formats,
        }


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

import re

from .brightcove import BrightcoveNewIE
from ..compat import compat_str
from ..utils import (
    try_get,
    update_url_query,
)

class SevenPlusIE(BrightcoveNewIE):
    IE_NAME = '7plus'
    _VALID_URL = r'https?://(?:www\.)?7plus\.com\.au/(?P<path>[^?]+\?.*?\bepisode-id=(?P<id>[^&#]+))'
    _TESTS = [{
        'url': 'https://7plus.com.au/MTYS?episode-id=MTYS7-003',
        'info_dict': {
            'id': 'MTYS7-003',
            'ext': 'mp4',
            'title': 'S7 E3 - Wind Surf',
            'description': 'md5:29c6a69f21accda7601278f81b46483d',
            'uploader_id': '5303576322001',
            'upload_date': '20171201',
            'timestamp': 1512106377,
            'series': 'Mighty Ships',
            'season_number': 7,
            'episode_number': 3,
            'episode': 'Wind Surf',
        },
        'params': {
            'format': 'bestvideo',
            'skip_download': True,
        }
    }, {
        'url': 'https://7plus.com.au/UUUU?episode-id=AUMS43-001',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        path, episode_id = re.match(self._VALID_URL, url).groups()

        media = self._download_json(
            'https://videoservice.swm.digital/playback', episode_id, query={
                'appId': '7plus',
                'deviceType': 'web',
                'platformType': 'web',
                'accountId': 5303576322001,
                'referenceId': 'ref:' + episode_id,
                'deliveryId': 'csai',
                'videoType': 'vod',
            })['media']

        for source in media.get('sources', {}):
            src = source.get('src')
            if not src:
                continue
            source['src'] = update_url_query(src, {'rule': ''})

        info = self._parse_brightcove_metadata(media, episode_id)

        content = self._download_json(
            'https://component-cdn.swm.digital/content/' + path,
            episode_id, headers={
                'market-id': 4,
            }, fatal=False) or {}
        for item in content.get('items', {}):
            if item.get('componentData', {}).get('componentType') == 'infoPanel':
                for src_key, dst_key in [('title', 'title'), ('shortSynopsis', 'description')]:
                    value = item.get(src_key)
                    if value:
                        info[dst_key] = value
                info['series'] = try_get(
                    item, lambda x: x['seriesLogo']['name'], compat_str)
                mobj = re.search(r'^S(\d+)\s+E(\d+)\s+-\s+(.+)$', info['title'])
                if mobj:
                    info.update({
                        'season_number': int(mobj.group(1)),
                        'episode_number': int(mobj.group(2)),
                        'episode': mobj.group(3),
                    })

        return info


code:
from __future__ import unicode_literals

from .common import InfoExtractor

class SexuIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?sexu\.com/(?P<id>\d+)'
    _TEST = {
        'url': 'http://sexu.com/961791/',
        'md5': 'ff615aca9691053c94f8f10d96cd7884',
        'info_dict': {
            'id': '961791',
            'ext': 'mp4',
            'title': 'md5:4d05a19a5fc049a63dbbaf05fb71d91b',
            'description': 'md5:2b75327061310a3afb3fbd7d09e2e403',
            'categories': list,  # NSFW
            'thumbnail': r're:https?://.*\.jpg$',
            'age_limit': 18,
        }
    }

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

        jwvideo = self._parse_json(
            self._search_regex(r'\.setup\(\s*({.+?})\s*\);', webpage, 'jwvideo'),
            video_id)

        sources = jwvideo['sources']

        formats = [{
            'url': source['file'].replace('\\', ''),
            'format_id': source.get('label'),
            'height': int(self._search_regex(
                r'^(\d+)[pP]', source.get('label', ''), 'height',
                default=None)),
        } for source in sources if source.get('file')]
        self._sort_formats(formats)

        title = self._html_search_regex(
            r'<title>([^<]+)\s*-\s*Sexu\.Com</title>', webpage, 'title')

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

        thumbnail = jwvideo.get('image')

        categories_str = self._html_search_meta(
            'keywords', webpage, 'categories')
        categories = (
            None if categories_str is None
            else categories_str.split(','))

        return {
            'id': video_id,
            'title': title,
            'description': description,
            'thumbnail': thumbnail,
            'categories': categories,
            'formats': formats,
            'age_limit': 18,
        }


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

import json
import math
import re

from .aws import AWSIE
from ..compat import compat_HTTPError
from ..utils import (
    clean_html,
    ExtractorError,
    InAdvancePagedList,
    int_or_none,
    parse_iso8601,
    str_or_none,
    urlencode_postdata,
)

class ShahidBaseIE(AWSIE):
    _AWS_PROXY_HOST = 'api2.shahid.net'
    _AWS_API_KEY = '2RRtuMHx95aNI1Kvtn2rChEuwsCogUd4samGPjLh'

    def _handle_error(self, e):
        fail_data = self._parse_json(
            e.cause.read().decode('utf-8'), None, fatal=False)
        if fail_data:
            faults = fail_data.get('faults', [])
            faults_message = ', '.join([clean_html(fault['userMessage']) for fault in faults if fault.get('userMessage')])
            if faults_message:
                raise ExtractorError(faults_message, expected=True)

    def _call_api(self, path, video_id, request=None):
        query = {}
        if request:
            query['request'] = json.dumps(request)
        try:
            return self._aws_execute_api({
                'uri': '/proxy/v2/' + path,
                'access_key': 'AKIAI6X4TYCIXM2B7MUQ',
                'secret_key': '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',
            }, video_id, query)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError):
                self._handle_error(e)
            raise

class ShahidIE(ShahidBaseIE):
    _NETRC_MACHINE = 'shahid'
    _VALID_URL = r'https?://shahid\.mbc\.net/ar/(?:serie|show|movie)s/[^/]+/(?P<type>episode|clip|movie)-(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://shahid.mbc.net/ar/shows/%D9%85%D8%AC%D9%84%D8%B3-%D8%A7%D9%84%D8%B4%D8%A8%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D9%88%D8%B3%D9%85-1-%D9%83%D9%84%D9%8A%D8%A8-1/clip-275286',
        'info_dict': {
            'id': '275286',
            'ext': 'mp4',
            'title': 'مجلس الشباب الموسم 1 كليب 1',
            'timestamp': 1506988800,
            'upload_date': '20171003',
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        }
    }, {
        'url': 'https://shahid.mbc.net/ar/movies/%D8%A7%D9%84%D9%82%D9%86%D8%A7%D8%B5%D8%A9/movie-151746',
        'only_matching': True
    }, {
        # shahid plus subscriber only
        'url': 'https://shahid.mbc.net/ar/series/%D9%85%D8%B1%D8%A7%D9%8A%D8%A7-2011-%D8%A7%D9%84%D9%85%D9%88%D8%B3%D9%85-1-%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A9-1/episode-90511',
        'only_matching': True
    }]

    def _real_initialize(self):
        email, password = self._get_login_info()
        if email is None:
            return

        try:
            user_data = self._download_json(
                'https://shahid.mbc.net/wd/service/users/login',
                None, 'Logging in', data=json.dumps({
                    'email': email,
                    'password': password,
                    'basic': 'false',
                }).encode('utf-8'), headers={
                    'Content-Type': 'application/json; charset=UTF-8',
                })['user']
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError):
                self._handle_error(e)
            raise

        self._download_webpage(
            'https://shahid.mbc.net/populateContext',
            None, 'Populate Context', data=urlencode_postdata({
                'firstName': user_data['firstName'],
                'lastName': user_data['lastName'],
                'userName': user_data['email'],
                'csg_user_name': user_data['email'],
                'subscriberId': user_data['id'],
                'sessionId': user_data['sessionId'],
            }))

    def _real_extract(self, url):
        page_type, video_id = re.match(self._VALID_URL, url).groups()
        if page_type == 'clip':
            page_type = 'episode'

        playout = self._call_api(
            'playout/url/' + video_id, video_id)['playout']

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

        formats = self._extract_m3u8_formats(playout['url'], video_id, 'mp4')
        self._sort_formats(formats)

        # video = self._call_api(
        #     'product/id', video_id, {
        #         'id': video_id,
        #         'productType': 'ASSET',
        #         'productSubType': page_type.upper()
        #     })['productModel']

        response = self._download_json(
            'http://api.shahid.net/api/v1_1/%s/%s' % (page_type, video_id),
            video_id, 'Downloading video JSON', query={
                'apiKey': 'sh@hid0nlin3',
                'hash': 'b2wMCTHpSmyxGqQjJFOycRmLSex+BpTK/ooxy6vHaqs=',
            })
        data = response.get('data', {})
        error = data.get('error')
        if error:
            raise ExtractorError(
                '%s returned error: %s' % (self.IE_NAME, '\n'.join(error.values())),
                expected=True)

        video = data[page_type]
        title = video['title']
        categories = [
            category['name']
            for category in video.get('genres', []) if 'name' in category]

        return {
            'id': video_id,
            'title': title,
            'description': video.get('description'),
            'thumbnail': video.get('thumbnailUrl'),
            'duration': int_or_none(video.get('duration')),
            'timestamp': parse_iso8601(video.get('referenceDate')),
            'categories': categories,
            'series': video.get('showTitle') or video.get('showName'),
            'season': video.get('seasonTitle'),
            'season_number': int_or_none(video.get('seasonNumber')),
            'season_id': str_or_none(video.get('seasonId')),
            'episode_number': int_or_none(video.get('number')),
            'episode_id': video_id,
            'formats': formats,
        }

class ShahidShowIE(ShahidBaseIE):
    _VALID_URL = r'https?://shahid\.mbc\.net/ar/(?:show|serie)s/[^/]+/(?:show|series)-(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://shahid.mbc.net/ar/shows/%D8%B1%D8%A7%D9%85%D8%B2-%D9%82%D8%B1%D8%B4-%D8%A7%D9%84%D8%A8%D8%AD%D8%B1/show-79187',
        'info_dict': {
            'id': '79187',
            'title': 'رامز قرش البحر',
            'description': 'md5:c88fa7e0f02b0abd39d417aee0d046ff',
        },
        'playlist_mincount': 32,
    }, {
        'url': 'https://shahid.mbc.net/ar/series/How-to-live-Longer-(The-Big-Think)/series-291861',
        'only_matching': True
    }]
    _PAGE_SIZE = 30

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

        product = self._call_api(
            'playableAsset', show_id, {'showId': show_id})['productModel']
        playlist = product['playlist']
        playlist_id = playlist['id']
        show = product.get('show', {})

        def page_func(page_num):
            playlist = self._call_api(
                'product/playlist', show_id, {
                    'playListId': playlist_id,
                    'pageNumber': page_num,
                    'pageSize': 30,
                    'sorts': [{
                        'order': 'DESC',
                        'type': 'SORTDATE'
                    }],
                })
            for product in playlist.get('productList', {}).get('products', []):
                product_url = product.get('productUrl', []).get('url')
                if not product_url:
                    continue
                yield self.url_result(
                    product_url, 'Shahid',
                    str_or_none(product.get('id')),
                    product.get('title'))

        entries = InAdvancePagedList(
            page_func,
            math.ceil(playlist['count'] / self._PAGE_SIZE),
            self._PAGE_SIZE)

        return self.playlist_result(
            entries, show_id, show.get('title'), show.get('description'))


code:
from __future__ import unicode_literals

from .common import InfoExtractor
from ..compat import (
    compat_b64decode,
    compat_urllib_parse_unquote_plus,
)
from ..utils import (
    determine_ext,
    ExtractorError,
    int_or_none,
    js_to_json,
    KNOWN_EXTENSIONS,
    parse_filesize,
    rot47,
    url_or_none,
    urlencode_postdata,
)

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

        webpage, urlh = self._download_webpage_handle(url, video_id)

        if self._FILE_NOT_FOUND in webpage:
            raise ExtractorError(
                'Video %s does not exist' % video_id, expected=True)

        video_url = self._extract_video_url(webpage, video_id, url)

        title = self._extract_title(webpage)
        filesize = int_or_none(self._extract_filesize(webpage))

        return {
            'id': video_id,
            'url': video_url,
            'ext': 'mp4',
            'filesize': filesize,
            'title': title,
        }

    def _extract_title(self, webpage):
        return compat_b64decode(self._html_search_meta(
            'full:title', webpage, 'title')).decode('utf-8')

    def _extract_filesize(self, webpage):
        return self._html_search_meta(
            'full:size', webpage, 'file size', fatal=False)

class SharedIE(SharedBaseIE):
    IE_DESC = 'shared.sx'
    _VALID_URL = r'https?://shared\.sx/(?P<id>[\da-z]{10})'
    _FILE_NOT_FOUND = '>File does not exist<'

    _TEST = {
        'url': 'http://shared.sx/0060718775',
        'md5': '106fefed92a8a2adb8c98e6a0652f49b',
        'info_dict': {
            'id': '0060718775',
            'ext': 'mp4',
            'title': 'Bmp4',
            'filesize': 1720110,
        },
    }

    def _extract_video_url(self, webpage, video_id, url):
        download_form = self._hidden_inputs(webpage)

        video_page = self._download_webpage(
            url, video_id, 'Downloading video page',
            data=urlencode_postdata(download_form),
            headers={
                'Content-Type': 'application/x-www-form-urlencoded',
                'Referer': url,
            })

        video_url = self._html_search_regex(
            r'data-url=(["\'])(?P<url>(?:(?!\1).)+)\1',
            video_page, 'video URL', group='url')

        return video_url

class VivoIE(SharedBaseIE):
    IE_DESC = 'vivo.sx'
    _VALID_URL = r'https?://vivo\.sx/(?P<id>[\da-z]{10})'
    _FILE_NOT_FOUND = '>The file you have requested does not exists or has been removed'

    _TEST = {
        'url': 'http://vivo.sx/d7ddda0e78',
        'md5': '15b3af41be0b4fe01f4df075c2678b2c',
        'info_dict': {
            'id': 'd7ddda0e78',
            'ext': 'mp4',
            'title': 'Chicken',
            'filesize': 515659,
        },
    }

    def _extract_title(self, webpage):
        title = self._html_search_regex(
            r'data-name\s*=\s*(["\'])(?P<title>(?:(?!\1).)+)\1', webpage,
            'title', default=None, group='title')
        if title:
            ext = determine_ext(title)
            if ext.lower() in KNOWN_EXTENSIONS:
                title = title.rpartition('.' + ext)[0]
            return title
        return self._og_search_title(webpage)

    def _extract_filesize(self, webpage):
        return parse_filesize(self._search_regex(
            r'data-type=["\']video["\'][^>]*>Watch.*?<strong>\s*\((.+?)\)',
            webpage, 'filesize', fatal=False))

    def _extract_video_url(self, webpage, video_id, url):
        def decode_url_old(encoded_url):
            return compat_b64decode(encoded_url).decode('utf-8')

        stream_url = self._search_regex(
            r'data-stream\s*=\s*(["\'])(?P<url>(?:(?!\1).)+)\1', webpage,
            'stream url', default=None, group='url')
        if stream_url:
            stream_url = url_or_none(decode_url_old(stream_url))
        if stream_url:
            return stream_url

        def decode_url(encoded_url):
            return rot47(compat_urllib_parse_unquote_plus(encoded_url))

        return decode_url(self._parse_json(
            self._search_regex(
                r'(?s)InitializeStream\s*\(\s*({.+?})\s*\)\s*;', webpage,
                'stream'),
            video_id, transform_source=js_to_json)['source'])


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

from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
    ExtractorError,
    int_or_none,
    urljoin,
)

class ShowRoomLiveIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?showroom-live\.com/(?!onlive|timetable|event|campaign|news|ranking|room)(?P<id>[^/?#&]+)'
    _TEST = {
        'url': 'https://www.showroom-live.com/48_Nana_Okada',
        'only_matching': True,
    }

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

        webpage = self._download_webpage(url, broadcaster_id)

        room_id = self._search_regex(
            (r'SrGlobal\.roomId\s*=\s*(\d+)',
             r'(?:profile|room)\?room_id\=(\d+)'), webpage, 'room_id')

        room = self._download_json(
            urljoin(url, '/api/room/profile?room_id=%s' % room_id),
            broadcaster_id)

        is_live = room.get('is_onlive')
        if is_live is not True:
            raise ExtractorError('%s is offline' % broadcaster_id, expected=True)

        uploader = room.get('performer_name') or broadcaster_id
        title = room.get('room_name') or room.get('main_name') or uploader

        streaming_url_list = self._download_json(
            urljoin(url, '/api/live/streaming_url?room_id=%s' % room_id),
            broadcaster_id)['streaming_url_list']

        formats = []
        for stream in streaming_url_list:
            stream_url = stream.get('url')
            if not stream_url:
                continue
            stream_type = stream.get('type')
            if stream_type == 'hls':
                m3u8_formats = self._extract_m3u8_formats(
                    stream_url, broadcaster_id, ext='mp4', m3u8_id='hls',
                    live=True)
                for f in m3u8_formats:
                    f['quality'] = int_or_none(stream.get('quality', 100))
                formats.extend(m3u8_formats)
            elif stream_type == 'rtmp':
                stream_name = stream.get('stream_name')
                if not stream_name:
                    continue
                formats.append({
                    'url': stream_url,
                    'play_path': stream_name,
                    'page_url': url,
                    'player_url': 'https://www.showroom-live.com/assets/swf/v3/ShowRoomLive.swf',
                    'rtmp_live': True,
                    'ext': 'flv',
                    'format_id': 'rtmp',
                    'format_note': stream.get('label'),
                    'quality': int_or_none(stream.get('quality', 100)),
                })
        self._sort_formats(formats)

        return {
            'id': compat_str(room.get('live_id') or broadcaster_id),
            'title': self._live_title(title),
            'description': room.get('description'),
            'timestamp': int_or_none(room.get('current_live_started_at')),
            'uploader': uploader,
            'uploader_id': broadcaster_id,
            'view_count': int_or_none(room.get('view_num')),
            'formats': formats,
            'is_live': True,
        }


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

import re

from .common import InfoExtractor
from ..utils import (
    HEADRequest,
    ExtractorError,
    int_or_none,
    update_url_query,
    qualities,
    get_element_by_attribute,
    clean_html,
)

class SinaIE(InfoExtractor):
    _VALID_URL = r'''(?x)https?://(?:.*?\.)?video\.sina\.com\.cn/
                        (?:
                            (?:view/|.*\#)(?P<video_id>\d+)|
                            .+?/(?P<pseudo_id>[^/?#]+)(?:\.s?html)|
                            # This is used by external sites like Weibo
                            api/sinawebApi/outplay.php/(?P<token>.+?)\.swf
                        )
                  '''

    _TESTS = [
        {
            'url': 'http://video.sina.com.cn/news/spj/topvideoes20160504/?opsubject_id=top1#250576622',
            'md5': 'd38433e2fc886007729735650ae4b3e9',
            'info_dict': {
                'id': '250576622',
                'ext': 'mp4',
                'title': '现场:克鲁兹宣布退选 特朗普将稳获提名',
            }
        },
        {
            'url': 'http://video.sina.com.cn/v/b/101314253-1290078633.html',
            'info_dict': {
                'id': '101314253',
                'ext': 'flv',
                'title': '军方提高对朝情报监视级别',
            },
            'skip': 'the page does not exist or has been deleted',
        },
        {
            'url': 'http://video.sina.com.cn/view/250587748.html',
            'md5': '3d1807a25c775092aab3bc157fff49b4',
            'info_dict': {
                'id': '250587748',
                'ext': 'mp4',
                'title': '瞬间泪目：8年前汶川地震珍贵视频首曝光',
            },
        },
    ]

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

        video_id = mobj.group('video_id')
        if not video_id:
            if mobj.group('token') is not None:
                # The video id is in the redirected url
                self.to_screen('Getting video id')
                request = HEADRequest(url)
                _, urlh = self._download_webpage_handle(request, 'NA', False)
                return self._real_extract(urlh.geturl())
            else:
                pseudo_id = mobj.group('pseudo_id')
                webpage = self._download_webpage(url, pseudo_id)
                error = get_element_by_attribute('class', 'errtitle', webpage)
                if error:
                    raise ExtractorError('%s said: %s' % (
                        self.IE_NAME, clean_html(error)), expected=True)
                video_id = self._search_regex(
                    r"video_id\s*:\s*'(\d+)'", webpage, 'video id')

        video_data = self._download_json(
            'http://s.video.sina.com.cn/video/h5play',
            video_id, query={'video_id': video_id})
        if video_data['code'] != 1:
            raise ExtractorError('%s said: %s' % (
                self.IE_NAME, video_data['message']), expected=True)
        else:
            video_data = video_data['data']
            title = video_data['title']
            description = video_data.get('description')
            if description:
                description = description.strip()

            preference = qualities(['cif', 'sd', 'hd', 'fhd', 'ffd'])
            formats = []
            for quality_id, quality in video_data.get('videos', {}).get('mp4', {}).items():
                file_api = quality.get('file_api')
                file_id = quality.get('file_id')
                if not file_api or not file_id:
                    continue
                formats.append({
                    'format_id': quality_id,
                    'url': update_url_query(file_api, {'vid': file_id}),
                    'preference': preference(quality_id),
                    'ext': 'mp4',
                })
            self._sort_formats(formats)

            return {
                'id': video_id,
                'title': title,
                'description': description,
                'thumbnail': video_data.get('image'),
                'duration': int_or_none(video_data.get('length')),
                'timestamp': int_or_none(video_data.get('create_time')),
                'formats': formats,
            }


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

import re

from .common import InfoExtractor
from ..compat import (
    compat_parse_qs,
    compat_str,
    compat_urllib_parse_urlparse,
)
from ..utils import (
    determine_ext,
    int_or_none,
    try_get,
    qualities,
)

class SixPlayIE(InfoExtractor):
    IE_NAME = '6play'
    _VALID_URL = r'(?:6play:|https?://(?:www\.)?(?P<domain>6play\.fr|rtlplay\.be|play\.rtl\.hr|rtlmost\.hu)/.+?-c_)(?P<id>[0-9]+)'
    _TESTS = [{
        'url': 'https://www.6play.fr/minute-par-minute-p_9533/le-but-qui-a-marque-lhistoire-du-football-francais-c_12041051',
        'md5': '31fcd112637baa0c2ab92c4fcd8baf27',
        'info_dict': {
            'id': '12041051',
            'ext': 'mp4',
            'title': 'Le but qui a marqué l\'histoire du football français !',
            'description': 'md5:b59e7e841d646ef1eb42a7868eb6a851',
        },
    }, {
        'url': 'https://www.rtlplay.be/rtl-info-13h-p_8551/les-titres-du-rtlinfo-13h-c_12045869',
        'only_matching': True,
    }, {
        'url': 'https://play.rtl.hr/pj-masks-p_9455/epizoda-34-sezona-1-catboyevo-cudo-na-dva-kotaca-c_11984989',
        'only_matching': True,
    }, {
        'url': 'https://www.rtlmost.hu/megtorve-p_14167/megtorve-6-resz-c_12397787',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        domain, video_id = re.search(self._VALID_URL, url).groups()
        service, consumer_name = {
            '6play.fr': ('6play', 'm6web'),
            'rtlplay.be': ('rtlbe_rtl_play', 'rtlbe'),
            'play.rtl.hr': ('rtlhr_rtl_play', 'rtlhr'),
            'rtlmost.hu': ('rtlhu_rtl_most', 'rtlhu'),
        }.get(domain, ('6play', 'm6web'))

        data = self._download_json(
            'https://pc.middleware.6play.fr/6play/v2/platforms/m6group_web/services/%s/videos/clip_%s' % (service, video_id),
            video_id, headers={
                'x-customer-name': consumer_name
            }, query={
                'csa': 5,
                'with': 'clips',
            })

        clip_data = data['clips'][0]
        title = clip_data['title']

        urls = []
        quality_key = qualities(['lq', 'sd', 'hq', 'hd'])
        formats = []
        subtitles = {}
        assets = clip_data.get('assets') or []
        for asset in assets:
            asset_url = asset.get('full_physical_path')
            protocol = asset.get('protocol')
            if not asset_url or ((protocol == 'primetime' or asset.get('type') == 'usp_hlsfp_h264') and not ('_drmnp.ism/' in asset_url or '_unpnp.ism/' in asset_url)) or asset_url in urls:
                continue
            urls.append(asset_url)
            container = asset.get('video_container')
            ext = determine_ext(asset_url)
            if protocol == 'http_subtitle' or ext == 'vtt':
                subtitles.setdefault('fr', []).append({'url': asset_url})
                continue
            if container == 'm3u8' or ext == 'm3u8':
                if protocol == 'usp':
                    if compat_parse_qs(compat_urllib_parse_urlparse(asset_url).query).get('token', [None])[0]:
                        urlh = self._request_webpage(
                            asset_url, video_id, fatal=False,
                            headers=self.geo_verification_headers())
                        if not urlh:
                            continue
                        asset_url = urlh.geturl()
                    asset_url = asset_url.replace('_drmnp.ism/', '_unpnp.ism/')
                    for i in range(3, 0, -1):
                        asset_url = asset_url = asset_url.replace('_sd1/', '_sd%d/' % i)
                        m3u8_formats = self._extract_m3u8_formats(
                            asset_url, video_id, 'mp4', 'm3u8_native',
                            m3u8_id='hls', fatal=False)
                        formats.extend(m3u8_formats)
                        formats.extend(self._extract_mpd_formats(
                            asset_url.replace('.m3u8', '.mpd'),
                            video_id, mpd_id='dash', fatal=False))
                        if m3u8_formats:
                            break
                else:
                    formats.extend(self._extract_m3u8_formats(
                        asset_url, video_id, 'mp4', 'm3u8_native',
                        m3u8_id='hls', fatal=False))
            elif container == 'mp4' or ext == 'mp4':
                quality = asset.get('video_quality')
                formats.append({
                    'url': asset_url,
                    'format_id': quality,
                    'quality': quality_key(quality),
                    'ext': ext,
                })
        self._sort_formats(formats)

        def get(getter):
            for src in (data, clip_data):
                v = try_get(src, getter, compat_str)
                if v:
                    return v

        return {
            'id': video_id,
            'title': title,
            'description': get(lambda x: x['description']),
            'duration': int_or_none(clip_data.get('duration')),
            'series': get(lambda x: x['program']['title']),
            'formats': formats,
            'subtitles': subtitles,
        }


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

from .common import InfoExtractor
from ..utils import (
    extract_attributes,
    smuggle_url,
    strip_or_none,
    urljoin,
)

class SkyBaseIE(InfoExtractor):
    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        video_data = extract_attributes(self._search_regex(
            r'(<div.+?class="[^"]*sdc-article-video__media-ooyala[^"]*"[^>]+>)',
            webpage, 'video data'))

        video_url = 'ooyala:%s' % video_data['data-video-id']
        if video_data.get('data-token-required') == 'true':
            token_fetch_options = self._parse_json(video_data.get(
                'data-token-fetch-options', '{}'), video_id, fatal=False) or {}
            token_fetch_url = token_fetch_options.get('url')
            if token_fetch_url:
                embed_token = self._download_webpage(urljoin(
                    url, token_fetch_url), video_id, fatal=False)
                if embed_token:
                    video_url = smuggle_url(
                        video_url, {'embed_token': embed_token.strip('"')})

        return {
            '_type': 'url_transparent',
            'id': video_id,
            'url': video_url,
            'title': self._og_search_title(webpage),
            'description': strip_or_none(self._og_search_description(webpage)),
            'ie_key': 'Ooyala',
        }

class SkySportsIE(SkyBaseIE):
    _VALID_URL = r'https?://(?:www\.)?skysports\.com/watch/video/(?P<id>[0-9]+)'
    _TEST = {
        'url': 'http://www.skysports.com/watch/video/10328419/bale-its-our-time-to-shine',
        'md5': '77d59166cddc8d3cb7b13e35eaf0f5ec',
        'info_dict': {
            'id': 'o3eWJnNDE6l7kfNO8BOoBlRxXRQ4ANNQ',
            'ext': 'mp4',
            'title': 'Bale: It\'s our time to shine',
            'description': 'md5:e88bda94ae15f7720c5cb467e777bb6d',
        },
        'add_ie': ['Ooyala'],
    }

class SkyNewsIE(SkyBaseIE):
    _VALID_URL = r'https?://news\.sky\.com/video/[0-9a-z-]+-(?P<id>[0-9]+)'
    _TEST = {
        'url': 'https://news.sky.com/video/russian-plane-inspected-after-deadly-fire-11712962',
        'md5': 'd6327e581473cea9976a3236ded370cd',
        'info_dict': {
            'id': '1ua21xaDE6lCtZDmbYfl8kwsKLooJbNM',
            'ext': 'mp4',
            'title': 'Russian plane inspected after deadly fire',
            'description': 'The Russian Investigative Committee has released video of the wreckage of a passenger plane which caught fire near Moscow.',
        },
        'add_ie': ['Ooyala'],
    }


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

from .common import InfoExtractor

class SkylineWebcamsIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?skylinewebcams\.com/[^/]+/webcam/(?:[^/]+/)+(?P<id>[^/]+)\.html'
    _TEST = {
        'url': 'https://www.skylinewebcams.com/it/webcam/italia/lazio/roma/scalinata-piazza-di-spagna-barcaccia.html',
        'info_dict': {
            'id': 'scalinata-piazza-di-spagna-barcaccia',
            'ext': 'mp4',
            'title': 're:^Live Webcam Scalinata di Piazza di Spagna - La Barcaccia [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
            'description': 'Roma, veduta sulla Scalinata di Piazza di Spagna e sulla Barcaccia',
            'is_live': True,
        },
        'params': {
            'skip_download': True,
        }
    }

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

        webpage = self._download_webpage(url, video_id)

        stream_url = self._search_regex(
            r'(?:url|source)\s*:\s*(["\'])(?P<url>(?:https?:)?//.+?\.m3u8.*?)\1', webpage,
            'stream url', group='url')

        title = self._og_search_title(webpage)
        description = self._og_search_description(webpage)

        return {
            'id': video_id,
            'url': stream_url,
            'ext': 'mp4',
            'title': self._live_title(title),
            'description': description,
            'is_live': True,
        }


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

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

class SkyNewsArabiaBaseIE(InfoExtractor):
    _IMAGE_BASE_URL = 'http://www.skynewsarabia.com/web/images'

    def _call_api(self, path, value):
        return self._download_json('http://api.skynewsarabia.com/web/rest/v2/%s/%s.json' % (path, value), value)

    def _get_limelight_media_id(self, url):
        return self._search_regex(r'/media/[^/]+/([a-z0-9]{32})', url, 'limelight media id')

    def _get_image_url(self, image_path_template, width='1600', height='1200'):
        return self._IMAGE_BASE_URL + image_path_template.format(width=width, height=height)

    def _extract_video_info(self, video_data):
        video_id = compat_str(video_data['id'])
        topic = video_data.get('topicTitle')
        return {
            '_type': 'url_transparent',
            'url': 'limelight:media:%s' % self._get_limelight_media_id(video_data['videoUrl'][0]['url']),
            'id': video_id,
            'title': video_data['headline'],
            'description': video_data.get('summary'),
            'thumbnail': self._get_image_url(video_data['mediaAsset']['imageUrl']),
            'timestamp': parse_iso8601(video_data.get('date')),
            'duration': parse_duration(video_data.get('runTime')),
            'tags': video_data.get('tags', []),
            'categories': [topic] if topic else [],
            'webpage_url': 'http://www.skynewsarabia.com/web/video/%s' % video_id,
            'ie_key': 'LimelightMedia',
        }

class SkyNewsArabiaIE(SkyNewsArabiaBaseIE):
    IE_NAME = 'skynewsarabia:video'
    _VALID_URL = r'https?://(?:www\.)?skynewsarabia\.com/web/video/(?P<id>[0-9]+)'
    _TEST = {
        'url': 'http://www.skynewsarabia.com/web/video/794902/%D9%86%D8%B5%D9%81-%D9%85%D9%84%D9%8A%D9%88%D9%86-%D9%85%D8%B5%D8%A8%D8%A7%D8%AD-%D8%B4%D8%AC%D8%B1%D8%A9-%D9%83%D8%B1%D9%8A%D8%B3%D9%85%D8%A7%D8%B3',
        'info_dict': {
            'id': '794902',
            'ext': 'flv',
            'title': 'نصف مليون مصباح على شجرة كريسماس',
            'description': 'md5:22f1b27f0850eeb10c7e59b1f16eb7c6',
            'upload_date': '20151128',
            'timestamp': 1448697198,
            'duration': 2119,
        },
        'params': {
            # rtmp download
            'skip_download': True,
        },
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)
        video_data = self._call_api('video', video_id)
        return self._extract_video_info(video_data)

class SkyNewsArabiaArticleIE(SkyNewsArabiaBaseIE):
    IE_NAME = 'skynewsarabia:article'
    _VALID_URL = r'https?://(?:www\.)?skynewsarabia\.com/web/article/(?P<id>[0-9]+)'
    _TESTS = [{
        'url': 'http://www.skynewsarabia.com/web/article/794549/%D8%A7%D9%94%D8%AD%D8%AF%D8%A7%D8%AB-%D8%A7%D9%84%D8%B4%D8%B1%D9%82-%D8%A7%D9%84%D8%A7%D9%94%D9%88%D8%B3%D8%B7-%D8%AE%D8%B1%D9%8A%D8%B7%D8%A9-%D8%A7%D9%84%D8%A7%D9%94%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%B0%D9%83%D9%8A%D8%A9',
        'info_dict': {
            'id': '794549',
            'ext': 'flv',
            'title': 'بالفيديو.. ألعاب ذكية تحاكي واقع المنطقة',
            'description': 'md5:0c373d29919a851e080ee4edd0c5d97f',
            'upload_date': '20151126',
            'timestamp': 1448559336,
            'duration': 281.6,
        },
        'params': {
            # rtmp download
            'skip_download': True,
        },
    }, {
        'url': 'http://www.skynewsarabia.com/web/article/794844/%D8%A7%D8%B3%D8%AA%D9%87%D8%AF%D8%A7%D9%81-%D9%82%D9%88%D8%A7%D8%B1%D8%A8-%D8%A7%D9%94%D8%B3%D9%84%D8%AD%D8%A9-%D9%84%D9%85%D9%8A%D9%84%D9%8A%D8%B4%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D9%88%D8%AB%D9%8A-%D9%88%D8%B5%D8%A7%D9%84%D8%AD',
        'info_dict': {
            'id': '794844',
            'title': 'إحباط تهريب أسلحة لميليشيات الحوثي وصالح بجنوب اليمن',
            'description': 'md5:5c927b8b2e805796e7f693538d96fc7e',
        },
        'playlist_mincount': 2,
    }]

    def _real_extract(self, url):
        article_id = self._match_id(url)
        article_data = self._call_api('article', article_id)
        media_asset = article_data['mediaAsset']
        if media_asset['type'] == 'VIDEO':
            topic = article_data.get('topicTitle')
            return {
                '_type': 'url_transparent',
                'url': 'limelight:media:%s' % self._get_limelight_media_id(media_asset['videoUrl'][0]['url']),
                'id': article_id,
                'title': article_data['headline'],
                'description': article_data.get('summary'),
                'thumbnail': self._get_image_url(media_asset['imageUrl']),
                'timestamp': parse_iso8601(article_data.get('date')),
                'tags': article_data.get('tags', []),
                'categories': [topic] if topic else [],
                'webpage_url': url,
                'ie_key': 'LimelightMedia',
            }
        entries = [self._extract_video_info(item) for item in article_data.get('inlineItems', []) if item['type'] == 'VIDEO']
        return self.playlist_result(entries, article_id, article_data['headline'], article_data.get('summary'))


code:
from __future__ import unicode_literals

import re
import json

from .common import InfoExtractor
from ..compat import (
    compat_urlparse,
)
from ..utils import (
    ExtractorError,
    get_element_by_id,
)

class SlideshareIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?slideshare\.net/[^/]+?/(?P<title>.+?)($|\?)'

    _TEST = {
        'url': 'http://www.slideshare.net/Dataversity/keynote-presentation-managing-scale-and-complexity',
        'info_dict': {
            'id': '25665706',
            'ext': 'mp4',
            'title': 'Managing Scale and Complexity',
            'description': 'This was a keynote presentation at the NoSQL Now! 2013 Conference & Expo (http://www.nosqlnow.com). This presentation was given by Adrian Cockcroft from Netflix.',
        },
    }

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        page_title = mobj.group('title')
        webpage = self._download_webpage(url, page_title)
        slideshare_obj = self._search_regex(
            r'\$\.extend\(.*?slideshare_object,\s*(\{.*?\})\);',
            webpage, 'slideshare object')
        info = json.loads(slideshare_obj)
        if info['slideshow']['type'] != 'video':
            raise ExtractorError('Webpage type is "%s": only video extraction is supported for Slideshare' % info['slideshow']['type'], expected=True)

        doc = info['doc']
        bucket = info['jsplayer']['video_bucket']
        ext = info['jsplayer']['video_extension']
        video_url = compat_urlparse.urljoin(bucket, doc + '-SD.' + ext)
        description = get_element_by_id('slideshow-description-paragraph', webpage) or self._html_search_regex(
            r'(?s)<p[^>]+itemprop="description"[^>]*>(.+?)</p>', webpage,
            'description', fatal=False)

        return {
            '_type': 'video',
            'id': info['slideshow']['id'],
            'title': info['slideshow']['title'],
            'ext': ext,
            'url': video_url,
            'thumbnail': info['slideshow']['pin_image_url'],
            'description': description.strip() if description else None,
        }


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

from .common import InfoExtractor
from ..utils import smuggle_url

class SlidesLiveIE(InfoExtractor):
    _VALID_URL = r'https?://slideslive\.com/(?P<id>[0-9]+)'
    _TESTS = [{
        # video_service_name = YOUTUBE
        'url': 'https://slideslive.com/38902413/gcc-ia16-backend',
        'md5': 'b29fcd6c6952d0c79c5079b0e7a07e6f',
        'info_dict': {
            'id': 'LMtgR8ba0b0',
            'ext': 'mp4',
            'title': 'GCC IA16 backend',
            'description': 'Watch full version of this video at https://slideslive.com/38902413.',
            'uploader': 'SlidesLive Videos - A',
            'uploader_id': 'UC62SdArr41t_-_fX40QCLRw',
            'upload_date': '20170925',
        }
    }, {
        # video_service_name = youtube
        'url': 'https://slideslive.com/38903721/magic-a-scientific-resurrection-of-an-esoteric-legend',
        'only_matching': True,
    }, {
        # video_service_name = url
        'url': 'https://slideslive.com/38922070/learning-transferable-skills-1',
        'only_matching': True,
    }, {
        # video_service_name = vimeo
        'url': 'https://slideslive.com/38921896/retrospectives-a-venue-for-selfreflection-in-ml-research-3',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        video_data = self._download_json(
            'https://ben.slideslive.com/player/' + video_id, video_id)
        service_name = video_data['video_service_name'].lower()
        assert service_name in ('url', 'vimeo', 'youtube')
        service_id = video_data['video_service_id']
        info = {
            'id': video_id,
            'thumbnail': video_data.get('thumbnail'),
            'url': service_id,
        }
        if service_name == 'url':
            info['title'] = video_data['title']
        else:
            info.update({
                '_type': 'url_transparent',
                'ie_key': service_name.capitalize(),
                'title': video_data.get('title'),
            })
            if service_name == 'vimeo':
                info['url'] = smuggle_url(
                    'https://player.vimeo.com/video/' + service_id,
                    {'http_headers': {'Referer': url}})
        return info


code:
from __future__ import unicode_literals

from .common import InfoExtractor

class SlutloadIE(InfoExtractor):
    _VALID_URL = r'https?://(?:\w+\.)?slutload\.com/(?:video/[^/]+|embed_player|watch)/(?P<id>[^/]+)'
    _TESTS = [{
        'url': 'http://www.slutload.com/video/virginie-baisee-en-cam/TD73btpBqSxc/',
        'md5': '868309628ba00fd488cf516a113fd717',
        'info_dict': {
            'id': 'TD73btpBqSxc',
            'ext': 'mp4',
            'title': 'virginie baisee en cam',
            'age_limit': 18,
            'thumbnail': r're:https?://.*?\.jpg'
        },
    }, {
        # mobile site
        'url': 'http://mobile.slutload.com/video/masturbation-solo/fviFLmc6kzJ/',
        'only_matching': True,
    }, {
        'url': 'http://www.slutload.com/embed_player/TD73btpBqSxc/',
        'only_matching': True,
    }, {
        'url': 'http://www.slutload.com/watch/TD73btpBqSxc/Virginie-Baisee-En-Cam.html',
        'only_matching': True,
    }]

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

        embed_page = self._download_webpage(
            'http://www.slutload.com/embed_player/%s' % video_id, video_id,
            'Downloading embed page', fatal=False)

        if embed_page:
            def extract(what):
                return self._html_search_regex(
                    r'data-video-%s=(["\'])(?P<url>(?:(?!\1).)+)\1' % what,
                    embed_page, 'video %s' % what, default=None, group='url')

            video_url = extract('url')
            if video_url:
                title = self._html_search_regex(
                    r'<title>([^<]+)', embed_page, 'title', default=video_id)
                return {
                    'id': video_id,
                    'url': video_url,
                    'title': title,
                    'thumbnail': extract('preview'),
                    'age_limit': 18
                }

        webpage = self._download_webpage(
            'http://www.slutload.com/video/_/%s/' % video_id, video_id)
        title = self._html_search_regex(
            r'
([^<]+)', webpage, 'title').strip()
        info = self._parse_html5_media_entries(url, webpage, video_id)[0]
        info.update({
            'id': video_id,
            'title': title,
            'age_limit': 18,
        })
        return info


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

import re
import json
import hashlib
import uuid

from .common import InfoExtractor
from ..utils import (
    ExtractorError,
    int_or_none,
    sanitized_Request,
    unified_strdate,
    urlencode_postdata,
    xpath_text,
)

class SmotriIE(InfoExtractor):
    IE_DESC = 'Smotri.com'
    IE_NAME = 'smotri'
    _VALID_URL = r'https?://(?:www\.)?(?:smotri\.com/video/view/\?id=|pics\.smotri\.com/(?:player|scrubber_custom8)\.swf\?file=)(?P<id>v(?P<realvideoid>[0-9]+)[a-z0-9]{4})'
    _NETRC_MACHINE = 'smotri'

    _TESTS = [
        # real video id 2610366
        {
            'url': 'http://smotri.com/video/view/?id=v261036632ab',
            'md5': '02c0dfab2102984e9c5bb585cc7cc321',
            'info_dict': {
                'id': 'v261036632ab',
                'ext': 'mp4',
                'title': 'катастрофа с камер видеонаблюдения',
                'uploader': 'rbc2008',
                'uploader_id': 'rbc08',
                'upload_date': '20131118',
                'thumbnail': 'http://frame6.loadup.ru/8b/a9/2610366.3.3.jpg',
            },
        },
        # real video id 57591
        {
            'url': 'http://smotri.com/video/view/?id=v57591cb20',
            'md5': '830266dfc21f077eac5afd1883091bcd',
            'info_dict': {
                'id': 'v57591cb20',
                'ext': 'flv',
                'title': 'test',
                'uploader': 'Support Photofile@photofile',
                'uploader_id': 'support-photofile',
                'upload_date': '20070704',
                'thumbnail': 'http://frame4.loadup.ru/03/ed/57591.2.3.jpg',
            },
        },
        # video-password, not approved by moderator
        {
            'url': 'http://smotri.com/video/view/?id=v1390466a13c',
            'md5': 'f6331cef33cad65a0815ee482a54440b',
            'info_dict': {
                'id': 'v1390466a13c',
                'ext': 'mp4',
                'title': 'TOCCA_A_NOI_-_LE_COSE_NON_VANNO_CAMBIAMOLE_ORA-1',
                'uploader': 'timoxa40',
                'uploader_id': 'timoxa40',
                'upload_date': '20100404',
                'thumbnail': 'http://frame7.loadup.ru/af/3f/1390466.3.3.jpg',
            },
            'params': {
                'videopassword': 'qwerty',
            },
            'skip': 'Video is not approved by moderator',
        },
        # video-password
        {
            'url': 'http://smotri.com/video/view/?id=v6984858774#',
            'md5': 'f11e01d13ac676370fc3b95b9bda11b0',
            'info_dict': {
                'id': 'v6984858774',
                'ext': 'mp4',
                'title': 'Дача Солженицина ПАРОЛЬ 223322',
                'uploader': 'psavari1',
                'uploader_id': 'psavari1',
                'upload_date': '20081103',
                'thumbnail': r're:^https?://.*\.jpg$',
            },
            'params': {
                'videopassword': '223322',
            },
        },
        # age limit + video-password, not approved by moderator
        {
            'url': 'http://smotri.com/video/view/?id=v15408898bcf',
            'md5': '91e909c9f0521adf5ee86fbe073aad70',
            'info_dict': {
                'id': 'v15408898bcf',
                'ext': 'flv',
                'title': 'этот ролик не покажут по ТВ',
                'uploader': 'zzxxx',
                'uploader_id': 'ueggb',
                'upload_date': '20101001',
                'thumbnail': 'http://frame3.loadup.ru/75/75/1540889.1.3.jpg',
                'age_limit': 18,
            },
            'params': {
                'videopassword': '333'
            },
            'skip': 'Video is not approved by moderator',
        },
        # age limit + video-password
        {
            'url': 'http://smotri.com/video/view/?id=v7780025814',
            'md5': 'b4599b068422559374a59300c5337d72',
            'info_dict': {
                'id': 'v7780025814',
                'ext': 'mp4',
                'title': 'Sexy Beach (пароль 123)',
                'uploader': 'вАся',
                'uploader_id': 'asya_prosto',
                'upload_date': '20081218',
                'thumbnail': r're:^https?://.*\.jpg$',
                'age_limit': 18,
            },
            'params': {
                'videopassword': '123'
            },
        },
        # swf player
        {
            'url': 'http://pics.smotri.com/scrubber_custom8.swf?file=v9188090500',
            'md5': '31099eeb4bc906712c5f40092045108d',
            'info_dict': {
                'id': 'v9188090500',
                'ext': 'mp4',
                'title': 'Shakira - Don\'t Bother',
                'uploader': 'HannahL',
                'uploader_id': 'lisaha95',
                'upload_date': '20090331',
                'thumbnail': 'http://frame8.loadup.ru/44/0b/918809.7.3.jpg',
            },
        },
    ]

    @classmethod
    def _extract_url(cls, webpage):
        mobj = re.search(
            r'<embed[^>]src=(["\'])(?P<url>http://pics\.smotri\.com/(?:player|scrubber_custom8)\.swf\?file=v.+?\1)',
            webpage)
        if mobj is not None:
            return mobj.group('url')

        mobj = re.search(
            r'''(?x)
http://smotri\.com/video/download/file/[^<]+
\s*

[^<]+
\s*

(?P<id>[^<]+)
''', webpage)
        if mobj is not None:
            return 'http://smotri.com/video/view/?id=%s' % mobj.group('id')

    def _search_meta(self, name, html, display_name=None):
        if display_name is None:
            display_name = name
        return self._html_search_meta(name, html, display_name)

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

        video_form = {
            'ticket': video_id,
            'video_url': '1',
            'frame_url': '1',
            'devid': 'LoadupFlashPlayer',
            'getvideoinfo': '1',
        }

        video_password = self._downloader.params.get('videopassword')
        if video_password:
            video_form['pass'] = hashlib.md5(video_password.encode('utf-8')).hexdigest()

        video = self._download_json(
            'http://smotri.com/video/view/url/bot/',
            video_id, 'Downloading video JSON',
            data=urlencode_postdata(video_form),
            headers={'Content-Type': 'application/x-www-form-urlencoded'})

        video_url = video.get('_vidURL') or video.get('_vidURL_mp4')

        if not video_url:
            if video.get('_moderate_no'):
                raise ExtractorError(
                    'Video %s has not been approved by moderator' % video_id, expected=True)

            if video.get('error'):
                raise ExtractorError('Video %s does not exist' % video_id, expected=True)

            if video.get('_pass_protected') == 1:
                msg = ('Invalid video password' if video_password
                       else 'This video is protected by a password, use the --video-password option')
                raise ExtractorError(msg, expected=True)

        title = video['title']
        thumbnail = video.get('_imgURL')
        upload_date = unified_strdate(video.get('added'))
        uploader = video.get('userNick')
        uploader_id = video.get('userLogin')
        duration = int_or_none(video.get('duration'))

        # Video JSON does not provide enough meta data
        # We will extract some from the video web page instead
        webpage_url = 'http://smotri.com/video/view/?id=%s' % video_id
        webpage = self._download_webpage(webpage_url, video_id, 'Downloading video page')

        # Warning if video is unavailable
        warning = self._html_search_regex(
            r'
]+class="videoUnModer"[^>]*>(.+?)
', webpage,
            'warning message', default=None)
        if warning is not None:
            self._downloader.report_warning(
                'Video %s may not be available; smotri said: %s ' %
                (video_id, warning))

        # Adult content
        if 'EroConfirmText">' in webpage:
            self.report_age_confirmation()
            confirm_string = self._html_search_regex(
                r']+href="/video/view/\?id=%s&confirm=([^"]+)"' % video_id,
                webpage, 'confirm string')
            confirm_url = webpage_url + '&confirm=%s' % confirm_string
            webpage = self._download_webpage(
                confirm_url, video_id,
                'Downloading video page (age confirmed)')
            adult_content = True
        else:
            adult_content = False

        view_count = self._html_search_regex(
            r'(?s)Общее количество просмотров.*?(\d+)',
            webpage, 'view count', fatal=False)

        return {
            'id': video_id,
            'url': video_url,
            'title': title,
            'thumbnail': thumbnail,
            'uploader': uploader,
            'upload_date': upload_date,
            'uploader_id': uploader_id,
            'duration': duration,
            'view_count': int_or_none(view_count),
            'age_limit': 18 if adult_content else 0,
        }

class SmotriCommunityIE(InfoExtractor):
    IE_DESC = 'Smotri.com community videos'
    IE_NAME = 'smotri:community'
    _VALID_URL = r'https?://(?:www\.)?smotri\.com/community/video/(?P<id>[0-9A-Za-z_\'-]+)'
    _TEST = {
        'url': 'http://smotri.com/community/video/kommuna',
        'info_dict': {
            'id': 'kommuna',
        },
        'playlist_mincount': 4,
    }

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

        rss = self._download_xml(
            'http://smotri.com/export/rss/video/by/community/-/%s/video.xml' % community_id,
            community_id, 'Downloading community RSS')

        entries = [
            self.url_result(video_url.text, SmotriIE.ie_key())
            for video_url in rss.findall('./channel/item/link')]

        return self.playlist_result(entries, community_id)

class SmotriUserIE(InfoExtractor):
    IE_DESC = 'Smotri.com user videos'
    IE_NAME = 'smotri:user'
    _VALID_URL = r'https?://(?:www\.)?smotri\.com/user/(?P<id>[0-9A-Za-z_\'-]+)'
    _TESTS = [{
        'url': 'http://smotri.com/user/inspector',
        'info_dict': {
            'id': 'inspector',
            'title': 'Inspector',
        },
        'playlist_mincount': 9,
    }]

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

        rss = self._download_xml(
            'http://smotri.com/export/rss/user/video/-/%s/video.xml' % user_id,
            user_id, 'Downloading user RSS')

        entries = [self.url_result(video_url.text, 'Smotri')
                   for video_url in rss.findall('./channel/item/link')]

        description_text = xpath_text(rss, './channel/description') or ''
        user_nickname = self._search_regex(
            '^Видео режиссера (.+)$', description_text,
            'user nickname', fatal=False)

        return self.playlist_result(entries, user_id, user_nickname)

class SmotriBroadcastIE(InfoExtractor):
    IE_DESC = 'Smotri.com broadcasts'
    IE_NAME = 'smotri:broadcast'
    _VALID_URL = r'https?://(?:www\.)?(?P<url>smotri\.com/live/(?P<id>[^/]+))/?.*'
    _NETRC_MACHINE = 'smotri'

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

        broadcast_url = 'http://' + mobj.group('url')
        broadcast_page = self._download_webpage(broadcast_url, broadcast_id, 'Downloading broadcast page')

        if re.search('>Режиссер с логином
"%s"
 не существует<' % broadcast_id, broadcast_page) is not None:
            raise ExtractorError(
                'Broadcast %s does not exist' % broadcast_id, expected=True)

        # Adult content
        if re.search('EroConfirmText">', broadcast_page) is not None:

            (username, password) = self._get_login_info()
            if username is None:
                self.raise_login_required(
                    'Erotic broadcasts allowed only for registered users')

            login_form = {
                'login-hint53': '1',
                'confirm_erotic': '1',
                'login': username,
                'password': password,
            }

            request = sanitized_Request(
                broadcast_url + '/?no_redirect=1', urlencode_postdata(login_form))
            request.add_header('Content-Type', 'application/x-www-form-urlencoded')
            broadcast_page = self._download_webpage(
                request, broadcast_id, 'Logging in and confirming age')

            if '>Неверный логин или пароль<' in broadcast_page:
                raise ExtractorError(
                    'Unable to log in: bad username or password', expected=True)

            adult_content = True
        else:
            adult_content = False

        ticket = self._html_search_regex(
            (r'data-user-file=(["\'])(?P<ticket>(?!\1).+)\1',
             r"window\.broadcast_control\.addFlashVar\('file'\s*,\s*'(?P<ticket>[^']+)'\)"),
            broadcast_page, 'broadcast ticket', group='ticket')

        broadcast_url = 'http://smotri.com/broadcast/view/url/?ticket=%s' % ticket

        broadcast_password = self._downloader.params.get('videopassword')
        if broadcast_password:
            broadcast_url += '&pass=%s' % hashlib.md5(broadcast_password.encode('utf-8')).hexdigest()

        broadcast_json_page = self._download_webpage(
            broadcast_url, broadcast_id, 'Downloading broadcast JSON')

        try:
            broadcast_json = json.loads(broadcast_json_page)

            protected_broadcast = broadcast_json['_pass_protected'] == 1
            if protected_broadcast and not broadcast_password:
                raise ExtractorError(
                    'This broadcast is protected by a password, use the --video-password option',
                    expected=True)

            broadcast_offline = broadcast_json['is_play'] == 0
            if broadcast_offline:
                raise ExtractorError('Broadcast %s is offline' % broadcast_id, expected=True)

            rtmp_url = broadcast_json['_server']
            mobj = re.search(r'^rtmp://[^/]+/(?P<app>.+)/?$', rtmp_url)
            if not mobj:
                raise ExtractorError('Unexpected broadcast rtmp URL')

            broadcast_playpath = broadcast_json['_streamName']
            broadcast_app = '%s/%s' % (mobj.group('app'), broadcast_json['_vidURL'])
            broadcast_thumbnail = broadcast_json.get('_imgURL')
            broadcast_title = self._live_title(broadcast_json['title'])
            broadcast_description = broadcast_json.get('description')
            broadcaster_nick = broadcast_json.get('nick')
            broadcaster_login = broadcast_json.get('login')
            rtmp_conn = 'S:%s' % uuid.uuid4().hex
        except KeyError:
            if protected_broadcast:
                raise ExtractorError('Bad broadcast password', expected=True)
            raise ExtractorError('Unexpected broadcast JSON')

        return {
            'id': broadcast_id,
            'url': rtmp_url,
            'title': broadcast_title,
            'thumbnail': broadcast_thumbnail,
            'description': broadcast_description,
            'uploader': broadcaster_nick,
            'uploader_id': broadcaster_login,
            'age_limit': 18 if adult_content else 0,
            'ext': 'flv',
            'play_path': broadcast_playpath,
            'player_url': 'http://pics.smotri.com/broadcast_play.swf',
            'app': broadcast_app,
            'rtmp_live': True,
            'rtmp_conn': rtmp_conn,
            'is_live': True,
        }


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

import re

from .common import InfoExtractor
from ..utils import (
    parse_duration,
    parse_filesize,
    str_to_int,
)

class SnotrIE(InfoExtractor):
    _VALID_URL = r'http?://(?:www\.)?snotr\.com/video/(?P<id>\d+)/([\w]+)'
    _TESTS = [{
        'url': 'http://www.snotr.com/video/13708/Drone_flying_through_fireworks',
        'info_dict': {
            'id': '13708',
            'ext': 'mp4',
            'title': 'Drone flying through fireworks!',
            'duration': 248,
            'filesize_approx': 40700000,
            'description': 'A drone flying through Fourth of July Fireworks',
            'thumbnail': r're:^https?://.*\.jpg$',
        },
        'expected_warnings': ['description'],
    }, {
        'url': 'http://www.snotr.com/video/530/David_Letteman_-_George_W_Bush_Top_10',
        'info_dict': {
            'id': '530',
            'ext': 'mp4',
            'title': 'David Letteman - George W. Bush Top 10',
            'duration': 126,
            'filesize_approx': 8500000,
            'description': 'The top 10 George W. Bush moments, brought to you by David Letterman!',
            'thumbnail': r're:^https?://.*\.jpg$',
        }
    }]

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

        webpage = self._download_webpage(url, video_id)
        title = self._og_search_title(webpage)

        description = self._og_search_description(webpage)
        info_dict = self._parse_html5_media_entries(
            url, webpage, video_id, m3u8_entry_protocol='m3u8_native')[0]

        view_count = str_to_int(self._html_search_regex(
            r'
]*>\s*]*>Views:\s*]*>([\d,\.]+)',
            webpage, 'view count', fatal=False))

        duration = parse_duration(self._html_search_regex(
            r'
]*>\s*]*>Length:\s*]*>([\d:]+)',
            webpage, 'duration', fatal=False))

        filesize_approx = parse_filesize(self._html_search_regex(
            r'
]*>\s*]*>Filesize:\s*]*>([^<]+)',
            webpage, 'filesize', fatal=False))

        info_dict.update({
            'id': video_id,
            'description': description,
            'title': title,
            'view_count': view_count,
            'duration': duration,
            'filesize_approx': filesize_approx,
        })

        return info_dict


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

import re

from .common import InfoExtractor
from ..compat import (
    compat_str,
    compat_urllib_parse_urlencode,
)
from ..utils import (
    ExtractorError,
    int_or_none,
    try_get,
)

class SohuIE(InfoExtractor):
    _VALID_URL = r'https?://(?P<mytv>my\.)?tv\.sohu\.com/.+?/(?(mytv)|n)(?P<id>\d+)\.shtml.*?'

    # Sohu videos give different MD5 sums on Travis CI and my machine
    _TESTS = [{
        'note': 'This video is available only in Mainland China',
        'url': 'http://tv.sohu.com/20130724/n382479172.shtml#super',
        'info_dict': {
            'id': '382479172',
            'ext': 'mp4',
            'title': 'MV：Far East Movement《The Illest》',
        },
        'skip': 'On available in China',
    }, {
        'url': 'http://tv.sohu.com/20150305/n409385080.shtml',
        'info_dict': {
            'id': '409385080',
            'ext': 'mp4',
            'title': '《2015湖南卫视羊年元宵晚会》唐嫣《花好月圆》',
        }
    }, {
        'url': 'http://my.tv.sohu.com/us/232799889/78693464.shtml',
        'info_dict': {
            'id': '78693464',
            'ext': 'mp4',
            'title': '【爱范品】第31期：MWC见不到的奇葩手机',
        }
    }, {
        'note': 'Multipart video',
        'url': 'http://my.tv.sohu.com/pl/8384802/78910339.shtml',
        'info_dict': {
            'id': '78910339',
            'title': '【神探苍实战秘籍】第13期 战争之影 赫卡里姆',
        },
        'playlist': [{
            'info_dict': {
                'id': '78910339_part1',
                'ext': 'mp4',
                'duration': 294,
                'title': '【神探苍实战秘籍】第13期 战争之影 赫卡里姆',
            }
        }, {
            'info_dict': {
                'id': '78910339_part2',
                'ext': 'mp4',
                'duration': 300,
                'title': '【神探苍实战秘籍】第13期 战争之影 赫卡里姆',
            }
        }, {
            'info_dict': {
                'id': '78910339_part3',
                'ext': 'mp4',
                'duration': 150,
                'title': '【神探苍实战秘籍】第13期 战争之影 赫卡里姆',
            }
        }]
    }, {
        'note': 'Video with title containing dash',
        'url': 'http://my.tv.sohu.com/us/249884221/78932792.shtml',
        'info_dict': {
            'id': '78932792',
            'ext': 'mp4',
            'title': 'youtube-dl testing video',
        },
        'params': {
            'skip_download': True
        }
    }]

    def _real_extract(self, url):

        def _fetch_data(vid_id, mytv=False):
            if mytv:
                base_data_url = 'http://my.tv.sohu.com/play/videonew.do?vid='
            else:
                base_data_url = 'http://hot.vrs.sohu.com/vrs_flash.action?vid='

            return self._download_json(
                base_data_url + vid_id, video_id,
                'Downloading JSON data for %s' % vid_id,
                headers=self.geo_verification_headers())

        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('id')
        mytv = mobj.group('mytv') is not None

        webpage = self._download_webpage(url, video_id)

        title = re.sub(r' - 搜狐视频$', '', self._og_search_title(webpage))

        vid = self._html_search_regex(
            r'var vid ?= ?["\'](\d+)["\']',
            webpage, 'video path')
        vid_data = _fetch_data(vid, mytv)
        if vid_data['play'] != 1:
            if vid_data.get('status') == 12:
                raise ExtractorError(
                    '%s said: There\'s something wrong in the video.' % self.IE_NAME,
                    expected=True)
            else:
                self.raise_geo_restricted(
                    '%s said: The video is only licensed to users in Mainland China.' % self.IE_NAME)

        formats_json = {}
        for format_id in ('nor', 'high', 'super', 'ori', 'h2644k', 'h2654k'):
            vid_id = vid_data['data'].get('%sVid' % format_id)
            if not vid_id:
                continue
            vid_id = compat_str(vid_id)
            formats_json[format_id] = vid_data if vid == vid_id else _fetch_data(vid_id, mytv)

        part_count = vid_data['data']['totalBlocks']

        playlist = []
        for i in range(part_count):
            formats = []
            for format_id, format_data in formats_json.items():
                allot = format_data['allot']

                data = format_data['data']
                clips_url = data['clipsURL']
                su = data['su']

                video_url = 'newflv.sohu.ccgslb.net'
                cdnId = None
                retries = 0

                while 'newflv.sohu.ccgslb.net' in video_url:
                    params = {
                        'prot': 9,
                        'file': clips_url[i],
                        'new': su[i],
                        'prod': 'flash',
                        'rb': 1,
                    }

                    if cdnId is not None:
                        params['idc'] = cdnId

                    download_note = 'Downloading %s video URL part %d of %d' % (
                        format_id, i + 1, part_count)

                    if retries > 0:
                        download_note += ' (retry #%d)' % retries
                    part_info = self._parse_json(self._download_webpage(
                        'http://%s/?%s' % (allot, compat_urllib_parse_urlencode(params)),
                        video_id, download_note), video_id)

                    video_url = part_info['url']
                    cdnId = part_info.get('nid')

                    retries += 1
                    if retries > 5:
                        raise ExtractorError('Failed to get video URL')

                formats.append({
                    'url': video_url,
                    'format_id': format_id,
                    'filesize': int_or_none(
                        try_get(data, lambda x: x['clipsBytes'][i])),
                    'width': int_or_none(data.get('width')),
                    'height': int_or_none(data.get('height')),
                    'fps': int_or_none(data.get('fps')),
                })
            self._sort_formats(formats)

            playlist.append({
                'id': '%s_part%d' % (video_id, i + 1),
                'title': title,
                'duration': vid_data['data']['clipsDuration'][i],
                'formats': formats,
            })

        if len(playlist) == 1:
            info = playlist[0]
            info['id'] = video_id
        else:
            info = {
                '_type': 'multi_video',
                'entries': playlist,
                'id': video_id,
                'title': title,
            }

        return info


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

from .common import InfoExtractor
from ..utils import smuggle_url

class SonyLIVIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?sonyliv\.com/details/[^/]+/(?P<id>\d+)'
    _TESTS = [{
        'url': "http://www.sonyliv.com/details/episodes/5024612095001/Ep.-1---Achaari-Cheese-Toast---Bachelor's-Delight",
        'info_dict': {
            'title': "Ep. 1 - Achaari Cheese Toast - Bachelor's Delight",
            'id': 'ref:5024612095001',
            'ext': 'mp4',
            'upload_date': '20170923',
            'description': 'md5:7f28509a148d5be9d0782b4d5106410d',
            'uploader_id': '5182475815001',
            'timestamp': 1506200547,
        },
        'params': {
            'skip_download': True,
        },
        'add_ie': ['BrightcoveNew'],
    }, {
        'url': 'http://www.sonyliv.com/details/full%20movie/4951168986001/Sei-Raat-(Bangla)',
        'only_matching': True,
    }]

    # BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/4338955589001/default_default/index.html?videoId=%s'
    BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/5182475815001/default_default/index.html?videoId=ref:%s'

    def _real_extract(self, url):
        brightcove_id = self._match_id(url)
        return self.url_result(
            smuggle_url(self.BRIGHTCOVE_URL_TEMPLATE % brightcove_id, {
                'geo_countries': ['IN'],
                'referrer': url,
            }),
            'BrightcoveNew', brightcove_id)