4 from __future__ import unicode_literals
6 # Allow direct execution
10 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
14 from test.helper import FakeYDL, assertRegexpMatches
15 from youtube_dl import YoutubeDL
16 from youtube_dl.compat import compat_str, compat_urllib_error
17 from youtube_dl.extractor import YoutubeIE
18 from youtube_dl.extractor.common import InfoExtractor
19 from youtube_dl.postprocessor.common import PostProcessor
20 from youtube_dl.utils import ExtractorError, match_filter_func
22 TEST_URL = 'http://localhost/sample.mp4'
26 def __init__(self, *args, **kwargs):
27 super(YDL, self).__init__(*args, **kwargs)
28 self.downloaded_info_dicts = []
31 def process_info(self, info_dict):
32 self.downloaded_info_dicts.append(info_dict)
34 def to_screen(self, msg):
38 def _make_result(formats, **kwargs):
42 'title': 'testttitle',
43 'extractor': 'testex',
44 'extractor_key': 'TestEx',
50 class TestFormatSelection(unittest.TestCase):
51 def test_prefer_free_formats(self):
52 # Same resolution => download webm
54 ydl.params['prefer_free_formats'] = True
56 {'ext': 'webm', 'height': 460, 'url': TEST_URL},
57 {'ext': 'mp4', 'height': 460, 'url': TEST_URL},
59 info_dict = _make_result(formats)
61 yie._sort_formats(info_dict['formats'])
62 ydl.process_ie_result(info_dict)
63 downloaded = ydl.downloaded_info_dicts[0]
64 self.assertEqual(downloaded['ext'], 'webm')
66 # Different resolution => download best quality (mp4)
68 ydl.params['prefer_free_formats'] = True
70 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
71 {'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
73 info_dict['formats'] = formats
75 yie._sort_formats(info_dict['formats'])
76 ydl.process_ie_result(info_dict)
77 downloaded = ydl.downloaded_info_dicts[0]
78 self.assertEqual(downloaded['ext'], 'mp4')
80 # No prefer_free_formats => prefer mp4 and flv for greater compatibility
82 ydl.params['prefer_free_formats'] = False
84 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
85 {'ext': 'mp4', 'height': 720, 'url': TEST_URL},
86 {'ext': 'flv', 'height': 720, 'url': TEST_URL},
88 info_dict['formats'] = formats
90 yie._sort_formats(info_dict['formats'])
91 ydl.process_ie_result(info_dict)
92 downloaded = ydl.downloaded_info_dicts[0]
93 self.assertEqual(downloaded['ext'], 'mp4')
96 ydl.params['prefer_free_formats'] = False
98 {'ext': 'flv', 'height': 720, 'url': TEST_URL},
99 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
101 info_dict['formats'] = formats
103 yie._sort_formats(info_dict['formats'])
104 ydl.process_ie_result(info_dict)
105 downloaded = ydl.downloaded_info_dicts[0]
106 self.assertEqual(downloaded['ext'], 'flv')
108 def test_format_selection(self):
110 {'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
111 {'format_id': 'example-with-dashes', 'ext': 'webm', 'preference': 1, 'url': TEST_URL},
112 {'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': TEST_URL},
113 {'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': TEST_URL},
114 {'format_id': '2', 'ext': 'flv', 'preference': 4, 'url': TEST_URL},
116 info_dict = _make_result(formats)
118 ydl = YDL({'format': '20/47'})
119 ydl.process_ie_result(info_dict.copy())
120 downloaded = ydl.downloaded_info_dicts[0]
121 self.assertEqual(downloaded['format_id'], '47')
123 ydl = YDL({'format': '20/71/worst'})
124 ydl.process_ie_result(info_dict.copy())
125 downloaded = ydl.downloaded_info_dicts[0]
126 self.assertEqual(downloaded['format_id'], '35')
129 ydl.process_ie_result(info_dict.copy())
130 downloaded = ydl.downloaded_info_dicts[0]
131 self.assertEqual(downloaded['format_id'], '2')
133 ydl = YDL({'format': 'webm/mp4'})
134 ydl.process_ie_result(info_dict.copy())
135 downloaded = ydl.downloaded_info_dicts[0]
136 self.assertEqual(downloaded['format_id'], '47')
138 ydl = YDL({'format': '3gp/40/mp4'})
139 ydl.process_ie_result(info_dict.copy())
140 downloaded = ydl.downloaded_info_dicts[0]
141 self.assertEqual(downloaded['format_id'], '35')
143 ydl = YDL({'format': 'example-with-dashes'})
144 ydl.process_ie_result(info_dict.copy())
145 downloaded = ydl.downloaded_info_dicts[0]
146 self.assertEqual(downloaded['format_id'], 'example-with-dashes')
148 def test_format_selection_audio(self):
150 {'format_id': 'audio-low', 'ext': 'webm', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
151 {'format_id': 'audio-mid', 'ext': 'webm', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
152 {'format_id': 'audio-high', 'ext': 'flv', 'preference': 3, 'vcodec': 'none', 'url': TEST_URL},
153 {'format_id': 'vid', 'ext': 'mp4', 'preference': 4, 'url': TEST_URL},
155 info_dict = _make_result(formats)
157 ydl = YDL({'format': 'bestaudio'})
158 ydl.process_ie_result(info_dict.copy())
159 downloaded = ydl.downloaded_info_dicts[0]
160 self.assertEqual(downloaded['format_id'], 'audio-high')
162 ydl = YDL({'format': 'worstaudio'})
163 ydl.process_ie_result(info_dict.copy())
164 downloaded = ydl.downloaded_info_dicts[0]
165 self.assertEqual(downloaded['format_id'], 'audio-low')
168 {'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
169 {'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
171 info_dict = _make_result(formats)
173 ydl = YDL({'format': 'bestaudio/worstaudio/best'})
174 ydl.process_ie_result(info_dict.copy())
175 downloaded = ydl.downloaded_info_dicts[0]
176 self.assertEqual(downloaded['format_id'], 'vid-high')
178 def test_format_selection_audio_exts(self):
180 {'format_id': 'mp3-64', 'ext': 'mp3', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
181 {'format_id': 'ogg-64', 'ext': 'ogg', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
182 {'format_id': 'aac-64', 'ext': 'aac', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
183 {'format_id': 'mp3-32', 'ext': 'mp3', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
184 {'format_id': 'aac-32', 'ext': 'aac', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
187 info_dict = _make_result(formats)
188 ydl = YDL({'format': 'best'})
190 ie._sort_formats(info_dict['formats'])
191 ydl.process_ie_result(copy.deepcopy(info_dict))
192 downloaded = ydl.downloaded_info_dicts[0]
193 self.assertEqual(downloaded['format_id'], 'aac-64')
195 ydl = YDL({'format': 'mp3'})
197 ie._sort_formats(info_dict['formats'])
198 ydl.process_ie_result(copy.deepcopy(info_dict))
199 downloaded = ydl.downloaded_info_dicts[0]
200 self.assertEqual(downloaded['format_id'], 'mp3-64')
202 ydl = YDL({'prefer_free_formats': True})
204 ie._sort_formats(info_dict['formats'])
205 ydl.process_ie_result(copy.deepcopy(info_dict))
206 downloaded = ydl.downloaded_info_dicts[0]
207 self.assertEqual(downloaded['format_id'], 'ogg-64')
209 def test_format_selection_video(self):
211 {'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': TEST_URL},
212 {'format_id': 'dash-video-high', 'ext': 'mp4', 'preference': 2, 'acodec': 'none', 'url': TEST_URL},
213 {'format_id': 'vid', 'ext': 'mp4', 'preference': 3, 'url': TEST_URL},
215 info_dict = _make_result(formats)
217 ydl = YDL({'format': 'bestvideo'})
218 ydl.process_ie_result(info_dict.copy())
219 downloaded = ydl.downloaded_info_dicts[0]
220 self.assertEqual(downloaded['format_id'], 'dash-video-high')
222 ydl = YDL({'format': 'worstvideo'})
223 ydl.process_ie_result(info_dict.copy())
224 downloaded = ydl.downloaded_info_dicts[0]
225 self.assertEqual(downloaded['format_id'], 'dash-video-low')
227 ydl = YDL({'format': 'bestvideo[format_id^=dash][format_id$=low]'})
228 ydl.process_ie_result(info_dict.copy())
229 downloaded = ydl.downloaded_info_dicts[0]
230 self.assertEqual(downloaded['format_id'], 'dash-video-low')
233 {'format_id': 'vid-vcodec-dot', 'ext': 'mp4', 'preference': 1, 'vcodec': 'avc1.123456', 'acodec': 'none', 'url': TEST_URL},
235 info_dict = _make_result(formats)
237 ydl = YDL({'format': 'bestvideo[vcodec=avc1.123456]'})
238 ydl.process_ie_result(info_dict.copy())
239 downloaded = ydl.downloaded_info_dicts[0]
240 self.assertEqual(downloaded['format_id'], 'vid-vcodec-dot')
242 def test_format_selection_string_ops(self):
244 {'format_id': 'abc-cba', 'ext': 'mp4', 'url': TEST_URL},
246 info_dict = _make_result(formats)
249 ydl = YDL({'format': '[format_id=abc-cba]'})
250 ydl.process_ie_result(info_dict.copy())
251 downloaded = ydl.downloaded_info_dicts[0]
252 self.assertEqual(downloaded['format_id'], 'abc-cba')
254 # does not equal (!=)
255 ydl = YDL({'format': '[format_id!=abc-cba]'})
256 self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
259 ydl = YDL({'format': '[format_id^=abc]'})
260 ydl.process_ie_result(info_dict.copy())
261 downloaded = ydl.downloaded_info_dicts[0]
262 self.assertEqual(downloaded['format_id'], 'abc-cba')
264 # does not start with (!^=)
265 ydl = YDL({'format': '[format_id!^=abc-cba]'})
266 self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
269 ydl = YDL({'format': '[format_id$=cba]'})
270 ydl.process_ie_result(info_dict.copy())
271 downloaded = ydl.downloaded_info_dicts[0]
272 self.assertEqual(downloaded['format_id'], 'abc-cba')
274 # does not end with (!$=)
275 ydl = YDL({'format': '[format_id!$=abc-cba]'})
276 self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
279 ydl = YDL({'format': '[format_id*=-]'})
280 ydl.process_ie_result(info_dict.copy())
281 downloaded = ydl.downloaded_info_dicts[0]
282 self.assertEqual(downloaded['format_id'], 'abc-cba')
284 # does not contain (!*=)
285 ydl = YDL({'format': '[format_id!*=-]'})
286 self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
288 def test_youtube_format_selection(self):
290 '38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '17', '36', '13',
291 # Apple HTTP Live Streaming
292 '96', '95', '94', '93', '92', '132', '151',
294 '85', '84', '102', '83', '101', '82', '100',
296 '137', '248', '136', '247', '135', '246',
297 '245', '244', '134', '243', '133', '242', '160',
299 '141', '172', '140', '171', '139',
302 def format_info(f_id):
303 info = YoutubeIE._formats[f_id].copy()
305 # XXX: In real cases InfoExtractor._parse_mpd_formats() fills up 'acodec'
306 # and 'vcodec', while in tests such information is incomplete since
307 # commit a6c2c24479e5f4827ceb06f64d855329c0a6f593
308 # test_YoutubeDL.test_youtube_format_selection is broken without
310 if 'acodec' in info and 'vcodec' not in info:
311 info['vcodec'] = 'none'
312 elif 'vcodec' in info and 'acodec' not in info:
313 info['acodec'] = 'none'
315 info['format_id'] = f_id
316 info['url'] = 'url:' + f_id
318 formats_order = [format_info(f_id) for f_id in order]
320 info_dict = _make_result(list(formats_order), extractor='youtube')
321 ydl = YDL({'format': 'bestvideo+bestaudio'})
323 yie._sort_formats(info_dict['formats'])
324 ydl.process_ie_result(info_dict)
325 downloaded = ydl.downloaded_info_dicts[0]
326 self.assertEqual(downloaded['format_id'], '137+141')
327 self.assertEqual(downloaded['ext'], 'mp4')
329 info_dict = _make_result(list(formats_order), extractor='youtube')
330 ydl = YDL({'format': 'bestvideo[height>=999999]+bestaudio/best'})
332 yie._sort_formats(info_dict['formats'])
333 ydl.process_ie_result(info_dict)
334 downloaded = ydl.downloaded_info_dicts[0]
335 self.assertEqual(downloaded['format_id'], '38')
337 info_dict = _make_result(list(formats_order), extractor='youtube')
338 ydl = YDL({'format': 'bestvideo/best,bestaudio'})
340 yie._sort_formats(info_dict['formats'])
341 ydl.process_ie_result(info_dict)
342 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
343 self.assertEqual(downloaded_ids, ['137', '141'])
345 info_dict = _make_result(list(formats_order), extractor='youtube')
346 ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])+bestaudio'})
348 yie._sort_formats(info_dict['formats'])
349 ydl.process_ie_result(info_dict)
350 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
351 self.assertEqual(downloaded_ids, ['137+141', '248+141'])
353 info_dict = _make_result(list(formats_order), extractor='youtube')
354 ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])[height<=720]+bestaudio'})
356 yie._sort_formats(info_dict['formats'])
357 ydl.process_ie_result(info_dict)
358 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
359 self.assertEqual(downloaded_ids, ['136+141', '247+141'])
361 info_dict = _make_result(list(formats_order), extractor='youtube')
362 ydl = YDL({'format': '(bestvideo[ext=none]/bestvideo[ext=webm])+bestaudio'})
364 yie._sort_formats(info_dict['formats'])
365 ydl.process_ie_result(info_dict)
366 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
367 self.assertEqual(downloaded_ids, ['248+141'])
369 for f1, f2 in zip(formats_order, formats_order[1:]):
370 info_dict = _make_result([f1, f2], extractor='youtube')
371 ydl = YDL({'format': 'best/bestvideo'})
373 yie._sort_formats(info_dict['formats'])
374 ydl.process_ie_result(info_dict)
375 downloaded = ydl.downloaded_info_dicts[0]
376 self.assertEqual(downloaded['format_id'], f1['format_id'])
378 info_dict = _make_result([f2, f1], extractor='youtube')
379 ydl = YDL({'format': 'best/bestvideo'})
381 yie._sort_formats(info_dict['formats'])
382 ydl.process_ie_result(info_dict)
383 downloaded = ydl.downloaded_info_dicts[0]
384 self.assertEqual(downloaded['format_id'], f1['format_id'])
386 def test_audio_only_extractor_format_selection(self):
387 # For extractors with incomplete formats (all formats are audio-only or
388 # video-only) best and worst should fallback to corresponding best/worst
389 # video-only or audio-only formats (as per
390 # https://github.com/rg3/youtube-dl/pull/5556)
392 {'format_id': 'low', 'ext': 'mp3', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
393 {'format_id': 'high', 'ext': 'mp3', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
395 info_dict = _make_result(formats)
397 ydl = YDL({'format': 'best'})
398 ydl.process_ie_result(info_dict.copy())
399 downloaded = ydl.downloaded_info_dicts[0]
400 self.assertEqual(downloaded['format_id'], 'high')
402 ydl = YDL({'format': 'worst'})
403 ydl.process_ie_result(info_dict.copy())
404 downloaded = ydl.downloaded_info_dicts[0]
405 self.assertEqual(downloaded['format_id'], 'low')
407 def test_format_not_available(self):
409 {'format_id': 'regular', 'ext': 'mp4', 'height': 360, 'url': TEST_URL},
410 {'format_id': 'video', 'ext': 'mp4', 'height': 720, 'acodec': 'none', 'url': TEST_URL},
412 info_dict = _make_result(formats)
414 # This must fail since complete video-audio format does not match filter
415 # and extractor does not provide incomplete only formats (i.e. only
416 # video-only or audio-only).
417 ydl = YDL({'format': 'best[height>360]'})
418 self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
420 def test_format_selection_issue_10083(self):
421 # See https://github.com/rg3/youtube-dl/issues/10083
423 {'format_id': 'regular', 'height': 360, 'url': TEST_URL},
424 {'format_id': 'video', 'height': 720, 'acodec': 'none', 'url': TEST_URL},
425 {'format_id': 'audio', 'vcodec': 'none', 'url': TEST_URL},
427 info_dict = _make_result(formats)
429 ydl = YDL({'format': 'best[height>360]/bestvideo[height>360]+bestaudio'})
430 ydl.process_ie_result(info_dict.copy())
431 self.assertEqual(ydl.downloaded_info_dicts[0]['format_id'], 'video+audio')
433 def test_invalid_format_specs(self):
434 def assert_syntax_error(format_spec):
435 ydl = YDL({'format': format_spec})
436 info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
437 self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
439 assert_syntax_error('bestvideo,,best')
440 assert_syntax_error('+bestaudio')
441 assert_syntax_error('bestvideo+')
442 assert_syntax_error('/')
444 def test_format_filtering(self):
446 {'format_id': 'A', 'filesize': 500, 'width': 1000},
447 {'format_id': 'B', 'filesize': 1000, 'width': 500},
448 {'format_id': 'C', 'filesize': 1000, 'width': 400},
449 {'format_id': 'D', 'filesize': 2000, 'width': 600},
450 {'format_id': 'E', 'filesize': 3000},
452 {'format_id': 'G', 'filesize': 1000000},
455 f['url'] = 'http://_/'
457 info_dict = _make_result(formats)
459 ydl = YDL({'format': 'best[filesize<3000]'})
460 ydl.process_ie_result(info_dict)
461 downloaded = ydl.downloaded_info_dicts[0]
462 self.assertEqual(downloaded['format_id'], 'D')
464 ydl = YDL({'format': 'best[filesize<=3000]'})
465 ydl.process_ie_result(info_dict)
466 downloaded = ydl.downloaded_info_dicts[0]
467 self.assertEqual(downloaded['format_id'], 'E')
469 ydl = YDL({'format': 'best[filesize <= ? 3000]'})
470 ydl.process_ie_result(info_dict)
471 downloaded = ydl.downloaded_info_dicts[0]
472 self.assertEqual(downloaded['format_id'], 'F')
474 ydl = YDL({'format': 'best [filesize = 1000] [width>450]'})
475 ydl.process_ie_result(info_dict)
476 downloaded = ydl.downloaded_info_dicts[0]
477 self.assertEqual(downloaded['format_id'], 'B')
479 ydl = YDL({'format': 'best [filesize = 1000] [width!=450]'})
480 ydl.process_ie_result(info_dict)
481 downloaded = ydl.downloaded_info_dicts[0]
482 self.assertEqual(downloaded['format_id'], 'C')
484 ydl = YDL({'format': '[filesize>?1]'})
485 ydl.process_ie_result(info_dict)
486 downloaded = ydl.downloaded_info_dicts[0]
487 self.assertEqual(downloaded['format_id'], 'G')
489 ydl = YDL({'format': '[filesize<1M]'})
490 ydl.process_ie_result(info_dict)
491 downloaded = ydl.downloaded_info_dicts[0]
492 self.assertEqual(downloaded['format_id'], 'E')
494 ydl = YDL({'format': '[filesize<1MiB]'})
495 ydl.process_ie_result(info_dict)
496 downloaded = ydl.downloaded_info_dicts[0]
497 self.assertEqual(downloaded['format_id'], 'G')
499 ydl = YDL({'format': 'all[width>=400][width<=600]'})
500 ydl.process_ie_result(info_dict)
501 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
502 self.assertEqual(downloaded_ids, ['B', 'C', 'D'])
504 ydl = YDL({'format': 'best[height<40]'})
506 ydl.process_ie_result(info_dict)
507 except ExtractorError:
509 self.assertEqual(ydl.downloaded_info_dicts, [])
511 def test_default_format_spec(self):
512 ydl = YDL({'simulate': True})
513 self.assertEqual(ydl._default_format_spec({}), 'bestvideo+bestaudio/best')
516 self.assertEqual(ydl._default_format_spec({'is_live': True}), 'best/bestvideo+bestaudio')
518 ydl = YDL({'simulate': True})
519 self.assertEqual(ydl._default_format_spec({'is_live': True}), 'bestvideo+bestaudio/best')
521 ydl = YDL({'outtmpl': '-'})
522 self.assertEqual(ydl._default_format_spec({}), 'best/bestvideo+bestaudio')
525 self.assertEqual(ydl._default_format_spec({}, download=False), 'bestvideo+bestaudio/best')
526 self.assertEqual(ydl._default_format_spec({'is_live': True}), 'best/bestvideo+bestaudio')
529 class TestYoutubeDL(unittest.TestCase):
530 def test_subtitles(self):
531 def s_formats(lang, autocaption=False):
534 'url': 'http://localhost/video.%s.%s' % (lang, ext),
535 '_auto': autocaption,
536 } for ext in ['vtt', 'srt', 'ass']]
537 subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
538 auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
542 'url': 'http://localhost/video.mp4',
543 'subtitles': subtitles,
544 'automatic_captions': auto_captions,
548 def get_info(params={}):
549 params.setdefault('simulate', True)
551 ydl.report_warning = lambda *args, **kargs: None
552 return ydl.process_video_result(info_dict, download=False)
555 self.assertFalse(result.get('requested_subtitles'))
556 self.assertEqual(result['subtitles'], subtitles)
557 self.assertEqual(result['automatic_captions'], auto_captions)
559 result = get_info({'writesubtitles': True})
560 subs = result['requested_subtitles']
561 self.assertTrue(subs)
562 self.assertEqual(set(subs.keys()), set(['en']))
563 self.assertTrue(subs['en'].get('data') is None)
564 self.assertEqual(subs['en']['ext'], 'ass')
566 result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
567 subs = result['requested_subtitles']
568 self.assertEqual(subs['en']['ext'], 'srt')
570 result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
571 subs = result['requested_subtitles']
572 self.assertTrue(subs)
573 self.assertEqual(set(subs.keys()), set(['es', 'fr']))
575 result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
576 subs = result['requested_subtitles']
577 self.assertTrue(subs)
578 self.assertEqual(set(subs.keys()), set(['es', 'pt']))
579 self.assertFalse(subs['es']['_auto'])
580 self.assertTrue(subs['pt']['_auto'])
582 result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
583 subs = result['requested_subtitles']
584 self.assertTrue(subs)
585 self.assertEqual(set(subs.keys()), set(['es', 'pt']))
586 self.assertTrue(subs['es']['_auto'])
587 self.assertTrue(subs['pt']['_auto'])
589 def test_add_extra_info(self):
595 'playlist': 'funny videos',
597 YDL.add_extra_info(test_dict, extra_info)
598 self.assertEqual(test_dict['extractor'], 'Foo')
599 self.assertEqual(test_dict['playlist'], 'funny videos')
601 def test_prepare_filename(self):
612 ydl = YoutubeDL({'outtmpl': templ})
613 return ydl.prepare_filename(info)
614 self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
615 self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
616 # Replace missing fields with 'NA'
617 self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4')
618 self.assertEqual(fname('%(height)d.%(ext)s'), '1080.mp4')
619 self.assertEqual(fname('%(height)6d.%(ext)s'), ' 1080.mp4')
620 self.assertEqual(fname('%(height)-6d.%(ext)s'), '1080 .mp4')
621 self.assertEqual(fname('%(height)06d.%(ext)s'), '001080.mp4')
622 self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
623 self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
624 self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
625 self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
626 self.assertEqual(fname('%(height) 0 6d.%(ext)s'), ' 01080.mp4')
627 self.assertEqual(fname('%%'), '%')
628 self.assertEqual(fname('%%%%'), '%%')
629 self.assertEqual(fname('%%(height)06d.%(ext)s'), '%(height)06d.mp4')
630 self.assertEqual(fname('%(width)06d.%(ext)s'), 'NA.mp4')
631 self.assertEqual(fname('%(width)06d.%%(ext)s'), 'NA.%(ext)s')
632 self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4')
633 self.assertEqual(fname('Hello %(title1)s'), 'Hello $PATH')
634 self.assertEqual(fname('Hello %(title2)s'), 'Hello %PATH%')
636 def test_format_note(self):
638 self.assertEqual(ydl._format_note({}), '')
639 assertRegexpMatches(self, ydl._format_note({
642 assertRegexpMatches(self, ydl._format_note({
646 def test_postprocessors(self):
647 filename = 'post-processor-testfile.mp4'
648 audiofile = filename + '.mp3'
650 class SimplePP(PostProcessor):
652 with open(audiofile, 'wt') as f:
654 return [info['filepath']], info
656 def run_pp(params, PP):
657 with open(filename, 'wt') as f:
659 ydl = YoutubeDL(params)
660 ydl.add_post_processor(PP())
661 ydl.post_process(filename, {'filepath': filename})
663 run_pp({'keepvideo': True}, SimplePP)
664 self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
665 self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
669 run_pp({'keepvideo': False}, SimplePP)
670 self.assertFalse(os.path.exists(filename), '%s exists' % filename)
671 self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
674 class ModifierPP(PostProcessor):
676 with open(info['filepath'], 'wt') as f:
680 run_pp({'keepvideo': False}, ModifierPP)
681 self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
684 def test_match_filter(self):
685 class FilterYDL(YDL):
686 def __init__(self, *args, **kwargs):
687 super(FilterYDL, self).__init__(*args, **kwargs)
688 self.params['simulate'] = True
690 def process_info(self, info_dict):
691 super(YDL, self).process_info(info_dict)
693 def _match_entry(self, info_dict, incomplete):
694 res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
696 self.downloaded_info_dicts.append(info_dict)
705 'filesize': 10 * 1024,
707 'uploader': "變態妍字幕版 太妍 тест",
708 'creator': "тест ' 123 ' тест--",
716 'description': 'foo',
717 'filesize': 5 * 1024,
719 'uploader': "тест 123",
721 videos = [first, second]
723 def get_videos(filter_=None):
724 ydl = FilterYDL({'match_filter': filter_})
726 ydl.process_ie_result(v, download=True)
727 return [v['id'] for v in ydl.downloaded_info_dicts]
730 self.assertEqual(res, ['1', '2'])
736 return 'Video id is not 1'
738 self.assertEqual(res, ['1'])
740 f = match_filter_func('duration < 30')
742 self.assertEqual(res, ['2'])
744 f = match_filter_func('description = foo')
746 self.assertEqual(res, ['2'])
748 f = match_filter_func('description =? foo')
750 self.assertEqual(res, ['1', '2'])
752 f = match_filter_func('filesize > 5KiB')
754 self.assertEqual(res, ['1'])
756 f = match_filter_func('playlist_id = 42')
758 self.assertEqual(res, ['1'])
760 f = match_filter_func('uploader = "變態妍字幕版 太妍 тест"')
762 self.assertEqual(res, ['1'])
764 f = match_filter_func('uploader != "變態妍字幕版 太妍 тест"')
766 self.assertEqual(res, ['2'])
768 f = match_filter_func('creator = "тест \' 123 \' тест--"')
770 self.assertEqual(res, ['1'])
772 f = match_filter_func("creator = 'тест \\' 123 \\' тест--'")
774 self.assertEqual(res, ['1'])
776 f = match_filter_func(r"creator = 'тест \' 123 \' тест--' & duration > 30")
778 self.assertEqual(res, [])
780 def test_playlist_items_selection(self):
783 'title': compat_str(i),
785 } for i in range(1, 5)]
790 'extractor': 'test:playlist',
791 'extractor_key': 'test:playlist',
792 'webpage_url': 'http://example.com',
797 # make a copy because the dictionary can be modified
798 ydl.process_ie_result(playlist.copy())
799 return [int(v['id']) for v in ydl.downloaded_info_dicts]
802 self.assertEqual(result, [1, 2, 3, 4])
804 result = get_ids({'playlistend': 10})
805 self.assertEqual(result, [1, 2, 3, 4])
807 result = get_ids({'playlistend': 2})
808 self.assertEqual(result, [1, 2])
810 result = get_ids({'playliststart': 10})
811 self.assertEqual(result, [])
813 result = get_ids({'playliststart': 2})
814 self.assertEqual(result, [2, 3, 4])
816 result = get_ids({'playlist_items': '2-4'})
817 self.assertEqual(result, [2, 3, 4])
819 result = get_ids({'playlist_items': '2,4'})
820 self.assertEqual(result, [2, 4])
822 result = get_ids({'playlist_items': '10'})
823 self.assertEqual(result, [])
825 result = get_ids({'playlist_items': '3-10'})
826 self.assertEqual(result, [3, 4])
828 result = get_ids({'playlist_items': '2-4,3-4,3'})
829 self.assertEqual(result, [2, 3, 4])
831 def test_urlopen_no_file_protocol(self):
832 # see https://github.com/rg3/youtube-dl/issues/8227
834 self.assertRaises(compat_urllib_error.URLError, ydl.urlopen, 'file:///etc/passwd')
836 def test_do_not_override_ie_key_in_url_transparent(self):
839 class Foo1IE(InfoExtractor):
840 _VALID_URL = r'foo1:'
842 def _real_extract(self, url):
844 '_type': 'url_transparent',
847 'title': 'foo1 title',
851 class Foo2IE(InfoExtractor):
852 _VALID_URL = r'foo2:'
854 def _real_extract(self, url):
861 class Foo3IE(InfoExtractor):
862 _VALID_URL = r'foo3:'
864 def _real_extract(self, url):
865 return _make_result([{'url': TEST_URL}], title='foo3 title')
867 ydl.add_info_extractor(Foo1IE(ydl))
868 ydl.add_info_extractor(Foo2IE(ydl))
869 ydl.add_info_extractor(Foo3IE(ydl))
870 ydl.extract_info('foo1:')
871 downloaded = ydl.downloaded_info_dicts[0]
872 self.assertEqual(downloaded['url'], TEST_URL)
873 self.assertEqual(downloaded['title'], 'foo1 title')
874 self.assertEqual(downloaded['id'], 'testid')
875 self.assertEqual(downloaded['extractor'], 'testex')
876 self.assertEqual(downloaded['extractor_key'], 'TestEx')
879 if __name__ == '__main__':