Merge branch 'niconico_nm' of https://github.com/ndac-todoroki/youtube-dl into ndac...
[youtube-dl] / test / test_YoutubeDL.py
1 #!/usr/bin/env python
2
3 from __future__ import unicode_literals
4
5 # Allow direct execution
6 import os
7 import sys
8 import unittest
9 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10
11 import copy
12
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
17
18 TEST_URL = 'http://localhost/sample.mp4'
19
20
21 class YDL(FakeYDL):
22     def __init__(self, *args, **kwargs):
23         super(YDL, self).__init__(*args, **kwargs)
24         self.downloaded_info_dicts = []
25         self.msgs = []
26
27     def process_info(self, info_dict):
28         self.downloaded_info_dicts.append(info_dict)
29
30     def to_screen(self, msg):
31         self.msgs.append(msg)
32
33
34 def _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
45 class 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
50         formats = [
51             {'ext': 'webm', 'height': 460, 'url': TEST_URL},
52             {'ext': 'mp4', 'height': 460, 'url': TEST_URL},
53         ]
54         info_dict = _make_result(formats)
55         yie = YoutubeIE(ydl)
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')
60
61         # Different resolution => download best quality (mp4)
62         ydl = YDL()
63         ydl.params['prefer_free_formats'] = True
64         formats = [
65             {'ext': 'webm', 'height': 720, 'url': TEST_URL},
66             {'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
67         ]
68         info_dict['formats'] = formats
69         yie = YoutubeIE(ydl)
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')
74
75         # No prefer_free_formats => prefer mp4 and flv for greater compatibility
76         ydl = YDL()
77         ydl.params['prefer_free_formats'] = False
78         formats = [
79             {'ext': 'webm', 'height': 720, 'url': TEST_URL},
80             {'ext': 'mp4', 'height': 720, 'url': TEST_URL},
81             {'ext': 'flv', 'height': 720, 'url': TEST_URL},
82         ]
83         info_dict['formats'] = formats
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]
88         self.assertEqual(downloaded['ext'], 'mp4')
89
90         ydl = YDL()
91         ydl.params['prefer_free_formats'] = False
92         formats = [
93             {'ext': 'flv', 'height': 720, 'url': TEST_URL},
94             {'ext': 'webm', 'height': 720, 'url': TEST_URL},
95         ]
96         info_dict['formats'] = formats
97         yie = YoutubeIE(ydl)
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')
102
103     def test_format_limit(self):
104         formats = [
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},
109         ]
110         info_dict = _make_result(formats)
111
112         ydl = YDL()
113         ydl.process_ie_result(info_dict)
114         downloaded = ydl.downloaded_info_dicts[0]
115         self.assertEqual(downloaded['format_id'], 'excellent')
116
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')
122
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])
129
130         ydl = YDL()
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')
135
136     def test_format_selection(self):
137         formats = [
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},
142         ]
143         info_dict = _make_result(formats)
144
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')
149
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')
154
155         ydl = YDL()
156         ydl.process_ie_result(info_dict.copy())
157         downloaded = ydl.downloaded_info_dicts[0]
158         self.assertEqual(downloaded['format_id'], '2')
159
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')
164
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')
169
170     def test_format_selection_audio(self):
171         formats = [
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},
176         ]
177         info_dict = _make_result(formats)
178
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')
183
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')
188
189         formats = [
190             {'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
191             {'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
192         ]
193         info_dict = _make_result(formats)
194
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')
199
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
231     def test_format_selection_video(self):
232         formats = [
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},
236         ]
237         info_dict = _make_result(formats)
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
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
257             '137', '248', '136', '247', '135', '246',
258             '245', '244', '134', '243', '133', '242', '160',
259             # Dash audio
260             '141', '172', '140', '171', '139',
261         ]
262
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
270
271             info_dict = _make_result([f1, f2], extractor='youtube')
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
279             info_dict = _make_result([f2, f1], extractor='youtube')
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
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
342
343 class TestYoutubeDL(unittest.TestCase):
344     def test_subtitles(self):
345         def s_formats(lang, autocaption=False):
346             return [{
347                 'ext': ext,
348                 'url': 'http://localhost/video.%s.%s' % (lang, ext),
349                 '_auto': autocaption,
350             } for ext in ['vtt', 'srt', 'ass']]
351         subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
352         auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
353         info_dict = {
354             'id': 'test',
355             'title': 'Test',
356             'url': 'http://localhost/video.mp4',
357             'subtitles': subtitles,
358             'automatic_captions': auto_captions,
359             'extractor': 'TEST',
360         }
361
362         def get_info(params={}):
363             params.setdefault('simulate', True)
364             ydl = YDL(params)
365             ydl.report_warning = lambda *args, **kargs: None
366             return ydl.process_video_result(info_dict, download=False)
367
368         result = get_info()
369         self.assertFalse(result.get('requested_subtitles'))
370         self.assertEqual(result['subtitles'], subtitles)
371         self.assertEqual(result['automatic_captions'], auto_captions)
372
373         result = get_info({'writesubtitles': True})
374         subs = result['requested_subtitles']
375         self.assertTrue(subs)
376         self.assertEqual(set(subs.keys()), set(['en']))
377         self.assertTrue(subs['en'].get('data') is None)
378         self.assertEqual(subs['en']['ext'], 'ass')
379
380         result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
381         subs = result['requested_subtitles']
382         self.assertEqual(subs['en']['ext'], 'srt')
383
384         result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
385         subs = result['requested_subtitles']
386         self.assertTrue(subs)
387         self.assertEqual(set(subs.keys()), set(['es', 'fr']))
388
389         result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
390         subs = result['requested_subtitles']
391         self.assertTrue(subs)
392         self.assertEqual(set(subs.keys()), set(['es', 'pt']))
393         self.assertFalse(subs['es']['_auto'])
394         self.assertTrue(subs['pt']['_auto'])
395
396         result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
397         subs = result['requested_subtitles']
398         self.assertTrue(subs)
399         self.assertEqual(set(subs.keys()), set(['es', 'pt']))
400         self.assertTrue(subs['es']['_auto'])
401         self.assertTrue(subs['pt']['_auto'])
402
403     def test_add_extra_info(self):
404         test_dict = {
405             'extractor': 'Foo',
406         }
407         extra_info = {
408             'extractor': 'Bar',
409             'playlist': 'funny videos',
410         }
411         YDL.add_extra_info(test_dict, extra_info)
412         self.assertEqual(test_dict['extractor'], 'Foo')
413         self.assertEqual(test_dict['playlist'], 'funny videos')
414
415     def test_prepare_filename(self):
416         info = {
417             'id': '1234',
418             'ext': 'mp4',
419             'width': None,
420         }
421
422         def fname(templ):
423             ydl = YoutubeDL({'outtmpl': templ})
424             return ydl.prepare_filename(info)
425         self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
426         self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
427         # Replace missing fields with 'NA'
428         self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4')
429
430     def test_format_note(self):
431         ydl = YoutubeDL()
432         self.assertEqual(ydl._format_note({}), '')
433         assertRegexpMatches(self, ydl._format_note({
434             'vbr': 10,
435         }), '^\s*10k$')
436
437     def test_postprocessors(self):
438         filename = 'post-processor-testfile.mp4'
439         audiofile = filename + '.mp3'
440
441         class SimplePP(PostProcessor):
442             def run(self, info):
443                 with open(audiofile, 'wt') as f:
444                     f.write('EXAMPLE')
445                 info['filepath']
446                 return False, info
447
448         def run_pp(params):
449             with open(filename, 'wt') as f:
450                 f.write('EXAMPLE')
451             ydl = YoutubeDL(params)
452             ydl.add_post_processor(SimplePP())
453             ydl.post_process(filename, {'filepath': filename})
454
455         run_pp({'keepvideo': True})
456         self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
457         self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
458         os.unlink(filename)
459         os.unlink(audiofile)
460
461         run_pp({'keepvideo': False})
462         self.assertFalse(os.path.exists(filename), '%s exists' % filename)
463         self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
464         os.unlink(audiofile)
465
466
467 if __name__ == '__main__':
468     unittest.main()