]> jfr.im git - yt-dlp.git/blame - test/test_YoutubeDL.py
[test/http] Add test for proxy support
[yt-dlp.git] / test / test_YoutubeDL.py
CommitLineData
e028d0d1
JMF
1#!/usr/bin/env python
2
89087418
PH
3from __future__ import unicode_literals
4
5d254f77
PH
5# Allow direct execution
6import os
e028d0d1
JMF
7import sys
8import unittest
5d254f77 9sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
e028d0d1 10
0217c783
PH
11import copy
12
c57f7757 13from test.helper import FakeYDL, assertRegexpMatches
26e63931 14from youtube_dl import YoutubeDL
3d4a70b8 15from youtube_dl.extractor import YoutubeIE
2b4ecde2 16from youtube_dl.postprocessor.common import PostProcessor
e028d0d1 17
8508557e
JMF
18TEST_URL = 'http://localhost/sample.mp4'
19
e028d0d1
JMF
20
21class YDL(FakeYDL):
f4d96df0
PH
22 def __init__(self, *args, **kwargs):
23 super(YDL, self).__init__(*args, **kwargs)
e028d0d1 24 self.downloaded_info_dicts = []
f4d96df0 25 self.msgs = []
5d254f77 26
e028d0d1
JMF
27 def process_info(self, info_dict):
28 self.downloaded_info_dicts.append(info_dict)
29
f4d96df0
PH
30 def to_screen(self, msg):
31 self.msgs.append(msg)
32
5d254f77 33
3537b93d
PH
34def _make_result(formats, **kwargs):
35 res = {
36 'formats': formats,
37 'id': 'testid',
38 'title': 'testttitle',
39 'extractor': 'testex',
40 }
41 res.update(**kwargs)
42 return res
43
44
e028d0d1
JMF
45class TestFormatSelection(unittest.TestCase):
46 def test_prefer_free_formats(self):
47 # Same resolution => download webm
48 ydl = YDL()
49 ydl.params['prefer_free_formats'] = True
5d254f77 50 formats = [
8508557e
JMF
51 {'ext': 'webm', 'height': 460, 'url': TEST_URL},
52 {'ext': 'mp4', 'height': 460, 'url': TEST_URL},
5d254f77 53 ]
3537b93d 54 info_dict = _make_result(formats)
3d4a70b8
PH
55 yie = YoutubeIE(ydl)
56 yie._sort_formats(info_dict['formats'])
e028d0d1
JMF
57 ydl.process_ie_result(info_dict)
58 downloaded = ydl.downloaded_info_dicts[0]
89087418 59 self.assertEqual(downloaded['ext'], 'webm')
e028d0d1
JMF
60
61 # Different resolution => download best quality (mp4)
62 ydl = YDL()
63 ydl.params['prefer_free_formats'] = True
5d254f77 64 formats = [
8508557e
JMF
65 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
66 {'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
5d254f77 67 ]
89087418 68 info_dict['formats'] = formats
3d4a70b8
PH
69 yie = YoutubeIE(ydl)
70 yie._sort_formats(info_dict['formats'])
e028d0d1
JMF
71 ydl.process_ie_result(info_dict)
72 downloaded = ydl.downloaded_info_dicts[0]
89087418 73 self.assertEqual(downloaded['ext'], 'mp4')
e028d0d1 74
1c783bca 75 # No prefer_free_formats => prefer mp4 and flv for greater compatibility
e028d0d1
JMF
76 ydl = YDL()
77 ydl.params['prefer_free_formats'] = False
5d254f77 78 formats = [
8508557e
JMF
79 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
80 {'ext': 'mp4', 'height': 720, 'url': TEST_URL},
81 {'ext': 'flv', 'height': 720, 'url': TEST_URL},
5d254f77 82 ]
89087418 83 info_dict['formats'] = formats
3d4a70b8
PH
84 yie = YoutubeIE(ydl)
85 yie._sort_formats(info_dict['formats'])
86 ydl.process_ie_result(info_dict)
87 downloaded = ydl.downloaded_info_dicts[0]
89087418 88 self.assertEqual(downloaded['ext'], 'mp4')
3d4a70b8
PH
89
90 ydl = YDL()
91 ydl.params['prefer_free_formats'] = False
92 formats = [
8508557e
JMF
93 {'ext': 'flv', 'height': 720, 'url': TEST_URL},
94 {'ext': 'webm', 'height': 720, 'url': TEST_URL},
3d4a70b8 95 ]
89087418 96 info_dict['formats'] = formats
3d4a70b8
PH
97 yie = YoutubeIE(ydl)
98 yie._sort_formats(info_dict['formats'])
e028d0d1
JMF
99 ydl.process_ie_result(info_dict)
100 downloaded = ydl.downloaded_info_dicts[0]
89087418 101 self.assertEqual(downloaded['ext'], 'flv')
e028d0d1 102
f4d96df0
PH
103 def test_format_limit(self):
104 formats = [
89087418
PH
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},
f4d96df0 109 ]
3537b93d 110 info_dict = _make_result(formats)
f4d96df0
PH
111
112 ydl = YDL()
113 ydl.process_ie_result(info_dict)
114 downloaded = ydl.downloaded_info_dicts[0]
89087418 115 self.assertEqual(downloaded['format_id'], 'excellent')
f4d96df0
PH
116
117 ydl = YDL({'format_limit': 'good'})
118 assert ydl.params['format_limit'] == 'good'
8e3e0322 119 ydl.process_ie_result(info_dict.copy())
f4d96df0 120 downloaded = ydl.downloaded_info_dicts[0]
89087418 121 self.assertEqual(downloaded['format_id'], 'good')
f4d96df0
PH
122
123 ydl = YDL({'format_limit': 'great', 'format': 'all'})
8e3e0322 124 ydl.process_ie_result(info_dict.copy())
89087418
PH
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')
f4d96df0
PH
128 self.assertTrue('3' in ydl.msgs[0])
129
130 ydl = YDL()
131 ydl.params['format_limit'] = 'excellent'
8e3e0322 132 ydl.process_ie_result(info_dict.copy())
f4d96df0 133 downloaded = ydl.downloaded_info_dicts[0]
89087418 134 self.assertEqual(downloaded['format_id'], 'excellent')
f4d96df0 135
a9c58ad9
JMF
136 def test_format_selection(self):
137 formats = [
8508557e
JMF
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},
a9c58ad9 142 ]
3537b93d 143 info_dict = _make_result(formats)
a9c58ad9 144
89087418 145 ydl = YDL({'format': '20/47'})
8e3e0322 146 ydl.process_ie_result(info_dict.copy())
a9c58ad9 147 downloaded = ydl.downloaded_info_dicts[0]
89087418 148 self.assertEqual(downloaded['format_id'], '47')
a9c58ad9 149
89087418 150 ydl = YDL({'format': '20/71/worst'})
8e3e0322 151 ydl.process_ie_result(info_dict.copy())
a9c58ad9 152 downloaded = ydl.downloaded_info_dicts[0]
89087418 153 self.assertEqual(downloaded['format_id'], '35')
a9c58ad9
JMF
154
155 ydl = YDL()
8e3e0322 156 ydl.process_ie_result(info_dict.copy())
a9c58ad9 157 downloaded = ydl.downloaded_info_dicts[0]
89087418 158 self.assertEqual(downloaded['format_id'], '2')
a9c58ad9 159
89087418 160 ydl = YDL({'format': 'webm/mp4'})
8e3e0322 161 ydl.process_ie_result(info_dict.copy())
49e86983 162 downloaded = ydl.downloaded_info_dicts[0]
89087418 163 self.assertEqual(downloaded['format_id'], '47')
49e86983 164
89087418 165 ydl = YDL({'format': '3gp/40/mp4'})
8e3e0322 166 ydl.process_ie_result(info_dict.copy())
49e86983 167 downloaded = ydl.downloaded_info_dicts[0]
89087418 168 self.assertEqual(downloaded['format_id'], '35')
49e86983 169
ba7678f9
PH
170 def test_format_selection_audio(self):
171 formats = [
8508557e
JMF
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},
ba7678f9 176 ]
3537b93d 177 info_dict = _make_result(formats)
ba7678f9 178
89087418 179 ydl = YDL({'format': 'bestaudio'})
ba7678f9
PH
180 ydl.process_ie_result(info_dict.copy())
181 downloaded = ydl.downloaded_info_dicts[0]
89087418 182 self.assertEqual(downloaded['format_id'], 'audio-high')
ba7678f9 183
89087418 184 ydl = YDL({'format': 'worstaudio'})
ba7678f9
PH
185 ydl.process_ie_result(info_dict.copy())
186 downloaded = ydl.downloaded_info_dicts[0]
89087418 187 self.assertEqual(downloaded['format_id'], 'audio-low')
ba7678f9
PH
188
189 formats = [
8508557e
JMF
190 {'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
191 {'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
ba7678f9 192 ]
3537b93d 193 info_dict = _make_result(formats)
ba7678f9 194
89087418 195 ydl = YDL({'format': 'bestaudio/worstaudio/best'})
ba7678f9
PH
196 ydl.process_ie_result(info_dict.copy())
197 downloaded = ydl.downloaded_info_dicts[0]
89087418 198 self.assertEqual(downloaded['format_id'], 'vid-high')
ba7678f9 199
0217c783
PH
200 def test_format_selection_audio_exts(self):
201 formats = [
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'},
207 ]
208
209 info_dict = _make_result(formats)
210 ydl = YDL({'format': 'best'})
211 ie = YoutubeIE(ydl)
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')
216
217 ydl = YDL({'format': 'mp3'})
218 ie = YoutubeIE(ydl)
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')
223
224 ydl = YDL({'prefer_free_formats': True})
225 ie = YoutubeIE(ydl)
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')
230
bc6d5978
JMF
231 def test_format_selection_video(self):
232 formats = [
8508557e
JMF
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},
bc6d5978 236 ]
3537b93d 237 info_dict = _make_result(formats)
bc6d5978
JMF
238
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')
243
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')
248
3d4a70b8
PH
249 def test_youtube_format_selection(self):
250 order = [
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',
254 # 3D
255 '85', '84', '102', '83', '101', '82', '100',
256 # Dash video
c11125f9 257 '137', '248', '136', '247', '135', '246',
3d4a70b8
PH
258 '245', '244', '134', '243', '133', '242', '160',
259 # Dash audio
a053c349 260 '141', '172', '140', '171', '139',
3d4a70b8
PH
261 ]
262
263 for f1id, f2id in zip(order, order[1:]):
264 f1 = YoutubeIE._formats[f1id].copy()
265 f1['format_id'] = f1id
3537b93d 266 f1['url'] = 'url:' + f1id
3d4a70b8
PH
267 f2 = YoutubeIE._formats[f2id].copy()
268 f2['format_id'] = f2id
3537b93d 269 f2['url'] = 'url:' + f2id
3d4a70b8 270
3537b93d 271 info_dict = _make_result([f1, f2], extractor='youtube')
3d4a70b8
PH
272 ydl = YDL()
273 yie = YoutubeIE(ydl)
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)
278
3537b93d 279 info_dict = _make_result([f2, f1], extractor='youtube')
3d4a70b8
PH
280 ydl = YDL()
281 yie = YoutubeIE(ydl)
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)
286
083c9df9
PH
287 def test_format_filtering(self):
288 formats = [
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},
294 {'format_id': 'F'},
295 {'format_id': 'G', 'filesize': 1000000},
296 ]
297 for f in formats:
298 f['url'] = 'http://_/'
299 f['ext'] = 'unknown'
300 info_dict = _make_result(formats)
301
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')
306
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')
311
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')
316
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')
321
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')
326
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')
331
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')
336
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')
341
ab84349b
JMF
342 def test_subtitles(self):
343 def s_formats(lang, autocaption=False):
344 return [{
345 'ext': ext,
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'])
351 info_dict = {
352 'id': 'test',
353 'title': 'Test',
354 'url': 'http://localhost/video.mp4',
355 'subtitles': subtitles,
356 'automatic_captions': auto_captions,
357 'extractor': 'TEST',
358 }
359
360 def get_info(params={}):
361 params.setdefault('simulate', True)
362 ydl = YDL(params)
363 ydl.report_warning = lambda *args, **kargs: None
364 return ydl.process_video_result(info_dict, download=False)
365
366 result = get_info()
367 self.assertFalse(result.get('requested_subtitles'))
368 self.assertEqual(result['subtitles'], subtitles)
369 self.assertEqual(result['automatic_captions'], auto_captions)
370
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')
377
378 result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
379 subs = result['requested_subtitles']
380 self.assertEqual(subs['en']['ext'], 'srt')
381
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']))
386
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'])
393
98c70d6f
JMF
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'])
400
b6c45014
JMF
401 def test_add_extra_info(self):
402 test_dict = {
403 'extractor': 'Foo',
404 }
405 extra_info = {
406 'extractor': 'Bar',
407 'playlist': 'funny videos',
408 }
409 YDL.add_extra_info(test_dict, extra_info)
410 self.assertEqual(test_dict['extractor'], 'Foo')
411 self.assertEqual(test_dict['playlist'], 'funny videos')
412
26e63931
JMF
413 def test_prepare_filename(self):
414 info = {
89087418
PH
415 'id': '1234',
416 'ext': 'mp4',
417 'width': None,
26e63931 418 }
5f6a1245 419
26e63931
JMF
420 def fname(templ):
421 ydl = YoutubeDL({'outtmpl': templ})
422 return ydl.prepare_filename(info)
89087418
PH
423 self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
424 self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
26e63931 425 # Replace missing fields with 'NA'
89087418 426 self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4')
26e63931 427
c57f7757
PH
428 def test_format_note(self):
429 ydl = YoutubeDL()
430 self.assertEqual(ydl._format_note({}), '')
431 assertRegexpMatches(self, ydl._format_note({
432 'vbr': 10,
1c783bca 433 }), '^\s*10k$')
f4d96df0 434
2b4ecde2
JMF
435 def test_postprocessors(self):
436 filename = 'post-processor-testfile.mp4'
437 audiofile = filename + '.mp3'
438
439 class SimplePP(PostProcessor):
440 def run(self, info):
2b4ecde2
JMF
441 with open(audiofile, 'wt') as f:
442 f.write('EXAMPLE')
443 info['filepath']
444 return False, info
445
446 def run_pp(params):
447 with open(filename, 'wt') as f:
448 f.write('EXAMPLE')
449 ydl = YoutubeDL(params)
450 ydl.add_post_processor(SimplePP())
451 ydl.post_process(filename, {'filepath': filename})
452
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)
456 os.unlink(filename)
457 os.unlink(audiofile)
458
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)
462 os.unlink(audiofile)
463
464
e028d0d1
JMF
465if __name__ == '__main__':
466 unittest.main()