3 from __future__ import unicode_literals
5 # Allow direct execution
9 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
13 from test.helper import FakeYDL, assertRegexpMatches
14 from youtube_dl import YoutubeDL
15 from youtube_dl.extractor import YoutubeIE
16 from youtube_dl.postprocessor.common import PostProcessor
18 TEST_URL = 'http://localhost/sample.mp4'
22 def __init__(self, *args, **kwargs):
23 super(YDL, self).__init__(*args, **kwargs)
24 self.downloaded_info_dicts = []
27 def process_info(self, info_dict):
28 self.downloaded_info_dicts.append(info_dict)
30 def to_screen(self, msg):
34 def _make_result(formats, **kwargs):
38 'title': 'testttitle',
39 'extractor': 'testex',
45 class TestFormatSelection(unittest.TestCase):
46 def test_prefer_free_formats(self):
47 # Same resolution => download webm
49 ydl.params['prefer_free_formats'] = True
51 {'ext': 'webm', 'height': 460, 'url': TEST_URL},
52 {'ext': 'mp4', 'height': 460, 'url': TEST_URL},
54 info_dict = _make_result(formats)
56 yie._sort_formats(info_dict['formats'])
57 ydl.process_ie_result(info_dict)
58 downloaded = ydl.downloaded_info_dicts[0]
59 self.assertEqual(downloaded['ext'], 'webm')
61 # Different resolution => download best quality (mp4)
63 ydl.params['prefer_free_formats'] = True
65 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
66 {'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
68 info_dict['formats'] = formats
70 yie._sort_formats(info_dict['formats'])
71 ydl.process_ie_result(info_dict)
72 downloaded = ydl.downloaded_info_dicts[0]
73 self.assertEqual(downloaded['ext'], 'mp4')
75 # No prefer_free_formats => prefer mp4 and flv for greater compatibility
77 ydl.params['prefer_free_formats'] = False
79 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
80 {'ext': 'mp4', 'height': 720, 'url': TEST_URL},
81 {'ext': 'flv', 'height': 720, 'url': TEST_URL},
83 info_dict['formats'] = formats
85 yie._sort_formats(info_dict['formats'])
86 ydl.process_ie_result(info_dict)
87 downloaded = ydl.downloaded_info_dicts[0]
88 self.assertEqual(downloaded['ext'], 'mp4')
91 ydl.params['prefer_free_formats'] = False
93 {'ext': 'flv', 'height': 720, 'url': TEST_URL},
94 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
96 info_dict['formats'] = formats
98 yie._sort_formats(info_dict['formats'])
99 ydl.process_ie_result(info_dict)
100 downloaded = ydl.downloaded_info_dicts[0]
101 self.assertEqual(downloaded['ext'], 'flv')
103 def test_format_limit(self):
105 {'format_id': 'meh', 'url': 'http://example.com/meh', 'preference': 1},
106 {'format_id': 'good', 'url': 'http://example.com/good', 'preference': 2},
107 {'format_id': 'great', 'url': 'http://example.com/great', 'preference': 3},
108 {'format_id': 'excellent', 'url': 'http://example.com/exc', 'preference': 4},
110 info_dict = _make_result(formats)
113 ydl.process_ie_result(info_dict)
114 downloaded = ydl.downloaded_info_dicts[0]
115 self.assertEqual(downloaded['format_id'], 'excellent')
117 ydl = YDL({'format_limit': 'good'})
118 assert ydl.params['format_limit'] == 'good'
119 ydl.process_ie_result(info_dict.copy())
120 downloaded = ydl.downloaded_info_dicts[0]
121 self.assertEqual(downloaded['format_id'], 'good')
123 ydl = YDL({'format_limit': 'great', 'format': 'all'})
124 ydl.process_ie_result(info_dict.copy())
125 self.assertEqual(ydl.downloaded_info_dicts[0]['format_id'], 'meh')
126 self.assertEqual(ydl.downloaded_info_dicts[1]['format_id'], 'good')
127 self.assertEqual(ydl.downloaded_info_dicts[2]['format_id'], 'great')
128 self.assertTrue('3' in ydl.msgs[0])
131 ydl.params['format_limit'] = 'excellent'
132 ydl.process_ie_result(info_dict.copy())
133 downloaded = ydl.downloaded_info_dicts[0]
134 self.assertEqual(downloaded['format_id'], 'excellent')
136 def test_format_selection(self):
138 {'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
139 {'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': TEST_URL},
140 {'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': TEST_URL},
141 {'format_id': '2', 'ext': 'flv', 'preference': 4, 'url': TEST_URL},
143 info_dict = _make_result(formats)
145 ydl = YDL({'format': '20/47'})
146 ydl.process_ie_result(info_dict.copy())
147 downloaded = ydl.downloaded_info_dicts[0]
148 self.assertEqual(downloaded['format_id'], '47')
150 ydl = YDL({'format': '20/71/worst'})
151 ydl.process_ie_result(info_dict.copy())
152 downloaded = ydl.downloaded_info_dicts[0]
153 self.assertEqual(downloaded['format_id'], '35')
156 ydl.process_ie_result(info_dict.copy())
157 downloaded = ydl.downloaded_info_dicts[0]
158 self.assertEqual(downloaded['format_id'], '2')
160 ydl = YDL({'format': 'webm/mp4'})
161 ydl.process_ie_result(info_dict.copy())
162 downloaded = ydl.downloaded_info_dicts[0]
163 self.assertEqual(downloaded['format_id'], '47')
165 ydl = YDL({'format': '3gp/40/mp4'})
166 ydl.process_ie_result(info_dict.copy())
167 downloaded = ydl.downloaded_info_dicts[0]
168 self.assertEqual(downloaded['format_id'], '35')
170 def test_format_selection_audio(self):
172 {'format_id': 'audio-low', 'ext': 'webm', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
173 {'format_id': 'audio-mid', 'ext': 'webm', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
174 {'format_id': 'audio-high', 'ext': 'flv', 'preference': 3, 'vcodec': 'none', 'url': TEST_URL},
175 {'format_id': 'vid', 'ext': 'mp4', 'preference': 4, 'url': TEST_URL},
177 info_dict = _make_result(formats)
179 ydl = YDL({'format': 'bestaudio'})
180 ydl.process_ie_result(info_dict.copy())
181 downloaded = ydl.downloaded_info_dicts[0]
182 self.assertEqual(downloaded['format_id'], 'audio-high')
184 ydl = YDL({'format': 'worstaudio'})
185 ydl.process_ie_result(info_dict.copy())
186 downloaded = ydl.downloaded_info_dicts[0]
187 self.assertEqual(downloaded['format_id'], 'audio-low')
190 {'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
191 {'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
193 info_dict = _make_result(formats)
195 ydl = YDL({'format': 'bestaudio/worstaudio/best'})
196 ydl.process_ie_result(info_dict.copy())
197 downloaded = ydl.downloaded_info_dicts[0]
198 self.assertEqual(downloaded['format_id'], 'vid-high')
200 def test_format_selection_audio_exts(self):
202 {'format_id': 'mp3-64', 'ext': 'mp3', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
203 {'format_id': 'ogg-64', 'ext': 'ogg', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
204 {'format_id': 'aac-64', 'ext': 'aac', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
205 {'format_id': 'mp3-32', 'ext': 'mp3', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
206 {'format_id': 'aac-32', 'ext': 'aac', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
209 info_dict = _make_result(formats)
210 ydl = YDL({'format': 'best'})
212 ie._sort_formats(info_dict['formats'])
213 ydl.process_ie_result(copy.deepcopy(info_dict))
214 downloaded = ydl.downloaded_info_dicts[0]
215 self.assertEqual(downloaded['format_id'], 'aac-64')
217 ydl = YDL({'format': 'mp3'})
219 ie._sort_formats(info_dict['formats'])
220 ydl.process_ie_result(copy.deepcopy(info_dict))
221 downloaded = ydl.downloaded_info_dicts[0]
222 self.assertEqual(downloaded['format_id'], 'mp3-64')
224 ydl = YDL({'prefer_free_formats': True})
226 ie._sort_formats(info_dict['formats'])
227 ydl.process_ie_result(copy.deepcopy(info_dict))
228 downloaded = ydl.downloaded_info_dicts[0]
229 self.assertEqual(downloaded['format_id'], 'ogg-64')
231 def test_format_selection_video(self):
233 {'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': TEST_URL},
234 {'format_id': 'dash-video-high', 'ext': 'mp4', 'preference': 2, 'acodec': 'none', 'url': TEST_URL},
235 {'format_id': 'vid', 'ext': 'mp4', 'preference': 3, 'url': TEST_URL},
237 info_dict = _make_result(formats)
239 ydl = YDL({'format': 'bestvideo'})
240 ydl.process_ie_result(info_dict.copy())
241 downloaded = ydl.downloaded_info_dicts[0]
242 self.assertEqual(downloaded['format_id'], 'dash-video-high')
244 ydl = YDL({'format': 'worstvideo'})
245 ydl.process_ie_result(info_dict.copy())
246 downloaded = ydl.downloaded_info_dicts[0]
247 self.assertEqual(downloaded['format_id'], 'dash-video-low')
249 def test_youtube_format_selection(self):
251 '38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '36', '17', '13',
252 # Apple HTTP Live Streaming
253 '96', '95', '94', '93', '92', '132', '151',
255 '85', '84', '102', '83', '101', '82', '100',
257 '137', '248', '136', '247', '135', '246',
258 '245', '244', '134', '243', '133', '242', '160',
260 '141', '172', '140', '171', '139',
263 for f1id, f2id in zip(order, order[1:]):
264 f1 = YoutubeIE._formats[f1id].copy()
265 f1['format_id'] = f1id
266 f1['url'] = 'url:' + f1id
267 f2 = YoutubeIE._formats[f2id].copy()
268 f2['format_id'] = f2id
269 f2['url'] = 'url:' + f2id
271 info_dict = _make_result([f1, f2], extractor='youtube')
274 yie._sort_formats(info_dict['formats'])
275 ydl.process_ie_result(info_dict)
276 downloaded = ydl.downloaded_info_dicts[0]
277 self.assertEqual(downloaded['format_id'], f1id)
279 info_dict = _make_result([f2, f1], extractor='youtube')
282 yie._sort_formats(info_dict['formats'])
283 ydl.process_ie_result(info_dict)
284 downloaded = ydl.downloaded_info_dicts[0]
285 self.assertEqual(downloaded['format_id'], f1id)
287 def test_format_filtering(self):
289 {'format_id': 'A', 'filesize': 500, 'width': 1000},
290 {'format_id': 'B', 'filesize': 1000, 'width': 500},
291 {'format_id': 'C', 'filesize': 1000, 'width': 400},
292 {'format_id': 'D', 'filesize': 2000, 'width': 600},
293 {'format_id': 'E', 'filesize': 3000},
295 {'format_id': 'G', 'filesize': 1000000},
298 f['url'] = 'http://_/'
300 info_dict = _make_result(formats)
302 ydl = YDL({'format': 'best[filesize<3000]'})
303 ydl.process_ie_result(info_dict)
304 downloaded = ydl.downloaded_info_dicts[0]
305 self.assertEqual(downloaded['format_id'], 'D')
307 ydl = YDL({'format': 'best[filesize<=3000]'})
308 ydl.process_ie_result(info_dict)
309 downloaded = ydl.downloaded_info_dicts[0]
310 self.assertEqual(downloaded['format_id'], 'E')
312 ydl = YDL({'format': 'best[filesize <= ? 3000]'})
313 ydl.process_ie_result(info_dict)
314 downloaded = ydl.downloaded_info_dicts[0]
315 self.assertEqual(downloaded['format_id'], 'F')
317 ydl = YDL({'format': 'best [filesize = 1000] [width>450]'})
318 ydl.process_ie_result(info_dict)
319 downloaded = ydl.downloaded_info_dicts[0]
320 self.assertEqual(downloaded['format_id'], 'B')
322 ydl = YDL({'format': 'best [filesize = 1000] [width!=450]'})
323 ydl.process_ie_result(info_dict)
324 downloaded = ydl.downloaded_info_dicts[0]
325 self.assertEqual(downloaded['format_id'], 'C')
327 ydl = YDL({'format': '[filesize>?1]'})
328 ydl.process_ie_result(info_dict)
329 downloaded = ydl.downloaded_info_dicts[0]
330 self.assertEqual(downloaded['format_id'], 'G')
332 ydl = YDL({'format': '[filesize<1M]'})
333 ydl.process_ie_result(info_dict)
334 downloaded = ydl.downloaded_info_dicts[0]
335 self.assertEqual(downloaded['format_id'], 'E')
337 ydl = YDL({'format': '[filesize<1MiB]'})
338 ydl.process_ie_result(info_dict)
339 downloaded = ydl.downloaded_info_dicts[0]
340 self.assertEqual(downloaded['format_id'], 'G')
342 def test_subtitles(self):
343 def s_formats(lang, autocaption=False):
346 'url': 'http://localhost/video.%s.%s' % (lang, ext),
347 '_auto': autocaption,
348 } for ext in ['vtt', 'srt', 'ass']]
349 subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
350 auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
354 'url': 'http://localhost/video.mp4',
355 'subtitles': subtitles,
356 'automatic_captions': auto_captions,
360 def get_info(params={}):
361 params.setdefault('simulate', True)
363 ydl.report_warning = lambda *args, **kargs: None
364 return ydl.process_video_result(info_dict, download=False)
367 self.assertFalse(result.get('requested_subtitles'))
368 self.assertEqual(result['subtitles'], subtitles)
369 self.assertEqual(result['automatic_captions'], auto_captions)
371 result = get_info({'writesubtitles': True})
372 subs = result['requested_subtitles']
373 self.assertTrue(subs)
374 self.assertEqual(set(subs.keys()), set(['en']))
375 self.assertTrue(subs['en'].get('data') is None)
376 self.assertEqual(subs['en']['ext'], 'ass')
378 result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
379 subs = result['requested_subtitles']
380 self.assertEqual(subs['en']['ext'], 'srt')
382 result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
383 subs = result['requested_subtitles']
384 self.assertTrue(subs)
385 self.assertEqual(set(subs.keys()), set(['es', 'fr']))
387 result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
388 subs = result['requested_subtitles']
389 self.assertTrue(subs)
390 self.assertEqual(set(subs.keys()), set(['es', 'pt']))
391 self.assertFalse(subs['es']['_auto'])
392 self.assertTrue(subs['pt']['_auto'])
394 result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
395 subs = result['requested_subtitles']
396 self.assertTrue(subs)
397 self.assertEqual(set(subs.keys()), set(['es', 'pt']))
398 self.assertTrue(subs['es']['_auto'])
399 self.assertTrue(subs['pt']['_auto'])
401 def test_add_extra_info(self):
407 'playlist': 'funny videos',
409 YDL.add_extra_info(test_dict, extra_info)
410 self.assertEqual(test_dict['extractor'], 'Foo')
411 self.assertEqual(test_dict['playlist'], 'funny videos')
413 def test_prepare_filename(self):
421 ydl = YoutubeDL({'outtmpl': templ})
422 return ydl.prepare_filename(info)
423 self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
424 self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
425 # Replace missing fields with 'NA'
426 self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4')
428 def test_format_note(self):
430 self.assertEqual(ydl._format_note({}), '')
431 assertRegexpMatches(self, ydl._format_note({
435 def test_postprocessors(self):
436 filename = 'post-processor-testfile.mp4'
437 audiofile = filename + '.mp3'
439 class SimplePP(PostProcessor):
441 with open(audiofile, 'wt') as f:
447 with open(filename, 'wt') as f:
449 ydl = YoutubeDL(params)
450 ydl.add_post_processor(SimplePP())
451 ydl.post_process(filename, {'filepath': filename})
453 run_pp({'keepvideo': True})
454 self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
455 self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
459 run_pp({'keepvideo': False})
460 self.assertFalse(os.path.exists(filename), '%s exists' % filename)
461 self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
465 if __name__ == '__main__':