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