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

Generated by cgit