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_youtube_format_selection(self):
244 '38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '17', '36', '13',
245 # Apple HTTP Live Streaming
246 '96', '95', '94', '93', '92', '132', '151',
248 '85', '84', '102', '83', '101', '82', '100',
250 '137', '248', '136', '247', '135', '246',
251 '245', '244', '134', '243', '133', '242', '160',
253 '141', '172', '140', '171', '139',
256 def format_info(f_id):
257 info = YoutubeIE._formats[f_id].copy()
259 # XXX: In real cases InfoExtractor._parse_mpd_formats() fills up 'acodec'
260 # and 'vcodec', while in tests such information is incomplete since
261 # commit a6c2c24479e5f4827ceb06f64d855329c0a6f593
262 # test_YoutubeDL.test_youtube_format_selection is broken without
264 if 'acodec' in info and 'vcodec' not in info:
265 info['vcodec'] = 'none'
266 elif 'vcodec' in info and 'acodec' not in info:
267 info['acodec'] = 'none'
269 info['format_id'] = f_id
270 info['url'] = 'url:' + f_id
272 formats_order = [format_info(f_id) for f_id in order]
274 info_dict = _make_result(list(formats_order), extractor='youtube')
275 ydl = YDL({'format': 'bestvideo+bestaudio'})
277 yie._sort_formats(info_dict['formats'])
278 ydl.process_ie_result(info_dict)
279 downloaded = ydl.downloaded_info_dicts[0]
280 self.assertEqual(downloaded['format_id'], '137+141')
281 self.assertEqual(downloaded['ext'], 'mp4')
283 info_dict = _make_result(list(formats_order), extractor='youtube')
284 ydl = YDL({'format': 'bestvideo[height>=999999]+bestaudio/best'})
286 yie._sort_formats(info_dict['formats'])
287 ydl.process_ie_result(info_dict)
288 downloaded = ydl.downloaded_info_dicts[0]
289 self.assertEqual(downloaded['format_id'], '38')
291 info_dict = _make_result(list(formats_order), extractor='youtube')
292 ydl = YDL({'format': 'bestvideo/best,bestaudio'})
294 yie._sort_formats(info_dict['formats'])
295 ydl.process_ie_result(info_dict)
296 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
297 self.assertEqual(downloaded_ids, ['137', '141'])
299 info_dict = _make_result(list(formats_order), extractor='youtube')
300 ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])+bestaudio'})
302 yie._sort_formats(info_dict['formats'])
303 ydl.process_ie_result(info_dict)
304 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
305 self.assertEqual(downloaded_ids, ['137+141', '248+141'])
307 info_dict = _make_result(list(formats_order), extractor='youtube')
308 ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])[height<=720]+bestaudio'})
310 yie._sort_formats(info_dict['formats'])
311 ydl.process_ie_result(info_dict)
312 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
313 self.assertEqual(downloaded_ids, ['136+141', '247+141'])
315 info_dict = _make_result(list(formats_order), extractor='youtube')
316 ydl = YDL({'format': '(bestvideo[ext=none]/bestvideo[ext=webm])+bestaudio'})
318 yie._sort_formats(info_dict['formats'])
319 ydl.process_ie_result(info_dict)
320 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
321 self.assertEqual(downloaded_ids, ['248+141'])
323 for f1, f2 in zip(formats_order, formats_order[1:]):
324 info_dict = _make_result([f1, f2], extractor='youtube')
325 ydl = YDL({'format': 'best/bestvideo'})
327 yie._sort_formats(info_dict['formats'])
328 ydl.process_ie_result(info_dict)
329 downloaded = ydl.downloaded_info_dicts[0]
330 self.assertEqual(downloaded['format_id'], f1['format_id'])
332 info_dict = _make_result([f2, f1], extractor='youtube')
333 ydl = YDL({'format': 'best/bestvideo'})
335 yie._sort_formats(info_dict['formats'])
336 ydl.process_ie_result(info_dict)
337 downloaded = ydl.downloaded_info_dicts[0]
338 self.assertEqual(downloaded['format_id'], f1['format_id'])
340 def test_audio_only_extractor_format_selection(self):
341 # For extractors with incomplete formats (all formats are audio-only or
342 # video-only) best and worst should fallback to corresponding best/worst
343 # video-only or audio-only formats (as per
344 # https://github.com/rg3/youtube-dl/pull/5556)
346 {'format_id': 'low', 'ext': 'mp3', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
347 {'format_id': 'high', 'ext': 'mp3', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
349 info_dict = _make_result(formats)
351 ydl = YDL({'format': 'best'})
352 ydl.process_ie_result(info_dict.copy())
353 downloaded = ydl.downloaded_info_dicts[0]
354 self.assertEqual(downloaded['format_id'], 'high')
356 ydl = YDL({'format': 'worst'})
357 ydl.process_ie_result(info_dict.copy())
358 downloaded = ydl.downloaded_info_dicts[0]
359 self.assertEqual(downloaded['format_id'], 'low')
361 def test_format_not_available(self):
363 {'format_id': 'regular', 'ext': 'mp4', 'height': 360, 'url': TEST_URL},
364 {'format_id': 'video', 'ext': 'mp4', 'height': 720, 'acodec': 'none', 'url': TEST_URL},
366 info_dict = _make_result(formats)
368 # This must fail since complete video-audio format does not match filter
369 # and extractor does not provide incomplete only formats (i.e. only
370 # video-only or audio-only).
371 ydl = YDL({'format': 'best[height>360]'})
372 self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
374 def test_invalid_format_specs(self):
375 def assert_syntax_error(format_spec):
376 ydl = YDL({'format': format_spec})
377 info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
378 self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
380 assert_syntax_error('bestvideo,,best')
381 assert_syntax_error('+bestaudio')
382 assert_syntax_error('bestvideo+')
383 assert_syntax_error('/')
385 def test_format_filtering(self):
387 {'format_id': 'A', 'filesize': 500, 'width': 1000},
388 {'format_id': 'B', 'filesize': 1000, 'width': 500},
389 {'format_id': 'C', 'filesize': 1000, 'width': 400},
390 {'format_id': 'D', 'filesize': 2000, 'width': 600},
391 {'format_id': 'E', 'filesize': 3000},
393 {'format_id': 'G', 'filesize': 1000000},
396 f['url'] = 'http://_/'
398 info_dict = _make_result(formats)
400 ydl = YDL({'format': 'best[filesize<3000]'})
401 ydl.process_ie_result(info_dict)
402 downloaded = ydl.downloaded_info_dicts[0]
403 self.assertEqual(downloaded['format_id'], 'D')
405 ydl = YDL({'format': 'best[filesize<=3000]'})
406 ydl.process_ie_result(info_dict)
407 downloaded = ydl.downloaded_info_dicts[0]
408 self.assertEqual(downloaded['format_id'], 'E')
410 ydl = YDL({'format': 'best[filesize <= ? 3000]'})
411 ydl.process_ie_result(info_dict)
412 downloaded = ydl.downloaded_info_dicts[0]
413 self.assertEqual(downloaded['format_id'], 'F')
415 ydl = YDL({'format': 'best [filesize = 1000] [width>450]'})
416 ydl.process_ie_result(info_dict)
417 downloaded = ydl.downloaded_info_dicts[0]
418 self.assertEqual(downloaded['format_id'], 'B')
420 ydl = YDL({'format': 'best [filesize = 1000] [width!=450]'})
421 ydl.process_ie_result(info_dict)
422 downloaded = ydl.downloaded_info_dicts[0]
423 self.assertEqual(downloaded['format_id'], 'C')
425 ydl = YDL({'format': '[filesize>?1]'})
426 ydl.process_ie_result(info_dict)
427 downloaded = ydl.downloaded_info_dicts[0]
428 self.assertEqual(downloaded['format_id'], 'G')
430 ydl = YDL({'format': '[filesize<1M]'})
431 ydl.process_ie_result(info_dict)
432 downloaded = ydl.downloaded_info_dicts[0]
433 self.assertEqual(downloaded['format_id'], 'E')
435 ydl = YDL({'format': '[filesize<1MiB]'})
436 ydl.process_ie_result(info_dict)
437 downloaded = ydl.downloaded_info_dicts[0]
438 self.assertEqual(downloaded['format_id'], 'G')
440 ydl = YDL({'format': 'all[width>=400][width<=600]'})
441 ydl.process_ie_result(info_dict)
442 downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
443 self.assertEqual(downloaded_ids, ['B', 'C', 'D'])
445 ydl = YDL({'format': 'best[height<40]'})
447 ydl.process_ie_result(info_dict)
448 except ExtractorError:
450 self.assertEqual(ydl.downloaded_info_dicts, [])
452 def test_default_format_spec(self):
453 ydl = YDL({'simulate': True})
454 self.assertEqual(ydl._default_format_spec({}), 'bestvideo+bestaudio/best')
456 ydl = YDL({'outtmpl': '-'})
457 self.assertEqual(ydl._default_format_spec({}), 'best')
460 self.assertEqual(ydl._default_format_spec({}, download=False), 'bestvideo+bestaudio/best')
461 self.assertEqual(ydl._default_format_spec({'is_live': True}), 'best')
464 class TestYoutubeDL(unittest.TestCase):
465 def test_subtitles(self):
466 def s_formats(lang, autocaption=False):
469 'url': 'http://localhost/video.%s.%s' % (lang, ext),
470 '_auto': autocaption,
471 } for ext in ['vtt', 'srt', 'ass']]
472 subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
473 auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
477 'url': 'http://localhost/video.mp4',
478 'subtitles': subtitles,
479 'automatic_captions': auto_captions,
483 def get_info(params={}):
484 params.setdefault('simulate', True)
486 ydl.report_warning = lambda *args, **kargs: None
487 return ydl.process_video_result(info_dict, download=False)
490 self.assertFalse(result.get('requested_subtitles'))
491 self.assertEqual(result['subtitles'], subtitles)
492 self.assertEqual(result['automatic_captions'], auto_captions)
494 result = get_info({'writesubtitles': True})
495 subs = result['requested_subtitles']
496 self.assertTrue(subs)
497 self.assertEqual(set(subs.keys()), set(['en']))
498 self.assertTrue(subs['en'].get('data') is None)
499 self.assertEqual(subs['en']['ext'], 'ass')
501 result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
502 subs = result['requested_subtitles']
503 self.assertEqual(subs['en']['ext'], 'srt')
505 result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
506 subs = result['requested_subtitles']
507 self.assertTrue(subs)
508 self.assertEqual(set(subs.keys()), set(['es', 'fr']))
510 result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
511 subs = result['requested_subtitles']
512 self.assertTrue(subs)
513 self.assertEqual(set(subs.keys()), set(['es', 'pt']))
514 self.assertFalse(subs['es']['_auto'])
515 self.assertTrue(subs['pt']['_auto'])
517 result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
518 subs = result['requested_subtitles']
519 self.assertTrue(subs)
520 self.assertEqual(set(subs.keys()), set(['es', 'pt']))
521 self.assertTrue(subs['es']['_auto'])
522 self.assertTrue(subs['pt']['_auto'])
524 def test_add_extra_info(self):
530 'playlist': 'funny videos',
532 YDL.add_extra_info(test_dict, extra_info)
533 self.assertEqual(test_dict['extractor'], 'Foo')
534 self.assertEqual(test_dict['playlist'], 'funny videos')
536 def test_prepare_filename(self):
547 ydl = YoutubeDL({'outtmpl': templ})
548 return ydl.prepare_filename(info)
549 self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
550 self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
551 # Replace missing fields with 'NA'
552 self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4')
553 self.assertEqual(fname('%(height)d.%(ext)s'), '1080.mp4')
554 self.assertEqual(fname('%(height)6d.%(ext)s'), ' 1080.mp4')
555 self.assertEqual(fname('%(height)-6d.%(ext)s'), '1080 .mp4')
556 self.assertEqual(fname('%(height)06d.%(ext)s'), '001080.mp4')
557 self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
558 self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
559 self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
560 self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
561 self.assertEqual(fname('%(height) 0 6d.%(ext)s'), ' 01080.mp4')
562 self.assertEqual(fname('%%'), '%')
563 self.assertEqual(fname('%%%%'), '%%')
564 self.assertEqual(fname('%%(height)06d.%(ext)s'), '%(height)06d.mp4')
565 self.assertEqual(fname('%(width)06d.%(ext)s'), 'NA.mp4')
566 self.assertEqual(fname('%(width)06d.%%(ext)s'), 'NA.%(ext)s')
567 self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4')
568 self.assertEqual(fname('Hello %(title1)s'), 'Hello $PATH')
569 self.assertEqual(fname('Hello %(title2)s'), 'Hello %PATH%')
571 def test_format_note(self):
573 self.assertEqual(ydl._format_note({}), '')
574 assertRegexpMatches(self, ydl._format_note({
577 assertRegexpMatches(self, ydl._format_note({
581 def test_postprocessors(self):
582 filename = 'post-processor-testfile.mp4'
583 audiofile = filename + '.mp3'
585 class SimplePP(PostProcessor):
587 with open(audiofile, 'wt') as f:
589 return [info['filepath']], info
591 def run_pp(params, PP):
592 with open(filename, 'wt') as f:
594 ydl = YoutubeDL(params)
595 ydl.add_post_processor(PP())
596 ydl.post_process(filename, {'filepath': filename})
598 run_pp({'keepvideo': True}, SimplePP)
599 self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
600 self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
604 run_pp({'keepvideo': False}, SimplePP)
605 self.assertFalse(os.path.exists(filename), '%s exists' % filename)
606 self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
609 class ModifierPP(PostProcessor):
611 with open(info['filepath'], 'wt') as f:
615 run_pp({'keepvideo': False}, ModifierPP)
616 self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
619 def test_match_filter(self):
620 class FilterYDL(YDL):
621 def __init__(self, *args, **kwargs):
622 super(FilterYDL, self).__init__(*args, **kwargs)
623 self.params['simulate'] = True
625 def process_info(self, info_dict):
626 super(YDL, self).process_info(info_dict)
628 def _match_entry(self, info_dict, incomplete):
629 res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
631 self.downloaded_info_dicts.append(info_dict)
640 'filesize': 10 * 1024,
642 'uploader': "變態妍字幕版 太妍 тест",
643 'creator': "тест ' 123 ' тест--",
651 'description': 'foo',
652 'filesize': 5 * 1024,
654 'uploader': "тест 123",
656 videos = [first, second]
658 def get_videos(filter_=None):
659 ydl = FilterYDL({'match_filter': filter_})
661 ydl.process_ie_result(v, download=True)
662 return [v['id'] for v in ydl.downloaded_info_dicts]
665 self.assertEqual(res, ['1', '2'])
671 return 'Video id is not 1'
673 self.assertEqual(res, ['1'])
675 f = match_filter_func('duration < 30')
677 self.assertEqual(res, ['2'])
679 f = match_filter_func('description = foo')
681 self.assertEqual(res, ['2'])
683 f = match_filter_func('description =? foo')
685 self.assertEqual(res, ['1', '2'])
687 f = match_filter_func('filesize > 5KiB')
689 self.assertEqual(res, ['1'])
691 f = match_filter_func('playlist_id = 42')
693 self.assertEqual(res, ['1'])
695 f = match_filter_func('uploader = "變態妍字幕版 太妍 тест"')
697 self.assertEqual(res, ['1'])
699 f = match_filter_func('uploader != "變態妍字幕版 太妍 тест"')
701 self.assertEqual(res, ['2'])
703 f = match_filter_func('creator = "тест \' 123 \' тест--"')
705 self.assertEqual(res, ['1'])
707 f = match_filter_func("creator = 'тест \\' 123 \\' тест--'")
709 self.assertEqual(res, ['1'])
711 f = match_filter_func(r"creator = 'тест \' 123 \' тест--' & duration > 30")
713 self.assertEqual(res, [])
715 def test_playlist_items_selection(self):
718 'title': compat_str(i),
720 } for i in range(1, 5)]
725 'extractor': 'test:playlist',
726 'extractor_key': 'test:playlist',
727 'webpage_url': 'http://example.com',
732 # make a copy because the dictionary can be modified
733 ydl.process_ie_result(playlist.copy())
734 return [int(v['id']) for v in ydl.downloaded_info_dicts]
737 self.assertEqual(result, [1, 2, 3, 4])
739 result = get_ids({'playlistend': 10})
740 self.assertEqual(result, [1, 2, 3, 4])
742 result = get_ids({'playlistend': 2})
743 self.assertEqual(result, [1, 2])
745 result = get_ids({'playliststart': 10})
746 self.assertEqual(result, [])
748 result = get_ids({'playliststart': 2})
749 self.assertEqual(result, [2, 3, 4])
751 result = get_ids({'playlist_items': '2-4'})
752 self.assertEqual(result, [2, 3, 4])
754 result = get_ids({'playlist_items': '2,4'})
755 self.assertEqual(result, [2, 4])
757 result = get_ids({'playlist_items': '10'})
758 self.assertEqual(result, [])
760 def test_urlopen_no_file_protocol(self):
761 # see https://github.com/rg3/youtube-dl/issues/8227
763 self.assertRaises(compat_urllib_error.URLError, ydl.urlopen, 'file:///etc/passwd')
765 def test_do_not_override_ie_key_in_url_transparent(self):
768 class Foo1IE(InfoExtractor):
769 _VALID_URL = r'foo1:'
771 def _real_extract(self, url):
773 '_type': 'url_transparent',
776 'title': 'foo1 title',
780 class Foo2IE(InfoExtractor):
781 _VALID_URL = r'foo2:'
783 def _real_extract(self, url):
790 class Foo3IE(InfoExtractor):
791 _VALID_URL = r'foo3:'
793 def _real_extract(self, url):
794 return _make_result([{'url': TEST_URL}], title='foo3 title')
796 ydl.add_info_extractor(Foo1IE(ydl))
797 ydl.add_info_extractor(Foo2IE(ydl))
798 ydl.add_info_extractor(Foo3IE(ydl))
799 ydl.extract_info('foo1:')
800 downloaded = ydl.downloaded_info_dicts[0]
801 self.assertEqual(downloaded['url'], TEST_URL)
802 self.assertEqual(downloaded['title'], 'foo1 title')
803 self.assertEqual(downloaded['id'], 'testid')
804 self.assertEqual(downloaded['extractor'], 'testex')
805 self.assertEqual(downloaded['extractor_key'], 'TestEx')
808 if __name__ == '__main__':