summaryrefslogtreecommitdiff
path: root/youtube_dl/extractor/generic.py
blob: 5976111572eb2eb3196729667626f0694d978e8c (plain)
    1 # coding: utf-8
    2 
    3 from __future__ import unicode_literals
    4 
    5 import os
    6 import re
    7 import sys
    8 
    9 from .common import InfoExtractor
   10 from .youtube import YoutubeIE
   11 from ..compat import (
   12     compat_etree_fromstring,
   13     compat_str,
   14     compat_urllib_parse_unquote,
   15     compat_urlparse,
   16     compat_xml_parse_error,
   17 )
   18 from ..utils import (
   19     determine_ext,
   20     ExtractorError,
   21     float_or_none,
   22     HEADRequest,
   23     int_or_none,
   24     is_html,
   25     js_to_json,
   26     KNOWN_EXTENSIONS,
   27     merge_dicts,
   28     mimetype2ext,
   29     orderedSet,
   30     parse_duration,
   31     parse_resolution,
   32     sanitized_Request,
   33     smuggle_url,
   34     unescapeHTML,
   35     unified_timestamp,
   36     unsmuggle_url,
   37     UnsupportedError,
   38     url_or_none,
   39     xpath_attr,
   40     xpath_text,
   41     xpath_with_ns,
   42 )
   43 from .commonprotocols import RtmpIE
   44 from .brightcove import (
   45     BrightcoveLegacyIE,
   46     BrightcoveNewIE,
   47 )
   48 from .nexx import (
   49     NexxIE,
   50     NexxEmbedIE,
   51 )
   52 from .nbc import NBCSportsVPlayerIE
   53 from .ooyala import OoyalaIE
   54 from .rutv import RUTVIE
   55 from .tvc import TVCIE
   56 from .sportbox import SportBoxIE
   57 from .myvi import MyviIE
   58 from .condenast import CondeNastIE
   59 from .udn import UDNEmbedIE
   60 from .senateisvp import SenateISVPIE
   61 from .svt import SVTIE
   62 from .pornhub import PornHubIE
   63 from .xhamster import XHamsterEmbedIE
   64 from .tnaflix import TNAFlixNetworkEmbedIE
   65 from .drtuber import DrTuberIE
   66 from .redtube import RedTubeIE
   67 from .tube8 import Tube8IE
   68 from .mofosex import MofosexEmbedIE
   69 from .spankwire import SpankwireIE
   70 from .youporn import YouPornIE
   71 from .vimeo import (
   72     VimeoIE,
   73     VHXEmbedIE,
   74 )
   75 from .dailymotion import DailymotionIE
   76 from .dailymail import DailyMailIE
   77 from .onionstudios import OnionStudiosIE
   78 from .viewlift import ViewLiftEmbedIE
   79 from .mtv import MTVServicesEmbeddedIE
   80 from .pladform import PladformIE
   81 from .videomore import VideomoreIE
   82 from .webcaster import WebcasterFeedIE
   83 from .googledrive import GoogleDriveIE
   84 from .jwplatform import JWPlatformIE
   85 from .digiteka import DigitekaIE
   86 from .arkena import ArkenaIE
   87 from .instagram import InstagramIE
   88 from .threeqsdn import ThreeQSDNIE
   89 from .theplatform import ThePlatformIE
   90 from .kaltura import KalturaIE
   91 from .eagleplatform import EaglePlatformIE
   92 from .facebook import FacebookIE
   93 from .soundcloud import SoundcloudEmbedIE
   94 from .tunein import TuneInBaseIE
   95 from .vbox7 import Vbox7IE
   96 from .dbtv import DBTVIE
   97 from .piksel import PikselIE
   98 from .videa import VideaIE
   99 from .twentymin import TwentyMinutenIE
  100 from .ustream import UstreamIE
  101 from .arte import ArteTVEmbedIE
  102 from .videopress import VideoPressIE
  103 from .rutube import RutubeIE
  104 from .limelight import LimelightBaseIE
  105 from .anvato import AnvatoIE
  106 from .washingtonpost import WashingtonPostIE
  107 from .wistia import WistiaIE
  108 from .mediaset import MediasetIE
  109 from .joj import JojIE
  110 from .megaphone import MegaphoneIE
  111 from .vzaar import VzaarIE
  112 from .channel9 import Channel9IE
  113 from .vshare import VShareIE
  114 from .mediasite import MediasiteIE
  115 from .springboardplatform import SpringboardPlatformIE
  116 from .yapfiles import YapFilesIE
  117 from .vice import ViceIE
  118 from .xfileshare import XFileShareIE
  119 from .cloudflarestream import CloudflareStreamIE
  120 from .peertube import PeerTubeIE
  121 from .teachable import TeachableIE
  122 from .indavideo import IndavideoEmbedIE
  123 from .apa import APAIE
  124 from .foxnews import FoxNewsIE
  125 from .viqeo import ViqeoIE
  126 from .expressen import ExpressenIE
  127 from .zype import ZypeIE
  128 from .odnoklassniki import OdnoklassnikiIE
  129 from .vk import VKIE
  130 from .kinja import KinjaEmbedIE
  131 from .arcpublishing import ArcPublishingIE
  132 from .medialaan import MedialaanIE
  133 from .simplecast import SimplecastIE
  134 
  135 
  136 class GenericIE(InfoExtractor):
  137     IE_DESC = 'Generic downloader that works on some sites'
  138     _VALID_URL = r'.*'
  139     IE_NAME = 'generic'
  140     _TESTS = [
  141         # Direct link to a video
  142         {
  143             'url': 'http://media.w3.org/2010/05/sintel/trailer.mp4',
  144             'md5': '67d406c2bcb6af27fa886f31aa934bbe',
  145             'info_dict': {
  146                 'id': 'trailer',
  147                 'ext': 'mp4',
  148                 'title': 'trailer',
  149                 'upload_date': '20100513',
  150             }
  151         },
  152         # Direct link to media delivered compressed (until Accept-Encoding is *)
  153         {
  154             'url': 'http://calimero.tk/muzik/FictionJunction-Parallel_Hearts.flac',
  155             'md5': '128c42e68b13950268b648275386fc74',
  156             'info_dict': {
  157                 'id': 'FictionJunction-Parallel_Hearts',
  158                 'ext': 'flac',
  159                 'title': 'FictionJunction-Parallel_Hearts',
  160                 'upload_date': '20140522',
  161             },
  162             'expected_warnings': [
  163                 'URL could be a direct video link, returning it as such.'
  164             ],
  165             'skip': 'URL invalid',
  166         },
  167         # Direct download with broken HEAD
  168         {
  169             'url': 'http://ai-radio.org:8000/radio.opus',
  170             'info_dict': {
  171                 'id': 'radio',
  172                 'ext': 'opus',
  173                 'title': 'radio',
  174             },
  175             'params': {
  176                 'skip_download': True,  # infinite live stream
  177             },
  178             'expected_warnings': [
  179                 r'501.*Not Implemented',
  180                 r'400.*Bad Request',
  181             ],
  182         },
  183         # Direct link with incorrect MIME type
  184         {
  185             'url': 'http://ftp.nluug.nl/video/nluug/2014-11-20_nj14/zaal-2/5_Lennart_Poettering_-_Systemd.webm',
  186             'md5': '4ccbebe5f36706d85221f204d7eb5913',
  187             'info_dict': {
  188                 'url': 'http://ftp.nluug.nl/video/nluug/2014-11-20_nj14/zaal-2/5_Lennart_Poettering_-_Systemd.webm',
  189                 'id': '5_Lennart_Poettering_-_Systemd',
  190                 'ext': 'webm',
  191                 'title': '5_Lennart_Poettering_-_Systemd',
  192                 'upload_date': '20141120',
  193             },
  194             'expected_warnings': [
  195                 'URL could be a direct video link, returning it as such.'
  196             ]
  197         },
  198         # RSS feed
  199         {
  200             'url': 'http://phihag.de/2014/youtube-dl/rss2.xml',
  201             'info_dict': {
  202                 'id': 'http://phihag.de/2014/youtube-dl/rss2.xml',
  203                 'title': 'Zero Punctuation',
  204                 'description': 're:.*groundbreaking video review series.*'
  205             },
  206             'playlist_mincount': 11,
  207         },
  208         # RSS feed with enclosure
  209         {
  210             'url': 'http://podcastfeeds.nbcnews.com/audio/podcast/MSNBC-MADDOW-NETCAST-M4V.xml',
  211             'info_dict': {
  212                 'id': 'http://podcastfeeds.nbcnews.com/nbcnews/video/podcast/MSNBC-MADDOW-NETCAST-M4V.xml',
  213                 'title': 'MSNBC Rachel Maddow (video)',
  214                 'description': 're:.*her unique approach to storytelling.*',
  215             },
  216             'playlist': [{
  217                 'info_dict': {
  218                     'ext': 'mov',
  219                     'id': 'pdv_maddow_netcast_mov-12-04-2020-224335',
  220                     'title': 're:MSNBC Rachel Maddow',
  221                     'description': 're:.*her unique approach to storytelling.*',
  222                     'timestamp': int,
  223                     'upload_date': compat_str,
  224                     'duration': float,
  225                 },
  226             }],
  227         },
  228         # RSS feed with item with description and thumbnails
  229         {
  230             'url': 'https://anchor.fm/s/dd00e14/podcast/rss',
  231             'info_dict': {
  232                 'id': 'https://anchor.fm/s/dd00e14/podcast/rss',
  233                 'title': 're:.*100% Hydrogen.*',
  234                 'description': 're:.*In this episode.*',
  235             },
  236             'playlist': [{
  237                 'info_dict': {
  238                     'ext': 'm4a',
  239                     'id': 'c1c879525ce2cb640b344507e682c36d',
  240                     'title': 're:Hydrogen!',
  241                     'description': 're:.*In this episode we are going.*',
  242                     'timestamp': 1567977776,
  243                     'upload_date': '20190908',
  244                     'duration': 459,
  245                     'thumbnail': r're:^https?://.*\.jpg$',
  246                     'episode_number': 1,
  247                     'season_number': 1,
  248                     'age_limit': 0,
  249                 },
  250             }],
  251             'params': {
  252                 'skip_download': True,
  253             },
  254         },
  255         # RSS feed with enclosures and unsupported link URLs
  256         {
  257             'url': 'http://www.hellointernet.fm/podcast?format=rss',
  258             'info_dict': {
  259                 'id': 'http://www.hellointernet.fm/podcast?format=rss',
  260                 'description': 'CGP Grey and Brady Haran talk about YouTube, life, work, whatever.',
  261                 'title': 'Hello Internet',
  262             },
  263             'playlist_mincount': 100,
  264         },
  265         # SMIL from http://videolectures.net/promogram_igor_mekjavic_eng
  266         {
  267             'url': 'http://videolectures.net/promogram_igor_mekjavic_eng/video/1/smil.xml',
  268             'info_dict': {
  269                 'id': 'smil',
  270                 'ext': 'mp4',
  271                 'title': 'Automatics, robotics and biocybernetics',
  272                 'description': 'md5:815fc1deb6b3a2bff99de2d5325be482',
  273                 'upload_date': '20130627',
  274                 'formats': 'mincount:16',
  275                 'subtitles': 'mincount:1',
  276             },
  277             'params': {
  278                 'force_generic_extractor': True,
  279                 'skip_download': True,
  280             },
  281         },
  282         # SMIL from http://www1.wdr.de/mediathek/video/livestream/index.html
  283         {
  284             'url': 'http://metafilegenerator.de/WDR/WDR_FS/hds/hds.smil',
  285             'info_dict': {
  286                 'id': 'hds',
  287                 'ext': 'flv',
  288                 'title': 'hds',
  289                 'formats': 'mincount:1',
  290             },
  291             'params': {
  292                 'skip_download': True,
  293             },
  294         },
  295         # SMIL from https://www.restudy.dk/video/play/id/1637
  296         {
  297             'url': 'https://www.restudy.dk/awsmedia/SmilDirectory/video_1637.xml',
  298             'info_dict': {
  299                 'id': 'video_1637',
  300                 'ext': 'flv',
  301                 'title': 'video_1637',
  302                 'formats': 'mincount:3',
  303             },
  304             'params': {
  305                 'skip_download': True,
  306             },
  307         },
  308         # SMIL from http://adventure.howstuffworks.com/5266-cool-jobs-iditarod-musher-video.htm
  309         {
  310             'url': 'http://services.media.howstuffworks.com/videos/450221/smil-service.smil',
  311             'info_dict': {
  312                 'id': 'smil-service',
  313                 'ext': 'flv',
  314                 'title': 'smil-service',
  315                 'formats': 'mincount:1',
  316             },
  317             'params': {
  318                 'skip_download': True,
  319             },
  320         },
  321         # SMIL from http://new.livestream.com/CoheedandCambria/WebsterHall/videos/4719370
  322         {
  323             'url': 'http://api.new.livestream.com/accounts/1570303/events/1585861/videos/4719370.smil',
  324             'info_dict': {
  325                 'id': '4719370',
  326                 'ext': 'mp4',
  327                 'title': '571de1fd-47bc-48db-abf9-238872a58d1f',
  328                 'formats': 'mincount:3',
  329             },
  330             'params': {
  331                 'skip_download': True,
  332             },
  333         },
  334         # XSPF playlist from http://www.telegraaf.nl/tv/nieuws/binnenland/24353229/__Tikibad_ontruimd_wegens_brand__.html
  335         {
  336             'url': 'http://www.telegraaf.nl/xml/playlist/2015/8/7/mZlp2ctYIUEB.xspf',
  337             'info_dict': {
  338                 'id': 'mZlp2ctYIUEB',
  339                 'ext': 'mp4',
  340                 'title': 'Tikibad ontruimd wegens brand',
  341                 'description': 'md5:05ca046ff47b931f9b04855015e163a4',
  342                 'thumbnail': r're:^https?://.*\.jpg$',
  343                 'duration': 33,
  344             },
  345             'params': {
  346                 'skip_download': True,
  347             },
  348         },
  349         # MPD from http://dash-mse-test.appspot.com/media.html
  350         {
  351             'url': 'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/car-20120827-manifest.mpd',
  352             'md5': '4b57baab2e30d6eb3a6a09f0ba57ef53',
  353             'info_dict': {
  354                 'id': 'car-20120827-manifest',
  355                 'ext': 'mp4',
  356                 'title': 'car-20120827-manifest',
  357                 'formats': 'mincount:9',
  358                 'upload_date': '20130904',
  359             },
  360             'params': {
  361                 'format': 'bestvideo',
  362             },
  363         },
  364         # m3u8 served with Content-Type: audio/x-mpegURL; charset=utf-8
  365         {
  366             'url': 'http://once.unicornmedia.com/now/master/playlist/bb0b18ba-64f5-4b1b-a29f-0ac252f06b68/77a785f3-5188-4806-b788-0893a61634ed/93677179-2d99-4ef4-9e17-fe70d49abfbf/content.m3u8',
  367             'info_dict': {
  368                 'id': 'content',
  369                 'ext': 'mp4',
  370                 'title': 'content',
  371                 'formats': 'mincount:8',
  372             },
  373             'params': {
  374                 # m3u8 downloads
  375                 'skip_download': True,
  376             },
  377             'skip': 'video gone',
  378         },
  379         # m3u8 served with Content-Type: text/plain
  380         {
  381             'url': 'http://www.nacentapps.com/m3u8/index.m3u8',
  382             'info_dict': {
  383                 'id': 'index',
  384                 'ext': 'mp4',
  385                 'title': 'index',
  386                 'upload_date': '20140720',
  387                 'formats': 'mincount:11',
  388             },
  389             'params': {
  390                 # m3u8 downloads
  391                 'skip_download': True,
  392             },
  393             'skip': 'video gone',
  394         },
  395         # google redirect
  396         {
  397             'url': 'http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CCUQtwIwAA&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DcmQHVoWB5FY&ei=F-sNU-LLCaXk4QT52ICQBQ&usg=AFQjCNEw4hL29zgOohLXvpJ-Bdh2bils1Q&bvm=bv.61965928,d.bGE',
  398             'info_dict': {
  399                 'id': 'cmQHVoWB5FY',
  400                 'ext': 'mp4',
  401                 'upload_date': '20130224',
  402                 'uploader_id': 'TheVerge',
  403                 'description': r're:^Chris Ziegler takes a look at the\.*',
  404                 'uploader': 'The Verge',
  405                 'title': 'First Firefox OS phones side-by-side',
  406             },
  407             'params': {
  408                 'skip_download': False,
  409             }
  410         },
  411         {
  412             # redirect in Refresh HTTP header
  413             'url': 'https://www.facebook.com/l.php?u=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DpO8h3EaFRdo&h=TAQHsoToz&enc=AZN16h-b6o4Zq9pZkCCdOLNKMN96BbGMNtcFwHSaazus4JHT_MFYkAA-WARTX2kvsCIdlAIyHZjl6d33ILIJU7Jzwk_K3mcenAXoAzBNoZDI_Q7EXGDJnIhrGkLXo_LJ_pAa2Jzbx17UHMd3jAs--6j2zaeto5w9RTn8T_1kKg3fdC5WPX9Dbb18vzH7YFX0eSJmoa6SP114rvlkw6pkS1-T&s=1',
  414             'info_dict': {
  415                 'id': 'pO8h3EaFRdo',
  416                 'ext': 'mp4',
  417                 'title': 'Tripeo Boiler Room x Dekmantel Festival DJ Set',
  418                 'description': 'md5:6294cc1af09c4049e0652b51a2df10d5',
  419                 'upload_date': '20150917',
  420                 'uploader_id': 'brtvofficial',
  421                 'uploader': 'Boiler Room',
  422             },
  423             'params': {
  424                 'skip_download': False,
  425             },
  426         },
  427         {
  428             'url': 'http://www.hodiho.fr/2013/02/regis-plante-sa-jeep.html',
  429             'md5': '85b90ccc9d73b4acd9138d3af4c27f89',
  430             'info_dict': {
  431                 'id': '13601338388002',
  432                 'ext': 'mp4',
  433                 'uploader': 'www.hodiho.fr',
  434                 'title': 'R\u00e9gis plante sa Jeep',
  435             }
  436         },
  437         # bandcamp page with custom domain
  438         {
  439             'add_ie': ['Bandcamp'],
  440             'url': 'http://bronyrock.com/track/the-pony-mash',
  441             'info_dict': {
  442                 'id': '3235767654',
  443                 'ext': 'mp3',
  444                 'title': 'The Pony Mash',
  445                 'uploader': 'M_Pallante',
  446             },
  447             'skip': 'There is a limit of 200 free downloads / month for the test song',
  448         },
  449         {
  450             # embedded brightcove video
  451             # it also tests brightcove videos that need to set the 'Referer'
  452             # in the http requests
  453             'add_ie': ['BrightcoveLegacy'],
  454             'url': 'http://www.bfmtv.com/video/bfmbusiness/cours-bourse/cours-bourse-l-analyse-technique-154522/',
  455             'info_dict': {
  456                 'id': '2765128793001',
  457                 'ext': 'mp4',
  458                 'title': 'Le cours de bourse : l’analyse technique',
  459                 'description': 'md5:7e9ad046e968cb2d1114004aba466fd9',
  460                 'uploader': 'BFM BUSINESS',
  461             },
  462             'params': {
  463                 'skip_download': True,
  464             },
  465         },
  466         {
  467             # embedded with itemprop embedURL and video id spelled as `idVideo`
  468             'add_id': ['BrightcoveLegacy'],
  469             'url': 'http://bfmbusiness.bfmtv.com/mediaplayer/chroniques/olivier-delamarche/',
  470             'info_dict': {
  471                 'id': '5255628253001',
  472                 'ext': 'mp4',
  473                 'title': 'md5:37c519b1128915607601e75a87995fc0',
  474                 'description': 'md5:37f7f888b434bb8f8cc8dbd4f7a4cf26',
  475                 'uploader': 'BFM BUSINESS',
  476                 'uploader_id': '876450612001',
  477                 'timestamp': 1482255315,
  478                 'upload_date': '20161220',
  479             },
  480             'params': {
  481                 'skip_download': True,
  482             },
  483         },
  484         {
  485             # https://github.com/ytdl-org/youtube-dl/issues/2253
  486             'url': 'http://bcove.me/i6nfkrc3',
  487             'md5': '0ba9446db037002366bab3b3eb30c88c',
  488             'info_dict': {
  489                 'id': '3101154703001',
  490                 'ext': 'mp4',
  491                 'title': 'Still no power',
  492                 'uploader': 'thestar.com',
  493                 'description': 'Mississauga resident David Farmer is still out of power as a result of the ice storm a month ago. To keep the house warm, Farmer cuts wood from his property for a wood burning stove downstairs.',
  494             },
  495             'add_ie': ['BrightcoveLegacy'],
  496             'skip': 'video gone',
  497         },
  498         {
  499             'url': 'http://www.championat.com/video/football/v/87/87499.html',
  500             'md5': 'fb973ecf6e4a78a67453647444222983',
  501             'info_dict': {
  502                 'id': '3414141473001',
  503                 'ext': 'mp4',
  504                 'title': 'Видео. Удаление Дзагоева (ЦСКА)',
  505                 'description': 'Онлайн-трансляция матча ЦСКА - "Волга"',
  506                 'uploader': 'Championat',
  507             },
  508         },
  509         {
  510             # https://github.com/ytdl-org/youtube-dl/issues/3541
  511             'add_ie': ['BrightcoveLegacy'],
  512             'url': 'http://www.kijk.nl/sbs6/leermijvrouwenkennen/videos/jqMiXKAYan2S/aflevering-1',
  513             'info_dict': {
  514                 'id': '3866516442001',
  515                 'ext': 'mp4',
  516                 'title': 'Leer mij vrouwen kennen: Aflevering 1',
  517                 'description': 'Leer mij vrouwen kennen: Aflevering 1',
  518                 'uploader': 'SBS Broadcasting',
  519             },
  520             'skip': 'Restricted to Netherlands',
  521             'params': {
  522                 'skip_download': True,  # m3u8 download
  523             },
  524         },
  525         {
  526             # Brightcove video in <iframe>
  527             'url': 'http://www.un.org/chinese/News/story.asp?NewsID=27724',
  528             'md5': '36d74ef5e37c8b4a2ce92880d208b968',
  529             'info_dict': {
  530                 'id': '5360463607001',
  531                 'ext': 'mp4',
  532                 'title': '叙利亚失明儿童在废墟上演唱《心跳》  呼吁获得正常童年生活',
  533                 'description': '联合国儿童基金会中东和北非区域大使、作曲家扎德·迪拉尼(Zade Dirani)在3月15日叙利亚冲突爆发7周年纪念日之际发布了为叙利亚谱写的歌曲《心跳》(HEARTBEAT),为受到六年冲突影响的叙利亚儿童发出强烈呐喊,呼吁世界做出共同努力,使叙利亚儿童重新获得享有正常童年生活的权利。',
  534                 'uploader': 'United Nations',
  535                 'uploader_id': '1362235914001',
  536                 'timestamp': 1489593889,
  537                 'upload_date': '20170315',
  538             },
  539             'add_ie': ['BrightcoveLegacy'],
  540         },
  541         {
  542             # Brightcove with alternative playerID key
  543             'url': 'http://www.nature.com/nmeth/journal/v9/n7/fig_tab/nmeth.2062_SV1.html',
  544             'info_dict': {
  545                 'id': 'nmeth.2062_SV1',
  546                 'title': 'Simultaneous multiview imaging of the Drosophila syncytial blastoderm : Quantitative high-speed imaging of entire developing embryos with simultaneous multiview light-sheet microscopy : Nature Methods : Nature Research',
  547             },
  548             'playlist': [{
  549                 'info_dict': {
  550                     'id': '2228375078001',
  551                     'ext': 'mp4',
  552                     'title': 'nmeth.2062-sv1',
  553                     'description': 'nmeth.2062-sv1',
  554                     'timestamp': 1363357591,
  555                     'upload_date': '20130315',
  556                     'uploader': 'Nature Publishing Group',
  557                     'uploader_id': '1964492299001',
  558                 },
  559             }],
  560         },
  561         {
  562             # Brightcove with UUID in videoPlayer
  563             'url': 'http://www8.hp.com/cn/zh/home.html',
  564             'info_dict': {
  565                 'id': '5255815316001',
  566                 'ext': 'mp4',
  567                 'title': 'Sprocket Video - China',
  568                 'description': 'Sprocket Video - China',
  569                 'uploader': 'HP-Video Gallery',
  570                 'timestamp': 1482263210,
  571                 'upload_date': '20161220',
  572                 'uploader_id': '1107601872001',
  573             },
  574             'params': {
  575                 'skip_download': True,  # m3u8 download
  576             },
  577             'skip': 'video rotates...weekly?',
  578         },
  579         {
  580             # Brightcove:new type [2].
  581             'url': 'http://www.delawaresportszone.com/video-st-thomas-more-earns-first-trip-to-basketball-semis',
  582             'md5': '2b35148fcf48da41c9fb4591650784f3',
  583             'info_dict': {
  584                 'id': '5348741021001',
  585                 'ext': 'mp4',
  586                 'upload_date': '20170306',
  587                 'uploader_id': '4191638492001',
  588                 'timestamp': 1488769918,
  589                 'title': 'VIDEO:  St. Thomas More earns first trip to basketball semis',
  590 
  591             },
  592         },
  593         {
  594             # Alternative brightcove <video> attributes
  595             'url': 'http://www.programme-tv.net/videos/extraits/81095-guillaume-canet-evoque-les-rumeurs-d-infidelite-de-marion-cotillard-avec-brad-pitt-dans-vivement-dimanche/',
  596             'info_dict': {
  597                 'id': '81095-guillaume-canet-evoque-les-rumeurs-d-infidelite-de-marion-cotillard-avec-brad-pitt-dans-vivement-dimanche',
  598                 'title': "Guillaume Canet évoque les rumeurs d'infidélité de Marion Cotillard avec Brad Pitt dans Vivement Dimanche, Extraits : toutes les vidéos avec Télé-Loisirs",
  599             },
  600             'playlist': [{
  601                 'md5': '732d22ba3d33f2f3fc253c39f8f36523',
  602                 'info_dict': {
  603                     'id': '5311302538001',
  604                     'ext': 'mp4',
  605                     'title': "Guillaume Canet évoque les rumeurs d'infidélité de Marion Cotillard avec Brad Pitt dans Vivement Dimanche",
  606                     'description': "Guillaume Canet évoque les rumeurs d'infidélité de Marion Cotillard avec Brad Pitt dans Vivement Dimanche (France 2, 5 février 2017)",
  607                     'timestamp': 1486321708,
  608                     'upload_date': '20170205',
  609                     'uploader_id': '800000640001',
  610                 },
  611                 'only_matching': True,
  612             }],
  613         },
  614         {
  615             # Brightcove with UUID in videoPlayer
  616             'url': 'http://www8.hp.com/cn/zh/home.html',
  617             'info_dict': {
  618                 'id': '5255815316001',
  619                 'ext': 'mp4',
  620                 'title': 'Sprocket Video - China',
  621                 'description': 'Sprocket Video - China',
  622                 'uploader': 'HP-Video Gallery',
  623                 'timestamp': 1482263210,
  624                 'upload_date': '20161220',
  625                 'uploader_id': '1107601872001',
  626             },
  627             'params': {
  628                 'skip_download': True,  # m3u8 download
  629             },
  630         },
  631         # ooyala video
  632         {
  633             'url': 'http://www.rollingstone.com/music/videos/norwegian-dj-cashmere-cat-goes-spartan-on-with-me-premiere-20131219',
  634             'md5': '166dd577b433b4d4ebfee10b0824d8ff',
  635             'info_dict': {
  636                 'id': 'BwY2RxaTrTkslxOfcan0UCf0YqyvWysJ',
  637                 'ext': 'mp4',
  638                 'title': '2cc213299525360.mov',  # that's what we get
  639                 'duration': 238.231,
  640             },
  641             'add_ie': ['Ooyala'],
  642         },
  643         {
  644             # ooyala video embedded with http://player.ooyala.com/iframe.js
  645             'url': 'http://www.macrumors.com/2015/07/24/steve-jobs-the-man-in-the-machine-first-trailer/',
  646             'info_dict': {
  647                 'id': 'p0MGJndjoG5SOKqO_hZJuZFPB-Tr5VgB',
  648                 'ext': 'mp4',
  649                 'title': '"Steve Jobs: Man in the Machine" trailer',
  650                 'description': 'The first trailer for the Alex Gibney documentary "Steve Jobs: Man in the Machine."',
  651                 'duration': 135.427,
  652             },
  653             'params': {
  654                 'skip_download': True,
  655             },
  656             'skip': 'movie expired',
  657         },
  658         # ooyala video embedded with http://player.ooyala.com/static/v4/production/latest/core.min.js
  659         {
  660             'url': 'http://wnep.com/2017/07/22/steampunk-fest-comes-to-honesdale/',
  661             'info_dict': {
  662                 'id': 'lwYWYxYzE6V5uJMjNGyKtwwiw9ZJD7t2',
  663                 'ext': 'mp4',
  664                 'title': 'Steampunk Fest Comes to Honesdale',
  665                 'duration': 43.276,
  666             },
  667             'params': {
  668                 'skip_download': True,
  669             }
  670         },
  671         # embed.ly video
  672         {
  673             'url': 'http://www.tested.com/science/weird/460206-tested-grinding-coffee-2000-frames-second/',
  674             'info_dict': {
  675                 'id': '9ODmcdjQcHQ',
  676                 'ext': 'mp4',
  677                 'title': 'Tested: Grinding Coffee at 2000 Frames Per Second',
  678                 'upload_date': '20140225',
  679                 'description': 'md5:06a40fbf30b220468f1e0957c0f558ff',
  680                 'uploader': 'Tested',
  681                 'uploader_id': 'testedcom',
  682             },
  683             # No need to test YoutubeIE here
  684             'params': {
  685                 'skip_download': True,
  686             },
  687         },
  688         # funnyordie embed
  689         {
  690             'url': 'http://www.theguardian.com/world/2014/mar/11/obama-zach-galifianakis-between-two-ferns',
  691             'info_dict': {
  692                 'id': '18e820ec3f',
  693                 'ext': 'mp4',
  694                 'title': 'Between Two Ferns with Zach Galifianakis: President Barack Obama',
  695                 'description': 'Episode 18: President Barack Obama sits down with Zach Galifianakis for his most memorable interview yet.',
  696             },
  697             # HEAD requests lead to endless 301, while GET is OK
  698             'expected_warnings': ['301'],
  699         },
  700         # RUTV embed
  701         {
  702             'url': 'http://www.rg.ru/2014/03/15/reg-dfo/anklav-anons.html',
  703             'info_dict': {
  704                 'id': '776940',
  705                 'ext': 'mp4',
  706                 'title': 'Охотское море стало целиком российским',
  707                 'description': 'md5:5ed62483b14663e2a95ebbe115eb8f43',
  708             },
  709             'params': {
  710                 # m3u8 download
  711                 'skip_download': True,
  712             },
  713         },
  714         # TVC embed
  715         {
  716             'url': 'http://sch1298sz.mskobr.ru/dou_edu/karamel_ki/filial_galleries/video/iframe_src_http_tvc_ru_video_iframe_id_55304_isplay_false_acc_video_id_channel_brand_id_11_show_episodes_episode_id_32307_frameb/',
  717             'info_dict': {
  718                 'id': '55304',
  719                 'ext': 'mp4',
  720                 'title': 'Дошкольное воспитание',
  721             },
  722         },
  723         # SportBox embed
  724         {
  725             'url': 'http://www.vestifinance.ru/articles/25753',
  726             'info_dict': {
  727                 'id': '25753',
  728                 'title': 'Прямые трансляции с Форума-выставки "Госзаказ-2013"',
  729             },
  730             'playlist': [{
  731                 'info_dict': {
  732                     'id': '370908',
  733                     'title': 'Госзаказ. День 3',
  734                     'ext': 'mp4',
  735                 }
  736             }, {
  737                 'info_dict': {
  738                     'id': '370905',
  739                     'title': 'Госзаказ. День 2',
  740                     'ext': 'mp4',
  741                 }
  742             }, {
  743                 'info_dict': {
  744                     'id': '370902',
  745                     'title': 'Госзаказ. День 1',
  746                     'ext': 'mp4',
  747                 }
  748             }],
  749             'params': {
  750                 # m3u8 download
  751                 'skip_download': True,
  752             },
  753         },
  754         # Myvi.ru embed
  755         {
  756             'url': 'http://www.kinomyvi.tv/news/detail/Pervij-dublirovannij-trejler--Uzhastikov-_nOw1',
  757             'info_dict': {
  758                 'id': 'f4dafcad-ff21-423d-89b5-146cfd89fa1e',
  759                 'ext': 'mp4',
  760                 'title': 'Ужастики, русский трейлер (2015)',
  761                 'thumbnail': r're:^https?://.*\.jpg$',
  762                 'duration': 153,
  763             }
  764         },
  765         # XHamster embed
  766         {
  767             'url': 'http://www.numisc.com/forum/showthread.php?11696-FM15-which-pumiscer-was-this-%28-vid-%29-%28-alfa-as-fuck-srx-%29&s=711f5db534502e22260dec8c5e2d66d8',
  768             'info_dict': {
  769                 'id': 'showthread',
  770                 'title': '[NSFL] [FM15] which pumiscer was this ( vid ) ( alfa as fuck srx )',
  771             },
  772             'playlist_mincount': 7,
  773             # This forum does not allow <iframe> syntaxes anymore
  774             # Now HTML tags are displayed as-is
  775             'skip': 'No videos on this page',
  776         },
  777         # Embedded TED video
  778         {
  779             'url': 'http://en.support.wordpress.com/videos/ted-talks/',
  780             'md5': '65fdff94098e4a607385a60c5177c638',
  781             'info_dict': {
  782                 'id': '1969',
  783                 'ext': 'mp4',
  784                 'title': 'Hidden miracles of the natural world',
  785                 'uploader': 'Louie Schwartzberg',
  786                 'description': 'md5:8145d19d320ff3e52f28401f4c4283b9',
  787             }
  788         },
  789         # nowvideo embed hidden behind percent encoding
  790         {
  791             'url': 'http://www.waoanime.tv/the-super-dimension-fortress-macross-episode-1/',
  792             'md5': '2baf4ddd70f697d94b1c18cf796d5107',
  793             'info_dict': {
  794                 'id': '06e53103ca9aa',
  795                 'ext': 'flv',
  796                 'title': 'Macross Episode 001  Watch Macross Episode 001 onl',
  797                 'description': 'No description',
  798             },
  799         },
  800         # arte embed
  801         {
  802             'url': 'http://www.tv-replay.fr/redirection/20-03-14/x-enius-arte-10753389.html',
  803             'md5': '7653032cbb25bf6c80d80f217055fa43',
  804             'info_dict': {
  805                 'id': '048195-004_PLUS7-F',
  806                 'ext': 'flv',
  807                 'title': 'X:enius',
  808                 'description': 'md5:d5fdf32ef6613cdbfd516ae658abf168',
  809                 'upload_date': '20140320',
  810             },
  811             'params': {
  812                 'skip_download': 'Requires rtmpdump'
  813             },
  814             'skip': 'video gone',
  815         },
  816         # francetv embed
  817         {
  818             'url': 'http://www.tsprod.com/replay-du-concert-alcaline-de-calogero',
  819             'info_dict': {
  820                 'id': 'EV_30231',
  821                 'ext': 'mp4',
  822                 'title': 'Alcaline, le concert avec Calogero',
  823                 'description': 'md5:61f08036dcc8f47e9cfc33aed08ffaff',
  824                 'upload_date': '20150226',
  825                 'timestamp': 1424989860,
  826                 'duration': 5400,
  827             },
  828             'params': {
  829                 # m3u8 downloads
  830                 'skip_download': True,
  831             },
  832             'expected_warnings': [
  833                 'Forbidden'
  834             ]
  835         },
  836         # Condé Nast embed
  837         {
  838             'url': 'http://www.wired.com/2014/04/honda-asimo/',
  839             'md5': 'ba0dfe966fa007657bd1443ee672db0f',
  840             'info_dict': {
  841                 'id': '53501be369702d3275860000',
  842                 'ext': 'mp4',
  843                 'title': 'Honda’s  New Asimo Robot Is More Human Than Ever',
  844             }
  845         },
  846         # Dailymotion embed
  847         {
  848             'url': 'http://www.spi0n.com/zap-spi0n-com-n216/',
  849             'md5': '441aeeb82eb72c422c7f14ec533999cd',
  850             'info_dict': {
  851                 'id': 'k2mm4bCdJ6CQ2i7c8o2',
  852                 'ext': 'mp4',
  853                 'title': 'Le Zap de Spi0n n°216 - Zapping du Web',
  854                 'description': 'md5:faf028e48a461b8b7fad38f1e104b119',
  855                 'uploader': 'Spi0n',
  856                 'uploader_id': 'xgditw',
  857                 'upload_date': '20140425',
  858                 'timestamp': 1398441542,
  859             },
  860             'add_ie': ['Dailymotion'],
  861         },
  862         # DailyMail embed
  863         {
  864             'url': 'http://www.bumm.sk/krimi/2017/07/05/biztonsagi-kamera-buktatta-le-az-agg-ferfit-utlegelo-apolot',
  865             'info_dict': {
  866                 'id': '1495629',
  867                 'ext': 'mp4',
  868                 'title': 'Care worker punches elderly dementia patient in head 11 times',
  869                 'description': 'md5:3a743dee84e57e48ec68bf67113199a5',
  870             },
  871             'add_ie': ['DailyMail'],
  872             'params': {
  873                 'skip_download': True,
  874             },
  875         },
  876         # YouTube embed
  877         {
  878             'url': 'http://www.badzine.de/ansicht/datum/2014/06/09/so-funktioniert-die-neue-englische-badminton-liga.html',
  879             'info_dict': {
  880                 'id': 'FXRb4ykk4S0',
  881                 'ext': 'mp4',
  882                 'title': 'The NBL Auction 2014',
  883                 'uploader': 'BADMINTON England',
  884                 'uploader_id': 'BADMINTONEvents',
  885                 'upload_date': '20140603',
  886                 'description': 'md5:9ef128a69f1e262a700ed83edb163a73',
  887             },
  888             'add_ie': ['Youtube'],
  889             'params': {
  890                 'skip_download': True,
  891             }
  892         },
  893         # MTVServices embed
  894         {
  895             'url': 'http://www.vulture.com/2016/06/new-key-peele-sketches-released.html',
  896             'md5': 'ca1aef97695ef2c1d6973256a57e5252',
  897             'info_dict': {
  898                 'id': '769f7ec0-0692-4d62-9b45-0d88074bffc1',
  899                 'ext': 'mp4',
  900                 'title': 'Key and Peele|October 10, 2012|2|203|Liam Neesons - Uncensored',
  901                 'description': 'Two valets share their love for movie star Liam Neesons.',
  902                 'timestamp': 1349922600,
  903                 'upload_date': '20121011',
  904             },
  905         },
  906         # YouTube embed via <data-embed-url="">
  907         {
  908             'url': 'https://play.google.com/store/apps/details?id=com.gameloft.android.ANMP.GloftA8HM',
  909             'info_dict': {
  910                 'id': '4vAffPZIT44',
  911                 'ext': 'mp4',
  912                 'title': 'Asphalt 8: Airborne - Update - Welcome to Dubai!',
  913                 'uploader': 'Gameloft',
  914                 'uploader_id': 'gameloft',
  915                 'upload_date': '20140828',
  916                 'description': 'md5:c80da9ed3d83ae6d1876c834de03e1c4',
  917             },
  918             'params': {
  919                 'skip_download': True,
  920             }
  921         },
  922         # YouTube <object> embed
  923         {
  924             'url': 'http://www.improbable.com/2017/04/03/untrained-modern-youths-and-ancient-masters-in-selfie-portraits/',
  925             'md5': '516718101ec834f74318df76259fb3cc',
  926             'info_dict': {
  927                 'id': 'msN87y-iEx0',
  928                 'ext': 'webm',
  929                 'title': 'Feynman: Mirrors FUN TO IMAGINE 6',
  930                 'upload_date': '20080526',
  931                 'description': 'md5:0ffc78ea3f01b2e2c247d5f8d1d3c18d',
  932                 'uploader': 'Christopher Sykes',
  933                 'uploader_id': 'ChristopherJSykes',
  934             },
  935             'add_ie': ['Youtube'],
  936         },
  937         # Camtasia studio
  938         {
  939             'url': 'http://www.ll.mit.edu/workshops/education/videocourses/antennas/lecture1/video/',
  940             'playlist': [{
  941                 'md5': '0c5e352edabf715d762b0ad4e6d9ee67',
  942                 'info_dict': {
  943                     'id': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final',
  944                     'title': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final - video1',
  945                     'ext': 'flv',
  946                     'duration': 2235.90,
  947                 }
  948             }, {
  949                 'md5': '10e4bb3aaca9fd630e273ff92d9f3c63',
  950                 'info_dict': {
  951                     'id': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final_PIP',
  952                     'title': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final - pip',
  953                     'ext': 'flv',
  954                     'duration': 2235.93,
  955                 }
  956             }],
  957             'info_dict': {
  958                 'title': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final',
  959             }
  960         },
  961         # Flowplayer
  962         {
  963             'url': 'http://www.handjobhub.com/video/busty-blonde-siri-tit-fuck-while-wank-6313.html',
  964             'md5': '9d65602bf31c6e20014319c7d07fba27',
  965             'info_dict': {
  966                 'id': '5123ea6d5e5a7',
  967                 'ext': 'mp4',
  968                 'age_limit': 18,
  969                 'uploader': 'www.handjobhub.com',
  970                 'title': 'Busty Blonde Siri Tit Fuck While Wank at HandjobHub.com',
  971             }
  972         },
  973         # Multiple brightcove videos
  974         # https://github.com/ytdl-org/youtube-dl/issues/2283
  975         {
  976             'url': 'http://www.newyorker.com/online/blogs/newsdesk/2014/01/always-never-nuclear-command-and-control.html',
  977             'info_dict': {
  978                 'id': 'always-never',
  979                 'title': 'Always / Never - The New Yorker',
  980             },
  981             'playlist_count': 3,
  982             'params': {
  983                 'extract_flat': False,
  984                 'skip_download': True,
  985             }
  986         },
  987         # MLB embed
  988         {
  989             'url': 'http://umpire-empire.com/index.php/topic/58125-laz-decides-no-thats-low/',
  990             'md5': '96f09a37e44da40dd083e12d9a683327',
  991             'info_dict': {
  992                 'id': '33322633',
  993                 'ext': 'mp4',
  994                 'title': 'Ump changes call to ball',
  995                 'description': 'md5:71c11215384298a172a6dcb4c2e20685',
  996                 'duration': 48,
  997                 'timestamp': 1401537900,
  998                 'upload_date': '20140531',
  999                 'thumbnail': r're:^https?://.*\.jpg$',
 1000             },
 1001         },
 1002         # Wistia embed
 1003         {
 1004             'url': 'http://study.com/academy/lesson/north-american-exploration-failed-colonies-of-spain-france-england.html#lesson',
 1005             'md5': '1953f3a698ab51cfc948ed3992a0b7ff',
 1006             'info_dict': {
 1007                 'id': '6e2wtrbdaf',
 1008                 'ext': 'mov',
 1009                 'title': 'paywall_north-american-exploration-failed-colonies-of-spain-france-england',
 1010                 'description': 'a Paywall Videos video from Remilon',
 1011                 'duration': 644.072,
 1012                 'uploader': 'study.com',
 1013                 'timestamp': 1459678540,
 1014                 'upload_date': '20160403',
 1015                 'filesize': 24687186,
 1016             },
 1017         },
 1018         {
 1019             'url': 'http://thoughtworks.wistia.com/medias/uxjb0lwrcz',
 1020             'md5': 'baf49c2baa8a7de5f3fc145a8506dcd4',
 1021             'info_dict': {
 1022                 'id': 'uxjb0lwrcz',
 1023                 'ext': 'mp4',
 1024                 'title': 'Conversation about Hexagonal Rails Part 1',
 1025                 'description': 'a Martin Fowler video from ThoughtWorks',
 1026                 'duration': 1715.0,
 1027                 'uploader': 'thoughtworks.wistia.com',
 1028                 'timestamp': 1401832161,
 1029                 'upload_date': '20140603',
 1030             },
 1031         },
 1032         # Wistia standard embed (async)
 1033         {
 1034             'url': 'https://www.getdrip.com/university/brennan-dunn-drip-workshop/',
 1035             'info_dict': {
 1036                 'id': '807fafadvk',
 1037                 'ext': 'mp4',
 1038                 'title': 'Drip Brennan Dunn Workshop',
 1039                 'description': 'a JV Webinars video from getdrip-1',
 1040                 'duration': 4986.95,
 1041                 'timestamp': 1463607249,
 1042                 'upload_date': '20160518',
 1043             },
 1044             'params': {
 1045                 'skip_download': True,
 1046             }
 1047         },
 1048         # Soundcloud embed
 1049         {
 1050             'url': 'http://nakedsecurity.sophos.com/2014/10/29/sscc-171-are-you-sure-that-1234-is-a-bad-password-podcast/',
 1051             'info_dict': {
 1052                 'id': '174391317',
 1053                 'ext': 'mp3',
 1054                 'description': 'md5:ff867d6b555488ad3c52572bb33d432c',
 1055                 'uploader': 'Sophos Security',
 1056                 'title': 'Chet Chat 171 - Oct 29, 2014',
 1057                 'upload_date': '20141029',
 1058             }
 1059         },
 1060         # Soundcloud multiple embeds
 1061         {
 1062             'url': 'http://www.guitarplayer.com/lessons/1014/legato-workout-one-hour-to-more-fluid-performance---tab/52809',
 1063             'info_dict': {
 1064                 'id': '52809',
 1065                 'title': 'Guitar Essentials: Legato Workout—One-Hour to Fluid Performance  | TAB + AUDIO',
 1066             },
 1067             'playlist_mincount': 7,
 1068         },
 1069         # TuneIn station embed
 1070         {
 1071             'url': 'http://radiocnrv.com/promouvoir-radio-cnrv/',
 1072             'info_dict': {
 1073                 'id': '204146',
 1074                 'ext': 'mp3',
 1075                 'title': 'CNRV',
 1076                 'location': 'Paris, France',
 1077                 'is_live': True,
 1078             },
 1079             'params': {
 1080                 # Live stream
 1081                 'skip_download': True,
 1082             },
 1083         },
 1084         # Livestream embed
 1085         {
 1086             'url': 'http://www.esa.int/Our_Activities/Space_Science/Rosetta/Philae_comet_touch-down_webcast',
 1087             'info_dict': {
 1088                 'id': '67864563',
 1089                 'ext': 'flv',
 1090                 'upload_date': '20141112',
 1091                 'title': 'Rosetta #CometLanding webcast HL 10',
 1092             }
 1093         },
 1094         # Another Livestream embed, without 'new.' in URL
 1095         {
 1096             'url': 'https://www.freespeech.org/',
 1097             'info_dict': {
 1098                 'id': '123537347',
 1099                 'ext': 'mp4',
 1100                 'title': 're:^FSTV [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
 1101             },
 1102             'params': {
 1103                 # Live stream
 1104                 'skip_download': True,
 1105             },
 1106         },
 1107         # LazyYT
 1108         {
 1109             'url': 'https://skiplagged.com/',
 1110             'info_dict': {
 1111                 'id': 'skiplagged',
 1112                 'title': 'Skiplagged: The smart way to find cheap flights',
 1113             },
 1114             'playlist_mincount': 1,
 1115             'add_ie': ['Youtube'],
 1116         },
 1117         # Cinchcast embed
 1118         {
 1119             'url': 'http://undergroundwellness.com/podcasts/306-5-steps-to-permanent-gut-healing/',
 1120             'info_dict': {
 1121                 'id': '7141703',
 1122                 'ext': 'mp3',
 1123                 'upload_date': '20141126',
 1124                 'title': 'Jack Tips: 5 Steps to Permanent Gut Healing',
 1125             }
 1126         },
 1127         # Cinerama player
 1128         {
 1129             'url': 'http://www.abc.net.au/7.30/content/2015/s4164797.htm',
 1130             'info_dict': {
 1131                 'id': '730m_DandD_1901_512k',
 1132                 'ext': 'mp4',
 1133                 'uploader': 'www.abc.net.au',
 1134                 'title': 'Game of Thrones with dice - Dungeons and Dragons fantasy role-playing game gets new life - 19/01/2015',
 1135             }
 1136         },
 1137         # embedded viddler video
 1138         {
 1139             'url': 'http://deadspin.com/i-cant-stop-watching-john-wall-chop-the-nuggets-with-th-1681801597',
 1140             'info_dict': {
 1141                 'id': '4d03aad9',
 1142                 'ext': 'mp4',
 1143                 'uploader': 'deadspin',
 1144                 'title': 'WALL-TO-GORTAT',
 1145                 'timestamp': 1422285291,
 1146                 'upload_date': '20150126',
 1147             },
 1148             'add_ie': ['Viddler'],
 1149         },
 1150         # Libsyn embed
 1151         {
 1152             'url': 'http://thedailyshow.cc.com/podcast/episodetwelve',
 1153             'info_dict': {
 1154                 'id': '3377616',
 1155                 'ext': 'mp3',
 1156                 'title': "The Daily Show Podcast without Jon Stewart - Episode 12: Bassem Youssef: Egypt's Jon Stewart",
 1157                 'description': 'md5:601cb790edd05908957dae8aaa866465',
 1158                 'upload_date': '20150220',
 1159             },
 1160             'skip': 'All The Daily Show URLs now redirect to http://www.cc.com/shows/',
 1161         },
 1162         # jwplayer YouTube
 1163         {
 1164             'url': 'http://media.nationalarchives.gov.uk/index.php/webinar-using-discovery-national-archives-online-catalogue/',
 1165             'info_dict': {
 1166                 'id': 'Mrj4DVp2zeA',
 1167                 'ext': 'mp4',
 1168                 'upload_date': '20150212',
 1169                 'uploader': 'The National Archives UK',
 1170                 'description': 'md5:8078af856dca76edc42910b61273dbbf',
 1171                 'uploader_id': 'NationalArchives08',
 1172                 'title': 'Webinar: Using Discovery, The National Archives’ online catalogue',
 1173             },
 1174         },
 1175         # jwplayer rtmp
 1176         {
 1177             'url': 'http://www.suffolk.edu/sjc/live.php',
 1178             'info_dict': {
 1179                 'id': 'live',
 1180                 'ext': 'flv',
 1181                 'title': 'Massachusetts Supreme Judicial Court Oral Arguments',
 1182                 'uploader': 'www.suffolk.edu',
 1183             },
 1184             'params': {
 1185                 'skip_download': True,
 1186             },
 1187             'skip': 'Only has video a few mornings per month, see http://www.suffolk.edu/sjc/',
 1188         },
 1189         # Complex jwplayer
 1190         {
 1191             'url': 'http://www.indiedb.com/games/king-machine/videos',
 1192             'info_dict': {
 1193                 'id': 'videos',
 1194                 'ext': 'mp4',
 1195                 'title': 'king machine trailer 1',
 1196                 'description': 'Browse King Machine videos & audio for sweet media. Your eyes will thank you.',
 1197                 'thumbnail': r're:^https?://.*\.jpg$',
 1198             },
 1199         },
 1200         {
 1201             # JWPlayer config passed as variable
 1202             'url': 'http://www.txxx.com/videos/3326530/ariele/',
 1203             'info_dict': {
 1204                 'id': '3326530_hq',
 1205                 'ext': 'mp4',
 1206                 'title': 'ARIELE | Tube Cup',
 1207                 'uploader': 'www.txxx.com',
 1208                 'age_limit': 18,
 1209             },
 1210             'params': {
 1211                 'skip_download': True,
 1212             }
 1213         },
 1214         {
 1215             # JWPlatform iframe
 1216             'url': 'https://www.mediaite.com/tv/dem-senator-claims-gary-cohn-faked-a-bad-connection-during-trump-call-to-get-him-off-the-phone/',
 1217             'md5': 'ca00a040364b5b439230e7ebfd02c4e9',
 1218             'info_dict': {
 1219                 'id': 'O0c5JcKT',
 1220                 'ext': 'mp4',
 1221                 'upload_date': '20171122',
 1222                 'timestamp': 1511366290,
 1223                 'title': 'Dem Senator Claims Gary Cohn Faked a Bad Connection During Trump Call to Get Him Off the Phone',
 1224             },
 1225             'add_ie': [JWPlatformIE.ie_key()],
 1226         },
 1227         {
 1228             # Video.js embed, multiple formats
 1229             'url': 'http://ortcam.com/solidworks-урок-6-настройка-чертежа_33f9b7351.html',
 1230             'info_dict': {
 1231                 'id': 'yygqldloqIk',
 1232                 'ext': 'mp4',
 1233                 'title': 'SolidWorks. Урок 6 Настройка чертежа',
 1234                 'description': 'md5:baf95267792646afdbf030e4d06b2ab3',
 1235                 'upload_date': '20130314',
 1236                 'uploader': 'PROстое3D',
 1237                 'uploader_id': 'PROstoe3D',
 1238             },
 1239             'params': {
 1240                 'skip_download': True,
 1241             },
 1242         },
 1243         {
 1244             # Video.js embed, single format
 1245             'url': 'https://www.vooplayer.com/v3/watch/watch.php?v=NzgwNTg=',
 1246             'info_dict': {
 1247                 'id': 'watch',
 1248                 'ext': 'mp4',
 1249                 'title': 'Step 1 -  Good Foundation',
 1250                 'description': 'md5:d1e7ff33a29fc3eb1673d6c270d344f4',
 1251             },
 1252             'params': {
 1253                 'skip_download': True,
 1254             },
 1255         },
 1256         # rtl.nl embed
 1257         {
 1258             'url': 'http://www.rtlnieuws.nl/nieuws/buitenland/aanslagen-kopenhagen',
 1259             'playlist_mincount': 5,
 1260             'info_dict': {
 1261                 'id': 'aanslagen-kopenhagen',
 1262                 'title': 'Aanslagen Kopenhagen',
 1263             }
 1264         },
 1265         # Zapiks embed
 1266         {
 1267             'url': 'http://www.skipass.com/news/116090-bon-appetit-s5ep3-baqueira-mi-cor.html',
 1268             'info_dict': {
 1269                 'id': '118046',
 1270                 'ext': 'mp4',
 1271                 'title': 'EP3S5 - Bon Appétit - Baqueira Mi Corazon !',
 1272             }
 1273         },
 1274         # Kaltura embed (different embed code)
 1275         {
 1276             'url': 'http://www.premierchristianradio.com/Shows/Saturday/Unbelievable/Conference-Videos/Os-Guinness-Is-It-Fools-Talk-Unbelievable-Conference-2014',
 1277             'info_dict': {
 1278                 'id': '1_a52wc67y',
 1279                 'ext': 'flv',
 1280                 'upload_date': '20150127',
 1281                 'uploader_id': 'PremierMedia',
 1282                 'timestamp': int,
 1283                 'title': 'Os Guinness // Is It Fools Talk? // Unbelievable? Conference 2014',
 1284             },
 1285         },
 1286         # Kaltura embed with single quotes
 1287         {
 1288             'url': 'http://fod.infobase.com/p_ViewPlaylist.aspx?AssignmentID=NUN8ZY',
 1289             'info_dict': {
 1290                 'id': '0_izeg5utt',
 1291                 'ext': 'mp4',
 1292                 'title': '35871',
 1293                 'timestamp': 1355743100,
 1294                 'upload_date': '20121217',
 1295                 'uploader_id': 'cplapp@learn360.com',
 1296             },
 1297             'add_ie': ['Kaltura'],
 1298         },
 1299         {
 1300             # Kaltura embedded via quoted entry_id
 1301             'url': 'https://www.oreilly.com/ideas/my-cloud-makes-pretty-pictures',
 1302             'info_dict': {
 1303                 'id': '0_utuok90b',
 1304                 'ext': 'mp4',
 1305                 'title': '06_matthew_brender_raj_dutt',
 1306                 'timestamp': 1466638791,
 1307                 'upload_date': '20160622',
 1308             },
 1309             'add_ie': ['Kaltura'],
 1310             'expected_warnings': [
 1311                 'Could not send HEAD request'
 1312             ],
 1313             'params': {
 1314                 'skip_download': True,
 1315             }
 1316         },
 1317         {
 1318             # Kaltura embedded, some fileExt broken (#11480)
 1319             'url': 'http://www.cornell.edu/video/nima-arkani-hamed-standard-models-of-particle-physics',
 1320             'info_dict': {
 1321                 'id': '1_sgtvehim',
 1322                 'ext': 'mp4',
 1323                 'title': 'Our "Standard Models" of particle physics and cosmology',
 1324                 'description': 'md5:67ea74807b8c4fea92a6f38d6d323861',
 1325                 'timestamp': 1321158993,
 1326                 'upload_date': '20111113',
 1327                 'uploader_id': 'kps1',
 1328             },
 1329             'add_ie': ['Kaltura'],
 1330         },
 1331         {
 1332             # Kaltura iframe embed
 1333             'url': 'http://www.gsd.harvard.edu/event/i-m-pei-a-centennial-celebration/',
 1334             'md5': 'ae5ace8eb09dc1a35d03b579a9c2cc44',
 1335             'info_dict': {
 1336                 'id': '0_f2cfbpwy',
 1337                 'ext': 'mp4',
 1338                 'title': 'I. M. Pei: A Centennial Celebration',
 1339                 'description': 'md5:1db8f40c69edc46ca180ba30c567f37c',
 1340                 'upload_date': '20170403',
 1341                 'uploader_id': 'batchUser',
 1342                 'timestamp': 1491232186,
 1343             },
 1344             'add_ie': ['Kaltura'],
 1345         },
 1346         {
 1347             # Kaltura iframe embed, more sophisticated
 1348             'url': 'http://www.cns.nyu.edu/~eero/math-tools/Videos/lecture-05sep2017.html',
 1349             'info_dict': {
 1350                 'id': '1_9gzouybz',
 1351                 'ext': 'mp4',
 1352                 'title': 'lecture-05sep2017',
 1353                 'description': 'md5:40f347d91fd4ba047e511c5321064b49',
 1354                 'upload_date': '20170913',
 1355                 'uploader_id': 'eps2',
 1356                 'timestamp': 1505340777,
 1357             },
 1358             'params': {
 1359                 'skip_download': True,
 1360             },
 1361             'add_ie': ['Kaltura'],
 1362         },
 1363         {
 1364             # meta twitter:player
 1365             'url': 'http://thechive.com/2017/12/08/all-i-want-for-christmas-is-more-twerk/',
 1366             'info_dict': {
 1367                 'id': '0_01b42zps',
 1368                 'ext': 'mp4',
 1369                 'title': 'Main Twerk (Video)',
 1370                 'upload_date': '20171208',
 1371                 'uploader_id': 'sebastian.salinas@thechive.com',
 1372                 'timestamp': 1512713057,
 1373             },
 1374             'params': {
 1375                 'skip_download': True,
 1376             },
 1377             'add_ie': ['Kaltura'],
 1378         },
 1379         # referrer protected EaglePlatform embed
 1380         {
 1381             'url': 'https://tvrain.ru/lite/teleshow/kak_vse_nachinalos/namin-418921/',
 1382             'info_dict': {
 1383                 'id': '582306',
 1384                 'ext': 'mp4',
 1385                 'title': 'Стас Намин: «Мы нарушили девственность Кремля»',
 1386                 'thumbnail': r're:^https?://.*\.jpg$',
 1387                 'duration': 3382,
 1388                 'view_count': int,
 1389             },
 1390             'params': {
 1391                 'skip_download': True,
 1392             },
 1393         },
 1394         # ClipYou (EaglePlatform) embed (custom URL)
 1395         {
 1396             'url': 'http://muz-tv.ru/play/7129/',
 1397             # Not checking MD5 as sometimes the direct HTTP link results in 404 and HLS is used
 1398             'info_dict': {
 1399                 'id': '12820',
 1400                 'ext': 'mp4',
 1401                 'title': "'O Sole Mio",
 1402                 'thumbnail': r're:^https?://.*\.jpg$',
 1403                 'duration': 216,
 1404                 'view_count': int,
 1405             },
 1406             'params': {
 1407                 'skip_download': True,
 1408             },
 1409             'skip': 'This video is unavailable.',
 1410         },
 1411         # Pladform embed
 1412         {
 1413             'url': 'http://muz-tv.ru/kinozal/view/7400/',
 1414             'info_dict': {
 1415                 'id': '100183293',
 1416                 'ext': 'mp4',
 1417                 'title': 'Тайны перевала Дятлова • 1 серия 2 часть',
 1418                 'description': 'Документальный сериал-расследование одной из самых жутких тайн ХХ века',
 1419                 'thumbnail': r're:^https?://.*\.jpg$',
 1420                 'duration': 694,
 1421                 'age_limit': 0,
 1422             },
 1423             'skip': 'HTTP Error 404: Not Found',
 1424         },
 1425         # Playwire embed
 1426         {
 1427             'url': 'http://www.cinemablend.com/new/First-Joe-Dirt-2-Trailer-Teaser-Stupid-Greatness-70874.html',
 1428             'info_dict': {
 1429                 'id': '3519514',
 1430                 'ext': 'mp4',
 1431                 'title': 'Joe Dirt 2 Beautiful Loser Teaser Trailer',
 1432                 'thumbnail': r're:^https?://.*\.png$',
 1433                 'duration': 45.115,
 1434             },
 1435         },
 1436         # 5min embed
 1437         {
 1438             'url': 'http://techcrunch.com/video/facebook-creates-on-this-day-crunch-report/518726732/',
 1439             'md5': '4c6f127a30736b59b3e2c19234ee2bf7',
 1440             'info_dict': {
 1441                 'id': '518726732',
 1442                 'ext': 'mp4',
 1443                 'title': 'Facebook Creates "On This Day" | Crunch Report',
 1444                 'description': 'Amazon updates Fire TV line, Tesla\'s Model X spotted in the wild',
 1445                 'timestamp': 1427237531,
 1446                 'uploader': 'Crunch Report',
 1447                 'upload_date': '20150324',
 1448             },
 1449             'params': {
 1450                 # m3u8 download
 1451                 'skip_download': True,
 1452             },
 1453         },
 1454         # Crooks and Liars embed
 1455         {
 1456             'url': 'http://crooksandliars.com/2015/04/fox-friends-says-protecting-atheists',
 1457             'info_dict': {
 1458                 'id': '8RUoRhRi',
 1459                 'ext': 'mp4',
 1460                 'title': "Fox & Friends Says Protecting Atheists From Discrimination Is Anti-Christian!",
 1461                 'description': 'md5:e1a46ad1650e3a5ec7196d432799127f',
 1462                 'timestamp': 1428207000,
 1463                 'upload_date': '20150405',
 1464                 'uploader': 'Heather',
 1465             },
 1466         },
 1467         # Crooks and Liars external embed
 1468         {
 1469             'url': 'http://theothermccain.com/2010/02/02/video-proves-that-bill-kristol-has-been-watching-glenn-beck/comment-page-1/',
 1470             'info_dict': {
 1471                 'id': 'MTE3MjUtMzQ2MzA',
 1472                 'ext': 'mp4',
 1473                 'title': 'md5:5e3662a81a4014d24c250d76d41a08d5',
 1474                 'description': 'md5:9b8e9542d6c3c5de42d6451b7d780cec',
 1475                 'timestamp': 1265032391,
 1476                 'upload_date': '20100201',
 1477                 'uploader': 'Heather',
 1478             },
 1479         },
 1480         # NBC Sports vplayer embed
 1481         {
 1482             'url': 'http://www.riderfans.com/forum/showthread.php?121827-Freeman&s=e98fa1ea6dc08e886b1678d35212494a',
 1483             'info_dict': {
 1484                 'id': 'ln7x1qSThw4k',
 1485                 'ext': 'flv',
 1486                 'title': "PFT Live: New leader in the 'new-look' defense",
 1487                 'description': 'md5:65a19b4bbfb3b0c0c5768bed1dfad74e',
 1488                 'uploader': 'NBCU-SPORTS',
 1489                 'upload_date': '20140107',
 1490                 'timestamp': 1389118457,
 1491             },
 1492             'skip': 'Invalid Page URL',
 1493         },
 1494         # NBC News embed
 1495         {
 1496             'url': 'http://www.vulture.com/2016/06/letterman-couldnt-care-less-about-late-night.html',
 1497             'md5': '1aa589c675898ae6d37a17913cf68d66',
 1498             'info_dict': {
 1499                 'id': 'x_dtl_oa_LettermanliftPR_160608',
 1500                 'ext': 'mp4',
 1501                 'title': 'David Letterman: A Preview',
 1502                 'description': 'A preview of Tom Brokaw\'s interview with David Letterman as part of the On Assignment series powered by Dateline. Airs Sunday June 12 at 7/6c.',
 1503                 'upload_date': '20160609',
 1504                 'timestamp': 1465431544,
 1505                 'uploader': 'NBCU-NEWS',
 1506             },
 1507         },
 1508         # UDN embed
 1509         {
 1510             'url': 'https://video.udn.com/news/300346',
 1511             'md5': 'fd2060e988c326991037b9aff9df21a6',
 1512             'info_dict': {
 1513                 'id': '300346',
 1514                 'ext': 'mp4',
 1515                 'title': '中一中男師變性 全校師生力挺',
 1516                 'thumbnail': r're:^https?://.*\.jpg$',
 1517             },
 1518             'params': {
 1519                 # m3u8 download
 1520                 'skip_download': True,
 1521             },
 1522             'expected_warnings': ['Failed to parse JSON Expecting value'],
 1523         },
 1524         # Brightcove URL in single quotes
 1525         {
 1526             'url': 'http://www.sportsnet.ca/baseball/mlb/sn-presents-russell-martin-world-citizen/',
 1527             'md5': '4ae374f1f8b91c889c4b9203c8c752af',
 1528             'info_dict': {
 1529                 'id': '4255764656001',
 1530                 'ext': 'mp4',
 1531                 'title': 'SN Presents: Russell Martin, World Citizen',
 1532                 'description': 'To understand why he was the Toronto Blue Jays’ top off-season priority is to appreciate his background and upbringing in Montreal, where he first developed his baseball skills. Written and narrated by Stephen Brunt.',
 1533                 'uploader': 'Rogers Sportsnet',
 1534                 'uploader_id': '1704050871',
 1535                 'upload_date': '20150525',
 1536                 'timestamp': 1432570283,
 1537             },
 1538         },
 1539         # Kinja embed
 1540         {
 1541             'url': 'http://www.clickhole.com/video/dont-understand-bitcoin-man-will-mumble-explanatio-2537',
 1542             'info_dict': {
 1543                 'id': '106351',
 1544                 'ext': 'mp4',
 1545                 'title': 'Don’t Understand Bitcoin? This Man Will Mumble An Explanation At You',
 1546                 'description': 'Migrated from OnionStudios',
 1547                 'thumbnail': r're:^https?://.*\.jpe?g$',
 1548                 'uploader': 'clickhole',
 1549                 'upload_date': '20150527',
 1550                 'timestamp': 1432744860,
 1551             }
 1552         },
 1553         # SnagFilms embed
 1554         {
 1555             'url': 'http://whilewewatch.blogspot.ru/2012/06/whilewewatch-whilewewatch-gripping.html',
 1556             'info_dict': {
 1557                 'id': '74849a00-85a9-11e1-9660-123139220831',
 1558                 'ext': 'mp4',
 1559                 'title': '#whilewewatch',
 1560             }
 1561         },
 1562         # AdobeTVVideo embed
 1563         {
 1564             'url': 'https://helpx.adobe.com/acrobat/how-to/new-experience-acrobat-dc.html?set=acrobat--get-started--essential-beginners',
 1565             'md5': '43662b577c018ad707a63766462b1e87',
 1566             'info_dict': {
 1567                 'id': '2456',
 1568                 'ext': 'mp4',
 1569                 'title': 'New experience with Acrobat DC',
 1570                 'description': 'New experience with Acrobat DC',
 1571                 'duration': 248.667,
 1572             },
 1573         },
 1574         # BrightcoveInPageEmbed embed
 1575         {
 1576             'url': 'http://www.geekandsundry.com/tabletop-bonus-wils-final-thoughts-on-dread/',
 1577             'info_dict': {
 1578                 'id': '4238694884001',
 1579                 'ext': 'flv',
 1580                 'title': 'Tabletop: Dread, Last Thoughts',
 1581                 'description': 'Tabletop: Dread, Last Thoughts',
 1582                 'duration': 51690,
 1583             },
 1584         },
 1585         # Brightcove embed, with no valid 'renditions' but valid 'IOSRenditions'
 1586         # This video can't be played in browsers if Flash disabled and UA set to iPhone, which is actually a false alarm
 1587         {
 1588             'url': 'https://dl.dropboxusercontent.com/u/29092637/interview.html',
 1589             'info_dict': {
 1590                 'id': '4785848093001',
 1591                 'ext': 'mp4',
 1592                 'title': 'The Cardinal Pell Interview',
 1593                 'description': 'Sky News Contributor Andrew Bolt interviews George Pell in Rome, following the Cardinal\'s evidence before the Royal Commission into Child Abuse. ',
 1594                 'uploader': 'GlobeCast Australia - GlobeStream',
 1595                 'uploader_id': '2733773828001',
 1596                 'upload_date': '20160304',
 1597                 'timestamp': 1457083087,
 1598             },
 1599             'params': {
 1600                 # m3u8 downloads
 1601                 'skip_download': True,
 1602             },
 1603         },
 1604         {
 1605             # Brightcove embed with whitespace around attribute names
 1606             'url': 'http://www.stack.com/video/3167554373001/learn-to-hit-open-three-pointers-with-damian-lillard-s-baseline-drift-drill',
 1607             'info_dict': {
 1608                 'id': '3167554373001',
 1609                 'ext': 'mp4',
 1610                 'title': "Learn to Hit Open Three-Pointers With Damian Lillard's Baseline Drift Drill",
 1611                 'description': 'md5:57bacb0e0f29349de4972bfda3191713',
 1612                 'uploader_id': '1079349493',
 1613                 'upload_date': '20140207',
 1614                 'timestamp': 1391810548,
 1615             },
 1616             'params': {
 1617                 'skip_download': True,
 1618             },
 1619         },
 1620         # Another form of arte.tv embed
 1621         {
 1622             'url': 'http://www.tv-replay.fr/redirection/09-04-16/arte-reportage-arte-11508975.html',
 1623             'md5': '850bfe45417ddf221288c88a0cffe2e2',
 1624             'info_dict': {
 1625                 'id': '030273-562_PLUS7-F',
 1626                 'ext': 'mp4',
 1627                 'title': 'ARTE Reportage - Nulle part, en France',
 1628                 'description': 'md5:e3a0e8868ed7303ed509b9e3af2b870d',
 1629                 'upload_date': '20160409',
 1630             },
 1631         },
 1632         # Duplicated embedded video URLs
 1633         {
 1634             'url': 'http://www.hudl.com/athlete/2538180/highlights/149298443',
 1635             'info_dict': {
 1636                 'id': '149298443_480_16c25b74_2',
 1637                 'ext': 'mp4',
 1638                 'title': 'vs. Blue Orange Spring Game',
 1639                 'uploader': 'www.hudl.com',
 1640             },
 1641         },
 1642         # twitter:player:stream embed
 1643         {
 1644             'url': 'http://www.rtl.be/info/video/589263.aspx?CategoryID=288',
 1645             'info_dict': {
 1646                 'id': 'master',
 1647                 'ext': 'mp4',
 1648                 'title': 'Une nouvelle espèce de dinosaure découverte en Argentine',
 1649                 'uploader': 'www.rtl.be',
 1650             },
 1651             'params': {
 1652                 # m3u8 downloads
 1653                 'skip_download': True,
 1654             },
 1655         },
 1656         # twitter:player embed
 1657         {
 1658             'url': 'http://www.theatlantic.com/video/index/484130/what-do-black-holes-sound-like/',
 1659             'md5': 'a3e0df96369831de324f0778e126653c',
 1660             'info_dict': {
 1661                 'id': '4909620399001',
 1662                 'ext': 'mp4',
 1663                 'title': 'What Do Black Holes Sound Like?',
 1664                 'description': 'what do black holes sound like',
 1665                 'upload_date': '20160524',
 1666                 'uploader_id': '29913724001',
 1667                 'timestamp': 1464107587,
 1668                 'uploader': 'TheAtlantic',
 1669             },
 1670             'add_ie': ['BrightcoveLegacy'],
 1671         },
 1672         # Facebook <iframe> embed
 1673         {
 1674             'url': 'https://www.hostblogger.de/blog/archives/6181-Auto-jagt-Betonmischer.html',
 1675             'md5': 'fbcde74f534176ecb015849146dd3aee',
 1676             'info_dict': {
 1677                 'id': '599637780109885',
 1678                 'ext': 'mp4',
 1679                 'title': 'Facebook video #599637780109885',
 1680             },
 1681         },
 1682         # Facebook <iframe> embed, plugin video
 1683         {
 1684             'url': 'http://5pillarsuk.com/2017/06/07/tariq-ramadan-disagrees-with-pr-exercise-by-imams-refusing-funeral-prayers-for-london-attackers/',
 1685             'info_dict': {
 1686                 'id': '1754168231264132',
 1687                 'ext': 'mp4',
 1688                 'title': 'About the Imams and Religious leaders refusing to perform funeral prayers for...',
 1689                 'uploader': 'Tariq Ramadan (official)',
 1690                 'timestamp': 1496758379,
 1691                 'upload_date': '20170606',
 1692             },
 1693             'params': {
 1694                 'skip_download': True,
 1695             },
 1696         },
 1697         # Facebook API embed
 1698         {
 1699             'url': 'http://www.lothype.com/blue-stars-2016-preview-standstill-full-show/',
 1700             'md5': 'a47372ee61b39a7b90287094d447d94e',
 1701             'info_dict': {
 1702                 'id': '10153467542406923',
 1703                 'ext': 'mp4',
 1704                 'title': 'Facebook video #10153467542406923',
 1705             },
 1706         },
 1707         # Wordpress "YouTube Video Importer" plugin
 1708         {
 1709             'url': 'http://www.lothype.com/blue-devils-drumline-stanford-lot-2016/',
 1710             'md5': 'd16797741b560b485194eddda8121b48',
 1711             'info_dict': {
 1712                 'id': 'HNTXWDXV9Is',
 1713                 'ext': 'mp4',
 1714                 'title': 'Blue Devils Drumline Stanford lot 2016',
 1715                 'upload_date': '20160627',
 1716                 'uploader_id': 'GENOCIDE8GENERAL10',
 1717                 'uploader': 'cylus cyrus',
 1718             },
 1719         },
 1720         {
 1721             # video stored on custom kaltura server
 1722             'url': 'http://www.expansion.com/multimedia/videos.html?media=EQcM30NHIPv',
 1723             'md5': '537617d06e64dfed891fa1593c4b30cc',
 1724             'info_dict': {
 1725                 'id': '0_1iotm5bh',
 1726                 'ext': 'mp4',
 1727                 'title': 'Elecciones británicas: 5 lecciones para Rajoy',
 1728                 'description': 'md5:435a89d68b9760b92ce67ed227055f16',
 1729                 'uploader_id': 'videos.expansion@el-mundo.net',
 1730                 'upload_date': '20150429',
 1731                 'timestamp': 1430303472,
 1732             },
 1733             'add_ie': ['Kaltura'],
 1734         },
 1735         {
 1736             # multiple kaltura embeds, nsfw
 1737             'url': 'https://www.quartier-rouge.be/prive/femmes/kamila-avec-video-jaime-sadomie.html',
 1738             'info_dict': {
 1739                 'id': 'kamila-avec-video-jaime-sadomie',
 1740                 'title': "Kamila avec vídeo “J'aime sadomie”",
 1741             },
 1742             'playlist_count': 8,
 1743         },
 1744         {
 1745             # Non-standard Vimeo embed
 1746             'url': 'https://openclassrooms.com/courses/understanding-the-web',
 1747             'md5': '64d86f1c7d369afd9a78b38cbb88d80a',
 1748             'info_dict': {
 1749                 'id': '148867247',
 1750                 'ext': 'mp4',
 1751                 'title': 'Understanding the web - Teaser',
 1752                 'description': 'This is "Understanding the web - Teaser" by openclassrooms on Vimeo, the home for high quality videos and the people who love them.',
 1753                 'upload_date': '20151214',
 1754                 'uploader': 'OpenClassrooms',
 1755                 'uploader_id': 'openclassrooms',
 1756             },
 1757             'add_ie': ['Vimeo'],
 1758         },
 1759         {
 1760             # generic vimeo embed that requires original URL passed as Referer
 1761             'url': 'http://racing4everyone.eu/2016/07/30/formula-1-2016-round12-germany/',
 1762             'only_matching': True,
 1763         },
 1764         {
 1765             'url': 'https://support.arkena.com/display/PLAY/Ways+to+embed+your+video',
 1766             'md5': 'b96f2f71b359a8ecd05ce4e1daa72365',
 1767             'info_dict': {
 1768                 'id': 'b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe',
 1769                 'ext': 'mp4',
 1770                 'title': 'Big Buck Bunny',
 1771                 'description': 'Royalty free test video',
 1772                 'timestamp': 1432816365,
 1773                 'upload_date': '20150528',
 1774                 'is_live': False,
 1775             },
 1776             'params': {
 1777                 'skip_download': True,
 1778             },
 1779             'add_ie': [ArkenaIE.ie_key()],
 1780         },
 1781         {
 1782             'url': 'http://nova.bg/news/view/2016/08/16/156543/%D0%BD%D0%B0-%D0%BA%D0%BE%D1%81%D1%8A%D0%BC-%D0%BE%D1%82-%D0%B2%D0%B7%D1%80%D0%B8%D0%B2-%D0%BE%D1%82%D1%86%D0%B5%D0%BF%D0%B8%D1%85%D0%B0-%D1%86%D1%8F%D0%BB-%D0%BA%D0%B2%D0%B0%D1%80%D1%82%D0%B0%D0%BB-%D0%B7%D0%B0%D1%80%D0%B0%D0%B4%D0%B8-%D0%B8%D0%B7%D1%82%D0%B8%D1%87%D0%B0%D0%BD%D0%B5-%D0%BD%D0%B0-%D0%B3%D0%B0%D0%B7-%D0%B2-%D0%BF%D0%BB%D0%BE%D0%B2%D0%B4%D0%B8%D0%B2/',
 1783             'info_dict': {
 1784                 'id': '1c7141f46c',
 1785                 'ext': 'mp4',
 1786                 'title': 'НА КОСЪМ ОТ ВЗРИВ: Изтичане на газ на бензиностанция в Пловдив',
 1787             },
 1788             'params': {
 1789                 'skip_download': True,
 1790             },
 1791             'add_ie': [Vbox7IE.ie_key()],
 1792         },
 1793         {
 1794             # DBTV embeds
 1795             'url': 'http://www.dagbladet.no/2016/02/23/nyheter/nordlys/ski/troms/ver/43254897/',
 1796             'info_dict': {
 1797                 'id': '43254897',
 1798                 'title': 'Etter ett års planlegging, klaffet endelig alt: - Jeg måtte ta en liten dans',
 1799             },
 1800             'playlist_mincount': 3,
 1801         },
 1802         {
 1803             # Videa embeds
 1804             'url': 'http://forum.dvdtalk.com/movie-talk/623756-deleted-magic-star-wars-ot-deleted-alt-scenes-docu-style.html',
 1805             'info_dict': {
 1806                 'id': '623756-deleted-magic-star-wars-ot-deleted-alt-scenes-docu-style',
 1807                 'title': 'Deleted Magic - Star Wars: OT Deleted / Alt. Scenes Docu. Style - DVD Talk Forum',
 1808             },
 1809             'playlist_mincount': 2,
 1810         },
 1811         {
 1812             # 20 minuten embed
 1813             'url': 'http://www.20min.ch/schweiz/news/story/So-kommen-Sie-bei-Eis-und-Schnee-sicher-an-27032552',
 1814             'info_dict': {
 1815                 'id': '523629',
 1816                 'ext': 'mp4',
 1817                 'title': 'So kommen Sie bei Eis und Schnee sicher an',
 1818                 'description': 'md5:117c212f64b25e3d95747e5276863f7d',
 1819             },
 1820             'params': {
 1821                 'skip_download': True,
 1822             },
 1823             'add_ie': [TwentyMinutenIE.ie_key()],
 1824         },
 1825         {
 1826             # VideoPress embed
 1827             'url': 'https://en.support.wordpress.com/videopress/',
 1828             'info_dict': {
 1829                 'id': 'OcobLTqC',
 1830                 'ext': 'm4v',
 1831                 'title': 'IMG_5786',
 1832                 'timestamp': 1435711927,
 1833                 'upload_date': '20150701',
 1834             },
 1835             'params': {
 1836                 'skip_download': True,
 1837             },
 1838             'add_ie': [VideoPressIE.ie_key()],
 1839         },
 1840         {
 1841             # Rutube embed
 1842             'url': 'http://magazzino.friday.ru/videos/vipuski/kazan-2',
 1843             'info_dict': {
 1844                 'id': '9b3d5bee0a8740bf70dfd29d3ea43541',
 1845                 'ext': 'flv',
 1846                 'title': 'Магаззино: Казань 2',
 1847                 'description': 'md5:99bccdfac2269f0e8fdbc4bbc9db184a',
 1848                 'uploader': 'Магаззино',
 1849                 'upload_date': '20170228',
 1850                 'uploader_id': '996642',
 1851             },
 1852             'params': {
 1853                 'skip_download': True,
 1854             },
 1855             'add_ie': [RutubeIE.ie_key()],
 1856         },
 1857         {
 1858             # ThePlatform embedded with whitespaces in URLs
 1859             'url': 'http://www.golfchannel.com/topics/shows/golftalkcentral.htm',
 1860             'only_matching': True,
 1861         },
 1862         {
 1863             # Senate ISVP iframe https
 1864             'url': 'https://www.hsgac.senate.gov/hearings/canadas-fast-track-refugee-plan-unanswered-questions-and-implications-for-us-national-security',
 1865             'md5': 'fb8c70b0b515e5037981a2492099aab8',
 1866             'info_dict': {
 1867                 'id': 'govtaff020316',
 1868                 'ext': 'mp4',
 1869                 'title': 'Integrated Senate Video Player',
 1870             },
 1871             'add_ie': [SenateISVPIE.ie_key()],
 1872         },
 1873         {
 1874             # Limelight embeds (1 channel embed + 4 media embeds)
 1875             'url': 'http://www.sedona.com/FacilitatorTraining2017',
 1876             'info_dict': {
 1877                 'id': 'FacilitatorTraining2017',
 1878                 'title': 'Facilitator Training 2017',
 1879             },
 1880             'playlist_mincount': 5,
 1881         },
 1882         {
 1883             # Limelight embed (LimelightPlayerUtil.embed)
 1884             'url': 'https://tv5.ca/videos?v=xuu8qowr291ri',
 1885             'info_dict': {
 1886                 'id': '95d035dc5c8a401588e9c0e6bd1e9c92',
 1887                 'ext': 'mp4',
 1888                 'title': '07448641',
 1889                 'timestamp': 1499890639,
 1890                 'upload_date': '20170712',
 1891             },
 1892             'params': {
 1893                 'skip_download': True,
 1894             },
 1895             'add_ie': ['LimelightMedia'],
 1896         },
 1897         {
 1898             'url': 'http://kron4.com/2017/04/28/standoff-with-walnut-creek-murder-suspect-ends-with-arrest/',
 1899             'info_dict': {
 1900                 'id': 'standoff-with-walnut-creek-murder-suspect-ends-with-arrest',
 1901                 'title': 'Standoff with Walnut Creek murder suspect ends',
 1902                 'description': 'md5:3ccc48a60fc9441eeccfc9c469ebf788',
 1903             },
 1904             'playlist_mincount': 4,
 1905         },
 1906         {
 1907             # WashingtonPost embed
 1908             'url': 'http://www.vanityfair.com/hollywood/2017/04/donald-trump-tv-pitches',
 1909             'info_dict': {
 1910                 'id': '8caf6e88-d0ec-11e5-90d3-34c2c42653ac',
 1911                 'ext': 'mp4',
 1912                 'title': "No one has seen the drama series based on Trump's life \u2014 until now",
 1913                 'description': 'Donald Trump wanted a weekly TV drama based on his life. It never aired. But The Washington Post recently obtained a scene from the pilot script — and enlisted actors.',
 1914                 'timestamp': 1455216756,
 1915                 'uploader': 'The Washington Post',
 1916                 'upload_date': '20160211',
 1917             },
 1918             'add_ie': [WashingtonPostIE.ie_key()],
 1919         },
 1920         {
 1921             # Mediaset embed
 1922             'url': 'http://www.tgcom24.mediaset.it/politica/serracchiani-voglio-vivere-in-una-societa-aperta-reazioni-sproporzionate-_3071354-201702a.shtml',
 1923             'info_dict': {
 1924                 'id': '720642',
 1925                 'ext': 'mp4',
 1926                 'title': 'Serracchiani: "Voglio vivere in una società aperta, con tutela del patto di fiducia"',
 1927             },
 1928             'params': {
 1929                 'skip_download': True,
 1930             },
 1931             'add_ie': [MediasetIE.ie_key()],
 1932         },
 1933         {
 1934             # JOJ.sk embeds
 1935             'url': 'https://www.noviny.sk/slovensko/238543-slovenskom-sa-prehnala-vlna-silnych-burok',
 1936             'info_dict': {
 1937                 'id': '238543-slovenskom-sa-prehnala-vlna-silnych-burok',
 1938                 'title': 'Slovenskom sa prehnala vlna silných búrok',
 1939             },
 1940             'playlist_mincount': 5,
 1941             'add_ie': [JojIE.ie_key()],
 1942         },
 1943         {
 1944             # AMP embed (see https://www.ampproject.org/docs/reference/components/amp-video)
 1945             'url': 'https://tvrain.ru/amp/418921/',
 1946             'md5': 'cc00413936695987e8de148b67d14f1d',
 1947             'info_dict': {
 1948                 'id': '418921',
 1949                 'ext': 'mp4',
 1950                 'title': 'Стас Намин: «Мы нарушили девственность Кремля»',
 1951             },
 1952         },
 1953         {
 1954             # vzaar embed
 1955             'url': 'http://help.vzaar.com/article/165-embedding-video',
 1956             'md5': '7e3919d9d2620b89e3e00bec7fe8c9d4',
 1957             'info_dict': {
 1958                 'id': '8707641',
 1959                 'ext': 'mp4',
 1960                 'title': 'Building A Business Online: Principal Chairs Q & A',
 1961             },
 1962         },
 1963         {
 1964             # multiple HTML5 videos on one page
 1965             'url': 'https://www.paragon-software.com/home/rk-free/keyscenarios.html',
 1966             'info_dict': {
 1967                 'id': 'keyscenarios',
 1968                 'title': 'Rescue Kit 14 Free Edition - Getting started',
 1969             },
 1970             'playlist_count': 4,
 1971         },
 1972         {
 1973             # vshare embed
 1974             'url': 'https://youtube-dl-demo.neocities.org/vshare.html',
 1975             'md5': '17b39f55b5497ae8b59f5fbce8e35886',
 1976             'info_dict': {
 1977                 'id': '0f64ce6',
 1978                 'title': 'vl14062007715967',
 1979                 'ext': 'mp4',
 1980             }
 1981         },
 1982         {
 1983             'url': 'http://www.heidelberg-laureate-forum.org/blog/video/lecture-friday-september-23-2016-sir-c-antony-r-hoare/',
 1984             'md5': 'aecd089f55b1cb5a59032cb049d3a356',
 1985             'info_dict': {
 1986                 'id': '90227f51a80c4d8f86c345a7fa62bd9a1d',
 1987                 'ext': 'mp4',
 1988                 'title': 'Lecture: Friday, September 23, 2016 - Sir Tony Hoare',
 1989                 'description': 'md5:5a51db84a62def7b7054df2ade403c6c',
 1990                 'timestamp': 1474354800,
 1991                 'upload_date': '20160920',
 1992             }
 1993         },
 1994         {
 1995             'url': 'http://www.kidzworld.com/article/30935-trolls-the-beat-goes-on-interview-skylar-astin-and-amanda-leighton',
 1996             'info_dict': {
 1997                 'id': '1731611',
 1998                 'ext': 'mp4',
 1999                 'title': 'Official Trailer | TROLLS: THE BEAT GOES ON!',
 2000                 'description': 'md5:eb5f23826a027ba95277d105f248b825',
 2001                 'timestamp': 1516100691,
 2002                 'upload_date': '20180116',
 2003             },
 2004             'params': {
 2005                 'skip_download': True,
 2006             },
 2007             'add_ie': [SpringboardPlatformIE.ie_key()],
 2008         },
 2009         {
 2010             'url': 'https://www.yapfiles.ru/show/1872528/690b05d3054d2dbe1e69523aa21bb3b1.mp4.html',
 2011             'info_dict': {
 2012                 'id': 'vMDE4NzI1Mjgt690b',
 2013                 'ext': 'mp4',
 2014                 'title': 'Котята',
 2015             },
 2016             'add_ie': [YapFilesIE.ie_key()],
 2017             'params': {
 2018                 'skip_download': True,
 2019             },
 2020         },
 2021         {
 2022             # CloudflareStream embed
 2023             'url': 'https://www.cloudflare.com/products/cloudflare-stream/',
 2024             'info_dict': {
 2025                 'id': '31c9291ab41fac05471db4e73aa11717',
 2026                 'ext': 'mp4',
 2027                 'title': '31c9291ab41fac05471db4e73aa11717',
 2028             },
 2029             'add_ie': [CloudflareStreamIE.ie_key()],
 2030             'params': {
 2031                 'skip_download': True,
 2032             },
 2033         },
 2034         {
 2035             # PeerTube embed
 2036             'url': 'https://joinpeertube.org/fr/home/',
 2037             'info_dict': {
 2038                 'id': 'home',
 2039                 'title': 'Reprenez le contrôle de vos vidéos ! #JoinPeertube',
 2040             },
 2041             'playlist_count': 2,
 2042         },
 2043         {
 2044             # Indavideo embed
 2045             'url': 'https://streetkitchen.hu/receptek/igy_kell_otthon_hamburgert_sutni/',
 2046             'info_dict': {
 2047                 'id': '1693903',
 2048                 'ext': 'mp4',
 2049                 'title': 'Így kell otthon hamburgert sütni',
 2050                 'description': 'md5:f5a730ecf900a5c852e1e00540bbb0f7',
 2051                 'timestamp': 1426330212,
 2052                 'upload_date': '20150314',
 2053                 'uploader': 'StreetKitchen',
 2054                 'uploader_id': '546363',
 2055             },
 2056             'add_ie': [IndavideoEmbedIE.ie_key()],
 2057             'params': {
 2058                 'skip_download': True,
 2059             },
 2060         },
 2061         {
 2062             # APA embed via JWPlatform embed
 2063             'url': 'http://www.vol.at/blue-man-group/5593454',
 2064             'info_dict': {
 2065                 'id': 'jjv85FdZ',
 2066                 'ext': 'mp4',
 2067                 'title': '"Blau ist mysteriös": Die Blue Man Group im Interview',
 2068                 'description': 'md5:d41d8cd98f00b204e9800998ecf8427e',
 2069                 'thumbnail': r're:^https?://.*\.jpg$',
 2070                 'duration': 254,
 2071                 'timestamp': 1519211149,
 2072                 'upload_date': '20180221',
 2073             },
 2074             'params': {
 2075                 'skip_download': True,
 2076             },
 2077         },
 2078         {
 2079             'url': 'http://share-videos.se/auto/video/83645793?uid=13',
 2080             'md5': 'b68d276de422ab07ee1d49388103f457',
 2081             'info_dict': {
 2082                 'id': '83645793',
 2083                 'title': 'Lock up and get excited',
 2084                 'ext': 'mp4'
 2085             },
 2086             'skip': 'TODO: fix nested playlists processing in tests',
 2087         },
 2088         {
 2089             # Viqeo embeds
 2090             'url': 'https://viqeo.tv/',
 2091             'info_dict': {
 2092                 'id': 'viqeo',
 2093                 'title': 'All-new video platform',
 2094             },
 2095             'playlist_count': 6,
 2096         },
 2097         {
 2098             # Squarespace video embed, 2019-08-28
 2099             'url': 'http://ootboxford.com',
 2100             'info_dict': {
 2101                 'id': 'Tc7b_JGdZfw',
 2102                 'title': 'Out of the Blue, at Childish Things 10',
 2103                 'ext': 'mp4',
 2104                 'description': 'md5:a83d0026666cf5ee970f8bd1cfd69c7f',
 2105                 'uploader_id': 'helendouglashouse',
 2106                 'uploader': 'Helen & Douglas House',
 2107                 'upload_date': '20140328',
 2108             },
 2109             'params': {
 2110                 'skip_download': True,
 2111             },
 2112         },
 2113         # {
 2114         #     # Zype embed
 2115         #     'url': 'https://www.cookscountry.com/episode/554-smoky-barbecue-favorites',
 2116         #     'info_dict': {
 2117         #         'id': '5b400b834b32992a310622b9',
 2118         #         'ext': 'mp4',
 2119         #         'title': 'Smoky Barbecue Favorites',
 2120         #         'thumbnail': r're:^https?://.*\.jpe?g',
 2121         #         'description': 'md5:5ff01e76316bd8d46508af26dc86023b',
 2122         #         'upload_date': '20170909',
 2123         #         'timestamp': 1504915200,
 2124         #     },
 2125         #     'add_ie': [ZypeIE.ie_key()],
 2126         #     'params': {
 2127         #         'skip_download': True,
 2128         #     },
 2129         # },
 2130         {
 2131             # videojs embed
 2132             'url': 'https://video.sibnet.ru/shell.php?videoid=3422904',
 2133             'info_dict': {
 2134                 'id': 'shell',
 2135                 'ext': 'mp4',
 2136                 'title': 'Доставщик пиццы спросил разрешения сыграть на фортепиано',
 2137                 'description': 'md5:89209cdc587dab1e4a090453dbaa2cb1',
 2138                 'thumbnail': r're:^https?://.*\.jpg$',
 2139             },
 2140             'params': {
 2141                 'skip_download': True,
 2142             },
 2143             'expected_warnings': ['Failed to download MPD manifest'],
 2144         },
 2145         {
 2146             # DailyMotion embed with DM.player
 2147             'url': 'https://www.beinsports.com/us/copa-del-rey/video/the-locker-room-valencia-beat-barca-in-copa/1203804',
 2148             'info_dict': {
 2149                 'id': 'k6aKkGHd9FJs4mtJN39',
 2150                 'ext': 'mp4',
 2151                 'title': 'The Locker Room: Valencia Beat Barca In Copa del Rey Final',
 2152                 'description': 'This video is private.',
 2153                 'uploader_id': 'x1jf30l',
 2154                 'uploader': 'beIN SPORTS USA',
 2155                 'upload_date': '20190528',
 2156                 'timestamp': 1559062971,
 2157             },
 2158             'params': {
 2159                 'skip_download': True,
 2160             },
 2161         },
 2162         # {
 2163         #     # TODO: find another test
 2164         #     # http://schema.org/VideoObject
 2165         #     'url': 'https://flipagram.com/f/nyvTSJMKId',
 2166         #     'md5': '888dcf08b7ea671381f00fab74692755',
 2167         #     'info_dict': {
 2168         #         'id': 'nyvTSJMKId',
 2169         #         'ext': 'mp4',
 2170         #         'title': 'Flipagram by sjuria101 featuring Midnight Memories by One Direction',
 2171         #         'description': '#love for cats.',
 2172         #         'timestamp': 1461244995,
 2173         #         'upload_date': '20160421',
 2174         #     },
 2175         #     'params': {
 2176         #         'force_generic_extractor': True,
 2177         #     },
 2178         # },
 2179         {
 2180             # VHX Embed
 2181             'url': 'https://demo.vhx.tv/category-c/videos/file-example-mp4-480-1-5mg-copy',
 2182             'info_dict': {
 2183                 'id': '858208',
 2184                 'ext': 'mp4',
 2185                 'title': 'Untitled',
 2186                 'uploader_id': 'user80538407',
 2187                 'uploader': 'OTT Videos',
 2188             },
 2189         },
 2190         {
 2191             # ArcPublishing PoWa video player
 2192             'url': 'https://www.adn.com/politics/2020/11/02/video-senate-candidates-campaign-in-anchorage-on-eve-of-election-day/',
 2193             'md5': 'b03b2fac8680e1e5a7cc81a5c27e71b3',
 2194             'info_dict': {
 2195                 'id': '8c99cb6e-b29c-4bc9-9173-7bf9979225ab',
 2196                 'ext': 'mp4',
 2197                 'title': 'Senate candidates wave to voters on Anchorage streets',
 2198                 'description': 'md5:91f51a6511f090617353dc720318b20e',
 2199                 'timestamp': 1604378735,
 2200                 'upload_date': '20201103',
 2201                 'duration': 1581,
 2202             },
 2203         },
 2204         {
 2205             # MyChannels SDK embed
 2206             # https://www.24kitchen.nl/populair/deskundige-dit-waarom-sommigen-gevoelig-zijn-voor-voedselallergieen
 2207             'url': 'https://www.demorgen.be/nieuws/burgemeester-rotterdam-richt-zich-in-videoboodschap-tot-relschoppers-voelt-het-goed~b0bcfd741/',
 2208             'md5': '90c0699c37006ef18e198c032d81739c',
 2209             'info_dict': {
 2210                 'id': '194165',
 2211                 'ext': 'mp4',
 2212                 'title': 'Burgemeester Aboutaleb spreekt relschoppers toe',
 2213                 'timestamp': 1611740340,
 2214                 'upload_date': '20210127',
 2215                 'duration': 159,
 2216             },
 2217         },
 2218         {
 2219             # Simplecast player embed
 2220             'url': 'https://www.bio.org/podcast',
 2221             'info_dict': {
 2222                 'id': 'podcast',
 2223                 'title': 'I AM BIO Podcast | BIO',
 2224             },
 2225             'playlist_mincount': 52,
 2226         },
 2227         {
 2228             # Sibnet embed (https://help.sibnet.ru/?sibnet_video_embed)
 2229             'url': 'https://phpbb3.x-tk.ru/bbcode-video-sibnet-t24.html',
 2230             'only_matching': True,
 2231         }, {
 2232             # KVS Player
 2233             'url': 'https://www.kvs-demo.com/videos/105/kelis-4th-of-july/',
 2234             'info_dict': {
 2235                 'id': '105',
 2236                 'display_id': 'kelis-4th-of-july',
 2237                 'ext': 'mp4',
 2238                 'title': 'Kelis - 4th Of July',
 2239                 'thumbnail': r're:https://(?:www\.)?kvs-demo.com/contents/videos_screenshots/0/105/preview.jpg',
 2240             },
 2241         }, {
 2242             # KVS Player
 2243             'url': 'https://www.kvs-demo.com/embed/105/',
 2244             'info_dict': {
 2245                 'id': '105',
 2246                 'display_id': 'kelis-4th-of-july',
 2247                 'ext': 'mp4',
 2248                 'title': 'Kelis - 4th Of July / Embed Player',
 2249                 'thumbnail': r're:https://(?:www\.)?kvs-demo.com/contents/videos_screenshots/0/105/preview.jpg',
 2250             },
 2251             'params': {
 2252                 'skip_download': True,
 2253             },
 2254         }, {
 2255             # KVS Player (tested also in thisvid.py)
 2256             'url': 'https://youix.com/video/leningrad-zoj/',
 2257             'md5': '94f96ba95706dc3880812b27b7d8a2b8',
 2258             'info_dict': {
 2259                 'id': '18485',
 2260                 'display_id': 'leningrad-zoj',
 2261                 'ext': 'mp4',
 2262                 'title': 'Клип: Ленинград - ЗОЖ скачать, смотреть онлайн | Youix.com',
 2263                 'thumbnail': r're:https://youix.com/contents/videos_screenshots/18000/18485/preview(?:_480x320_youix_com.mp4)?\.jpg',
 2264             },
 2265         }, {
 2266             # KVS Player
 2267             'url': 'https://youix.com/embed/18485',
 2268             'md5': '94f96ba95706dc3880812b27b7d8a2b8',
 2269             'info_dict': {
 2270                 'id': '18485',
 2271                 'display_id': 'leningrad-zoj',
 2272                 'ext': 'mp4',
 2273                 'title': 'Ленинград - ЗОЖ',
 2274                 'thumbnail': r're:https://youix.com/contents/videos_screenshots/18000/18485/preview(?:_480x320_youix_com.mp4)?\.jpg',
 2275             },
 2276         }, {
 2277             # KVS Player
 2278             'url': 'https://bogmedia.org/videos/21217/40-nochey-40-nights-2016/',
 2279             'md5': '94166bdb26b4cb1fb9214319a629fc51',
 2280             'info_dict': {
 2281                 'id': '21217',
 2282                 'display_id': '40-nochey-2016',
 2283                 'ext': 'mp4',
 2284                 'title': '40 ночей (2016) - BogMedia.org',
 2285                 'description': 'md5:4e6d7d622636eb7948275432eb256dc3',
 2286                 'thumbnail': 'https://bogmedia.org/contents/videos_screenshots/21000/21217/preview_480p.mp4.jpg',
 2287             },
 2288         }, {
 2289             # KVS Player (for sites that serve kt_player.js via non-https urls)
 2290             'url': 'http://www.camhub.world/embed/389508',
 2291             'md5': 'fbe89af4cfb59c8fd9f34a202bb03e32',
 2292             'info_dict': {
 2293                 'id': '389508',
 2294                 'display_id': 'syren-de-mer-onlyfans-05-07-2020have-a-happy-safe-holiday5f014e68a220979bdb8cd-source',
 2295                 'ext': 'mp4',
 2296                 'title': 'Syren De Mer  onlyfans_05-07-2020Have_a_happy_safe_holiday5f014e68a220979bdb8cd_source / Embed плеер',
 2297                 'thumbnail': r're:https?://www\.camhub\.world/contents/videos_screenshots/389000/389508/preview\.mp4\.jpg',
 2298             },
 2299         }, {
 2300             'url': 'https://mrdeepfakes.com/video/5/selena-gomez-pov-deep-fakes',
 2301             'md5': 'fec4ad5ec150f655e0c74c696a4a2ff4',
 2302             'info_dict': {
 2303                 'id': '5',
 2304                 'display_id': 'selena-gomez-pov-deep-fakes',
 2305                 'ext': 'mp4',
 2306                 'title': 'Selena Gomez POV (Deep Fakes) DeepFake Porn - MrDeepFakes',
 2307                 'description': 'md5:17d1f84b578c9c26875ac5ef9a932354',
 2308                 'height': 720,
 2309                 'age_limit': 18,
 2310             },
 2311         },
 2312     ]
 2313 
 2314     def report_following_redirect(self, new_url):
 2315         """Report information extraction."""
 2316         self._downloader.to_screen('[redirect] Following redirect to %s' % new_url)
 2317 
 2318     def _extract_rss(self, url, video_id, doc):
 2319         playlist_title = doc.find('./channel/title').text
 2320         playlist_desc_el = doc.find('./channel/description')
 2321         playlist_desc = None if playlist_desc_el is None else playlist_desc_el.text
 2322 
 2323         NS_MAP = {
 2324             'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd',
 2325         }
 2326 
 2327         entries = []
 2328         for it in doc.findall('./channel/item'):
 2329             next_url = None
 2330             enclosure_nodes = it.findall('./enclosure')
 2331             for e in enclosure_nodes:
 2332                 next_url = e.attrib.get('url')
 2333                 if next_url:
 2334                     break
 2335 
 2336             if not next_url:
 2337                 next_url = xpath_text(it, 'link', fatal=False)
 2338 
 2339             if not next_url:
 2340                 continue
 2341 
 2342             def itunes(key):
 2343                 return xpath_text(
 2344                     it, xpath_with_ns('./itunes:%s' % key, NS_MAP),
 2345                     default=None)
 2346 
 2347             duration = itunes('duration')
 2348             explicit = (itunes('explicit') or '').lower()
 2349             if explicit in ('true', 'yes'):
 2350                 age_limit = 18
 2351             elif explicit in ('false', 'no'):
 2352                 age_limit = 0
 2353             else:
 2354                 age_limit = None
 2355 
 2356             entries.append({
 2357                 '_type': 'url_transparent',
 2358                 'url': next_url,
 2359                 'title': it.find('title').text,
 2360                 'description': xpath_text(it, 'description', default=None),
 2361                 'timestamp': unified_timestamp(
 2362                     xpath_text(it, 'pubDate', default=None)),
 2363                 'duration': int_or_none(duration) or parse_duration(duration),
 2364                 'thumbnail': url_or_none(xpath_attr(it, xpath_with_ns('./itunes:image', NS_MAP), 'href')),
 2365                 'episode': itunes('title'),
 2366                 'episode_number': int_or_none(itunes('episode')),
 2367                 'season_number': int_or_none(itunes('season')),
 2368                 'age_limit': age_limit,
 2369             })
 2370 
 2371         return {
 2372             '_type': 'playlist',
 2373             'id': url,
 2374             'title': playlist_title,
 2375             'description': playlist_desc,
 2376             'entries': entries,
 2377         }
 2378 
 2379     def _extract_camtasia(self, url, video_id, webpage):
 2380         """ Returns None if no camtasia video can be found. """
 2381 
 2382         camtasia_cfg = self._search_regex(
 2383             r'fo\.addVariable\(\s*"csConfigFile",\s*"([^"]+)"\s*\);',
 2384             webpage, 'camtasia configuration file', default=None)
 2385         if camtasia_cfg is None:
 2386             return None
 2387 
 2388         title = self._html_search_meta('DC.title', webpage, fatal=True)
 2389 
 2390         camtasia_url = compat_urlparse.urljoin(url, camtasia_cfg)
 2391         camtasia_cfg = self._download_xml(
 2392             camtasia_url, video_id,
 2393             note='Downloading camtasia configuration',
 2394             errnote='Failed to download camtasia configuration')
 2395         fileset_node = camtasia_cfg.find('./playlist/array/fileset')
 2396 
 2397         entries = []
 2398         for n in fileset_node.getchildren():
 2399             url_n = n.find('./uri')
 2400             if url_n is None:
 2401                 continue
 2402 
 2403             entries.append({
 2404                 'id': os.path.splitext(url_n.text.rpartition('/')[2])[0],
 2405                 'title': '%s - %s' % (title, n.tag),
 2406                 'url': compat_urlparse.urljoin(url, url_n.text),
 2407                 'duration': float_or_none(n.find('./duration').text),
 2408             })
 2409 
 2410         return {
 2411             '_type': 'playlist',
 2412             'entries': entries,
 2413             'title': title,
 2414         }
 2415 
 2416     def _extract_kvs(self, url, webpage, video_id):
 2417 
 2418         def getlicensetoken(license):
 2419             modlicense = license.replace('$', '').replace('0', '1')
 2420             center = int(len(modlicense) / 2)
 2421             fronthalf = int(modlicense[:center + 1])
 2422             backhalf = int(modlicense[center:])
 2423 
 2424             modlicense = compat_str(4 * abs(fronthalf - backhalf))
 2425 
 2426             def parts():
 2427                 for o in range(0, center + 1):
 2428                     for i in range(1, 5):
 2429                         yield compat_str((int(license[o + i]) + int(modlicense[o])) % 10)
 2430 
 2431             return ''.join(parts())
 2432 
 2433         def getrealurl(video_url, license_code):
 2434             if not video_url.startswith('function/0/'):
 2435                 return video_url  # not obfuscated
 2436 
 2437             url_path, _, url_query = video_url.partition('?')
 2438             urlparts = url_path.split('/')[2:]
 2439             license = getlicensetoken(license_code)
 2440             newmagic = urlparts[5][:32]
 2441 
 2442             def spells(x, o):
 2443                 l = (o + sum(int(n) for n in license[o:])) % 32
 2444                 for i in range(0, len(x)):
 2445                     yield {l: x[o], o: x[l]}.get(i, x[i])
 2446 
 2447             for o in range(len(newmagic) - 1, -1, -1):
 2448                 newmagic = ''.join(spells(newmagic, o))
 2449 
 2450             urlparts[5] = newmagic + urlparts[5][32:]
 2451             return '/'.join(urlparts) + '?' + url_query
 2452 
 2453         flashvars = self._search_regex(
 2454             r'(?s)<script\b[^>]*>.*?var\s+flashvars\s*=\s*(\{.+?\});.*?</script>',
 2455             webpage, 'flashvars')
 2456         flashvars = self._parse_json(flashvars, video_id, transform_source=js_to_json)
 2457 
 2458         # extract the part after the last / as the display_id from the
 2459         # canonical URL.
 2460         display_id = self._search_regex(
 2461             r'(?:<link href="https?://[^"]+/(.+?)/?" rel="canonical"\s*/?>'
 2462             r'|<link rel="canonical" href="https?://[^"]+/(.+?)/?"\s*/?>)',
 2463             webpage, 'display_id', fatal=False
 2464         )
 2465         title = self._html_search_regex(r'<(?:h1|title)>(?:Video: )?(.+?)</(?:h1|title)>', webpage, 'title')
 2466 
 2467         thumbnail = flashvars['preview_url']
 2468         if thumbnail.startswith('//'):
 2469             protocol, _, _ = url.partition('/')
 2470             thumbnail = protocol + thumbnail
 2471 
 2472         url_keys = list(filter(re.compile(r'^video_(?:url|alt_url\d*)$').match, flashvars.keys()))
 2473         formats = []
 2474         for key in url_keys:
 2475             if '/get_file/' not in flashvars[key]:
 2476                 continue
 2477             format_id = flashvars.get(key + '_text', key)
 2478             formats.append(merge_dicts(
 2479                 parse_resolution(format_id) or parse_resolution(flashvars[key]), {
 2480                     'url': getrealurl(flashvars[key], flashvars['license_code']),
 2481                     'format_id': format_id,
 2482                     'ext': 'mp4',
 2483                     'http_headers': {'Referer': url},
 2484                 }))
 2485             if not formats[-1].get('height'):
 2486                 formats[-1]['quality'] = 1
 2487 
 2488         self._sort_formats(formats)
 2489 
 2490         return {
 2491             'id': flashvars['video_id'],
 2492             'display_id': display_id,
 2493             'title': title,
 2494             'thumbnail': thumbnail,
 2495             'formats': formats,
 2496         }
 2497 
 2498     def _real_extract(self, url):
 2499         if url.startswith('//'):
 2500             return self.url_result(self.http_scheme() + url)
 2501 
 2502         parsed_url = compat_urlparse.urlparse(url)
 2503         if not parsed_url.scheme:
 2504             default_search = self._downloader.params.get('default_search')
 2505             if default_search is None:
 2506                 default_search = 'fixup_error'
 2507 
 2508             if default_search in ('auto', 'auto_warning', 'fixup_error'):
 2509                 if re.match(r'^[^\s/]+\.[^\s/]+/', url):
 2510                     self._downloader.report_warning('The url doesn\'t specify the protocol, trying with http')
 2511                     return self.url_result('http://' + url)
 2512                 elif default_search != 'fixup_error':
 2513                     if default_search == 'auto_warning':
 2514                         if re.match(r'^(?:url|URL)$', url):
 2515                             raise ExtractorError(
 2516                                 'Invalid URL:  %r . Call youtube-dl like this:  youtube-dl -v "https://www.youtube.com/watch?v=BaW_jenozKc"  ' % url,
 2517                                 expected=True)
 2518                         else:
 2519                             self._downloader.report_warning(
 2520                                 'Falling back to youtube search for  %s . Set --default-search "auto" to suppress this warning.' % url)
 2521                     return self.url_result('ytsearch:' + url)
 2522 
 2523             if default_search in ('error', 'fixup_error'):
 2524                 raise ExtractorError(
 2525                     '%r is not a valid URL. '
 2526                     'Set --default-search "ytsearch" (or run  youtube-dl "ytsearch:%s" ) to search YouTube'
 2527                     % (url, url), expected=True)
 2528             else:
 2529                 if ':' not in default_search:
 2530                     default_search += ':'
 2531                 return self.url_result(default_search + url)
 2532 
 2533         url, smuggled_data = unsmuggle_url(url)
 2534         force_videoid = None
 2535         is_intentional = smuggled_data and smuggled_data.get('to_generic')
 2536         if smuggled_data and 'force_videoid' in smuggled_data:
 2537             force_videoid = smuggled_data['force_videoid']
 2538             video_id = force_videoid
 2539         else:
 2540             video_id = self._generic_id(url)
 2541 
 2542         self.to_screen('%s: Requesting header' % video_id)
 2543 
 2544         head_req = HEADRequest(url)
 2545         head_response = self._request_webpage(
 2546             head_req, video_id,
 2547             note=False, errnote='Could not send HEAD request to %s' % url,
 2548             fatal=False)
 2549 
 2550         if head_response is not False:
 2551             # Check for redirect
 2552             new_url = head_response.geturl()
 2553             if url != new_url:
 2554                 self.report_following_redirect(new_url)
 2555                 if force_videoid:
 2556                     new_url = smuggle_url(
 2557                         new_url, {'force_videoid': force_videoid})
 2558                 return self.url_result(new_url)
 2559 
 2560         full_response = None
 2561         if head_response is False:
 2562             request = sanitized_Request(url)
 2563             request.add_header('Accept-Encoding', '*')
 2564             full_response = self._request_webpage(request, video_id)
 2565             head_response = full_response
 2566 
 2567         info_dict = {
 2568             'id': video_id,
 2569             'title': self._generic_title(url),
 2570             'timestamp': unified_timestamp(head_response.headers.get('Last-Modified'))
 2571         }
 2572 
 2573         # Check for direct link to a video
 2574         content_type = head_response.headers.get('Content-Type', '').lower()
 2575         m = re.match(r'^(?P<type>audio|video|application(?=/(?:ogg$|(?:vnd\.apple\.|x-)?mpegurl)))/(?P<format_id>[^;\s]+)', content_type)
 2576         if m:
 2577             format_id = compat_str(m.group('format_id'))
 2578             if format_id.endswith('mpegurl'):
 2579                 formats = self._extract_m3u8_formats(url, video_id, 'mp4')
 2580             elif format_id == 'f4m':
 2581                 formats = self._extract_f4m_formats(url, video_id)
 2582             else:
 2583                 formats = [{
 2584                     'format_id': format_id,
 2585                     'url': url,
 2586                     'vcodec': 'none' if m.group('type') == 'audio' else None
 2587                 }]
 2588                 info_dict['direct'] = True
 2589             self._sort_formats(formats)
 2590             info_dict['formats'] = formats
 2591             return info_dict
 2592 
 2593         if not self._downloader.params.get('test', False) and not is_intentional:
 2594             force = self._downloader.params.get('force_generic_extractor', False)
 2595             self._downloader.report_warning(
 2596                 '%s on generic information extractor.' % ('Forcing' if force else 'Falling back'))
 2597 
 2598         if not full_response:
 2599             request = sanitized_Request(url)
 2600             # Some webservers may serve compressed content of rather big size (e.g. gzipped flac)
 2601             # making it impossible to download only chunk of the file (yet we need only 512kB to
 2602             # test whether it's HTML or not). According to youtube-dl default Accept-Encoding
 2603             # that will always result in downloading the whole file that is not desirable.
 2604             # Therefore for extraction pass we have to override Accept-Encoding to any in order
 2605             # to accept raw bytes and being able to download only a chunk.
 2606             # It may probably better to solve this by checking Content-Type for application/octet-stream
 2607             # after HEAD request finishes, but not sure if we can rely on this.
 2608             request.add_header('Accept-Encoding', '*')
 2609             full_response = self._request_webpage(request, video_id)
 2610 
 2611         first_bytes = full_response.read(512)
 2612 
 2613         # Is it an M3U playlist?
 2614         if first_bytes.startswith(b'#EXTM3U'):
 2615             info_dict['formats'] = self._extract_m3u8_formats(url, video_id, 'mp4')
 2616             self._sort_formats(info_dict['formats'])
 2617             return info_dict
 2618 
 2619         # Maybe it's a direct link to a video?
 2620         # Be careful not to download the whole thing!
 2621         if not is_html(first_bytes):
 2622             self._downloader.report_warning(
 2623                 'URL could be a direct video link, returning it as such.')
 2624             info_dict.update({
 2625                 'direct': True,
 2626                 'url': url,
 2627             })
 2628             return info_dict
 2629 
 2630         webpage = self._webpage_read_content(
 2631             full_response, url, video_id, prefix=first_bytes)
 2632 
 2633         if '<title>DPG Media Privacy Gate</title>' in webpage:
 2634             webpage = self._download_webpage(url, video_id)
 2635 
 2636         self.report_extraction(video_id)
 2637 
 2638         # Is it an RSS feed, a SMIL file, an XSPF playlist or a MPD manifest?
 2639         try:
 2640             doc = compat_etree_fromstring(webpage.encode('utf-8'))
 2641             if doc.tag == 'rss':
 2642                 return self._extract_rss(url, video_id, doc)
 2643             elif doc.tag == 'SmoothStreamingMedia':
 2644                 info_dict['formats'] = self._parse_ism_formats(doc, url)
 2645                 self._sort_formats(info_dict['formats'])
 2646                 return info_dict
 2647             elif re.match(r'^(?:{[^}]+})?smil$', doc.tag):
 2648                 smil = self._parse_smil(doc, url, video_id)
 2649                 self._sort_formats(smil['formats'])
 2650                 return smil
 2651             elif doc.tag == '{http://xspf.org/ns/0/}playlist':
 2652                 return self.playlist_result(
 2653                     self._parse_xspf(
 2654                         doc, video_id, xspf_url=url,
 2655                         xspf_base_url=full_response.geturl()),
 2656                     video_id)
 2657             elif re.match(r'(?i)^(?:{[^}]+})?MPD$', doc.tag):
 2658                 info_dict['formats'] = self._parse_mpd_formats(
 2659                     doc,
 2660                     mpd_base_url=full_response.geturl().rpartition('/')[0],
 2661                     mpd_url=url)
 2662                 self._sort_formats(info_dict['formats'])
 2663                 return info_dict
 2664             elif re.match(r'^{http://ns\.adobe\.com/f4m/[12]\.0}manifest$', doc.tag):
 2665                 info_dict['formats'] = self._parse_f4m_formats(doc, url, video_id)
 2666                 self._sort_formats(info_dict['formats'])
 2667                 return info_dict
 2668         except compat_xml_parse_error:
 2669             pass
 2670 
 2671         # Is it a Camtasia project?
 2672         camtasia_res = self._extract_camtasia(url, video_id, webpage)
 2673         if camtasia_res is not None:
 2674             return camtasia_res
 2675 
 2676         # Sometimes embedded video player is hidden behind percent encoding
 2677         # (e.g. https://github.com/ytdl-org/youtube-dl/issues/2448)
 2678         # Unescaping the whole page allows to handle those cases in a generic way
 2679         # FIXME: unescaping the whole page may break URLs, commenting out for now.
 2680         # There probably should be a second run of generic extractor on unescaped webpage.
 2681         # webpage = compat_urllib_parse_unquote(webpage)
 2682 
 2683         # Unescape squarespace embeds to be detected by generic extractor,
 2684         # see https://github.com/ytdl-org/youtube-dl/issues/21294
 2685         webpage = re.sub(
 2686             r'<div[^>]+class=[^>]*?\bsqs-video-wrapper\b[^>]*>',
 2687             lambda x: unescapeHTML(x.group(0)), webpage)
 2688 
 2689         # it's tempting to parse this further, but you would
 2690         # have to take into account all the variations like
 2691         #   Video Title - Site Name
 2692         #   Site Name | Video Title
 2693         #   Video Title - Tagline | Site Name
 2694         # and so on and so forth; it's just not practical
 2695         video_title = self._og_search_title(
 2696             webpage, default=None) or self._html_search_regex(
 2697             r'(?s)<title>(.*?)</title>', webpage, 'video title',
 2698             default='video')
 2699 
 2700         # Try to detect age limit automatically
 2701         age_limit = self._rta_search(webpage)
 2702         # And then there are the jokers who advertise that they use RTA,
 2703         # but actually don't.
 2704         AGE_LIMIT_MARKERS = [
 2705             r'Proudly Labeled <a href="http://www\.rtalabel\.org/" title="Restricted to Adults">RTA</a>',
 2706             r'>[^<]*you acknowledge you are at least (\d+) years old',
 2707         ]
 2708         for marker in AGE_LIMIT_MARKERS:
 2709             m = re.search(marker, webpage)
 2710             if not m:
 2711                 continue
 2712             age_limit = max(
 2713                 age_limit or 0,
 2714                 int_or_none(m.groups() and m.group(1), default=18))
 2715 
 2716         # video uploader is domain name
 2717         video_uploader = self._search_regex(
 2718             r'^(?:https?://)?([^/]*)/.*', url, 'video uploader')
 2719 
 2720         video_description = self._og_search_description(webpage, default=None)
 2721         video_thumbnail = self._og_search_thumbnail(webpage, default=None)
 2722 
 2723         info_dict.update({
 2724             'title': video_title,
 2725             'description': video_description,
 2726             'thumbnail': video_thumbnail,
 2727             'age_limit': age_limit,
 2728         })
 2729 
 2730         # Look for Brightcove Legacy Studio embeds
 2731         bc_urls = BrightcoveLegacyIE._extract_brightcove_urls(webpage)
 2732         if bc_urls:
 2733             entries = [{
 2734                 '_type': 'url',
 2735                 'url': smuggle_url(bc_url, {'Referer': url}),
 2736                 'ie_key': 'BrightcoveLegacy'
 2737             } for bc_url in bc_urls]
 2738 
 2739             return {
 2740                 '_type': 'playlist',
 2741                 'title': video_title,
 2742                 'id': video_id,
 2743                 'entries': entries,
 2744             }
 2745 
 2746         # Look for Brightcove New Studio embeds
 2747         bc_urls = BrightcoveNewIE._extract_urls(self, webpage)
 2748         if bc_urls:
 2749             return self.playlist_from_matches(
 2750                 bc_urls, video_id, video_title,
 2751                 getter=lambda x: smuggle_url(x, {'referrer': url}),
 2752                 ie='BrightcoveNew')
 2753 
 2754         # Look for Nexx embeds
 2755         nexx_urls = NexxIE._extract_urls(webpage)
 2756         if nexx_urls:
 2757             return self.playlist_from_matches(nexx_urls, video_id, video_title, ie=NexxIE.ie_key())
 2758 
 2759         # Look for Nexx iFrame embeds
 2760         nexx_embed_urls = NexxEmbedIE._extract_urls(webpage)
 2761         if nexx_embed_urls:
 2762             return self.playlist_from_matches(nexx_embed_urls, video_id, video_title, ie=NexxEmbedIE.ie_key())
 2763 
 2764         # Look for ThePlatform embeds
 2765         tp_urls = ThePlatformIE._extract_urls(webpage)
 2766         if tp_urls:
 2767             return self.playlist_from_matches(tp_urls, video_id, video_title, ie='ThePlatform')
 2768 
 2769         arc_urls = ArcPublishingIE._extract_urls(webpage)
 2770         if arc_urls:
 2771             return self.playlist_from_matches(arc_urls, video_id, video_title, ie=ArcPublishingIE.ie_key())
 2772 
 2773         mychannels_urls = MedialaanIE._extract_urls(webpage)
 2774         if mychannels_urls:
 2775             return self.playlist_from_matches(
 2776                 mychannels_urls, video_id, video_title, ie=MedialaanIE.ie_key())
 2777 
 2778         # Look for embedded rtl.nl player
 2779         matches = re.findall(
 2780             r'<iframe[^>]+?src="((?:https?:)?//(?:(?:www|static)\.)?rtl\.nl/(?:system/videoplayer/[^"]+(?:video_)?)?embed[^"]+)"',
 2781             webpage)
 2782         if matches:
 2783             return self.playlist_from_matches(matches, video_id, video_title, ie='RtlNl')
 2784 
 2785         vimeo_urls = VimeoIE._extract_urls(url, webpage)
 2786         if vimeo_urls:
 2787             return self.playlist_from_matches(vimeo_urls, video_id, video_title, ie=VimeoIE.ie_key())
 2788 
 2789         vhx_url = VHXEmbedIE._extract_url(webpage)
 2790         if vhx_url:
 2791             return self.url_result(vhx_url, VHXEmbedIE.ie_key())
 2792 
 2793         vid_me_embed_url = self._search_regex(
 2794             r'src=[\'"](https?://vid\.me/[^\'"]+)[\'"]',
 2795             webpage, 'vid.me embed', default=None)
 2796         if vid_me_embed_url is not None:
 2797             return self.url_result(vid_me_embed_url, 'Vidme')
 2798 
 2799         # Look for YouTube embeds
 2800         youtube_urls = YoutubeIE._extract_urls(webpage)
 2801         if youtube_urls:
 2802             return self.playlist_from_matches(
 2803                 youtube_urls, video_id, video_title, ie=YoutubeIE.ie_key())
 2804 
 2805         matches = DailymotionIE._extract_urls(webpage)
 2806         if matches:
 2807             return self.playlist_from_matches(matches, video_id, video_title)
 2808 
 2809         # Look for embedded Dailymotion playlist player (#3822)
 2810         m = re.search(
 2811             r'<iframe[^>]+?src=(["\'])(?P<url>(?:https?:)?//(?:www\.)?dailymotion\.[a-z]{2,3}/widget/jukebox\?.+?)\1', webpage)
 2812         if m:
 2813             playlists = re.findall(
 2814                 r'list\[\]=/playlist/([^/]+)/', unescapeHTML(m.group('url')))
 2815             if playlists:
 2816                 return self.playlist_from_matches(
 2817                     playlists, video_id, video_title, lambda p: '//dailymotion.com/playlist/%s' % p)
 2818 
 2819         # Look for DailyMail embeds
 2820         dailymail_urls = DailyMailIE._extract_urls(webpage)
 2821         if dailymail_urls:
 2822             return self.playlist_from_matches(
 2823                 dailymail_urls, video_id, video_title, ie=DailyMailIE.ie_key())
 2824 
 2825         # Look for Teachable embeds, must be before Wistia
 2826         teachable_url = TeachableIE._extract_url(webpage, url)
 2827         if teachable_url:
 2828             return self.url_result(teachable_url)
 2829 
 2830         # Look for embedded Wistia player
 2831         wistia_urls = WistiaIE._extract_urls(webpage)
 2832         if wistia_urls:
 2833             playlist = self.playlist_from_matches(wistia_urls, video_id, video_title, ie=WistiaIE.ie_key())
 2834             for entry in playlist['entries']:
 2835                 entry.update({
 2836                     '_type': 'url_transparent',
 2837                     'uploader': video_uploader,
 2838                 })
 2839             return playlist
 2840 
 2841         # Look for SVT player
 2842         svt_url = SVTIE._extract_url(webpage)
 2843         if svt_url:
 2844             return self.url_result(svt_url, 'SVT')
 2845 
 2846         # Look for Bandcamp pages with custom domain
 2847         mobj = re.search(r'<meta property="og:url"[^>]*?content="(.*?bandcamp\.com.*?)"', webpage)
 2848         if mobj is not None:
 2849             burl = unescapeHTML(mobj.group(1))
 2850             # Don't set the extractor because it can be a track url or an album
 2851             return self.url_result(burl)
 2852 
 2853         # Look for embedded Vevo player
 2854         mobj = re.search(
 2855             r'<iframe[^>]+?src=(["\'])(?P<url>(?:https?:)?//(?:cache\.)?vevo\.com/.+?)\1', webpage)
 2856         if mobj is not None:
 2857             return self.url_result(mobj.group('url'))
 2858 
 2859         # Look for embedded Viddler player
 2860         mobj = re.search(
 2861             r'<(?:iframe[^>]+?src|param[^>]+?value)=(["\'])(?P<url>(?:https?:)?//(?:www\.)?viddler\.com/(?:embed|player)/.+?)\1',
 2862             webpage)
 2863         if mobj is not None:
 2864             return self.url_result(mobj.group('url'))
 2865 
 2866         # Look for NYTimes player
 2867         mobj = re.search(
 2868             r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//graphics8\.nytimes\.com/bcvideo/[^/]+/iframe/embed\.html.+?)\1>',
 2869             webpage)
 2870         if mobj is not None:
 2871             return self.url_result(mobj.group('url'))
 2872 
 2873         # Look for Libsyn player
 2874         mobj = re.search(
 2875             r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//html5-player\.libsyn\.com/embed/.+?)\1', webpage)
 2876         if mobj is not None:
 2877             return self.url_result(mobj.group('url'))
 2878 
 2879         # Look for Ooyala videos
 2880         mobj = (re.search(r'player\.ooyala\.com/[^"?]+[?#][^"]*?(?:embedCode|ec)=(?P<ec>[^"&]+)', webpage)
 2881                 or re.search(r'OO\.Player\.create\([\'"].*?[\'"],\s*[\'"](?P<ec>.{32})[\'"]', webpage)
 2882                 or re.search(r'OO\.Player\.create\.apply\(\s*OO\.Player\s*,\s*op\(\s*\[\s*[\'"][^\'"]*[\'"]\s*,\s*[\'"](?P<ec>.{32})[\'"]', webpage)
 2883                 or re.search(r'SBN\.VideoLinkset\.ooyala\([\'"](?P<ec>.{32})[\'"]\)', webpage)
 2884                 or re.search(r'data-ooyala-video-id\s*=\s*[\'"](?P<ec>.{32})[\'"]', webpage))
 2885         if mobj is not None:
 2886             embed_token = self._search_regex(
 2887                 r'embedToken[\'"]?\s*:\s*[\'"]([^\'"]+)',
 2888                 webpage, 'ooyala embed token', default=None)
 2889             return OoyalaIE._build_url_result(smuggle_url(
 2890                 mobj.group('ec'), {
 2891                     'domain': url,
 2892                     'embed_token': embed_token,
 2893                 }))
 2894 
 2895         # Look for multiple Ooyala embeds on SBN network websites
 2896         mobj = re.search(r'SBN\.VideoLinkset\.entryGroup\((\[.*?\])', webpage)
 2897         if mobj is not None:
 2898             embeds = self._parse_json(mobj.group(1), video_id, fatal=False)
 2899             if embeds:
 2900                 return self.playlist_from_matches(
 2901                     embeds, video_id, video_title,
 2902                     getter=lambda v: OoyalaIE._url_for_embed_code(smuggle_url(v['provider_video_id'], {'domain': url})), ie='Ooyala')
 2903 
 2904         # Look for Aparat videos
 2905         mobj = re.search(r'<iframe .*?src="(http://www\.aparat\.com/video/[^"]+)"', webpage)
 2906         if mobj is not None:
 2907             return self.url_result(mobj.group(1), 'Aparat')
 2908 
 2909         # Look for MPORA videos
 2910         mobj = re.search(r'<iframe .*?src="(http://mpora\.(?:com|de)/videos/[^"]+)"', webpage)
 2911         if mobj is not None:
 2912             return self.url_result(mobj.group(1), 'Mpora')
 2913 
 2914         # Look for embedded Facebook player
 2915         facebook_urls = FacebookIE._extract_urls(webpage)
 2916         if facebook_urls:
 2917             return self.playlist_from_matches(facebook_urls, video_id, video_title)
 2918 
 2919         # Look for embedded VK player
 2920         mobj = re.search(r'<iframe[^>]+?src=(["\'])(?P<url>https?://vk\.com/video_ext\.php.+?)\1', webpage)
 2921         if mobj is not None:
 2922             return self.url_result(mobj.group('url'), 'VK')
 2923 
 2924         # Look for embedded Odnoklassniki player
 2925         odnoklassniki_url = OdnoklassnikiIE._extract_url(webpage)
 2926         if odnoklassniki_url:
 2927             return self.url_result(odnoklassniki_url, OdnoklassnikiIE.ie_key())
 2928 
 2929         # Look for sibnet embedded player
 2930         sibnet_urls = VKIE._extract_sibnet_urls(webpage)
 2931         if sibnet_urls:
 2932             return self.playlist_from_matches(sibnet_urls, video_id, video_title)
 2933 
 2934         # Look for embedded ivi player
 2935         mobj = re.search(r'<embed[^>]+?src=(["\'])(?P<url>https?://(?:www\.)?ivi\.ru/video/player.+?)\1', webpage)
 2936         if mobj is not None:
 2937             return self.url_result(mobj.group('url'), 'Ivi')
 2938 
 2939         # Look for embedded Huffington Post player
 2940         mobj = re.search(
 2941             r'<iframe[^>]+?src=(["\'])(?P<url>https?://embed\.live\.huffingtonpost\.com/.+?)\1', webpage)
 2942         if mobj is not None:
 2943             return self.url_result(mobj.group('url'), 'HuffPost')
 2944 
 2945         # Look for embed.ly
 2946         mobj = re.search(r'class=["\']embedly-card["\'][^>]href=["\'](?P<url>[^"\']+)', webpage)
 2947         if mobj is not None:
 2948             return self.url_result(mobj.group('url'))
 2949         mobj = re.search(r'class=["\']embedly-embed["\'][^>]src=["\'][^"\']*url=(?P<url>[^&]+)', webpage)
 2950         if mobj is not None:
 2951             return self.url_result(compat_urllib_parse_unquote(mobj.group('url')))
 2952 
 2953         # Look for funnyordie embed
 2954         matches = re.findall(r'<iframe[^>]+?src="(https?://(?:www\.)?funnyordie\.com/embed/[^"]+)"', webpage)
 2955         if matches:
 2956             return self.playlist_from_matches(
 2957                 matches, video_id, video_title, getter=unescapeHTML, ie='FunnyOrDie')
 2958 
 2959         # Look for Simplecast embeds
 2960         simplecast_urls = SimplecastIE._extract_urls(webpage)
 2961         if simplecast_urls:
 2962             return self.playlist_from_matches(
 2963                 simplecast_urls, video_id, video_title)
 2964 
 2965         # Look for BBC iPlayer embed
 2966         matches = re.findall(r'setPlaylist\("(https?://www\.bbc\.co\.uk/iplayer/[^/]+/[\da-z]{8})"\)', webpage)
 2967         if matches:
 2968             return self.playlist_from_matches(matches, video_id, video_title, ie='BBCCoUk')
 2969 
 2970         # Look for embedded RUTV player
 2971         rutv_url = RUTVIE._extract_url(webpage)
 2972         if rutv_url:
 2973             return self.url_result(rutv_url, 'RUTV')
 2974 
 2975         # Look for embedded TVC player
 2976         tvc_url = TVCIE._extract_url(webpage)
 2977         if tvc_url:
 2978             return self.url_result(tvc_url, 'TVC')
 2979 
 2980         # Look for embedded SportBox player
 2981         sportbox_urls = SportBoxIE._extract_urls(webpage)
 2982         if sportbox_urls:
 2983             return self.playlist_from_matches(sportbox_urls, video_id, video_title, ie=SportBoxIE.ie_key())
 2984 
 2985         # Look for embedded XHamster player
 2986         xhamster_urls = XHamsterEmbedIE._extract_urls(webpage)
 2987         if xhamster_urls:
 2988             return self.playlist_from_matches(xhamster_urls, video_id, video_title, ie='XHamsterEmbed')
 2989 
 2990         # Look for embedded TNAFlixNetwork player
 2991         tnaflix_urls = TNAFlixNetworkEmbedIE._extract_urls(webpage)
 2992         if tnaflix_urls:
 2993             return self.playlist_from_matches(tnaflix_urls, video_id, video_title, ie=TNAFlixNetworkEmbedIE.ie_key())
 2994 
 2995         # Look for embedded PornHub player
 2996         pornhub_urls = PornHubIE._extract_urls(webpage)
 2997         if pornhub_urls:
 2998             return self.playlist_from_matches(pornhub_urls, video_id, video_title, ie=PornHubIE.ie_key())
 2999 
 3000         # Look for embedded DrTuber player
 3001         drtuber_urls = DrTuberIE._extract_urls(webpage)
 3002         if drtuber_urls:
 3003             return self.playlist_from_matches(drtuber_urls, video_id, video_title, ie=DrTuberIE.ie_key())
 3004 
 3005         # Look for embedded RedTube player
 3006         redtube_urls = RedTubeIE._extract_urls(webpage)
 3007         if redtube_urls:
 3008             return self.playlist_from_matches(redtube_urls, video_id, video_title, ie=RedTubeIE.ie_key())
 3009 
 3010         # Look for embedded Tube8 player
 3011         tube8_urls = Tube8IE._extract_urls(webpage)
 3012         if tube8_urls:
 3013             return self.playlist_from_matches(tube8_urls, video_id, video_title, ie=Tube8IE.ie_key())
 3014 
 3015         # Look for embedded Mofosex player
 3016         mofosex_urls = MofosexEmbedIE._extract_urls(webpage)
 3017         if mofosex_urls:
 3018             return self.playlist_from_matches(mofosex_urls, video_id, video_title, ie=MofosexEmbedIE.ie_key())
 3019 
 3020         # Look for embedded Spankwire player
 3021         spankwire_urls = SpankwireIE._extract_urls(webpage)
 3022         if spankwire_urls:
 3023             return self.playlist_from_matches(spankwire_urls, video_id, video_title, ie=SpankwireIE.ie_key())
 3024 
 3025         # Look for embedded YouPorn player
 3026         youporn_urls = YouPornIE._extract_urls(webpage)
 3027         if youporn_urls:
 3028             return self.playlist_from_matches(youporn_urls, video_id, video_title, ie=YouPornIE.ie_key())
 3029 
 3030         # Look for embedded Tvigle player
 3031         mobj = re.search(
 3032             r'<iframe[^>]+?src=(["\'])(?P<url>(?:https?:)?//cloud\.tvigle\.ru/video/.+?)\1', webpage)
 3033         if mobj is not None:
 3034             return self.url_result(mobj.group('url'), 'Tvigle')
 3035 
 3036         # Look for embedded TED player
 3037         mobj = re.search(
 3038             r'<iframe[^>]+?src=(["\'])(?P<url>https?://embed(?:-ssl)?\.ted\.com/.+?)\1', webpage)
 3039         if mobj is not None:
 3040             return self.url_result(mobj.group('url'), 'TED')
 3041 
 3042         # Look for embedded Ustream videos
 3043         ustream_url = UstreamIE._extract_url(webpage)
 3044         if ustream_url:
 3045             return self.url_result(ustream_url, UstreamIE.ie_key())
 3046 
 3047         # Look for embedded arte.tv player
 3048         arte_urls = ArteTVEmbedIE._extract_urls(webpage)
 3049         if arte_urls:
 3050             return self.playlist_from_matches(arte_urls, video_id, video_title)
 3051 
 3052         # Look for embedded francetv player
 3053         mobj = re.search(
 3054             r'<iframe[^>]+?src=(["\'])(?P<url>(?:https?://)?embed\.francetv\.fr/\?ue=.+?)\1',
 3055             webpage)
 3056         if mobj is not None:
 3057             return self.url_result(mobj.group('url'))
 3058 
 3059         # Look for embedded Myvi.ru player
 3060         myvi_url = MyviIE._extract_url(webpage)
 3061         if myvi_url:
 3062             return self.url_result(myvi_url)
 3063 
 3064         # Look for embedded soundcloud player
 3065         soundcloud_urls = SoundcloudEmbedIE._extract_urls(webpage)
 3066         if soundcloud_urls:
 3067             return self.playlist_from_matches(soundcloud_urls, video_id, video_title, getter=unescapeHTML)
 3068 
 3069         # Look for tunein player
 3070         tunein_urls = TuneInBaseIE._extract_urls(webpage)
 3071         if tunein_urls:
 3072             return self.playlist_from_matches(tunein_urls, video_id, video_title)
 3073 
 3074         # Look for embedded mtvservices player
 3075         mtvservices_url = MTVServicesEmbeddedIE._extract_url(webpage)
 3076         if mtvservices_url:
 3077             return self.url_result(mtvservices_url, ie='MTVServicesEmbedded')
 3078 
 3079         # Look for embedded yahoo player
 3080         mobj = re.search(
 3081             r'<iframe[^>]+?src=(["\'])(?P<url>https?://(?:screen|movies)\.yahoo\.com/.+?\.html\?format=embed)\1',
 3082             webpage)
 3083         if mobj is not None:
 3084             return self.url_result(mobj.group('url'), 'Yahoo')
 3085 
 3086         # Look for embedded sbs.com.au player
 3087         mobj = re.search(
 3088             r'''(?x)
 3089             (?:
 3090                 <meta\s+property="og:video"\s+content=|
 3091                 <iframe[^>]+?src=
 3092             )
 3093             (["\'])(?P<url>https?://(?:www\.)?sbs\.com\.au/ondemand/video/.+?)\1''',
 3094             webpage)
 3095         if mobj is not None:
 3096             return self.url_result(mobj.group('url'), 'SBS')
 3097 
 3098         # Look for embedded Cinchcast player
 3099         mobj = re.search(
 3100             r'<iframe[^>]+?src=(["\'])(?P<url>https?://player\.cinchcast\.com/.+?)\1',
 3101             webpage)
 3102         if mobj is not None:
 3103             return self.url_result(mobj.group('url'), 'Cinchcast')
 3104 
 3105         mobj = re.search(
 3106             r'<iframe[^>]+?src=(["\'])(?P<url>https?://m(?:lb)?\.mlb\.com/shared/video/embed/embed\.html\?.+?)\1',
 3107             webpage)
 3108         if not mobj:
 3109             mobj = re.search(
 3110                 r'data-video-link=["\'](?P<url>http://m\.mlb\.com/video/[^"\']+)',
 3111                 webpage)
 3112         if mobj is not None:
 3113             return self.url_result(mobj.group('url'), 'MLB')
 3114 
 3115         mobj = re.search(
 3116             r'<(?:iframe|script)[^>]+?src=(["\'])(?P<url>%s)\1' % CondeNastIE.EMBED_URL,
 3117             webpage)
 3118         if mobj is not None:
 3119             return self.url_result(self._proto_relative_url(mobj.group('url'), scheme='http:'), 'CondeNast')
 3120 
 3121         mobj = re.search(
 3122             r'<iframe[^>]+src="(?P<url>https?://(?:new\.)?livestream\.com/[^"]+/player[^"]+)"',
 3123             webpage)
 3124         if mobj is not None:
 3125             return self.url_result(mobj.group('url'), 'Livestream')
 3126 
 3127         # Look for Zapiks embed
 3128         mobj = re.search(
 3129             r'<iframe[^>]+src="(?P<url>https?://(?:www\.)?zapiks\.fr/index\.php\?.+?)"', webpage)
 3130         if mobj is not None:
 3131             return self.url_result(mobj.group('url'), 'Zapiks')
 3132 
 3133         # Look for Kaltura embeds
 3134         kaltura_urls = KalturaIE._extract_urls(webpage)
 3135         if kaltura_urls:
 3136             return self.playlist_from_matches(
 3137                 kaltura_urls, video_id, video_title,
 3138                 getter=lambda x: smuggle_url(x, {'source_url': url}),
 3139                 ie=KalturaIE.ie_key())
 3140 
 3141         # Look for EaglePlatform embeds
 3142         eagleplatform_url = EaglePlatformIE._extract_url(webpage)
 3143         if eagleplatform_url:
 3144             return self.url_result(smuggle_url(eagleplatform_url, {'referrer': url}), EaglePlatformIE.ie_key())
 3145 
 3146         # Look for ClipYou (uses EaglePlatform) embeds
 3147         mobj = re.search(
 3148             r'<iframe[^>]+src="https?://(?P<host>media\.clipyou\.ru)/index/player\?.*\brecord_id=(?P<id>\d+).*"', webpage)
 3149         if mobj is not None:
 3150             return self.url_result('eagleplatform:%(host)s:%(id)s' % mobj.groupdict(), 'EaglePlatform')
 3151 
 3152         # Look for Pladform embeds
 3153         pladform_url = PladformIE._extract_url(webpage)
 3154         if pladform_url:
 3155             return self.url_result(pladform_url)
 3156 
 3157         # Look for Videomore embeds
 3158         videomore_url = VideomoreIE._extract_url(webpage)
 3159         if videomore_url:
 3160             return self.url_result(videomore_url)
 3161 
 3162         # Look for Webcaster embeds
 3163         webcaster_url = WebcasterFeedIE._extract_url(self, webpage)
 3164         if webcaster_url:
 3165             return self.url_result(webcaster_url, ie=WebcasterFeedIE.ie_key())
 3166 
 3167         # Look for Playwire embeds
 3168         mobj = re.search(
 3169             r'<script[^>]+data-config=(["\'])(?P<url>(?:https?:)?//config\.playwire\.com/.+?)\1', webpage)
 3170         if mobj is not None:
 3171             return self.url_result(mobj.group('url'))
 3172 
 3173         # Look for 5min embeds
 3174         mobj = re.search(
 3175             r'<meta[^>]+property="og:video"[^>]+content="https?://embed\.5min\.com/(?P<id>[0-9]+)/?', webpage)
 3176         if mobj is not None:
 3177             return self.url_result('5min:%s' % mobj.group('id'), 'FiveMin')
 3178 
 3179         # Look for Crooks and Liars embeds
 3180         mobj = re.search(
 3181             r'<(?:iframe[^>]+src|param[^>]+value)=(["\'])(?P<url>(?:https?:)?//embed\.crooksandliars\.com/(?:embed|v)/.+?)\1', webpage)
 3182         if mobj is not None:
 3183             return self.url_result(mobj.group('url'))
 3184 
 3185         # Look for NBC Sports VPlayer embeds
 3186         nbc_sports_url = NBCSportsVPlayerIE._extract_url(webpage)
 3187         if nbc_sports_url:
 3188             return self.url_result(nbc_sports_url, 'NBCSportsVPlayer')
 3189 
 3190         # Look for NBC News embeds
 3191         nbc_news_embed_url = re.search(
 3192             r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//www\.nbcnews\.com/widget/video-embed/[^"\']+)\1', webpage)
 3193         if nbc_news_embed_url:
 3194             return self.url_result(nbc_news_embed_url.group('url'), 'NBCNews')
 3195 
 3196         # Look for Google Drive embeds
 3197         google_drive_url = GoogleDriveIE._extract_url(webpage)
 3198         if google_drive_url:
 3199             return self.url_result(google_drive_url, 'GoogleDrive')
 3200 
 3201         # Look for UDN embeds
 3202         mobj = re.search(
 3203             r'<iframe[^>]+src="(?:https?:)?(?P<url>%s)"' % UDNEmbedIE._PROTOCOL_RELATIVE_VALID_URL, webpage)
 3204         if mobj is not None:
 3205             return self.url_result(
 3206                 compat_urlparse.urljoin(url, mobj.group('url')), 'UDNEmbed')
 3207 
 3208         # Look for Senate ISVP iframe
 3209         senate_isvp_url = SenateISVPIE._search_iframe_url(webpage)
 3210         if senate_isvp_url:
 3211             return self.url_result(senate_isvp_url, 'SenateISVP')
 3212 
 3213         # Look for Kinja embeds
 3214         kinja_embed_urls = KinjaEmbedIE._extract_urls(webpage, url)
 3215         if kinja_embed_urls:
 3216             return self.playlist_from_matches(
 3217                 kinja_embed_urls, video_id, video_title)
 3218 
 3219         # Look for OnionStudios embeds
 3220         onionstudios_url = OnionStudiosIE._extract_url(webpage)
 3221         if onionstudios_url:
 3222             return self.url_result(onionstudios_url)
 3223 
 3224         # Look for ViewLift embeds
 3225         viewlift_url = ViewLiftEmbedIE._extract_url(webpage)
 3226         if viewlift_url:
 3227             return self.url_result(viewlift_url)
 3228 
 3229         # Look for JWPlatform embeds
 3230         jwplatform_urls = JWPlatformIE._extract_urls(webpage)
 3231         if jwplatform_urls:
 3232             return self.playlist_from_matches(jwplatform_urls, video_id, video_title, ie=JWPlatformIE.ie_key())
 3233 
 3234         # Look for Digiteka embeds
 3235         digiteka_url = DigitekaIE._extract_url(webpage)
 3236         if digiteka_url:
 3237             return self.url_result(self._proto_relative_url(digiteka_url), DigitekaIE.ie_key())
 3238 
 3239         # Look for Arkena embeds
 3240         arkena_url = ArkenaIE._extract_url(webpage)
 3241         if arkena_url:
 3242             return self.url_result(arkena_url, ArkenaIE.ie_key())
 3243 
 3244         # Look for Piksel embeds
 3245         piksel_url = PikselIE._extract_url(webpage)
 3246         if piksel_url:
 3247             return self.url_result(piksel_url, PikselIE.ie_key())
 3248 
 3249         # Look for Limelight embeds
 3250         limelight_urls = LimelightBaseIE._extract_urls(webpage, url)
 3251         if limelight_urls:
 3252             return self.playlist_result(
 3253                 limelight_urls, video_id, video_title, video_description)
 3254 
 3255         # Look for Anvato embeds
 3256         anvato_urls = AnvatoIE._extract_urls(self, webpage, video_id)
 3257         if anvato_urls:
 3258             return self.playlist_result(
 3259                 anvato_urls, video_id, video_title, video_description)
 3260 
 3261         # Look for AdobeTVVideo embeds
 3262         mobj = re.search(
 3263             r'<iframe[^>]+src=[\'"]((?:https?:)?//video\.tv\.adobe\.com/v/\d+[^"]+)[\'"]',
 3264             webpage)
 3265         if mobj is not None:
 3266             return self.url_result(
 3267                 self._proto_relative_url(unescapeHTML(mobj.group(1))),
 3268                 'AdobeTVVideo')
 3269 
 3270         # Look for Vine embeds
 3271         mobj = re.search(
 3272             r'<iframe[^>]+src=[\'"]((?:https?:)?//(?:www\.)?vine\.co/v/[^/]+/embed/(?:simple|postcard))',
 3273             webpage)
 3274         if mobj is not None:
 3275             return self.url_result(
 3276                 self._proto_relative_url(unescapeHTML(mobj.group(1))), 'Vine')
 3277 
 3278         # Look for VODPlatform embeds
 3279         mobj = re.search(
 3280             r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//(?:(?:www\.)?vod-platform\.net|embed\.kwikmotion\.com)/[eE]mbed/.+?)\1',
 3281             webpage)
 3282         if mobj is not None:
 3283             return self.url_result(
 3284                 self._proto_relative_url(unescapeHTML(mobj.group('url'))), 'VODPlatform')
 3285 
 3286         # Look for Mangomolo embeds
 3287         mobj = re.search(
 3288             r'''(?x)<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//
 3289                 (?:
 3290                     admin\.mangomolo\.com/analytics/index\.php/customers/embed|
 3291                     player\.mangomolo\.com/v1
 3292                 )/
 3293                 (?:
 3294                     video\?.*?\bid=(?P<video_id>\d+)|
 3295                     (?:index|live)\?.*?\bchannelid=(?P<channel_id>(?:[A-Za-z0-9+/=]|%2B|%2F|%3D)+)
 3296                 ).+?)\1''', webpage)
 3297         if mobj is not None:
 3298             info = {
 3299                 '_type': 'url_transparent',
 3300                 'url': self._proto_relative_url(unescapeHTML(mobj.group('url'))),
 3301                 'title': video_title,
 3302                 'description': video_description,
 3303                 'thumbnail': video_thumbnail,
 3304                 'uploader': video_uploader,
 3305             }
 3306             video_id = mobj.group('video_id')
 3307             if video_id:
 3308                 info.update({
 3309                     'ie_key': 'MangomoloVideo',
 3310                     'id': video_id,
 3311                 })
 3312             else:
 3313                 info.update({
 3314                     'ie_key': 'MangomoloLive',
 3315                     'id': mobj.group('channel_id'),
 3316                 })
 3317             return info
 3318 
 3319         # Look for Instagram embeds
 3320         instagram_embed_url = InstagramIE._extract_embed_url(webpage)
 3321         if instagram_embed_url is not None:
 3322             return self.url_result(
 3323                 self._proto_relative_url(instagram_embed_url), InstagramIE.ie_key())
 3324 
 3325         # Look for 3Q SDN embeds
 3326         threeqsdn_url = ThreeQSDNIE._extract_url(webpage)
 3327         if threeqsdn_url:
 3328             return {
 3329                 '_type': 'url_transparent',
 3330                 'ie_key': ThreeQSDNIE.ie_key(),
 3331                 'url': self._proto_relative_url(threeqsdn_url),
 3332                 'title': video_title,
 3333                 'description': video_description,
 3334                 'thumbnail': video_thumbnail,
 3335                 'uploader': video_uploader,
 3336             }
 3337 
 3338         # Look for VBOX7 embeds
 3339         vbox7_url = Vbox7IE._extract_url(webpage)
 3340         if vbox7_url:
 3341             return self.url_result(vbox7_url, Vbox7IE.ie_key())
 3342 
 3343         # Look for DBTV embeds
 3344         dbtv_urls = DBTVIE._extract_urls(webpage)
 3345         if dbtv_urls:
 3346             return self.playlist_from_matches(dbtv_urls, video_id, video_title, ie=DBTVIE.ie_key())
 3347 
 3348         # Look for Videa embeds
 3349         videa_urls = VideaIE._extract_urls(webpage)
 3350         if videa_urls:
 3351             return self.playlist_from_matches(videa_urls, video_id, video_title, ie=VideaIE.ie_key())
 3352 
 3353         # Look for 20 minuten embeds
 3354         twentymin_urls = TwentyMinutenIE._extract_urls(webpage)
 3355         if twentymin_urls:
 3356             return self.playlist_from_matches(
 3357                 twentymin_urls, video_id, video_title, ie=TwentyMinutenIE.ie_key())
 3358 
 3359         # Look for VideoPress embeds
 3360         videopress_urls = VideoPressIE._extract_urls(webpage)
 3361         if videopress_urls:
 3362             return self.playlist_from_matches(
 3363                 videopress_urls, video_id, video_title, ie=VideoPressIE.ie_key())
 3364 
 3365         # Look for Rutube embeds
 3366         rutube_urls = RutubeIE._extract_urls(webpage)
 3367         if rutube_urls:
 3368             return self.playlist_from_matches(
 3369                 rutube_urls, video_id, video_title, ie=RutubeIE.ie_key())
 3370 
 3371         # Look for WashingtonPost embeds
 3372         wapo_urls = WashingtonPostIE._extract_urls(webpage)
 3373         if wapo_urls:
 3374             return self.playlist_from_matches(
 3375                 wapo_urls, video_id, video_title, ie=WashingtonPostIE.ie_key())
 3376 
 3377         # Look for Mediaset embeds
 3378         mediaset_urls = MediasetIE._extract_urls(self, webpage)
 3379         if mediaset_urls:
 3380             return self.playlist_from_matches(
 3381                 mediaset_urls, video_id, video_title, ie=MediasetIE.ie_key())
 3382 
 3383         # Look for JOJ.sk embeds
 3384         joj_urls = JojIE._extract_urls(webpage)
 3385         if joj_urls:
 3386             return self.playlist_from_matches(
 3387                 joj_urls, video_id, video_title, ie=JojIE.ie_key())
 3388 
 3389         # Look for megaphone.fm embeds
 3390         mpfn_urls = MegaphoneIE._extract_urls(webpage)
 3391         if mpfn_urls:
 3392             return self.playlist_from_matches(
 3393                 mpfn_urls, video_id, video_title, ie=MegaphoneIE.ie_key())
 3394 
 3395         # Look for vzaar embeds
 3396         vzaar_urls = VzaarIE._extract_urls(webpage)
 3397         if vzaar_urls:
 3398             return self.playlist_from_matches(
 3399                 vzaar_urls, video_id, video_title, ie=VzaarIE.ie_key())
 3400 
 3401         channel9_urls = Channel9IE._extract_urls(webpage)
 3402         if channel9_urls:
 3403             return self.playlist_from_matches(
 3404                 channel9_urls, video_id, video_title, ie=Channel9IE.ie_key())
 3405 
 3406         vshare_urls = VShareIE._extract_urls(webpage)
 3407         if vshare_urls:
 3408             return self.playlist_from_matches(
 3409                 vshare_urls, video_id, video_title, ie=VShareIE.ie_key())
 3410 
 3411         # Look for Mediasite embeds
 3412         mediasite_urls = MediasiteIE._extract_urls(webpage)
 3413         if mediasite_urls:
 3414             entries = [
 3415                 self.url_result(smuggle_url(
 3416                     compat_urlparse.urljoin(url, mediasite_url),
 3417                     {'UrlReferrer': url}), ie=MediasiteIE.ie_key())
 3418                 for mediasite_url in mediasite_urls]
 3419             return self.playlist_result(entries, video_id, video_title)
 3420 
 3421         springboardplatform_urls = SpringboardPlatformIE._extract_urls(webpage)
 3422         if springboardplatform_urls:
 3423             return self.playlist_from_matches(
 3424                 springboardplatform_urls, video_id, video_title,
 3425                 ie=SpringboardPlatformIE.ie_key())
 3426 
 3427         yapfiles_urls = YapFilesIE._extract_urls(webpage)
 3428         if yapfiles_urls:
 3429             return self.playlist_from_matches(
 3430                 yapfiles_urls, video_id, video_title, ie=YapFilesIE.ie_key())
 3431 
 3432         vice_urls = ViceIE._extract_urls(webpage)
 3433         if vice_urls:
 3434             return self.playlist_from_matches(
 3435                 vice_urls, video_id, video_title, ie=ViceIE.ie_key())
 3436 
 3437         xfileshare_urls = XFileShareIE._extract_urls(webpage)
 3438         if xfileshare_urls:
 3439             return self.playlist_from_matches(
 3440                 xfileshare_urls, video_id, video_title, ie=XFileShareIE.ie_key())
 3441 
 3442         cloudflarestream_urls = CloudflareStreamIE._extract_urls(webpage)
 3443         if cloudflarestream_urls:
 3444             return self.playlist_from_matches(
 3445                 cloudflarestream_urls, video_id, video_title, ie=CloudflareStreamIE.ie_key())
 3446 
 3447         peertube_urls = PeerTubeIE._extract_urls(webpage, url)
 3448         if peertube_urls:
 3449             return self.playlist_from_matches(
 3450                 peertube_urls, video_id, video_title, ie=PeerTubeIE.ie_key())
 3451 
 3452         indavideo_urls = IndavideoEmbedIE._extract_urls(webpage)
 3453         if indavideo_urls:
 3454             return self.playlist_from_matches(
 3455                 indavideo_urls, video_id, video_title, ie=IndavideoEmbedIE.ie_key())
 3456 
 3457         apa_urls = APAIE._extract_urls(webpage)
 3458         if apa_urls:
 3459             return self.playlist_from_matches(
 3460                 apa_urls, video_id, video_title, ie=APAIE.ie_key())
 3461 
 3462         foxnews_urls = FoxNewsIE._extract_urls(webpage)
 3463         if foxnews_urls:
 3464             return self.playlist_from_matches(
 3465                 foxnews_urls, video_id, video_title, ie=FoxNewsIE.ie_key())
 3466 
 3467         sharevideos_urls = [sharevideos_mobj.group('url') for sharevideos_mobj in re.finditer(
 3468             r'<iframe[^>]+?\bsrc\s*=\s*(["\'])(?P<url>(?:https?:)?//embed\.share-videos\.se/auto/embed/\d+\?.*?\buid=\d+.*?)\1',
 3469             webpage)]
 3470         if sharevideos_urls:
 3471             return self.playlist_from_matches(
 3472                 sharevideos_urls, video_id, video_title)
 3473 
 3474         viqeo_urls = ViqeoIE._extract_urls(webpage)
 3475         if viqeo_urls:
 3476             return self.playlist_from_matches(
 3477                 viqeo_urls, video_id, video_title, ie=ViqeoIE.ie_key())
 3478 
 3479         expressen_urls = ExpressenIE._extract_urls(webpage)
 3480         if expressen_urls:
 3481             return self.playlist_from_matches(
 3482                 expressen_urls, video_id, video_title, ie=ExpressenIE.ie_key())
 3483 
 3484         zype_urls = ZypeIE._extract_urls(webpage)
 3485         if zype_urls:
 3486             return self.playlist_from_matches(
 3487                 zype_urls, video_id, video_title, ie=ZypeIE.ie_key())
 3488 
 3489         # Look for HTML5 media
 3490         entries = self._parse_html5_media_entries(url, webpage, video_id, m3u8_id='hls')
 3491         if entries:
 3492             if len(entries) == 1:
 3493                 entries[0].update({
 3494                     'id': video_id,
 3495                     'title': video_title,
 3496                 })
 3497             else:
 3498                 for num, entry in enumerate(entries, start=1):
 3499                     entry.update({
 3500                         'id': '%s-%s' % (video_id, num),
 3501                         'title': '%s (%d)' % (video_title, num),
 3502                     })
 3503             for entry in entries:
 3504                 self._sort_formats(entry['formats'])
 3505             return self.playlist_result(entries, video_id, video_title)
 3506 
 3507         jwplayer_data = self._find_jwplayer_data(
 3508             webpage, video_id, transform_source=js_to_json)
 3509         if jwplayer_data:
 3510             try:
 3511                 info = self._parse_jwplayer_data(
 3512                     jwplayer_data, video_id, require_title=False, base_url=url)
 3513                 return merge_dicts(info, info_dict)
 3514             except ExtractorError:
 3515                 # See https://github.com/ytdl-org/youtube-dl/pull/16735
 3516                 pass
 3517 
 3518         # Video.js embed
 3519         mobj = re.search(
 3520             r'(?s)\bvideojs\s*\(.+?\.src\s*\(\s*((?:\[.+?\]|{.+?}))\s*\)\s*;',
 3521             webpage)
 3522         if mobj is not None:
 3523             sources = self._parse_json(
 3524                 mobj.group(1), video_id, transform_source=js_to_json,
 3525                 fatal=False) or []
 3526             if not isinstance(sources, list):
 3527                 sources = [sources]
 3528             formats = []
 3529             for source in sources:
 3530                 src = source.get('src')
 3531                 if not src or not isinstance(src, compat_str):
 3532                     continue
 3533                 src = compat_urlparse.urljoin(url, src)
 3534                 src_type = source.get('type')
 3535                 if isinstance(src_type, compat_str):
 3536                     src_type = src_type.lower()
 3537                 ext = determine_ext(src).lower()
 3538                 if src_type == 'video/youtube':
 3539                     return self.url_result(src, YoutubeIE.ie_key())
 3540                 if src_type == 'application/dash+xml' or ext == 'mpd':
 3541                     formats.extend(self._extract_mpd_formats(
 3542                         src, video_id, mpd_id='dash', fatal=False))
 3543                 elif src_type == 'application/x-mpegurl' or ext == 'm3u8':
 3544                     formats.extend(self._extract_m3u8_formats(
 3545                         src, video_id, 'mp4', entry_protocol='m3u8_native',
 3546                         m3u8_id='hls', fatal=False))
 3547                 else:
 3548                     formats.append({
 3549                         'url': src,
 3550                         'ext': (mimetype2ext(src_type)
 3551                                 or ext if ext in KNOWN_EXTENSIONS else 'mp4'),
 3552                         'http_headers': {
 3553                             'Referer': full_response.geturl(),
 3554                         },
 3555                     })
 3556             if formats:
 3557                 self._sort_formats(formats)
 3558                 info_dict['formats'] = formats
 3559                 return info_dict
 3560 
 3561         # Look for generic KVS player (before ld+json for tests)
 3562         found = re.search(
 3563             r'<script\b[^>]+?\bsrc\s*=\s*(["\'])https?://(?:\S+?/)+kt_player\.js\?v=(?P<ver>(?P<maj_ver>\d+)(\.\d+)+)\1[^>]*>',
 3564             webpage)
 3565         if found:
 3566             self.report_extraction('KVS Player')
 3567             if found.group('maj_ver') not in ('4', '5', '6'):
 3568                 self.report_warning('Untested major version (%s) in player engine - download may fail.' % (found.group('ver'), ))
 3569             return merge_dicts(
 3570                 self._extract_kvs(url, webpage, video_id),
 3571                 info_dict)
 3572 
 3573         # Looking for http://schema.org/VideoObject
 3574         json_ld = self._search_json_ld(
 3575             webpage, video_id, default={}, expected_type='VideoObject')
 3576         if json_ld.get('url'):
 3577             return merge_dicts(json_ld, info_dict)
 3578 
 3579         def check_video(vurl):
 3580             if YoutubeIE.suitable(vurl):
 3581                 return True
 3582             if RtmpIE.suitable(vurl):
 3583                 return True
 3584             vpath = compat_urlparse.urlparse(vurl).path
 3585             vext = determine_ext(vpath)
 3586             return '.' in vpath and vext not in ('swf', 'png', 'jpg', 'srt', 'sbv', 'sub', 'vtt', 'ttml', 'js', 'xml')
 3587 
 3588         def filter_video(urls):
 3589             return list(filter(check_video, urls))
 3590 
 3591         # Start with something easy: JW Player in SWFObject
 3592         found = filter_video(re.findall(r'flashvars: [\'"](?:.*&)?file=(http[^\'"&]*)', webpage))
 3593         if not found:
 3594             # Look for gorilla-vid style embedding
 3595             found = filter_video(re.findall(r'''(?sx)
 3596                 (?:
 3597                     jw_plugins|
 3598                     JWPlayerOptions|
 3599                     jwplayer\s*\(\s*["'][^'"]+["']\s*\)\s*\.setup
 3600                 )
 3601                 .*?
 3602                 ['"]?file['"]?\s*:\s*["\'](.*?)["\']''', webpage))
 3603         if not found:
 3604             # Broaden the search a little bit
 3605             found = filter_video(re.findall(r'[^A-Za-z0-9]?(?:file|source)=(http[^\'"&]*)', webpage))
 3606         if not found:
 3607             # Broaden the findall a little bit: JWPlayer JS loader
 3608             found = filter_video(re.findall(
 3609                 r'[^A-Za-z0-9]?(?:file|video_url)["\']?:\s*["\'](http(?![^\'"]+\.[0-9]+[\'"])[^\'"]+)["\']', webpage))
 3610         if not found:
 3611             # Flow player
 3612             found = filter_video(re.findall(r'''(?xs)
 3613                 flowplayer\("[^"]+",\s*
 3614                     \{[^}]+?\}\s*,
 3615                     \s*\{[^}]+? ["']?clip["']?\s*:\s*\{\s*
 3616                         ["']?url["']?\s*:\s*["']([^"']+)["']
 3617             ''', webpage))
 3618         if not found:
 3619             # Cinerama player
 3620             found = re.findall(
 3621                 r"cinerama\.embedPlayer\(\s*\'[^']+\',\s*'([^']+)'", webpage)
 3622         if not found:
 3623             # Try to find twitter cards info
 3624             # twitter:player:stream should be checked before twitter:player since
 3625             # it is expected to contain a raw stream (see
 3626             # https://dev.twitter.com/cards/types/player#On_twitter.com_via_desktop_browser)
 3627             found = filter_video(re.findall(
 3628                 r'<meta (?:property|name)="twitter:player:stream" (?:content|value)="(.+?)"', webpage))
 3629         if not found:
 3630             # We look for Open Graph info:
 3631             # We have to match any number spaces between elements, some sites try to align them (eg.: statigr.am)
 3632             m_video_type = re.findall(r'<meta.*?property="og:video:type".*?content="video/(.*?)"', webpage)
 3633             # We only look in og:video if the MIME type is a video, don't try if it's a Flash player:
 3634             if m_video_type is not None:
 3635                 found = filter_video(re.findall(r'<meta.*?property="og:(?:video|audio)".*?content="(.*?)"', webpage))
 3636         if not found:
 3637             REDIRECT_REGEX = r'[0-9]{,2};\s*(?:URL|url)=\'?([^\'"]+)'
 3638             found = re.search(
 3639                 r'(?i)<meta\s+(?=(?:[a-z-]+="[^"]+"\s+)*http-equiv="refresh")'
 3640                 r'(?:[a-z-]+="[^"]+"\s+)*?content="%s' % REDIRECT_REGEX,
 3641                 webpage)
 3642             if not found:
 3643                 # Look also in Refresh HTTP header
 3644                 refresh_header = head_response.headers.get('Refresh')
 3645                 if refresh_header:
 3646                     # In python 2 response HTTP headers are bytestrings
 3647                     if sys.version_info < (3, 0) and isinstance(refresh_header, str):
 3648                         refresh_header = refresh_header.decode('iso-8859-1')
 3649                     found = re.search(REDIRECT_REGEX, refresh_header)
 3650             if found:
 3651                 new_url = compat_urlparse.urljoin(url, unescapeHTML(found.group(1)))
 3652                 if new_url != url:
 3653                     self.report_following_redirect(new_url)
 3654                     return {
 3655                         '_type': 'url',
 3656                         'url': new_url,
 3657                     }
 3658                 else:
 3659                     found = None
 3660 
 3661         if not found:
 3662             # twitter:player is a https URL to iframe player that may or may not
 3663             # be supported by youtube-dl thus this is checked the very last (see
 3664             # https://dev.twitter.com/cards/types/player#On_twitter.com_via_desktop_browser)
 3665             embed_url = self._html_search_meta('twitter:player', webpage, default=None)
 3666             if embed_url and embed_url != url:
 3667                 return self.url_result(embed_url)
 3668 
 3669         if not found:
 3670             raise UnsupportedError(url)
 3671 
 3672         entries = []
 3673         for video_url in orderedSet(found):
 3674             video_url = unescapeHTML(video_url)
 3675             video_url = video_url.replace('\\/', '/')
 3676             video_url = compat_urlparse.urljoin(url, video_url)
 3677             video_id = compat_urllib_parse_unquote(os.path.basename(video_url))
 3678 
 3679             # Sometimes, jwplayer extraction will result in a YouTube URL
 3680             if YoutubeIE.suitable(video_url):
 3681                 entries.append(self.url_result(video_url, 'Youtube'))
 3682                 continue
 3683 
 3684             # here's a fun little line of code for you:
 3685             video_id = os.path.splitext(video_id)[0]
 3686 
 3687             entry_info_dict = {
 3688                 'id': video_id,
 3689                 'uploader': video_uploader,
 3690                 'title': video_title,
 3691                 'age_limit': age_limit,
 3692             }
 3693 
 3694             if RtmpIE.suitable(video_url):
 3695                 entry_info_dict.update({
 3696                     '_type': 'url_transparent',
 3697                     'ie_key': RtmpIE.ie_key(),
 3698                     'url': video_url,
 3699                 })
 3700                 entries.append(entry_info_dict)
 3701                 continue
 3702 
 3703             ext = determine_ext(video_url)
 3704             if ext == 'smil':
 3705                 entry_info_dict['formats'] = self._extract_smil_formats(video_url, video_id)
 3706             elif ext == 'xspf':
 3707                 return self.playlist_result(self._extract_xspf_playlist(video_url, video_id), video_id)
 3708             elif ext == 'm3u8':
 3709                 entry_info_dict['formats'] = self._extract_m3u8_formats(video_url, video_id, ext='mp4')
 3710             elif ext == 'mpd':
 3711                 entry_info_dict['formats'] = self._extract_mpd_formats(video_url, video_id)
 3712             elif ext == 'f4m':
 3713                 entry_info_dict['formats'] = self._extract_f4m_formats(video_url, video_id)
 3714             elif re.search(r'(?i)\.(?:ism|smil)/manifest', video_url) and video_url != url:
 3715                 # Just matching .ism/manifest is not enough to be reliably sure
 3716                 # whether it's actually an ISM manifest or some other streaming
 3717                 # manifest since there are various streaming URL formats
 3718                 # possible (see [1]) as well as some other shenanigans like
 3719                 # .smil/manifest URLs that actually serve an ISM (see [2]) and
 3720                 # so on.
 3721                 # Thus the most reasonable way to solve this is to delegate
 3722                 # to generic extractor in order to look into the contents of
 3723                 # the manifest itself.
 3724                 # 1. https://azure.microsoft.com/en-us/documentation/articles/media-services-deliver-content-overview/#streaming-url-formats
 3725                 # 2. https://svs.itworkscdn.net/lbcivod/smil:itwfcdn/lbci/170976.smil/Manifest
 3726                 entry_info_dict = self.url_result(
 3727                     smuggle_url(video_url, {'to_generic': True}),
 3728                     GenericIE.ie_key())
 3729             else:
 3730                 entry_info_dict['url'] = video_url
 3731 
 3732             if entry_info_dict.get('formats'):
 3733                 self._sort_formats(entry_info_dict['formats'])
 3734 
 3735             entries.append(entry_info_dict)
 3736 
 3737         if len(entries) == 1:
 3738             return entries[0]
 3739         else:
 3740             for num, e in enumerate(entries, start=1):
 3741                 # 'url' results don't have a title
 3742                 if e.get('title') is not None:
 3743                     e['title'] = '%s (%d)' % (e['title'], num)
 3744             return {
 3745                 '_type': 'playlist',
 3746                 'entries': entries,
 3747             }

Generated by cgit