code:
import base64
import hashlib
import hmac
import json
import random
import string
import time
import urllib.parse

from .common import InfoExtractor
from ..compat import compat_HTTPError, compat_urllib_parse_urlencode
from ..utils import (
    ExtractorError,
    float_or_none,
    int_or_none,
    join_nonempty,
    traverse_obj,
)

class VRVBaseIE(InfoExtractor):
    _API_DOMAIN = None
    _API_PARAMS = {}
    _CMS_SIGNING = {}
    _TOKEN = None
    _TOKEN_SECRET = ''

    def _call_api(self, path, video_id, note, data=None):
        # https://tools.ietf.org/html/rfc5849#section-3
        base_url = self._API_DOMAIN + '/core/' + path
        query = [
            ('oauth_consumer_key', self._API_PARAMS['oAuthKey']),
            ('oauth_nonce', ''.join([random.choice(string.ascii_letters) for _ in range(32)])),
            ('oauth_signature_method', 'HMAC-SHA1'),
            ('oauth_timestamp', int(time.time())),
        ]
        if self._TOKEN:
            query.append(('oauth_token', self._TOKEN))
        encoded_query = compat_urllib_parse_urlencode(query)
        headers = self.geo_verification_headers()
        if data:
            data = json.dumps(data).encode()
            headers['Content-Type'] = 'application/json'
        base_string = '&'.join([
            'POST' if data else 'GET',
            urllib.parse.quote(base_url, ''),
            urllib.parse.quote(encoded_query, '')])
        oauth_signature = base64.b64encode(hmac.new(
            (self._API_PARAMS['oAuthSecret'] + '&' + self._TOKEN_SECRET).encode('ascii'),
            base_string.encode(), hashlib.sha1).digest()).decode()
        encoded_query += '&oauth_signature=' + urllib.parse.quote(oauth_signature, '')
        try:
            return self._download_json(
                '?'.join([base_url, encoded_query]), video_id,
                note='Downloading %s JSON metadata' % note, headers=headers, data=data)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 401:
                raise ExtractorError(json.loads(e.cause.read().decode())['message'], expected=True)
            raise

    def _call_cms(self, path, video_id, note):
        if not self._CMS_SIGNING:
            index = self._call_api('index', video_id, 'CMS Signing')
            self._CMS_SIGNING = index.get('cms_signing') or {}
            if not self._CMS_SIGNING:
                for signing_policy in index.get('signing_policies', []):
                    signing_path = signing_policy.get('path')
                    if signing_path and signing_path.startswith('/cms/'):
                        name, value = signing_policy.get('name'), signing_policy.get('value')
                        if name and value:
                            self._CMS_SIGNING[name] = value
        return self._download_json(
            self._API_DOMAIN + path, video_id, query=self._CMS_SIGNING,
            note='Downloading %s JSON metadata' % note, headers=self.geo_verification_headers())

    def _get_cms_resource(self, resource_key, video_id):
        return self._call_api(
            'cms_resource', video_id, 'resource path', data={
                'resource_key': resource_key,
            })['__links__']['cms_resource']['href']

    def _extract_vrv_formats(self, url, video_id, stream_format, audio_lang, hardsub_lang):
        if not url or stream_format not in ('hls', 'dash', 'adaptive_hls'):
            return []
        format_id = join_nonempty(
            stream_format,
            audio_lang and 'audio-%s' % audio_lang,
            hardsub_lang and 'hardsub-%s' % hardsub_lang)
        if 'hls' in stream_format:
            adaptive_formats = self._extract_m3u8_formats(
                url, video_id, 'mp4', m3u8_id=format_id,
                note='Downloading %s information' % format_id,
                fatal=False)
        elif stream_format == 'dash':
            adaptive_formats = self._extract_mpd_formats(
                url, video_id, mpd_id=format_id,
                note='Downloading %s information' % format_id,
                fatal=False)
        if audio_lang:
            for f in adaptive_formats:
                if f.get('acodec') != 'none':
                    f['language'] = audio_lang
        return adaptive_formats

    def _set_api_params(self):
        webpage = self._download_webpage(
            'https://vrv.co/', None, headers=self.geo_verification_headers())
        self._API_PARAMS = self._parse_json(self._search_regex(
            [
                r'window\.__APP_CONFIG__\s*=\s*({.+?})(?:</script>|;)',
                r'window\.__APP_CONFIG__\s*=\s*({.+})'
            ], webpage, 'app config'), None)['cxApiParams']
        self._API_DOMAIN = self._API_PARAMS.get('apiDomain', 'https://api.vrv.co')

class VRVIE(VRVBaseIE):
    IE_NAME = 'vrv'
    _VALID_URL = r'https?://(?:www\.)?vrv\.co/watch/(?P<id>[A-Z0-9]+)'
    _TESTS = [{
        'url': 'https://vrv.co/watch/GR9PNZ396/Hidden-America-with-Jonah-Ray:BOSTON-WHERE-THE-PAST-IS-THE-PRESENT',
        'info_dict': {
            'id': 'GR9PNZ396',
            'ext': 'mp4',
            'title': 'BOSTON: WHERE THE PAST IS THE PRESENT',
            'description': 'md5:4ec8844ac262ca2df9e67c0983c6b83f',
            'uploader_id': 'seeso',
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }, {
        # movie listing
        'url': 'https://vrv.co/watch/G6NQXZ1J6/Lily-CAT',
        'info_dict': {
            'id': 'G6NQXZ1J6',
            'title': 'Lily C.A.T',
            'description': 'md5:988b031e7809a6aeb60968be4af7db07',
        },
        'playlist_count': 2,
    }]
    _NETRC_MACHINE = 'vrv'

    def _perform_login(self, username, password):
        token_credentials = self._call_api(
            'authenticate/by:credentials', None, 'Token Credentials', data={
                'email': username,
                'password': password,
            })
        self._TOKEN = token_credentials['oauth_token']
        self._TOKEN_SECRET = token_credentials['oauth_token_secret']

    def _initialize_pre_login(self):
        return self._set_api_params()

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

        object_data = self._call_cms(self._get_cms_resource(
            'cms:/objects/' + video_id, video_id), video_id, 'object')['items'][0]
        resource_path = object_data['__links__']['resource']['href']
        video_data = self._call_cms(resource_path, video_id, 'video')
        title = video_data['title']
        description = video_data.get('description')

        if video_data.get('__class__') == 'movie_listing':
            items = self._call_cms(
                video_data['__links__']['movie_listing/movies']['href'],
                video_id, 'movie listing').get('items') or []
            if len(items) != 1:
                entries = []
                for item in items:
                    item_id = item.get('id')
                    if not item_id:
                        continue
                    entries.append(self.url_result(
                        'https://vrv.co/watch/' + item_id,
                        self.ie_key(), item_id, item.get('title')))
                return self.playlist_result(entries, video_id, title, description)
            video_data = items[0]

        streams_path = video_data['__links__'].get('streams', {}).get('href')
        if not streams_path:
            self.raise_login_required()
        streams_json = self._call_cms(streams_path, video_id, 'streams')

        audio_locale = streams_json.get('audio_locale')
        formats = []
        for stream_type, streams in streams_json.get('streams', {}).items():
            if stream_type in ('adaptive_hls', 'adaptive_dash'):
                for stream in streams.values():
                    formats.extend(self._extract_vrv_formats(
                        stream.get('url'), video_id, stream_type.split('_')[1],
                        audio_locale, stream.get('hardsub_locale')))
        self._sort_formats(formats)

        subtitles = {}
        for k in ('captions', 'subtitles'):
            for subtitle in streams_json.get(k, {}).values():
                subtitle_url = subtitle.get('url')
                if not subtitle_url:
                    continue
                subtitles.setdefault(subtitle.get('locale', 'en-US'), []).append({
                    'url': subtitle_url,
                    'ext': subtitle.get('format', 'ass'),
                })

        thumbnails = []
        for thumbnail in traverse_obj(video_data, ('images', 'thumbnail', ..., ...)) or []:
            thumbnail_url = thumbnail.get('source')
            if not thumbnail_url:
                continue
            thumbnails.append({
                'url': thumbnail_url,
                'width': int_or_none(thumbnail.get('width')),
                'height': int_or_none(thumbnail.get('height')),
            })

        return {
            'id': video_id,
            'title': title,
            'formats': formats,
            'subtitles': subtitles,
            'thumbnails': thumbnails,
            'description': description,
            'duration': float_or_none(video_data.get('duration_ms'), 1000),
            'uploader_id': video_data.get('channel_id'),
            'series': video_data.get('series_title'),
            'season': video_data.get('season_title'),
            'season_number': int_or_none(video_data.get('season_number')),
            'season_id': video_data.get('season_id'),
            'episode': title,
            'episode_number': int_or_none(video_data.get('episode_number')),
            'episode_id': video_data.get('production_episode_id'),
        }

class VRVSeriesIE(VRVBaseIE):
    IE_NAME = 'vrv:series'
    _VALID_URL = r'https?://(?:www\.)?vrv\.co/series/(?P<id>[A-Z0-9]+)'
    _TEST = {
        'url': 'https://vrv.co/series/G68VXG3G6/The-Perfect-Insider',
        'info_dict': {
            'id': 'G68VXG3G6',
        },
        'playlist_mincount': 11,
    }

    def _initialize_pre_login(self):
        return self._set_api_params()

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

        seasons_path = self._get_cms_resource(
            'cms:/seasons?series_id=' + series_id, series_id)
        seasons_data = self._call_cms(seasons_path, series_id, 'seasons')

        entries = []
        for season in seasons_data.get('items', []):
            episodes_path = season['__links__']['season/episodes']['href']
            episodes = self._call_cms(episodes_path, series_id, 'episodes')
            for episode in episodes.get('items', []):
                episode_id = episode['id']
                entries.append(self.url_result(
                    'https://vrv.co/watch/' + episode_id,
                    'VRV', episode_id, episode.get('title')))

        return self.playlist_result(entries, series_id)


code:
from .common import InfoExtractor
from ..utils import ExtractorError, decode_packed_codes

class VShareIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?vshare\.io/[dv]/(?P<id>[^/?#&]+)'
    _EMBED_REGEX = [r'<iframe[^>]+?src=["\'](?P<url>(?:https?:)?//(?:www\.)?vshare\.io/v/[^/?#&]+)']
    _TESTS = [{
        'url': 'https://vshare.io/d/0f64ce6',
        'md5': '17b39f55b5497ae8b59f5fbce8e35886',
        'info_dict': {
            'id': '0f64ce6',
            'title': 'vl14062007715967',
            'ext': 'mp4',
        }
    }, {
        'url': 'https://vshare.io/v/0f64ce6/width-650/height-430/1',
        'only_matching': True,
    }]

    def _extract_packed(self, webpage):
        packed = self._search_regex(
            r'(eval\(function.+)', webpage, 'packed code')
        unpacked = decode_packed_codes(packed)
        digits = self._search_regex(r'\[((?:\d+,?)+)\]', unpacked, 'digits')
        digits = [int(digit) for digit in digits.split(',')]
        key_digit = self._search_regex(
            r'fromCharCode\(.+?(\d+)\)}', unpacked, 'key digit')
        chars = [chr(d - int(key_digit)) for d in digits]
        return ''.join(chars)

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

        webpage = self._download_webpage(
            'https://vshare.io/v/%s/width-650/height-430/1' % video_id,
            video_id, headers={'Referer': url})

        title = self._html_extract_title(webpage)
        title = title.split(' - ')[0]

        error = self._html_search_regex(
            r'(?s)<div[^>]+\bclass=["\']xxx-error[^>]+>(.+?)</div', webpage,
            'error', default=None)
        if error:
            raise ExtractorError(error, expected=True)

        info = self._parse_html5_media_entries(
            url, '<video>%s</video>' % self._extract_packed(webpage),
            video_id)[0]

        self._sort_formats(info['formats'])

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

        return info

repo_name: Lesmiscore/ytdl


code:
from .common import InfoExtractor
from ..utils import (
    int_or_none,
    parse_iso8601,
    try_get,
)

class VTMIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?vtm\.be/([^/?&#]+)~v(?P<id>[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})'
    _TEST = {
        'url': 'https://vtm.be/gast-vernielt-genkse-hotelkamer~ve7534523-279f-4b4d-a5c9-a33ffdbe23e1',
        'md5': '37dca85fbc3a33f2de28ceb834b071f8',
        'info_dict': {
            'id': '192445',
            'ext': 'mp4',
            'title': 'Gast vernielt Genkse hotelkamer',
            'timestamp': 1611060180,
            'upload_date': '20210119',
            'duration': 74,
            # TODO: fix url _type result processing
            # 'series': 'Op Interventie',
        }
    }

    def _real_extract(self, url):
        uuid = self._match_id(url)
        video = self._download_json(
            'https://omc4vm23offuhaxx6hekxtzspi.appsync-api.eu-west-1.amazonaws.com/graphql',
            uuid, query={
                'query': '''{
  getComponent(type: Video, uuid: "%s") {
    ... on Video {
      description
      duration
      myChannelsVideo
      program {
        title
      }
      publishedAt
      title
    }
  }
}''' % uuid,
            }, headers={
                'x-api-key': 'da2-lz2cab4tfnah3mve6wiye4n77e',
            })['data']['getComponent']

        return {
            '_type': 'url',
            'id': uuid,
            'title': video.get('title'),
            'url': 'http://mychannels.video/embed/%d' % video['myChannelsVideo'],
            'description': video.get('description'),
            'timestamp': parse_iso8601(video.get('publishedAt')),
            'duration': int_or_none(video.get('duration')),
            'series': try_get(video, lambda x: x['program']['title']),
            'ie_key': 'Medialaan',
        }


code:
import re

from .common import InfoExtractor
from ..compat import (
    compat_urllib_parse_urlparse,
)
from ..utils import (
    ExtractorError,
    parse_duration,
    remove_end,
)

class VuClipIE(InfoExtractor):
    _VALID_URL = r'https?://(?:m\.)?vuclip\.com/w\?.*?cid=(?P<id>[0-9]+)'

    _TEST = {
        'url': 'http://m.vuclip.com/w?cid=1129900602&bu=8589892792&frm=w&z=34801&op=0&oc=843169247&section=recommend',
        'info_dict': {
            'id': '1129900602',
            'ext': '3gp',
            'title': 'Top 10 TV Convicts',
            'duration': 733,
        }
    }

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

        ad_m = re.search(
            r'''value="No.*?" onClick="location.href='([^"']+)'"''', webpage)
        if ad_m:
            urlr = compat_urllib_parse_urlparse(url)
            adfree_url = urlr.scheme + '://' + urlr.netloc + ad_m.group(1)
            webpage = self._download_webpage(
                adfree_url, video_id, note='Download post-ad page')

        error_msg = self._html_search_regex(
            r'
(.*?)
', webpage, 'error message',
            default=None)
        if error_msg:
            raise ExtractorError(
                '%s said: %s' % (self.IE_NAME, error_msg), expected=True)

        # These clowns alternate between two page types
        video_url = self._search_regex(
            r']+href="([^"]+)"[^>]*>]+src="[^"]*/play\.gif',
            webpage, 'video URL', default=None)
        if video_url:
            formats = [{
                'url': video_url,
            }]
        else:
            formats = self._parse_html5_media_entries(url, webpage, video_id)[0]['formats']

        title = remove_end(self._html_search_regex(
            r'<title>(.*?)-\s*Vuclip</title>', webpage, 'title').strip(), ' - Video')

        duration = parse_duration(self._html_search_regex(
            r'[(>]([0-9]+:[0-9]+)(?:<span|\))', webpage, 'duration', fatal=False))

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


code:
from .common import InfoExtractor
from ..utils import (
    parse_duration,
    parse_filesize,
    extract_attributes,
    int_or_none,
    js_to_json
)

class VuploadIE(InfoExtractor):
    _VALID_URL = r'https://vupload\.com/v/(?P<id>[a-z0-9]+)'
    _TESTS = [{
        'url': 'https://vupload.com/v/u28d0pl2tphy',
        'md5': '9b42a4a193cca64d80248e58527d83c8',
        'info_dict': {
            'id': 'u28d0pl2tphy',
            'ext': 'mp4',
            'description': 'md5:e9e6c0045c78cbf0d5bb19a55ce199fb',
            'title': 'md5:e9e6c0045c78cbf0d5bb19a55ce199fb',
        }
    }]

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

        title = self._html_extract_title(webpage)
        video_json = self._parse_json(self._html_search_regex(r'sources:\s*(.+?]),', webpage, 'video'), video_id, transform_source=js_to_json)
        formats = []
        for source in video_json:
            if source['src'].endswith('.m3u8'):
                formats.extend(self._extract_m3u8_formats(source['src'], video_id, m3u8_id='hls'))
        duration = parse_duration(self._html_search_regex(
            r'\s*([\d:]+)\s*
', webpage, 'duration', fatal=False))
        filesize_approx = parse_filesize(self._html_search_regex(
            r'\s*([^<]+)\s*
', webpage, 'filesize', fatal=False))
        extra_video_info = extract_attributes(self._html_search_regex(
            r'(<video[^>]+>)', webpage, 'video_info', fatal=False))
        description = self._html_search_meta('description', webpage)

        return {
            'id': video_id,
            'formats': formats,
            'duration': duration,
            'filesize_approx': filesize_approx,
            'width': int_or_none(extra_video_info.get('width')),
            'height': int_or_none(extra_video_info.get('height')),
            'format_id': extra_video_info.get('height', '') + 'p',
            'title': title,
            'description': description,
        }


code:
import re

from .common import InfoExtractor
from .youtube import YoutubeIE
from ..utils import (
    ExtractorError,
    int_or_none,
    str_or_none,
)

class VVVVIDIE(InfoExtractor):
    _VALID_URL_BASE = r'https?://(?:www\.)?vvvvid\.it/(?:#!)?(?:show|anime|film|series)/'
    _VALID_URL = r'%s(?P<show_id>\d+)/[^/]+/(?P<season_id>\d+)/(?P<id>[0-9]+)' % _VALID_URL_BASE
    _TESTS = [{
        # video_type == 'video/vvvvid'
        'url': 'https://www.vvvvid.it/#!show/434/perche-dovrei-guardarlo-di-dario-moccia/437/489048/ping-pong',
        'md5': 'b8d3cecc2e981adc3835adf07f6df91b',
        'info_dict': {
            'id': '489048',
            'ext': 'mp4',
            'title': 'Ping Pong',
            'duration': 239,
            'series': '"Perché dovrei guardarlo?" di Dario Moccia',
            'season_id': '437',
            'episode': 'Ping Pong',
            'episode_number': 1,
            'episode_id': '3334',
            'view_count': int,
            'like_count': int,
            'repost_count': int,
        },
        'params': {
            'skip_download': True,
        },
    }, {
        # video_type == 'video/rcs'
        'url': 'https://www.vvvvid.it/#!show/376/death-note-live-action/377/482493/episodio-01',
        'md5': '33e0edfba720ad73a8782157fdebc648',
        'info_dict': {
            'id': '482493',
            'ext': 'mp4',
            'title': 'Episodio 01',
        },
        'params': {
            'skip_download': True,
        },
    }, {
        # video_type == 'video/youtube'
        'url': 'https://www.vvvvid.it/show/404/one-punch-man/406/486683/trailer',
        'md5': '33e0edfba720ad73a8782157fdebc648',
        'info_dict': {
            'id': 'RzmFKUDOUgw',
            'ext': 'mp4',
            'title': 'Trailer',
            'upload_date': '20150906',
            'description': 'md5:a5e802558d35247fee285875328c0b80',
            'uploader_id': 'BandaiVisual',
            'uploader': 'BANDAI NAMCO Arts Channel',
        },
        'params': {
            'skip_download': True,
        },
    }, {
        # video_type == 'video/dash'
        'url': 'https://www.vvvvid.it/show/683/made-in-abyss/1542/693786/nanachi',
        'info_dict': {
            'id': '693786',
            'ext': 'mp4',
            'title': 'Nanachi',
        },
        'params': {
            'skip_download': True,
            'format': 'mp4',
        },
    }, {
        'url': 'https://www.vvvvid.it/show/434/perche-dovrei-guardarlo-di-dario-moccia/437/489048',
        'only_matching': True
    }]
    _conn_id = None

    def _real_initialize(self):
        self._conn_id = self._download_json(
            'https://www.vvvvid.it/user/login',
            None, headers=self.geo_verification_headers())['data']['conn_id']

    def _download_info(self, show_id, path, video_id, fatal=True, query=None):
        q = {
            'conn_id': self._conn_id,
        }
        if query:
            q.update(query)
        response = self._download_json(
            'https://www.vvvvid.it/vvvvid/ondemand/%s/%s' % (show_id, path),
            video_id, headers=self.geo_verification_headers(), query=q, fatal=fatal)
        if not (response or fatal):
            return
        if response.get('result') == 'error':
            raise ExtractorError('%s said: %s' % (
                self.IE_NAME, response['message']), expected=True)
        return response['data']

    def _extract_common_video_info(self, video_data):
        return {
            'thumbnail': video_data.get('thumbnail'),
            'episode_id': str_or_none(video_data.get('id')),
        }

    def _real_extract(self, url):
        show_id, season_id, video_id = self._match_valid_url(url).groups()

        response = self._download_info(
            show_id, 'season/%s' % season_id,
            video_id, query={'video_id': video_id})

        vid = int(video_id)
        video_data = list(filter(
            lambda episode: episode.get('video_id') == vid, response))[0]
        title = video_data['title']
        formats = []

        # vvvvid embed_info decryption algorithm is reverse engineered from function $ds(h) at vvvvid.js
        def ds(h):
            g = "MNOPIJKL89+/4567UVWXQRSTEFGHABCDcdefYZabstuvopqr0123wxyzklmnghij"

            def f(m):
                l = []
                o = 0
                b = False
                m_len = len(m)
                while ((not b) and o < m_len):
                    n = m[o] << 2
                    o += 1
                    k = -1
                    j = -1
                    if o < m_len:
                        n += m[o] >> 4
                        o += 1
                        if o < m_len:
                            k = (m[o - 1] << 4) & 255
                            k += m[o] >> 2
                            o += 1
                            if o < m_len:
                                j = (m[o - 1] << 6) & 255
                                j += m[o]
                                o += 1
                            else:
                                b = True
                        else:
                            b = True
                    else:
                        b = True
                    l.append(n)
                    if k != -1:
                        l.append(k)
                    if j != -1:
                        l.append(j)
                return l

            c = []
            for e in h:
                c.append(g.index(e))

            c_len = len(c)
            for e in range(c_len * 2 - 1, -1, -1):
                a = c[e % c_len] ^ c[(e + 1) % c_len]
                c[e % c_len] = a

            c = f(c)
            d = ''
            for e in c:
                d += chr(e)

            return d

        info = {}

        def metadata_from_url(r_url):
            if not info and r_url:
                mobj = re.search(r'_(?:S(\d+))?Ep(\d+)', r_url)
                if mobj:
                    info['episode_number'] = int(mobj.group(2))
                    season_number = mobj.group(1)
                    if season_number:
                        info['season_number'] = int(season_number)

        video_type = video_data.get('video_type')
        is_youtube = False
        for quality in ('', '_sd'):
            embed_code = video_data.get('embed_info' + quality)
            if not embed_code:
                continue
            embed_code = ds(embed_code)
            if video_type == 'video/kenc':
                embed_code = re.sub(r'https?(://[^/]+)/z/', r'https\1/i/', embed_code).replace('/manifest.f4m', '/master.m3u8')
                kenc = self._download_json(
                    'https://www.vvvvid.it/kenc', video_id, query={
                        'action': 'kt',
                        'conn_id': self._conn_id,
                        'url': embed_code,
                    }, fatal=False) or {}
                kenc_message = kenc.get('message')
                if kenc_message:
                    embed_code += '?' + ds(kenc_message)
                formats.extend(self._extract_m3u8_formats(
                    embed_code, video_id, 'mp4', m3u8_id='hls', fatal=False))
            elif video_type == 'video/rcs':
                formats.extend(self._extract_akamai_formats(embed_code, video_id))
            elif video_type == 'video/youtube':
                info.update({
                    '_type': 'url_transparent',
                    'ie_key': YoutubeIE.ie_key(),
                    'url': embed_code,
                })
                is_youtube = True
                break
            elif video_type == 'video/dash':
                formats.extend(self._extract_m3u8_formats(
                    embed_code, video_id, 'mp4', m3u8_id='hls', fatal=False))
            else:
                formats.extend(self._extract_wowza_formats(
                    'http://sb.top-ix.org/videomg/_definst_/mp4:%s/playlist.m3u8' % embed_code, video_id))
            metadata_from_url(embed_code)

        if not is_youtube:
            self._sort_formats(formats)
            info['formats'] = formats

        metadata_from_url(video_data.get('thumbnail'))
        info.update(self._extract_common_video_info(video_data))
        info.update({
            'id': video_id,
            'title': title,
            'duration': int_or_none(video_data.get('length')),
            'series': video_data.get('show_title'),
            'season_id': season_id,
            'episode': title,
            'view_count': int_or_none(video_data.get('views')),
            'like_count': int_or_none(video_data.get('video_likes')),
            'repost_count': int_or_none(video_data.get('video_shares')),
        })
        return info

class VVVVIDShowIE(VVVVIDIE):
    _VALID_URL = r'(?P<base_url>%s(?P<id>\d+)(?:/(?P<show_title>[^/?&#]+))?)/?(?:[?#&]|$)' % VVVVIDIE._VALID_URL_BASE
    _TESTS = [{
        'url': 'https://www.vvvvid.it/show/156/psyco-pass',
        'info_dict': {
            'id': '156',
            'title': 'Psycho-Pass',
            'description': 'md5:94d572c0bd85894b193b8aebc9a3a806',
        },
        'playlist_count': 46,
    }, {
        'url': 'https://www.vvvvid.it/show/156',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        base_url, show_id, show_title = self._match_valid_url(url).groups()

        seasons = self._download_info(
            show_id, 'seasons/', show_title)

        show_info = self._download_info(
            show_id, 'info/', show_title, fatal=False)

        if not show_title:
            base_url += "/title"

        entries = []
        for season in (seasons or []):
            episodes = season.get('episodes') or []
            playlist_title = season.get('name') or show_info.get('title')
            for episode in episodes:
                if episode.get('playable') is False:
                    continue
                season_id = str_or_none(episode.get('season_id'))
                video_id = str_or_none(episode.get('video_id'))
                if not (season_id and video_id):
                    continue
                info = self._extract_common_video_info(episode)
                info.update({
                    '_type': 'url_transparent',
                    'ie_key': VVVVIDIE.ie_key(),
                    'url': '/'.join([base_url, season_id, video_id]),
                    'title': episode.get('title'),
                    'description': episode.get('description'),
                    'season_id': season_id,
                    'playlist_title': playlist_title,
                })
                entries.append(info)

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


code:
from .common import InfoExtractor
from ..compat import compat_str

class VyboryMosIE(InfoExtractor):
    _VALID_URL = r'https?://vybory\.mos\.ru/(?:#precinct/|account/channels\?.*?\bstation_id=)(?P<id>\d+)'
    _TESTS = [{
        'url': 'http://vybory.mos.ru/#precinct/13636',
        'info_dict': {
            'id': '13636',
            'ext': 'mp4',
            'title': 're:^Участковая избирательная комиссия №2231 [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
            'description': 'Россия, Москва, улица Введенского, 32А',
            'is_live': True,
        },
        'params': {
            'skip_download': True,
        }
    }, {
        'url': 'http://vybory.mos.ru/account/channels?station_id=13636',
        'only_matching': True,
    }]

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

        channels = self._download_json(
            'http://vybory.mos.ru/account/channels?station_id=%s' % station_id,
            station_id, 'Downloading channels JSON')

        formats = []
        for cam_num, (sid, hosts, name, _) in enumerate(channels, 1):
            for num, host in enumerate(hosts, 1):
                formats.append({
                    'url': 'http://%s/master.m3u8?sid=%s' % (host, sid),
                    'ext': 'mp4',
                    'format_id': 'camera%d-host%d' % (cam_num, num),
                    'format_note': '%s, %s' % (name, host),
                })

        info = self._download_json(
            'http://vybory.mos.ru/json/voting_stations/%s/%s.json'
            % (compat_str(station_id)[:3], station_id),
            station_id, 'Downloading station JSON', fatal=False) or {}

        return {
            'id': station_id,
            'title': info.get('name') or station_id,
            'description': info.get('address'),
            'is_live': True,
            'formats': formats,
        }


code:
from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
    int_or_none,
    float_or_none,
    unified_timestamp,
    url_or_none,
)

class VzaarIE(InfoExtractor):
    _VALID_URL = r'https?://(?:(?:www|view)\.)?vzaar\.com/(?:videos/)?(?P<id>\d+)'
    _EMBED_REGEX = [r'<iframe[^>]+src=["\'](?P<url>(?:https?:)?//(?:view\.vzaar\.com)/[0-9]+)']
    _TESTS = [{
        # HTTP and HLS
        'url': 'https://vzaar.com/videos/1152805',
        'md5': 'bde5ddfeb104a6c56a93a06b04901dbf',
        'info_dict': {
            'id': '1152805',
            'ext': 'mp4',
            'title': 'sample video (public)',
        },
    }, {
        'url': 'https://view.vzaar.com/27272/player',
        'md5': '3b50012ac9bbce7f445550d54e0508f2',
        'info_dict': {
            'id': '27272',
            'ext': 'mp3',
            'title': 'MP3',
        },
    }, {
        # hlsAes = true
        'url': 'https://view.vzaar.com/11379930/player',
        'info_dict': {
            'id': '11379930',
            'ext': 'mp4',
            'title': 'Videoaula',
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }, {
        # with null videoTitle
        'url': 'https://view.vzaar.com/20313539/download',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        video_data = self._download_json(
            'http://view.vzaar.com/v2/%s/video' % video_id, video_id)

        title = video_data.get('videoTitle') or video_id

        formats = []

        source_url = url_or_none(video_data.get('sourceUrl'))
        if source_url:
            f = {
                'url': source_url,
                'format_id': 'http',
                'quality': 1,
            }
            if 'audio' in source_url:
                f.update({
                    'vcodec': 'none',
                    'ext': 'mp3',
                })
            else:
                f.update({
                    'width': int_or_none(video_data.get('width')),
                    'height': int_or_none(video_data.get('height')),
                    'ext': 'mp4',
                    'fps': float_or_none(video_data.get('fps')),
                })
            formats.append(f)

        video_guid = video_data.get('guid')
        usp = video_data.get('usp')
        if video_data.get('uspEnabled') and isinstance(video_guid, compat_str) and isinstance(usp, dict):
            hls_aes = video_data.get('hlsAes')
            qs = '&'.join('%s=%s' % (k, v) for k, v in usp.items())
            url_templ = 'http://%%s.vzaar.com/v5/usp%s/%s/%s.ism%%s?' % ('aes' if hls_aes else '', video_guid, video_id)
            m3u8_formats = self._extract_m3u8_formats(
                url_templ % ('fable', '/.m3u8') + qs, video_id, 'mp4', 'm3u8_native',
                m3u8_id='hls', fatal=False)
            if hls_aes:
                for f in m3u8_formats:
                    f['_decryption_key_url'] = url_templ % ('goose', '') + qs
            formats.extend(m3u8_formats)

        self._sort_formats(formats)

        return {
            'id': video_id,
            'title': title,
            'thumbnail': self._proto_relative_url(video_data.get('poster')),
            'duration': float_or_none(video_data.get('videoDuration')),
            'timestamp': unified_timestamp(video_data.get('ts')),
            'formats': formats,
        }


code:
from urllib.parse import unquote

from .common import InfoExtractor
from ..utils import (
    merge_dicts,
    urljoin,
)

class WakanimIE(InfoExtractor):
    _VALID_URL = r'https://(?:www\.)?wakanim\.tv/[^/]+/v2/catalogue/episode/(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://www.wakanim.tv/de/v2/catalogue/episode/2997/the-asterisk-war-omu-staffel-1-episode-02-omu',
        'info_dict': {
            'id': '2997',
            'ext': 'mp4',
            'title': 'Episode 02',
            'description': 'md5:2927701ea2f7e901de8bfa8d39b2852d',
            'series': 'The Asterisk War  (OmU.)',
            'season_number': 1,
            'episode': 'Episode 02',
            'episode_number': 2,
        },
        'params': {
            'skip_download': True,
        },
    }, {
        # DRM Protected
        'url': 'https://www.wakanim.tv/de/v2/catalogue/episode/7843/sword-art-online-alicization-omu-arc-2-folge-15-omu',
        'only_matching': True,
    }]
    _GEO_BYPASS = False

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

        webpage = self._download_webpage(url, video_id)

        if 'Geoblocking' in webpage:
            if '/de/' in url:
                self.raise_geo_restricted(countries=['DE', 'AT', 'CH'])
            else:
                self.raise_geo_restricted(countries=['RU'])

        manifest_url = urljoin(url, self._search_regex(
            r'file\s*:\s*(["\'])(?P<url>(?:(?!\1).)+)\1', webpage, 'manifest url',
            group='url'))
        if not self.get_param('allow_unplayable_formats'):
            # https://docs.microsoft.com/en-us/azure/media-services/previous/media-services-content-protection-overview#streaming-urls
            encryption = self._search_regex(
                r'encryption%3D(c(?:enc|bc(?:s-aapl)?))',
                manifest_url, 'encryption', default=None)
            if encryption in ('cenc', 'cbcs-aapl'):
                self.report_drm(video_id)

        if 'format=mpd-time-cmaf' in unquote(manifest_url):
            formats = self._extract_mpd_formats(
                manifest_url, video_id, mpd_id='dash')
        else:
            formats = self._extract_m3u8_formats(
                manifest_url, video_id, 'mp4', entry_protocol='m3u8_native',
                m3u8_id='hls')

        info = self._search_json_ld(webpage, video_id, default={})

        title = self._search_regex(
            (r'<h1[^>]+\bclass=["\']episode_h1[^>]+\btitle=(["\'])(?P<title>(?:(?!\1).)+)\1',
             r'<span[^>]+\bclass=["\']episode_title["\'][^>]*>(?P<title>[^<]+)'),
            webpage, 'title', default=None, group='title')

        return merge_dicts(info, {
            'id': video_id,
            'title': title,
            'formats': formats,
        })


code:
import re

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

class WallaIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.walla\.co\.il/[^/]+/(?P<id>\d+)/(?P<display_id>.+)'
    _TEST = {
        'url': 'http://vod.walla.co.il/movie/2642630/one-direction-all-for-one',
        'info_dict': {
            'id': '2642630',
            'display_id': 'one-direction-all-for-one',
            'ext': 'flv',
            'title': 'וואן דיירקשן: ההיסטריה',
            'description': 'md5:de9e2512a92442574cdb0913c49bc4d8',
            'thumbnail': r're:^https?://.*\.jpg',
            'duration': 3600,
        },
        'params': {
            # rtmp download
            'skip_download': True,
        }
    }

    _SUBTITLE_LANGS = {
        'עברית': 'heb',
    }

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        video_id = mobj.group('id')
        display_id = mobj.group('display_id')

        video = self._download_xml(
            'http://video2.walla.co.il/?w=null/null/%s/@@/video/flv_pl' % video_id,
            display_id)

        item = video.find('./items/item')

        title = xpath_text(item, './title', 'title')
        description = xpath_text(item, './synopsis', 'description')
        thumbnail = xpath_text(item, './preview_pic', 'thumbnail')
        duration = int_or_none(xpath_text(item, './duration', 'duration'))

        subtitles = {}
        for subtitle in item.findall('./subtitles/subtitle'):
            lang = xpath_text(subtitle, './title')
            subtitles[self._SUBTITLE_LANGS.get(lang, lang)] = [{
                'ext': 'srt',
                'url': xpath_text(subtitle, './src'),
            }]

        formats = []
        for quality in item.findall('./qualities/quality'):
            format_id = xpath_text(quality, './title')
            fmt = {
                'url': 'rtmp://wafla.walla.co.il/vod',
                'play_path': xpath_text(quality, './src'),
                'player_url': 'http://isc.walla.co.il/w9/swf/video_swf/vod/WallaMediaPlayerAvod.swf',
                'page_url': url,
                'ext': 'flv',
                'format_id': xpath_text(quality, './title'),
            }
            m = re.search(r'^(?P<height>\d+)[Pp]', format_id)
            if m:
                fmt['height'] = int(m.group('height'))
            formats.append(fmt)
        self._sort_formats(formats)

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


code:
from .common import InfoExtractor
from ..utils import (
    ExtractorError,
    int_or_none,
    parse_iso8601,
    traverse_obj,
    try_get,
)

class WASDTVBaseIE(InfoExtractor):

    def _fetch(self, path, video_id, description, query={}):
        response = self._download_json(
            f'https://wasd.tv/api/{path}', video_id, query=query,
            note=f'Downloading {description} metadata',
            errnote=f'Unable to download {description} metadata')
        error = response.get('error')
        if error:
            raise ExtractorError(f'{self.IE_NAME} returned error: {error}', expected=True)
        return response.get('result')

    def _extract_thumbnails(self, thumbnails_dict):
        return [{
            'url': url,
            'preference': index,
        } for index, url in enumerate(
            traverse_obj(thumbnails_dict, (('small', 'medium', 'large'),))) if url]

    def _real_extract(self, url):
        container = self._get_container(url)
        stream = traverse_obj(container, ('media_container_streams', 0))
        media = try_get(stream, lambda x: x['stream_media'][0])
        if not media:
            raise ExtractorError('Can not extract media data.', expected=True)
        media_meta = media.get('media_meta')
        media_url, is_live = self._get_media_url(media_meta)
        video_id = media.get('media_id') or container.get('media_container_id')
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(media_url, video_id, 'mp4')
        self._sort_formats(formats)
        return {
            'id': str(video_id),
            'title': container.get('media_container_name') or self._og_search_title(self._download_webpage(url, video_id)),
            'description': container.get('media_container_description'),
            'thumbnails': self._extract_thumbnails(media_meta.get('media_preview_images')),
            'timestamp': parse_iso8601(container.get('created_at')),
            'view_count': int_or_none(stream.get('stream_current_viewers' if is_live else 'stream_total_viewers')),
            'is_live': is_live,
            'formats': formats,
            'subtitles': subtitles,
        }

    def _get_container(self, url):
        raise NotImplementedError('Subclass for get media container')

    def _get_media_url(self, media_meta):
        raise NotImplementedError('Subclass for get media url')

class WASDTVStreamIE(WASDTVBaseIE):
    IE_NAME = 'wasdtv:stream'
    _VALID_URL = r'https?://wasd\.tv/(?P<id>[^/#?]+)$'
    _TESTS = [{
        'url': 'https://wasd.tv/24_7',
        'info_dict': {
            'id': '559738',
            'ext': 'mp4',
            'title': 'Live 24/7 Music',
            'description': '24/7 Music',
            'timestamp': int,
            'upload_date': r're:^\d{8}$',
            'is_live': True,
            'view_count': int,
        },
    }]

    def _get_container(self, url):
        nickname = self._match_id(url)
        channel = self._fetch(f'channels/nicknames/{nickname}', video_id=nickname, description='channel')
        channel_id = channel.get('channel_id')
        containers = self._fetch(
            'v2/media-containers', channel_id, 'running media containers',
            query={
                'channel_id': channel_id,
                'media_container_type': 'SINGLE',
                'media_container_status': 'RUNNING',
            })
        if not containers:
            raise ExtractorError(f'{nickname} is offline', expected=True)
        return containers[0]

    def _get_media_url(self, media_meta):
        return media_meta['media_url'], True

class WASDTVRecordIE(WASDTVBaseIE):
    IE_NAME = 'wasdtv:record'
    _VALID_URL = r'https?://wasd\.tv/[^/#?]+(?:/videos)?\?record=(?P<id>\d+)$'
    _TESTS = [{
        'url': 'https://wasd.tv/spacemita/videos?record=907755',
        'md5': 'c9899dd85be4cc997816ff9f9ca516ce',
        'info_dict': {
            'id': '906825',
            'ext': 'mp4',
            'title': 'Музыкальный',
            'description': 'md5:f510388d929ff60ae61d4c3cab3137cc',
            'timestamp': 1645812079,
            'upload_date': '20220225',
            'thumbnail': r're:^https?://.+\.jpg',
            'is_live': False,
            'view_count': int,
        },
    }, {
        'url': 'https://wasd.tv/spacemita?record=907755',
        'only_matching': True,
    }]

    def _get_container(self, url):
        container_id = self._match_id(url)
        return self._fetch(
            f'v2/media-containers/{container_id}', container_id, 'media container')

    def _get_media_url(self, media_meta):
        media_archive_url = media_meta.get('media_archive_url')
        if media_archive_url:
            return media_archive_url, False
        return media_meta['media_url'], True

class WASDTVClipIE(WASDTVBaseIE):
    IE_NAME = 'wasdtv:clip'
    _VALID_URL = r'https?://wasd\.tv/[^/#?]+/clips\?clip=(?P<id>\d+)$'
    _TESTS = [{
        'url': 'https://wasd.tv/spacemita/clips?clip=26804',
        'md5': '818885e720143d7a4e776ff66fcff148',
        'info_dict': {
            'id': '26804',
            'ext': 'mp4',
            'title': 'Пуш флексит на голове стримера',
            'timestamp': 1646682908,
            'upload_date': '20220307',
            'thumbnail': r're:^https?://.+\.jpg',
            'view_count': int,
        },
    }]

    def _real_extract(self, url):
        clip_id = self._match_id(url)
        clip = self._fetch(f'v2/clips/{clip_id}', video_id=clip_id, description='clip')
        clip_data = clip.get('clip_data')
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(clip_data.get('url'), video_id=clip_id, ext='mp4')
        self._sort_formats(formats)
        return {
            'id': clip_id,
            'title': clip.get('clip_title') or self._og_search_title(self._download_webpage(url, clip_id, fatal=False)),
            'thumbnails': self._extract_thumbnails(clip_data.get('preview')),
            'timestamp': parse_iso8601(clip.get('created_at')),
            'view_count': int_or_none(clip.get('clip_views_count')),
            'formats': formats,
            'subtitles': subtitles,
        }


code:
import re

from .common import InfoExtractor

from ..utils import traverse_obj

class WashingtonPostIE(InfoExtractor):
    IE_NAME = 'washingtonpost'
    _VALID_URL = r'(?:washingtonpost:|https?://(?:www\.)?washingtonpost\.com/(?:video|posttv)/(?:[^/]+/)*)(?P<id>[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12})'
    _EMBED_REGEX = [r'<iframe[^>]+\bsrc=["\'](?P<url>https?://(?:www\.)?washingtonpost\.com/video/c/embed/[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12})']
    _TESTS = [{
        'url': 'https://www.washingtonpost.com/video/c/video/480ba4ee-1ec7-11e6-82c2-a7dcb313287d',
        'md5': '6f537e1334b714eb15f9563bd4b9cdfa',
        'info_dict': {
            'id': '480ba4ee-1ec7-11e6-82c2-a7dcb313287d',
            'ext': 'mp4',
            'title': 'Egypt finds belongings, debris from plane crash',
            'description': 'md5:a17ceee432f215a5371388c1f680bd86',
            'upload_date': '20160520',
            'timestamp': 1463775187,
        },
    }, {
        'url': 'https://www.washingtonpost.com/video/world/egypt-finds-belongings-debris-from-plane-crash/2016/05/20/480ba4ee-1ec7-11e6-82c2-a7dcb313287d_video.html',
        'only_matching': True,
    }, {
        'url': 'https://www.washingtonpost.com/posttv/world/iraq-to-track-down-antiquities-after-islamic-state-museum-rampage/2015/02/28/7c57e916-bf86-11e4-9dfb-03366e719af8_video.html',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        return self.url_result(
            'arcpublishing:wapo:' + video_id, 'ArcPublishing', video_id)

class WashingtonPostArticleIE(InfoExtractor):
    IE_NAME = 'washingtonpost:article'
    _VALID_URL = r'https?://(?:www\.)?washingtonpost\.com/(?:[^/]+/)*(?P<id>[^/?#]+)'
    _TESTS = [{
        'url': 'http://www.washingtonpost.com/sf/national/2014/03/22/sinkhole-of-bureaucracy/',
        'info_dict': {
            'id': 'sinkhole-of-bureaucracy',
            'title': 'Sinkhole of bureaucracy',
        },
        'playlist': [{
            'md5': '7ccf53ea8cbb77de5f570242b3b21a59',
            'info_dict': {
                'id': 'fc433c38-b146-11e3-b8b3-44b1d1cd4c1f',
                'ext': 'mp4',
                'title': 'Breaking Points: The Paper Mine',
                'duration': 1290,
                'description': 'Overly complicated paper pushing is nothing new to government bureaucracy. But the way federal retirement applications are filed may be the most outdated. David Fahrenthold explains.',
                'timestamp': 1395440416,
                'upload_date': '20140321',
                'thumbnail': r're:https://[^\.]+.cloudfront\.net/PAPERMINESplash\.jpg',
            },
        }, {
            'md5': '7ccf53ea8cbb77de5f570242b3b21a59',
            'info_dict': {
                'id': '41255e28-b14a-11e3-b8b3-44b1d1cd4c1f',
                'ext': 'mp4',
                'title': 'The town bureaucracy sustains',
                'description': 'Underneath the friendly town of Boyers is a sea of government paperwork. In a disused limestone mine, hundreds of locals now track, file and process retirement applications for the federal government. We set out to find out what it\'s like to do paperwork 230 feet underground.',
                'duration': 2220,
                'timestamp': 1395441819,
                'upload_date': '20140321',
                'thumbnail': r're:https://[^\.]+.cloudfront\.net/BoyersSplash\.jpeg',
            },
        }],
    }, {
        'url': 'http://www.washingtonpost.com/blogs/wonkblog/wp/2014/12/31/one-airline-figured-out-how-to-make-sure-its-airplanes-never-disappear/',
        'info_dict': {
            'id': 'one-airline-figured-out-how-to-make-sure-its-airplanes-never-disappear',
            'title': 'One airline figured out how to make sure its airplanes never disappear',
        },
        'playlist': [{
            'md5': 'a7c1b5634ba5e57a6a82cdffa5b1e0d0',
            'info_dict': {
                'id': '0e4bb54c-9065-11e4-a66f-0ca5037a597d',
                'ext': 'mp4',
                'description': 'Washington Post transportation reporter Ashley Halsey III explains why a plane\'s black box needs to be recovered from a crash site instead of having its information streamed in real time throughout the flight.',
                'upload_date': '20141230',
                'timestamp': 1419972442,
                'title': 'Why black boxes don’t transmit data in real time',
            }
        }],
        'skip': 'Doesnt have a video anymore',
    }, {
        'url': 'https://www.washingtonpost.com/nation/2021/08/05/dixie-river-fire-california-climate/',
        'only_matching': True,
    }]

    @classmethod
    def suitable(cls, url):
        return False if WashingtonPostIE.suitable(url) else super(WashingtonPostArticleIE, cls).suitable(url)

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

        title = self._og_search_title(webpage)

        uuids = re.findall(r'''(?x)
            (?:
                <div\s+class="posttv-video-embed[^>]*?data-uuid=|
                data-video-uuid=
            )"([^"]+)"''', webpage)

        if not uuids:
            json_data = self._search_nextjs_data(webpage, page_id)
            for content_element in traverse_obj(json_data, ('props', 'pageProps', 'globalContent', 'content_elements')):
                if content_element.get('type') == 'video':
                    uuids.append(content_element.get('_id'))

        entries = [self.url_result('washingtonpost:%s' % uuid, 'WashingtonPost', uuid) for uuid in uuids]

        return {
            '_type': 'playlist',
            'entries': entries,
            'id': page_id,
            'title': title,
        }


code:
from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
    ExtractorError,
    int_or_none,
    try_get,
    unified_strdate,
)

class WatIE(InfoExtractor):
    _VALID_URL = r'(?:wat:|https?://(?:www\.)?wat\.tv/video/.*-)(?P<id>[0-9a-z]+)'
    IE_NAME = 'wat.tv'
    _TESTS = [
        {
            'url': 'http://www.wat.tv/video/soupe-figues-l-orange-aux-epices-6z1uz_2hvf7_.html',
            'info_dict': {
                'id': '11713067',
                'ext': 'mp4',
                'title': 'Soupe de figues à l\'orange et aux épices',
                'description': 'Retrouvez l\'émission "Petits plats en équilibre", diffusée le 18 août 2014.',
                'upload_date': '20140819',
                'duration': 120,
            },
            'params': {
                # m3u8 download
                'skip_download': True,
            },
            'expected_warnings': ['HTTP Error 404'],
            'skip': 'This content is no longer available',
        },
        {
            'url': 'http://www.wat.tv/video/gregory-lemarchal-voix-ange-6z1v7_6ygkj_.html',
            'md5': 'b16574df2c3cd1a36ca0098f2a791925',
            'info_dict': {
                'id': '11713075',
                'ext': 'mp4',
                'title': 'Grégory Lemarchal, une voix d\'ange depuis 10 ans (1/3)',
                'upload_date': '20140816',
            },
            'expected_warnings': ["Ce contenu n'est pas disponible pour l'instant."],
            'skip': 'This content is no longer available',
        },
    ]
    _GEO_BYPASS = False

    def _real_extract(self, url):
        video_id = self._match_id(url)
        video_id = video_id if video_id.isdigit() and len(video_id) > 6 else compat_str(int(video_id, 36))

        # 'contentv4' is used in the website, but it also returns the related
        # videos, we don't need them
        # video_data = self._download_json(
        #     'http://www.wat.tv/interface/contentv4s/' + video_id, video_id)
        video_data = self._download_json(
            'https://mediainfo.tf1.fr/mediainfocombo/' + video_id,
            video_id, query={'context': 'MYTF1', 'pver': '4020003'})
        video_info = video_data['media']

        error_desc = video_info.get('error_desc')
        if error_desc:
            if video_info.get('error_code') == 'GEOBLOCKED':
                self.raise_geo_restricted(error_desc, video_info.get('geoList'))
            raise ExtractorError(error_desc, expected=True)

        title = video_info['title']

        formats = []
        subtitles = {}

        def extract_formats(manifest_urls):
            for f, f_url in manifest_urls.items():
                if not f_url:
                    continue
                if f in ('dash', 'mpd'):
                    fmts, subs = self._extract_mpd_formats_and_subtitles(
                        f_url.replace('://das-q1.tf1.fr/', '://das-q1-ssl.tf1.fr/'),
                        video_id, mpd_id='dash', fatal=False)
                elif f == 'hls':
                    fmts, subs = self._extract_m3u8_formats_and_subtitles(
                        f_url, video_id, 'mp4',
                        'm3u8_native', m3u8_id='hls', fatal=False)
                else:
                    continue
                formats.extend(fmts)
                self._merge_subtitles(subs, target=subtitles)

        delivery = video_data.get('delivery') or {}
        extract_formats({delivery.get('format'): delivery.get('url')})
        if not formats:
            if delivery.get('drm'):
                self.report_drm(video_id)
            manifest_urls = self._download_json(
                'http://www.wat.tv/get/webhtml/' + video_id, video_id, fatal=False)
            if manifest_urls:
                extract_formats(manifest_urls)

        self._sort_formats(formats)

        return {
            'id': video_id,
            'title': title,
            'thumbnail': video_info.get('preview'),
            'upload_date': unified_strdate(try_get(
                video_data, lambda x: x['mediametrie']['chapters'][0]['estatS4'])),
            'duration': int_or_none(video_info.get('duration')),
            'formats': formats,
            'subtitles': subtitles,
        }


code:
from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
    int_or_none,
    js_to_json,
    strip_or_none,
    try_get,
    unescapeHTML,
    unified_timestamp,
)

class WatchBoxIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?watchbox\.de/(?P<kind>serien|filme)/(?:[^/]+/)*[^/]+-(?P<id>\d+)'
    _TESTS = [{
        # film
        'url': 'https://www.watchbox.de/filme/free-jimmy-12325.html',
        'info_dict': {
            'id': '341368',
            'ext': 'mp4',
            'title': 'Free Jimmy',
            'description': 'md5:bcd8bafbbf9dc0ef98063d344d7cc5f6',
            'thumbnail': r're:^https?://.*\.jpg$',
            'duration': 4890,
            'age_limit': 16,
            'release_year': 2009,
        },
        'params': {
            'skip_download': True,
        },
        'expected_warnings': ['Failed to download m3u8 information'],
    }, {
        # episode
        'url': 'https://www.watchbox.de/serien/ugly-americans-12231/staffel-1/date-in-der-hoelle-328286.html',
        'info_dict': {
            'id': '328286',
            'ext': 'mp4',
            'title': 'S01 E01 - Date in der Hölle',
            'description': 'md5:2f31c74a8186899f33cb5114491dae2b',
            'thumbnail': r're:^https?://.*\.jpg$',
            'duration': 1291,
            'age_limit': 12,
            'release_year': 2010,
            'series': 'Ugly Americans',
            'season_number': 1,
            'episode': 'Date in der Hölle',
            'episode_number': 1,
        },
        'params': {
            'skip_download': True,
        },
        'expected_warnings': ['Failed to download m3u8 information'],
    }, {
        'url': 'https://www.watchbox.de/serien/ugly-americans-12231/staffel-2/der-ring-des-powers-328270',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        kind, video_id = mobj.group('kind', 'id')

        webpage = self._download_webpage(url, video_id)

        player_config = self._parse_json(
            self._search_regex(
                r'data-player-conf=(["\'])(?P<data>{.+?})\1', webpage,
                'player config', default='{}', group='data'),
            video_id, transform_source=unescapeHTML, fatal=False)

        if not player_config:
            player_config = self._parse_json(
                self._search_regex(
                    r'playerConf\s*=\s*({.+?})\s*;', webpage, 'player config',
                    default='{}'),
                video_id, transform_source=js_to_json, fatal=False) or {}

        source = player_config.get('source') or {}

        video_id = compat_str(source.get('videoId') or video_id)

        devapi = self._download_json(
            'http://api.watchbox.de/devapi/id/%s' % video_id, video_id, query={
                'format': 'json',
                'apikey': 'hbbtv',
            }, fatal=False)

        item = try_get(devapi, lambda x: x['items'][0], dict) or {}

        title = item.get('title') or try_get(
            item, lambda x: x['movie']['headline_movie'],
            compat_str) or source['title']

        formats = []
        hls_url = item.get('media_videourl_hls') or source.get('hls')
        if hls_url:
            formats.extend(self._extract_m3u8_formats(
                hls_url, video_id, 'mp4', entry_protocol='m3u8_native',
                m3u8_id='hls', fatal=False))
        dash_url = item.get('media_videourl_wv') or source.get('dash')
        if dash_url:
            formats.extend(self._extract_mpd_formats(
                dash_url, video_id, mpd_id='dash', fatal=False))
        mp4_url = item.get('media_videourl')
        if mp4_url:
            formats.append({
                'url': mp4_url,
                'format_id': 'mp4',
                'width': int_or_none(item.get('width')),
                'height': int_or_none(item.get('height')),
                'tbr': int_or_none(item.get('bitrate')),
            })
        self._sort_formats(formats)

        description = strip_or_none(item.get('descr'))
        thumbnail = item.get('media_content_thumbnail_large') or source.get('poster') or item.get('media_thumbnail')
        duration = int_or_none(item.get('media_length') or source.get('length'))
        timestamp = unified_timestamp(item.get('pubDate'))
        view_count = int_or_none(item.get('media_views'))
        age_limit = int_or_none(try_get(item, lambda x: x['movie']['fsk']))
        release_year = int_or_none(try_get(item, lambda x: x['movie']['rel_year']))

        info = {
            'id': video_id,
            'title': title,
            'description': description,
            'thumbnail': thumbnail,
            'duration': duration,
            'timestamp': timestamp,
            'view_count': view_count,
            'age_limit': age_limit,
            'release_year': release_year,
            'formats': formats,
        }

        if kind.lower() == 'serien':
            series = try_get(
                item, lambda x: x['special']['title'],
                compat_str) or source.get('format')
            season_number = int_or_none(self._search_regex(
                r'^S(\d{1,2})\s*E\d{1,2}', title, 'season number',
                default=None) or self._search_regex(
                    r'/staffel-(\d+)/', url, 'season number', default=None))
            episode = source.get('title')
            episode_number = int_or_none(self._search_regex(
                r'^S\d{1,2}\s*E(\d{1,2})', title, 'episode number',
                default=None))
            info.update({
                'series': series,
                'season_number': season_number,
                'episode': episode,
                'episode_number': episode_number,
            })

        return info


code:
import re

from .common import InfoExtractor
from ..utils import parse_duration

class WatchIndianPornIE(InfoExtractor):
    IE_DESC = 'Watch Indian Porn'
    _VALID_URL = r'https?://(?:www\.)?watchindianporn\.net/(?:[^/]+/)*video/(?P<display_id>[^/]+)-(?P<id>[a-zA-Z0-9]+)\.html'
    _TEST = {
        'url': 'http://www.watchindianporn.net/video/hot-milf-from-kerala-shows-off-her-gorgeous-large-breasts-on-camera-RZa2avywNPa.html',
        'md5': '249589a164dde236ec65832bfce17440',
        'info_dict': {
            'id': 'RZa2avywNPa',
            'display_id': 'hot-milf-from-kerala-shows-off-her-gorgeous-large-breasts-on-camera',
            'ext': 'mp4',
            'title': 'Hot milf from kerala shows off her gorgeous large breasts on camera',
            'thumbnail': r're:^https?://.*\.jpg$',
            'duration': 226,
            'view_count': int,
            'categories': list,
            'age_limit': 18,
        }
    }

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        video_id = mobj.group('id')
        display_id = mobj.group('display_id')

        webpage = self._download_webpage(url, display_id)

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

        title = self._html_search_regex((
            r'<title>(.+?)\s*-\s*Indian\s+Porn</title>',
            r'
(.+?)
'
        ), webpage, 'title')

        duration = parse_duration(self._search_regex(
            r'Time:\s*\s*(.+?)\s*',
            webpage, 'duration', fatal=False))

        view_count = int(self._search_regex(
            r'(?s)Time:\s*.*?.*?\s*(\d+)\s*',
            webpage, 'view count', fatal=False))

        categories = re.findall(
            r']+class=[\'"]categories[\'"][^>]*>\s*([^<]+)\s*',
            webpage)

        info_dict.update({
            'id': video_id,
            'display_id': display_id,
            'http_headers': {
                'Referer': url,
            },
            'title': title,
            'duration': duration,
            'view_count': view_count,
            'categories': categories,
            'age_limit': 18,
        })

        return info_dict


code:
import re

from .common import InfoExtractor
from ..compat import (
    compat_str,
    compat_urlparse,
)
from ..utils import (
    determine_ext,
    dict_get,
    ExtractorError,
    js_to_json,
    strip_jsonp,
    try_get,
    unified_strdate,
    update_url_query,
    urlhandle_detect_ext,
    url_or_none,
)

class WDRIE(InfoExtractor):
    __API_URL_TPL = '//deviceids-medp.wdr.de/ondemand/%s/%s'
    _VALID_URL = r'''(?x)https?://
        (?:deviceids-medp\.wdr\.de/ondemand/\d+/|
           kinder\.wdr\.de/(?!mediathek/)[^#?]+-)
        (?P<id>\d+)\.(?:js|assetjsonp)
    '''
    _GEO_COUNTRIES = ['DE']
    _TESTS = [{
        'url': 'http://deviceids-medp.wdr.de/ondemand/155/1557833.js',
        'info_dict': {
            'id': 'mdb-1557833',
            'ext': 'mp4',
            'title': 'Biathlon-Staffel verpasst Podest bei Olympia-Generalprobe',
            'upload_date': '20180112',
        },
    }]

    def _asset_url(self, wdr_id):
        id_len = max(len(wdr_id), 5)
        return ''.join(('https:', self.__API_URL_TPL % (wdr_id[:id_len - 4], wdr_id, ), '.js'))

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

        if url.startswith('wdr:'):
            video_id = url[4:]
            url = self._asset_url(video_id)

        metadata = self._download_json(
            url, video_id, transform_source=strip_jsonp)

        is_live = metadata.get('mediaType') == 'live'

        tracker_data = metadata['trackerData']
        title = tracker_data['trackerClipTitle']
        media_resource = metadata['mediaResource']

        formats = []
        subtitles = {}

        # check if the metadata contains a direct URL to a file
        for kind, media in media_resource.items():
            if kind == 'captionsHash':
                for ext, url in media.items():
                    subtitles.setdefault('de', []).append({
                        'url': url,
                        'ext': ext,
                    })
                continue

            if kind not in ('dflt', 'alt'):
                continue
            if not isinstance(media, dict):
                continue

            for tag_name, medium_url in media.items():
                if tag_name not in ('videoURL', 'audioURL'):
                    continue

                ext = determine_ext(medium_url)
                if ext == 'm3u8':
                    formats.extend(self._extract_m3u8_formats(
                        medium_url, video_id, 'mp4', 'm3u8_native',
                        m3u8_id='hls'))
                elif ext == 'f4m':
                    manifest_url = update_url_query(
                        medium_url, {'hdcore': '3.2.0', 'plugin': 'aasp-3.2.0.77.18'})
                    formats.extend(self._extract_f4m_formats(
                        manifest_url, video_id, f4m_id='hds', fatal=False))
                elif ext == 'smil':
                    formats.extend(self._extract_smil_formats(
                        medium_url, 'stream', fatal=False))
                else:
                    a_format = {
                        'url': medium_url
                    }
                    if ext == 'unknown_video':
                        urlh = self._request_webpage(
                            medium_url, video_id, note='Determining extension')
                        ext = urlhandle_detect_ext(urlh)
                        a_format['ext'] = ext
                    formats.append(a_format)

        self._sort_formats(formats)

        caption_url = media_resource.get('captionURL')
        if caption_url:
            subtitles['de'] = [{
                'url': caption_url,
                'ext': 'ttml',
            }]
        captions_hash = media_resource.get('captionsHash')
        if isinstance(captions_hash, dict):
            for ext, format_url in captions_hash.items():
                format_url = url_or_none(format_url)
                if not format_url:
                    continue
                subtitles.setdefault('de', []).append({
                    'url': format_url,
                    'ext': determine_ext(format_url, None) or ext,
                })

        return {
            'id': tracker_data.get('trackerClipId', video_id),
            'title': title,
            'alt_title': tracker_data.get('trackerClipSubcategory'),
            'formats': formats,
            'subtitles': subtitles,
            'upload_date': unified_strdate(tracker_data.get('trackerClipAirTime')),
            'is_live': is_live,
        }

class WDRPageIE(WDRIE):
    _MAUS_REGEX = r'https?://(?:www\.)wdrmaus.de/(?:[^/]+/)*?(?P<maus_id>[^/?#.]+)(?:/?|/index\.php5|\.php5)$'
    _PAGE_REGEX = r'/(?:mediathek/)?(?:[^/]+/)*(?P<display_id>[^/]+)\.html'
    _VALID_URL = r'https?://(?:www\d?\.)?(?:(?:kinder\.)?wdr\d?|sportschau)\.de' + _PAGE_REGEX + '|' + _MAUS_REGEX

    _TESTS = [
        {
            'url': 'http://www1.wdr.de/mediathek/video/sendungen/doku-am-freitag/video-geheimnis-aachener-dom-100.html',
            # HDS download, MD5 is unstable
            'info_dict': {
                'id': 'mdb-1058683',
                'ext': 'flv',
                'display_id': 'doku-am-freitag/video-geheimnis-aachener-dom-100',
                'title': 'Geheimnis Aachener Dom',
                'alt_title': 'Doku am Freitag',
                'upload_date': '20160304',
                'description': 'md5:87be8ff14d8dfd7a7ee46f0299b52318',
                'is_live': False,
                'subtitles': {'de': [{
                    'url': 'http://ondemand-ww.wdr.de/medp/fsk0/105/1058683/1058683_12220974.xml',
                    'ext': 'ttml',
                }]},
            },
            'skip': 'HTTP Error 404: Not Found',
        },
        {
            'url': 'http://www1.wdr.de/mediathek/audio/wdr3/wdr3-gespraech-am-samstag/audio-schriftstellerin-juli-zeh-100.html',
            'md5': 'f4c1f96d01cf285240f53ea4309663d8',
            'info_dict': {
                'id': 'mdb-1072000',
                'ext': 'mp3',
                'display_id': 'wdr3-gespraech-am-samstag/audio-schriftstellerin-juli-zeh-100',
                'title': 'Schriftstellerin Juli Zeh',
                'alt_title': 'WDR 3 Gespräch am Samstag',
                'upload_date': '20160312',
                'description': 'md5:e127d320bc2b1f149be697ce044a3dd7',
                'is_live': False,
                'subtitles': {}
            },
            'skip': 'HTTP Error 404: Not Found',
        },
        {
            'url': 'http://www1.wdr.de/mediathek/video/live/index.html',
            'info_dict': {
                'id': 'mdb-2296252',
                'ext': 'mp4',
                'title': r're:^WDR Fernsehen im Livestream (?:\(nur in Deutschland erreichbar\) )?[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
                'alt_title': 'WDR Fernsehen Live',
                'upload_date': '20201112',
                'is_live': True,
            },
            'params': {
                'skip_download': True,  # m3u8 download
            },
        },
        {
            'url': 'http://www1.wdr.de/mediathek/video/sendungen/aktuelle-stunde/aktuelle-stunde-120.html',
            'playlist_mincount': 6,
            'info_dict': {
                'id': 'aktuelle-stunde-120',
            },
        },
        {
            'url': 'http://www.wdrmaus.de/aktuelle-sendung/index.php5',
            'info_dict': {
                'id': 'mdb-2627637',
                'ext': 'mp4',
                'upload_date': 're:^[0-9]{8}$',
                'title': 're:^Die Sendung (?:mit der Maus )?vom [0-9.]{10}$',
            },
            'skip': 'The id changes from week to week because of the new episode'
        },
        {
            'url': 'http://www.wdrmaus.de/filme/sachgeschichten/achterbahn.php5',
            'md5': '803138901f6368ee497b4d195bb164f2',
            'info_dict': {
                'id': 'mdb-186083',
                'ext': 'mp4',
                'upload_date': '20130919',
                'title': 'Sachgeschichte - Achterbahn ',
            },
            'skip': 'HTTP Error 404: Not Found',
        },
        {
            'url': 'http://www1.wdr.de/radio/player/radioplayer116~_layout-popupVersion.html',
            # Live stream, MD5 unstable
            'info_dict': {
                'id': 'mdb-869971',
                'ext': 'mp4',
                'title': r're:^COSMO Livestream [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
                'upload_date': '20160101',
            },
            'params': {
                'skip_download': True,  # m3u8 download
            }
        },
        {
            'url': 'http://www.sportschau.de/handballem2018/handball-nationalmannschaft-em-stolperstein-vorrunde-100.html',
            'info_dict': {
                'id': 'mdb-1556012',
                'ext': 'mp4',
                'title': 'DHB-Vizepräsident Bob Hanning - "Die Weltspitze ist extrem breit"',
                'upload_date': '20180111',
            },
            'params': {
                'skip_download': True,
            },
            'skip': 'HTTP Error 404: Not Found',
        },
        {
            'url': 'http://www.sportschau.de/handballem2018/audio-vorschau---die-handball-em-startet-mit-grossem-favoritenfeld-100.html',
            'only_matching': True,
        },
        {
            'url': 'https://kinder.wdr.de/tv/die-sendung-mit-dem-elefanten/av/video-folge---astronaut-100.html',
            'only_matching': True,
        },
    ]

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        display_id = dict_get(mobj.groupdict(), ('display_id', 'maus_id'), 'wdrmaus')
        webpage = self._download_webpage(url, display_id)

        entries = []

        # Article with several videos

        # for wdr.de the data-extension is in a tag with the class "mediaLink"
        # for wdr.de radio players, in a tag with the class "wdrrPlayerPlayBtn"
        # for wdrmaus, in a tag with the class "videoButton" (previously a link
        # to the page in a multiline "videoLink"-tag)
        for mobj in re.finditer(
            r'''(?sx)class=
                    (?:
                        (["\'])(?:mediaLink|wdrrPlayerPlayBtn|videoButton)\b.*?\1[^>]+|
                        (["\'])videoLink\b.*?\2[\s]*>\n[^\n]*
                    )data-extension=(["\'])(?P<data>(?:(?!\3).)+)\3
                    ''', webpage):
            media_link_obj = self._parse_json(
                mobj.group('data'), display_id, transform_source=js_to_json,
                fatal=False)
            if not media_link_obj:
                continue
            jsonp_url = try_get(
                media_link_obj, lambda x: x['mediaObj']['url'], compat_str)
            if jsonp_url:
                # metadata, or player JS with ['ref'] giving WDR id, or just media, perhaps
                clip_id = media_link_obj['mediaObj'].get('ref')
                if jsonp_url.endswith('.assetjsonp'):
                    asset = self._download_json(
                        jsonp_url, display_id, fatal=False, transform_source=strip_jsonp)
                    clip_id = try_get(asset, lambda x: x['trackerData']['trackerClipId'], compat_str)
                if clip_id:
                    jsonp_url = self._asset_url(clip_id[4:])
                entries.append(self.url_result(jsonp_url, ie=WDRIE.ie_key()))

        # Playlist (e.g. https://www1.wdr.de/mediathek/video/sendungen/aktuelle-stunde/aktuelle-stunde-120.html)
        if not entries:
            entries = [
                self.url_result(
                    compat_urlparse.urljoin(url, mobj.group('href')),
                    ie=WDRPageIE.ie_key())
                for mobj in re.finditer(
                    r'<a[^>]+\bhref=(["\'])(?P<href>(?:(?!\1).)+)\1[^>]+\bdata-extension=',
                    webpage) if re.match(self._PAGE_REGEX, mobj.group('href'))
            ]

        return self.playlist_result(entries, playlist_id=display_id)

class WDRElefantIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)wdrmaus\.de/elefantenseite/#(?P<id>.+)'
    _TEST = {
        'url': 'http://www.wdrmaus.de/elefantenseite/#elefantenkino_wippe',
        # adaptive stream: unstable file MD5
        'info_dict': {
            'title': 'Wippe',
            'id': 'mdb-1198320',
            'ext': 'mp4',
            'age_limit': None,
            'upload_date': '20071003'
        },
    }

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

        # Table of Contents seems to always be at this address, so fetch it directly.
        # The website fetches configurationJS.php5, which links to tableOfContentsJS.php5.
        table_of_contents = self._download_json(
            'https://www.wdrmaus.de/elefantenseite/data/tableOfContentsJS.php5',
            display_id)
        if display_id not in table_of_contents:
            raise ExtractorError(
                'No entry in site\'s table of contents for this URL. '
                'Is the fragment part of the URL (after the #) correct?',
                expected=True)
        xml_metadata_path = table_of_contents[display_id]['xmlPath']
        xml_metadata = self._download_xml(
            'https://www.wdrmaus.de/elefantenseite/' + xml_metadata_path,
            display_id)
        zmdb_url_element = xml_metadata.find('./movie/zmdb_url')
        if zmdb_url_element is None:
            raise ExtractorError(
                '%s is not a video' % display_id, expected=True)
        return self.url_result(zmdb_url_element.text, ie=WDRIE.ie_key())

class WDRMobileIE(InfoExtractor):
    _VALID_URL = r'''(?x)
        https?://mobile-ondemand\.wdr\.de/
        .*?/fsk(?P<age_limit>[0-9]+)
        /[0-9]+/[0-9]+/
        (?P<id>[0-9]+)_(?P<title>[0-9]+)'''
    IE_NAME = 'wdr:mobile'
    _WORKING = False  # no such domain
    _TEST = {
        'url': 'http://mobile-ondemand.wdr.de/CMS2010/mdb/ondemand/weltweit/fsk0/42/421735/421735_4283021.mp4',
        'info_dict': {
            'title': '4283021',
            'id': '421735',
            'ext': 'mp4',
            'age_limit': 0,
        },
        'skip': 'Problems with loading data.'
    }

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        return {
            'id': mobj.group('id'),
            'title': mobj.group('title'),
            'age_limit': int(mobj.group('age_limit')),
            'url': url,
            'http_headers': {
                'User-Agent': 'mobile',
            },
        }


code:
import re

from .common import InfoExtractor
from ..utils import (
    determine_ext,
    join_nonempty,
    xpath_text,
)

class WebcasterIE(InfoExtractor):
    _VALID_URL = r'https?://bl\.webcaster\.pro/(?:quote|media)/start/free_(?P<id>[^/]+)'
    _TESTS = [{
        # http://video.khl.ru/quotes/393859
        'url': 'http://bl.webcaster.pro/quote/start/free_c8cefd240aa593681c8d068cff59f407_hd/q393859/eb173f99dd5f558674dae55f4ba6806d/1480289104?sr%3D105%26fa%3D1%26type_id%3D18',
        'md5': '0c162f67443f30916ff1c89425dcd4cd',
        'info_dict': {
            'id': 'c8cefd240aa593681c8d068cff59f407_hd',
            'ext': 'mp4',
            'title': 'Сибирь - Нефтехимик. Лучшие моменты первого периода',
            'thumbnail': r're:^https?://.*\.jpg$',
        },
    }, {
        'url': 'http://bl.webcaster.pro/media/start/free_6246c7a4453ac4c42b4398f840d13100_hd/2_2991109016/e8d0d82587ef435480118f9f9c41db41/4635726126',
        'only_matching': True,
    }]

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

        video = self._download_xml(url, video_id)

        title = xpath_text(video, './/event_name', 'event name', fatal=True)

        formats = []
        for format_id in (None, 'noise'):
            track_tag = join_nonempty('track', format_id, delim='_')
            for track in video.findall('.//iphone/%s' % track_tag):
                track_url = track.text
                if not track_url:
                    continue
                if determine_ext(track_url) == 'm3u8':
                    m3u8_formats = self._extract_m3u8_formats(
                        track_url, video_id, 'mp4',
                        entry_protocol='m3u8_native',
                        m3u8_id=join_nonempty('hls', format_id, delim='-'), fatal=False)
                    for f in m3u8_formats:
                        f.update({
                            'source_preference': 0 if format_id == 'noise' else 1,
                            'format_note': track.get('title'),
                        })
                    formats.extend(m3u8_formats)
        self._sort_formats(formats)

        thumbnail = xpath_text(video, './/image', 'thumbnail')

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

class WebcasterFeedIE(InfoExtractor):
    _VALID_URL = r'https?://bl\.webcaster\.pro/feed/start/free_(?P<id>[^/]+)'
    _EMBED_REGEX = [r'<(?:object|a[^>]+class=["\']webcaster-player["\'])[^>]+data(?:-config)?=(["\']).*?config=(?P<url>https?://bl\.webcaster\.pro/feed/start/free_.*?)(?:[?&]|\1)']
    _TEST = {
        'url': 'http://bl.webcaster.pro/feed/start/free_c8cefd240aa593681c8d068cff59f407_hd/q393859/eb173f99dd5f558674dae55f4ba6806d/1480289104',
        'only_matching': True,
    }

    def _extract_from_webpage(self, url, webpage):
        yield from super()._extract_from_webpage(url, webpage)

        for secure in (True, False):
            video_url = self._og_search_video_url(webpage, secure=secure, default=None)
            if video_url:
                mobj = re.search(
                    r'config=(?P<url>https?://bl\.webcaster\.pro/feed/start/free_[^?&=]+)',
                    video_url)
                if mobj:
                    yield self.url_result(mobj.group('url'), self)

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

        feed = self._download_xml(url, video_id)

        video_url = xpath_text(
            feed, ('video_hd', 'video'), 'video url', fatal=True)

        return self.url_result(video_url, WebcasterIE.ie_key())


code:
import re

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

class WebOfStoriesIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?webofstories\.com/play/(?:[^/]+/)?(?P<id>[0-9]+)'
    _VIDEO_DOMAIN = 'http://eu-mobile.webofstories.com/'
    _GREAT_LIFE_STREAMER = 'rtmp://eu-cdn1.webofstories.com/cfx/st/'
    _USER_STREAMER = 'rtmp://eu-users.webofstories.com/cfx/st/'
    _TESTS = [{
        'url': 'http://www.webofstories.com/play/hans.bethe/71',
        'md5': '373e4dd915f60cfe3116322642ddf364',
        'info_dict': {
            'id': '4536',
            'ext': 'mp4',
            'title': 'The temperature of the sun',
            'thumbnail': r're:^https?://.*\.jpg$',
            'description': 'Hans Bethe talks about calculating the temperature of the sun',
            'duration': 238,
        }
    }, {
        'url': 'http://www.webofstories.com/play/55908',
        'md5': '2985a698e1fe3211022422c4b5ed962c',
        'info_dict': {
            'id': '55908',
            'ext': 'mp4',
            'title': 'The story of Gemmata obscuriglobus',
            'thumbnail': r're:^https?://.*\.jpg$',
            'description': 'Planctomycete talks about The story of Gemmata obscuriglobus',
            'duration': 169,
        },
        'skip': 'notfound',
    }, {
        # malformed og:title meta
        'url': 'http://www.webofstories.com/play/54215?o=MS',
        'info_dict': {
            'id': '54215',
            'ext': 'mp4',
            'title': '"A Leg to Stand On"',
            'thumbnail': r're:^https?://.*\.jpg$',
            'description': 'Oliver Sacks talks about the death and resurrection of a limb',
            'duration': 97,
        },
        'params': {
            'skip_download': True,
        },
    }]

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

        webpage = self._download_webpage(url, video_id)
        # Sometimes og:title meta is malformed
        title = self._og_search_title(webpage, default=None) or self._html_search_regex(
            r'(?s)Title:\s*(.+?)<', webpage, 'title')
        description = self._html_search_meta('description', webpage)
        thumbnail = self._og_search_thumbnail(webpage)

        embed_params = [s.strip(" \r\n\t'") for s in self._search_regex(
            r'(?s)\$\("#embedCode"\).html\(getEmbedCode\((.*?)\)',
            webpage, 'embed params').split(',')]

        (
            _, speaker_id, story_id, story_duration,
            speaker_type, great_life, _thumbnail, _has_subtitles,
            story_filename, _story_order) = embed_params

        is_great_life_series = great_life == 'true'
        duration = int_or_none(story_duration)

        # URL building, see: http://www.webofstories.com/scripts/player.js
        ms_prefix = ''
        if speaker_type.lower() == 'ms':
            ms_prefix = 'mini_sites/'

        if is_great_life_series:
            mp4_url = '{0:}lives/{1:}/{2:}.mp4'.format(
                self._VIDEO_DOMAIN, speaker_id, story_filename)
            rtmp_ext = 'flv'
            streamer = self._GREAT_LIFE_STREAMER
            play_path = 'stories/{0:}/{1:}'.format(
                speaker_id, story_filename)
        else:
            mp4_url = '{0:}{1:}{2:}/{3:}.mp4'.format(
                self._VIDEO_DOMAIN, ms_prefix, speaker_id, story_filename)
            rtmp_ext = 'mp4'
            streamer = self._USER_STREAMER
            play_path = 'mp4:{0:}{1:}/{2}.mp4'.format(
                ms_prefix, speaker_id, story_filename)

        formats = [{
            'format_id': 'mp4_sd',
            'url': mp4_url,
        }, {
            'format_id': 'rtmp_sd',
            'page_url': url,
            'url': streamer,
            'ext': rtmp_ext,
            'play_path': play_path,
        }]

        self._sort_formats(formats)

        return {
            'id': story_id,
            'title': title,
            'formats': formats,
            'thumbnail': thumbnail,
            'description': description,
            'duration': duration,
        }

class WebOfStoriesPlaylistIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?webofstories\.com/playAll/(?P<id>[^/]+)'
    _TEST = {
        'url': 'http://www.webofstories.com/playAll/donald.knuth',
        'info_dict': {
            'id': 'donald.knuth',
            'title': 'Donald Knuth (Scientist)',
        },
        'playlist_mincount': 97,
    }

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

        webpage = self._download_webpage(url, playlist_id)

        entries = [
            self.url_result(
                'http://www.webofstories.com/play/%s' % video_id,
                'WebOfStories', video_id=video_id)
            for video_id in orderedSet(re.findall(r'\bid=["\']td_(\d+)', webpage))
        ]

        title = self._search_regex(
            r'
\s*([^<]+)',
            webpage, 'speaker', default=None)
        if title:
            field = self._search_regex(
                r'([^<]+)',
                webpage, 'field', default=None)
            if field:
                title += ' (%s)' % field

        if not title:
            title = self._search_regex(
                r'<title>Play\s+all\s+stories\s*-\s*([^<]+)\s*-\s*Web\s+of\s+Stories</title>',
                webpage, 'title')

        return self.playlist_result(entries, playlist_id, title)


code:
from .common import InfoExtractor

import json
import random
import re

from ..compat import (
    compat_parse_qs,
    compat_str,
)
from ..utils import (
    js_to_json,
    strip_jsonp,
    urlencode_postdata,
)

class WeiboIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?weibo\.com/[0-9]+/(?P<id>[a-zA-Z0-9]+)'
    _TEST = {
        'url': 'https://weibo.com/6275294458/Fp6RGfbff?type=comment',
        'info_dict': {
            'id': 'Fp6RGfbff',
            'ext': 'mp4',
            'title': 'You should have servants to massage you,... 来自Hosico_猫 - 微博',
        }
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)
        # to get Referer url for genvisitor
        webpage, urlh = self._download_webpage_handle(url, video_id)

        visitor_url = urlh.geturl()

        if 'passport.weibo.com' in visitor_url:
            # first visit
            visitor_data = self._download_json(
                'https://passport.weibo.com/visitor/genvisitor', video_id,
                note='Generating first-visit data',
                transform_source=strip_jsonp,
                headers={'Referer': visitor_url},
                data=urlencode_postdata({
                    'cb': 'gen_callback',
                    'fp': json.dumps({
                        'os': '2',
                        'browser': 'Gecko57,0,0,0',
                        'fonts': 'undefined',
                        'screenInfo': '1440*900*24',
                        'plugins': '',
                    }),
                }))

            tid = visitor_data['data']['tid']
            cnfd = '%03d' % visitor_data['data']['confidence']

            self._download_webpage(
                'https://passport.weibo.com/visitor/visitor', video_id,
                note='Running first-visit callback',
                query={
                    'a': 'incarnate',
                    't': tid,
                    'w': 2,
                    'c': cnfd,
                    'cb': 'cross_domain',
                    'from': 'weibo',
                    '_rand': random.random(),
                })

            webpage = self._download_webpage(
                url, video_id, note='Revisiting webpage')

        title = self._html_extract_title(webpage)

        video_formats = compat_parse_qs(self._search_regex(
            r'video-sources=\\\"(.+?)\"', webpage, 'video_sources'))

        formats = []
        supported_resolutions = (480, 720)
        for res in supported_resolutions:
            vid_urls = video_formats.get(compat_str(res))
            if not vid_urls or not isinstance(vid_urls, list):
                continue

            vid_url = vid_urls[0]
            formats.append({
                'url': vid_url,
                'height': res,
            })

        self._sort_formats(formats)

        uploader = self._og_search_property(
            'nick-name', webpage, 'uploader', default=None)

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

class WeiboMobileIE(InfoExtractor):
    _VALID_URL = r'https?://m\.weibo\.cn/status/(?P<id>[0-9]+)(\?.+)?'
    _TEST = {
        'url': 'https://m.weibo.cn/status/4189191225395228?wm=3333_2001&sourcetype=weixin&featurecode=newtitle&from=singlemessage&isappinstalled=0',
        'info_dict': {
            'id': '4189191225395228',
            'ext': 'mp4',
            'title': '午睡当然是要甜甜蜜蜜的啦',
            'uploader': '柴犬柴犬'
        }
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)
        # to get Referer url for genvisitor
        webpage = self._download_webpage(url, video_id, note='visit the page')

        weibo_info = self._parse_json(self._search_regex(
            r'var\s+\$render_data\s*=\s*\[({.*})\]\[0\]\s*\|\|\s*{};',
            webpage, 'js_code', flags=re.DOTALL),
            video_id, transform_source=js_to_json)

        status_data = weibo_info.get('status', {})
        page_info = status_data.get('page_info')
        title = status_data['status_title']
        uploader = status_data.get('user', {}).get('screen_name')

        return {
            'id': video_id,
            'title': title,
            'uploader': uploader,
            'url': page_info['media_info']['stream_url']
        }


code:
from .common import InfoExtractor

class WeiqiTVIE(InfoExtractor):
    IE_DESC = 'WQTV'
    _VALID_URL = r'https?://(?:www\.)?weiqitv\.com/index/video_play\?videoId=(?P<id>[A-Za-z0-9]+)'

    _TESTS = [{
        'url': 'http://www.weiqitv.com/index/video_play?videoId=53c744f09874f0e76a8b46f3',
        'md5': '26450599afd64c513bc77030ad15db44',
        'info_dict': {
            'id': '53c744f09874f0e76a8b46f3',
            'ext': 'mp4',
            'title': '2013年度盘点',
        },
    }, {
        'url': 'http://www.weiqitv.com/index/video_play?videoId=567379a2d4c36cca518b4569',
        'info_dict': {
            'id': '567379a2d4c36cca518b4569',
            'ext': 'mp4',
            'title': '民国围棋史',
        },
    }, {
        'url': 'http://www.weiqitv.com/index/video_play?videoId=5430220a9874f088658b4567',
        'info_dict': {
            'id': '5430220a9874f088658b4567',
            'ext': 'mp4',
            'title': '二路托过的手段和运用',
        },
    }]

    def _real_extract(self, url):
        media_id = self._match_id(url)
        page = self._download_webpage(url, media_id)

        info_json_str = self._search_regex(
            r'var\s+video\s*=\s*(.+});', page, 'info json str')
        info_json = self._parse_json(info_json_str, media_id)

        letvcloud_url = self._search_regex(
            r'var\s+letvurl\s*=\s*"([^"]+)', page, 'letvcloud url')

        return {
            '_type': 'url_transparent',
            'ie_key': 'LetvCloud',
            'url': letvcloud_url,
            'title': info_json['name'],
            'id': media_id,
        }


code:
from .common import InfoExtractor

class WhatIsMyIpIE(InfoExtractor):
    _VALID_URL = r'(?:what-is-)?(?:my-)?ip'
    _TESTS = [{
        'url': 'what-is-my-ip',
        'only_matching': True,
    }, {
        'url': 'my-ip',
        'only_matching': True,
    }, {
        'url': 'ip',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        amznaws = self._download_webpage('https://checkip.amazonaws.com', None, note=False, fatal=False).strip()
        self.to_screen(amznaws)


code:
from .common import InfoExtractor
from ..utils import (
    int_or_none,
    qualities,
    try_call,
    try_get,
    ExtractorError,
)
from ..compat import compat_str

class WhoWatchIE(InfoExtractor):
    IE_NAME = 'whowatch'
    _VALID_URL = r'https?://whowatch\.tv/viewer/(?P<id>\d+)'

    _TESTS = [{
        'url': 'https://whowatch.tv/viewer/21450171',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        self._download_webpage(url, video_id)
        metadata = self._download_json('https://api.whowatch.tv/lives/%s' % video_id, video_id)
        live_data = self._download_json('https://api.whowatch.tv/lives/%s/play' % video_id, video_id)

        title = try_call(
            lambda: live_data['share_info']['live_title'][1:-1],
            lambda: metadata['live']['title'],
            expected_type=str)

        hls_url = live_data.get('hls_url')
        if not hls_url:
            raise ExtractorError(live_data.get('error_message') or 'The user is offline.', expected=True)

        QUALITIES = qualities(['low', 'medium', 'high', 'veryhigh'])
        formats = []

        for i, fmt in enumerate(live_data.get('streams') or []):
            name = fmt.get('quality') or fmt.get('name') or compat_str(i)
            hls_url = fmt.get('hls_url')
            rtmp_url = fmt.get('rtmp_url')
            audio_only = fmt.get('audio_only')
            quality = QUALITIES(fmt.get('quality'))

            if hls_url:
                hls_fmts = self._extract_m3u8_formats(
                    hls_url, video_id, ext='mp4', m3u8_id=f'hls-{name}', quality=quality)
                formats.extend(hls_fmts)
            else:
                hls_fmts = []

            # RTMP url for audio_only is same as high format, so skip it
            if rtmp_url and not audio_only:
                formats.append({
                    'url': rtmp_url,
                    'format_id': f'rtmp-{name}',
                    'ext': 'mp4',
                    'protocol': 'rtmp_ffmpeg',  # ffmpeg can, while rtmpdump can't
                    'vcodec': 'h264',
                    'acodec': 'aac',
                    'quality': quality,
                    'format_note': fmt.get('label'),
                    # note: HLS and RTMP have same resolution for now, so it's acceptable
                    'width': try_get(hls_fmts, lambda x: x[0]['width'], int),
                    'height': try_get(hls_fmts, lambda x: x[0]['height'], int),
                })

        self._remove_duplicate_formats(formats)
        self._sort_formats(formats)

        uploader_url = try_get(metadata, lambda x: x['live']['user']['user_path'], compat_str)
        if uploader_url:
            uploader_url = f'https://whowatch.tv/profile/{uploader_url}'
        uploader_id = compat_str(try_get(metadata, lambda x: x['live']['user']['id'], int))
        uploader = try_get(metadata, lambda x: x['live']['user']['name'], compat_str)
        thumbnail = try_get(metadata, lambda x: x['live']['latest_thumbnail_url'], compat_str)
        timestamp = int_or_none(try_get(metadata, lambda x: x['live']['started_at'], int), scale=1000)
        view_count = try_get(metadata, lambda x: x['live']['total_view_count'], int)
        comment_count = try_get(metadata, lambda x: x['live']['comment_count'], int)

        return {
            'id': video_id,
            'title': title,
            'uploader_id': uploader_id,
            'uploader_url': uploader_url,
            'uploader': uploader,
            'formats': formats,
            'thumbnail': thumbnail,
            'timestamp': timestamp,
            'view_count': view_count,
            'comment_count': comment_count,
            'is_live': True,
        }