Merge remote-tracking branch 'origin/prefer-ffmpeg'
[youtube-dl] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 __authors__  = (
5     'Ricardo Garcia Gonzalez',
6     'Danny Colligan',
7     'Benjamin Johnson',
8     'Vasyl\' Vavrychuk',
9     'Witold Baryluk',
10     'Paweł Paprota',
11     'Gergely Imreh',
12     'Rogério Brito',
13     'Philipp Hagemeister',
14     'Sören Schulze',
15     'Kevin Ngo',
16     'Ori Avtalion',
17     'shizeeg',
18     'Filippo Valsorda',
19     'Christian Albrecht',
20     'Dave Vasilevsky',
21     'Jaime Marquínez Ferrándiz',
22     'Jeff Crouse',
23     'Osama Khalid',
24     'Michael Walter',
25     'M. Yasoob Ullah Khalid',
26     'Julien Fraichard',
27     'Johny Mo Swag',
28     'Axel Noack',
29     'Albert Kim',
30     'Pierre Rudloff',
31     'Huarong Huo',
32     'Ismael Mejía',
33     'Steffan \'Ruirize\' James',
34     'Andras Elso',
35     'Jelle van der Waa',
36     'Marcin Cieślak',
37     'Anton Larionov',
38     'Takuya Tsuchida',
39     'Sergey M.',
40     'Michael Orlitzky',
41     'Chris Gahan',
42 )
43
44 __license__ = 'Public Domain'
45
46 import codecs
47 import getpass
48 import locale
49 import optparse
50 import os
51 import random
52 import re
53 import shlex
54 import sys
55
56
57 from .utils import (
58     compat_print,
59     DateRange,
60     decodeOption,
61     get_term_width,
62     DownloadError,
63     get_cachedir,
64     MaxDownloadsReached,
65     preferredencoding,
66     SameFileError,
67     setproctitle,
68     std_headers,
69     write_string,
70 )
71 from .update import update_self
72 from .FileDownloader import (
73     FileDownloader,
74 )
75 from .extractor import gen_extractors
76 from .version import __version__
77 from .YoutubeDL import YoutubeDL
78 from .postprocessor import (
79     FFmpegMetadataPP,
80     FFmpegVideoConvertor,
81     FFmpegExtractAudioPP,
82     FFmpegEmbedSubtitlePP,
83     XAttrMetadataPP,
84 )
85
86
87 def parseOpts(overrideArguments=None):
88     def _readOptions(filename_bytes, default=[]):
89         try:
90             optionf = open(filename_bytes)
91         except IOError:
92             return default  # silently skip if file is not present
93         try:
94             res = []
95             for l in optionf:
96                 res += shlex.split(l, comments=True)
97         finally:
98             optionf.close()
99         return res
100
101     def _format_option_string(option):
102         ''' ('-o', '--option') -> -o, --format METAVAR'''
103
104         opts = []
105
106         if option._short_opts:
107             opts.append(option._short_opts[0])
108         if option._long_opts:
109             opts.append(option._long_opts[0])
110         if len(opts) > 1:
111             opts.insert(1, ', ')
112
113         if option.takes_value(): opts.append(' %s' % option.metavar)
114
115         return "".join(opts)
116
117     def _comma_separated_values_options_callback(option, opt_str, value, parser):
118         setattr(parser.values, option.dest, value.split(','))
119
120     def _hide_login_info(opts):
121         opts = list(opts)
122         for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
123             try:
124                 i = opts.index(private_opt)
125                 opts[i+1] = '<PRIVATE>'
126             except ValueError:
127                 pass
128         return opts
129
130     max_width = 80
131     max_help_position = 80
132
133     # No need to wrap help messages if we're on a wide console
134     columns = get_term_width()
135     if columns: max_width = columns
136
137     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
138     fmt.format_option_strings = _format_option_string
139
140     kw = {
141         'version'   : __version__,
142         'formatter' : fmt,
143         'usage' : '%prog [options] url [url...]',
144         'conflict_handler' : 'resolve',
145     }
146
147     parser = optparse.OptionParser(**kw)
148
149     # option groups
150     general        = optparse.OptionGroup(parser, 'General Options')
151     selection      = optparse.OptionGroup(parser, 'Video Selection')
152     authentication = optparse.OptionGroup(parser, 'Authentication Options')
153     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
154     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
155     downloader     = optparse.OptionGroup(parser, 'Download Options')
156     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
157     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
158     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
159
160     general.add_option('-h', '--help',
161             action='help', help='print this help text and exit')
162     general.add_option('-v', '--version',
163             action='version', help='print program version and exit')
164     general.add_option('-U', '--update',
165             action='store_true', dest='update_self', help='update this program to latest version. Make sure that you have sufficient permissions (run with sudo if needed)')
166     general.add_option('-i', '--ignore-errors',
167             action='store_true', dest='ignoreerrors', help='continue on download errors, for example to to skip unavailable videos in a playlist', default=False)
168     general.add_option('--abort-on-error',
169             action='store_false', dest='ignoreerrors',
170             help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
171     general.add_option('--dump-user-agent',
172             action='store_true', dest='dump_user_agent',
173             help='display the current browser identification', default=False)
174     general.add_option('--user-agent',
175             dest='user_agent', help='specify a custom user agent', metavar='UA')
176     general.add_option('--referer',
177             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
178             metavar='REF', default=None)
179     general.add_option('--list-extractors',
180             action='store_true', dest='list_extractors',
181             help='List all supported extractors and the URLs they would handle', default=False)
182     general.add_option('--extractor-descriptions',
183             action='store_true', dest='list_extractor_descriptions',
184             help='Output descriptions of all supported extractors', default=False)
185     general.add_option(
186         '--proxy', dest='proxy', default=None, metavar='URL',
187         help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
188     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
189     general.add_option(
190         '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
191         help='Location in the filesystem where youtube-dl can store some downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl . At the moment, only YouTube player files (for videos with obfuscated signatures) are cached, but that may change.')
192     general.add_option(
193         '--no-cache-dir', action='store_const', const=None, dest='cachedir',
194         help='Disable filesystem caching')
195     general.add_option(
196         '--socket-timeout', dest='socket_timeout',
197         type=float, default=None, help=u'Time to wait before giving up, in seconds')
198     general.add_option(
199         '--bidi-workaround', dest='bidi_workaround', action='store_true',
200         help=u'Work around terminals that lack bidirectional text support. Requires bidiv or fribidi executable in PATH')
201
202
203     selection.add_option(
204         '--playlist-start',
205         dest='playliststart', metavar='NUMBER', default=1, type=int,
206         help='playlist video to start at (default is %default)')
207     selection.add_option(
208         '--playlist-end',
209         dest='playlistend', metavar='NUMBER', default=None, type=int,
210         help='playlist video to end at (default is last)')
211     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
212     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
213     selection.add_option('--max-downloads', metavar='NUMBER',
214                          dest='max_downloads', type=int, default=None,
215                          help='Abort after downloading NUMBER files')
216     selection.add_option('--min-filesize', metavar='SIZE', dest='min_filesize', help="Do not download any videos smaller than SIZE (e.g. 50k or 44.6m)", default=None)
217     selection.add_option('--max-filesize', metavar='SIZE', dest='max_filesize', help="Do not download any videos larger than SIZE (e.g. 50k or 44.6m)", default=None)
218     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
219     selection.add_option(
220         '--datebefore', metavar='DATE', dest='datebefore', default=None,
221         help='download only videos uploaded on or before this date (i.e. inclusive)')
222     selection.add_option(
223         '--dateafter', metavar='DATE', dest='dateafter', default=None,
224         help='download only videos uploaded on or after this date (i.e. inclusive)')
225     selection.add_option(
226         '--min-views', metavar='COUNT', dest='min_views',
227         default=None, type=int,
228         help="Do not download any videos with less than COUNT views",)
229     selection.add_option(
230         '--max-views', metavar='COUNT', dest='max_views',
231         default=None, type=int,
232         help="Do not download any videos with more than COUNT views",)
233     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
234     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
235                          help='download only videos suitable for the given age',
236                          default=None, type=int)
237     selection.add_option('--download-archive', metavar='FILE',
238                          dest='download_archive',
239                          help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
240
241
242     authentication.add_option('-u', '--username',
243             dest='username', metavar='USERNAME', help='account username')
244     authentication.add_option('-p', '--password',
245             dest='password', metavar='PASSWORD', help='account password')
246     authentication.add_option('-n', '--netrc',
247             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
248     authentication.add_option('--video-password',
249             dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
250
251
252     video_format.add_option('-f', '--format',
253             action='store', dest='format', metavar='FORMAT', default='best',
254             help='video format code, specify the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported')
255     video_format.add_option('--all-formats',
256             action='store_const', dest='format', help='download all available video formats', const='all')
257     video_format.add_option('--prefer-free-formats',
258             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
259     video_format.add_option('--max-quality',
260             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
261     video_format.add_option('-F', '--list-formats',
262             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
263
264     subtitles.add_option('--write-sub', '--write-srt',
265             action='store_true', dest='writesubtitles',
266             help='write subtitle file', default=False)
267     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
268             action='store_true', dest='writeautomaticsub',
269             help='write automatic subtitle file (youtube only)', default=False)
270     subtitles.add_option('--all-subs',
271             action='store_true', dest='allsubtitles',
272             help='downloads all the available subtitles of the video', default=False)
273     subtitles.add_option('--list-subs',
274             action='store_true', dest='listsubtitles',
275             help='lists all available subtitles for the video', default=False)
276     subtitles.add_option('--sub-format',
277             action='store', dest='subtitlesformat', metavar='FORMAT',
278             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
279     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
280             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
281             default=[], callback=_comma_separated_values_options_callback,
282             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
283
284     downloader.add_option('-r', '--rate-limit',
285             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
286     downloader.add_option('-R', '--retries',
287             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
288     downloader.add_option('--buffer-size',
289             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
290     downloader.add_option('--no-resize-buffer',
291             action='store_true', dest='noresizebuffer',
292             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
293     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
294
295     verbosity.add_option('-q', '--quiet',
296             action='store_true', dest='quiet', help='activates quiet mode', default=False)
297     verbosity.add_option('-s', '--simulate',
298             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
299     verbosity.add_option('--skip-download',
300             action='store_true', dest='skip_download', help='do not download the video', default=False)
301     verbosity.add_option('-g', '--get-url',
302             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
303     verbosity.add_option('-e', '--get-title',
304             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
305     verbosity.add_option('--get-id',
306             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
307     verbosity.add_option('--get-thumbnail',
308             action='store_true', dest='getthumbnail',
309             help='simulate, quiet but print thumbnail URL', default=False)
310     verbosity.add_option('--get-description',
311             action='store_true', dest='getdescription',
312             help='simulate, quiet but print video description', default=False)
313     verbosity.add_option('--get-duration',
314             action='store_true', dest='getduration',
315             help='simulate, quiet but print video length', default=False)
316     verbosity.add_option('--get-filename',
317             action='store_true', dest='getfilename',
318             help='simulate, quiet but print output filename', default=False)
319     verbosity.add_option('--get-format',
320             action='store_true', dest='getformat',
321             help='simulate, quiet but print output format', default=False)
322     verbosity.add_option('-j', '--dump-json',
323             action='store_true', dest='dumpjson',
324             help='simulate, quiet but print JSON information', default=False)
325     verbosity.add_option('--newline',
326             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
327     verbosity.add_option('--no-progress',
328             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
329     verbosity.add_option('--console-title',
330             action='store_true', dest='consoletitle',
331             help='display progress in console titlebar', default=False)
332     verbosity.add_option('-v', '--verbose',
333             action='store_true', dest='verbose', help='print various debugging information', default=False)
334     verbosity.add_option('--dump-intermediate-pages',
335             action='store_true', dest='dump_intermediate_pages', default=False,
336             help='print downloaded pages to debug problems(very verbose)')
337     verbosity.add_option('--write-pages',
338             action='store_true', dest='write_pages', default=False,
339             help='Write downloaded intermediary pages to files in the current directory to debug problems')
340     verbosity.add_option('--youtube-print-sig-code',
341             action='store_true', dest='youtube_print_sig_code', default=False,
342             help=optparse.SUPPRESS_HELP)
343     verbosity.add_option('--print-traffic',
344             dest='debug_printtraffic', action='store_true', default=False,
345             help=optparse.SUPPRESS_HELP)
346
347     filesystem.add_option('-t', '--title',
348             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
349     filesystem.add_option('--id',
350             action='store_true', dest='useid', help='use only video ID in file name', default=False)
351     filesystem.add_option('-l', '--literal',
352             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
353     filesystem.add_option('-A', '--auto-number',
354             action='store_true', dest='autonumber',
355             help='number downloaded files starting from 00000', default=False)
356     filesystem.add_option('-o', '--output',
357             dest='outtmpl', metavar='TEMPLATE',
358             help=('output filename template. Use %(title)s to get the title, '
359                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
360                   '%(autonumber)s to get an automatically incremented number, '
361                   '%(ext)s for the filename extension, '
362                   '%(format)s for the format description (like "22 - 1280x720" or "HD"),'
363                   '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"),'
364                   '%(upload_date)s for the upload date (YYYYMMDD), '
365                   '%(extractor)s for the provider (youtube, metacafe, etc), '
366                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
367                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
368                   'Use - to output to stdout. Can also be used to download to a different directory, '
369                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
370     filesystem.add_option('--autonumber-size',
371             dest='autonumber_size', metavar='NUMBER',
372             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
373     filesystem.add_option('--restrict-filenames',
374             action='store_true', dest='restrictfilenames',
375             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
376     filesystem.add_option('-a', '--batch-file',
377             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
378     filesystem.add_option('--load-info',
379             dest='load_info_filename', metavar='FILE',
380             help='json file containing the video information (created with the "--write-json" option')
381     filesystem.add_option('-w', '--no-overwrites',
382             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
383     filesystem.add_option('-c', '--continue',
384             action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
385     filesystem.add_option('--no-continue',
386             action='store_false', dest='continue_dl',
387             help='do not resume partially downloaded files (restart from beginning)')
388     filesystem.add_option('--cookies',
389             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
390     filesystem.add_option('--no-part',
391             action='store_true', dest='nopart', help='do not use .part files', default=False)
392     filesystem.add_option('--no-mtime',
393             action='store_false', dest='updatetime',
394             help='do not use the Last-modified header to set the file modification time', default=True)
395     filesystem.add_option('--write-description',
396             action='store_true', dest='writedescription',
397             help='write video description to a .description file', default=False)
398     filesystem.add_option('--write-info-json',
399             action='store_true', dest='writeinfojson',
400             help='write video metadata to a .info.json file', default=False)
401     filesystem.add_option('--write-annotations',
402             action='store_true', dest='writeannotations',
403             help='write video annotations to a .annotation file', default=False)
404     filesystem.add_option('--write-thumbnail',
405             action='store_true', dest='writethumbnail',
406             help='write thumbnail image to disk', default=False)
407
408
409     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
410             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
411     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
412             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
413     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
414             help='ffmpeg/avconv audio quality specification, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default 5)')
415     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
416             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
417     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
418             help='keeps the video file on disk after the post-processing; the video is erased by default')
419     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
420             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
421     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
422             help='embed subtitles in the video (only for mp4 videos)')
423     postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
424             help='write metadata to the video file')
425     postproc.add_option('--xattrs', action='store_true', dest='xattrs', default=False,
426             help='write metadata to the video file\'s xattrs (using dublin core and xdg standards)')
427     postproc.add_option('--prefer-avconv', action='store_false', dest='prefer_ffmpeg',
428         help='Prefer avconv over ffmpeg for running the postprocessors (default)')
429     postproc.add_option('--prefer-ffmpeg', action='store_true', dest='prefer_ffmpeg',
430         help='Prefer ffmpeg over avconv for running the postprocessors')
431
432
433     parser.add_option_group(general)
434     parser.add_option_group(selection)
435     parser.add_option_group(downloader)
436     parser.add_option_group(filesystem)
437     parser.add_option_group(verbosity)
438     parser.add_option_group(video_format)
439     parser.add_option_group(subtitles)
440     parser.add_option_group(authentication)
441     parser.add_option_group(postproc)
442
443     if overrideArguments is not None:
444         opts, args = parser.parse_args(overrideArguments)
445         if opts.verbose:
446             write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
447     else:
448         systemConf = _readOptions('/etc/youtube-dl.conf')
449
450         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
451         if xdg_config_home:
452             userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
453             if not os.path.isfile(userConfFile):
454                 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
455         else:
456             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
457             if not os.path.isfile(userConfFile):
458                 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
459         userConf = _readOptions(userConfFile, None)
460
461         if userConf is None:
462             appdata_dir = os.environ.get('appdata')
463             if appdata_dir:
464                 userConf = _readOptions(
465                     os.path.join(appdata_dir, 'youtube-dl', 'config'),
466                     default=None)
467                 if userConf is None:
468                     userConf = _readOptions(
469                         os.path.join(appdata_dir, 'youtube-dl', 'config.txt'),
470                         default=None)
471
472         if userConf is None:
473             userConf = _readOptions(
474                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf'),
475                 default=None)
476         if userConf is None:
477             userConf = _readOptions(
478                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf.txt'),
479                 default=None)
480
481         if userConf is None:
482             userConf = []
483
484         commandLineConf = sys.argv[1:]
485         argv = systemConf + userConf + commandLineConf
486         opts, args = parser.parse_args(argv)
487         if opts.verbose:
488             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
489             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
490             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
491             write_string(u'[debug] Encodings: locale %r, fs %r, out %r, pref: %r\n' %
492                          (locale.getpreferredencoding(), sys.getfilesystemencoding(), sys.stdout.encoding, preferredencoding()))
493
494     return parser, opts, args
495
496
497 def _real_main(argv=None):
498     # Compatibility fixes for Windows
499     if sys.platform == 'win32':
500         # https://github.com/rg3/youtube-dl/issues/820
501         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
502
503     setproctitle(u'youtube-dl')
504
505     parser, opts, args = parseOpts(argv)
506
507     # Set user agent
508     if opts.user_agent is not None:
509         std_headers['User-Agent'] = opts.user_agent
510
511     # Set referer
512     if opts.referer is not None:
513         std_headers['Referer'] = opts.referer
514
515     # Dump user agent
516     if opts.dump_user_agent:
517         compat_print(std_headers['User-Agent'])
518         sys.exit(0)
519
520     # Batch file verification
521     batchurls = []
522     if opts.batchfile is not None:
523         try:
524             if opts.batchfile == '-':
525                 batchfd = sys.stdin
526             else:
527                 batchfd = open(opts.batchfile, 'r')
528             batchurls = batchfd.readlines()
529             batchurls = [x.strip() for x in batchurls]
530             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
531             if opts.verbose:
532                 write_string(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
533         except IOError:
534             sys.exit(u'ERROR: batch file could not be read')
535     all_urls = batchurls + args
536     all_urls = [url.strip() for url in all_urls]
537     _enc = preferredencoding()
538     all_urls = [url.decode(_enc, 'ignore') if isinstance(url, bytes) else url for url in all_urls]
539
540     extractors = gen_extractors()
541
542     if opts.list_extractors:
543         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
544             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
545             matchedUrls = [url for url in all_urls if ie.suitable(url)]
546             for mu in matchedUrls:
547                 compat_print(u'  ' + mu)
548         sys.exit(0)
549     if opts.list_extractor_descriptions:
550         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
551             if not ie._WORKING:
552                 continue
553             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
554             if desc is False:
555                 continue
556             if hasattr(ie, 'SEARCH_KEY'):
557                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
558                 _COUNTS = (u'', u'5', u'10', u'all')
559                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
560             compat_print(desc)
561         sys.exit(0)
562
563
564     # Conflicting, missing and erroneous options
565     if opts.usenetrc and (opts.username is not None or opts.password is not None):
566         parser.error(u'using .netrc conflicts with giving username/password')
567     if opts.password is not None and opts.username is None:
568         parser.error(u' account username missing\n')
569     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
570         parser.error(u'using output template conflicts with using title, video ID or auto number')
571     if opts.usetitle and opts.useid:
572         parser.error(u'using title conflicts with using video ID')
573     if opts.username is not None and opts.password is None:
574         opts.password = getpass.getpass(u'Type account password and press return:')
575     if opts.ratelimit is not None:
576         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
577         if numeric_limit is None:
578             parser.error(u'invalid rate limit specified')
579         opts.ratelimit = numeric_limit
580     if opts.min_filesize is not None:
581         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
582         if numeric_limit is None:
583             parser.error(u'invalid min_filesize specified')
584         opts.min_filesize = numeric_limit
585     if opts.max_filesize is not None:
586         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
587         if numeric_limit is None:
588             parser.error(u'invalid max_filesize specified')
589         opts.max_filesize = numeric_limit
590     if opts.retries is not None:
591         try:
592             opts.retries = int(opts.retries)
593         except (TypeError, ValueError):
594             parser.error(u'invalid retry count specified')
595     if opts.buffersize is not None:
596         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
597         if numeric_buffersize is None:
598             parser.error(u'invalid buffer size specified')
599         opts.buffersize = numeric_buffersize
600     if opts.playliststart <= 0:
601         raise ValueError(u'Playlist start must be positive')
602     if opts.playlistend not in (-1, None) and opts.playlistend < opts.playliststart:
603         raise ValueError(u'Playlist end must be greater than playlist start')
604     if opts.extractaudio:
605         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
606             parser.error(u'invalid audio format specified')
607     if opts.audioquality:
608         opts.audioquality = opts.audioquality.strip('k').strip('K')
609         if not opts.audioquality.isdigit():
610             parser.error(u'invalid audio quality specified')
611     if opts.recodevideo is not None:
612         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
613             parser.error(u'invalid video recode format specified')
614     if opts.date is not None:
615         date = DateRange.day(opts.date)
616     else:
617         date = DateRange(opts.dateafter, opts.datebefore)
618
619     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
620     # this was the old behaviour if only --all-sub was given.
621     if opts.allsubtitles and (opts.writeautomaticsub == False):
622         opts.writesubtitles = True
623
624     if sys.version_info < (3,):
625         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
626         if opts.outtmpl is not None:
627             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
628     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
629             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
630             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
631             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
632             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
633             or (opts.useid and u'%(id)s.%(ext)s')
634             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
635             or u'%(title)s-%(id)s.%(ext)s')
636     if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
637         parser.error(u'Cannot download a video and extract audio into the same'
638                      u' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
639                      u' template'.format(outtmpl))
640
641     any_printing = opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson
642
643     ydl_opts = {
644         'usenetrc': opts.usenetrc,
645         'username': opts.username,
646         'password': opts.password,
647         'videopassword': opts.videopassword,
648         'quiet': (opts.quiet or any_printing),
649         'forceurl': opts.geturl,
650         'forcetitle': opts.gettitle,
651         'forceid': opts.getid,
652         'forcethumbnail': opts.getthumbnail,
653         'forcedescription': opts.getdescription,
654         'forceduration': opts.getduration,
655         'forcefilename': opts.getfilename,
656         'forceformat': opts.getformat,
657         'forcejson': opts.dumpjson,
658         'simulate': opts.simulate,
659         'skip_download': (opts.skip_download or opts.simulate or any_printing),
660         'format': opts.format,
661         'format_limit': opts.format_limit,
662         'listformats': opts.listformats,
663         'outtmpl': outtmpl,
664         'autonumber_size': opts.autonumber_size,
665         'restrictfilenames': opts.restrictfilenames,
666         'ignoreerrors': opts.ignoreerrors,
667         'ratelimit': opts.ratelimit,
668         'nooverwrites': opts.nooverwrites,
669         'retries': opts.retries,
670         'buffersize': opts.buffersize,
671         'noresizebuffer': opts.noresizebuffer,
672         'continuedl': opts.continue_dl,
673         'noprogress': opts.noprogress,
674         'progress_with_newline': opts.progress_with_newline,
675         'playliststart': opts.playliststart,
676         'playlistend': opts.playlistend,
677         'noplaylist': opts.noplaylist,
678         'logtostderr': opts.outtmpl == '-',
679         'consoletitle': opts.consoletitle,
680         'nopart': opts.nopart,
681         'updatetime': opts.updatetime,
682         'writedescription': opts.writedescription,
683         'writeannotations': opts.writeannotations,
684         'writeinfojson': opts.writeinfojson,
685         'writethumbnail': opts.writethumbnail,
686         'writesubtitles': opts.writesubtitles,
687         'writeautomaticsub': opts.writeautomaticsub,
688         'allsubtitles': opts.allsubtitles,
689         'listsubtitles': opts.listsubtitles,
690         'subtitlesformat': opts.subtitlesformat,
691         'subtitleslangs': opts.subtitleslangs,
692         'matchtitle': decodeOption(opts.matchtitle),
693         'rejecttitle': decodeOption(opts.rejecttitle),
694         'max_downloads': opts.max_downloads,
695         'prefer_free_formats': opts.prefer_free_formats,
696         'verbose': opts.verbose,
697         'dump_intermediate_pages': opts.dump_intermediate_pages,
698         'write_pages': opts.write_pages,
699         'test': opts.test,
700         'keepvideo': opts.keepvideo,
701         'min_filesize': opts.min_filesize,
702         'max_filesize': opts.max_filesize,
703         'min_views': opts.min_views,
704         'max_views': opts.max_views,
705         'daterange': date,
706         'cachedir': opts.cachedir,
707         'youtube_print_sig_code': opts.youtube_print_sig_code,
708         'age_limit': opts.age_limit,
709         'download_archive': opts.download_archive,
710         'cookiefile': opts.cookiefile,
711         'nocheckcertificate': opts.no_check_certificate,
712         'proxy': opts.proxy,
713         'socket_timeout': opts.socket_timeout,
714         'bidi_workaround': opts.bidi_workaround,
715         'debug_printtraffic': opts.debug_printtraffic,
716         'prefer_ffmpeg': opts.prefer_ffmpeg,
717     }
718
719     with YoutubeDL(ydl_opts) as ydl:
720         ydl.print_debug_header()
721         ydl.add_default_info_extractors()
722
723         # PostProcessors
724         # Add the metadata pp first, the other pps will copy it
725         if opts.addmetadata:
726             ydl.add_post_processor(FFmpegMetadataPP())
727         if opts.extractaudio:
728             ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
729         if opts.recodevideo:
730             ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
731         if opts.embedsubtitles:
732             ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
733         if opts.xattrs:
734             ydl.add_post_processor(XAttrMetadataPP())
735
736         # Update version
737         if opts.update_self:
738             update_self(ydl.to_screen, opts.verbose)
739
740         # Maybe do nothing
741         if (len(all_urls) < 1) and (opts.load_info_filename is None):
742             if not opts.update_self:
743                 parser.error(u'you must provide at least one URL')
744             else:
745                 sys.exit()
746
747         try:
748             if opts.load_info_filename is not None:
749                 retcode = ydl.download_with_info_file(opts.load_info_filename)
750             else:
751                 retcode = ydl.download(all_urls)
752         except MaxDownloadsReached:
753             ydl.to_screen(u'--max-download limit reached, aborting.')
754             retcode = 101
755
756     sys.exit(retcode)
757
758
759 def main(argv=None):
760     try:
761         _real_main(argv)
762     except DownloadError:
763         sys.exit(1)
764     except SameFileError:
765         sys.exit(u'ERROR: fixed output name but more than one file to download')
766     except KeyboardInterrupt:
767         sys.exit(u'\nERROR: Interrupted by user')