clean up printing in __init__.py
[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     )
29
30 __license__ = 'Public Domain'
31
32 import codecs
33 import getpass
34 import optparse
35 import os
36 import re
37 import shlex
38 import socket
39 import subprocess
40 import sys
41 import warnings
42 import platform
43
44 from .utils import *
45 from .update import update_self
46 from .version import __version__
47 from .FileDownloader import *
48 from .extractor import gen_extractors
49 from .YoutubeDL import YoutubeDL
50 from .PostProcessor import *
51
52 def parseOpts(overrideArguments=None):
53     def _readOptions(filename_bytes):
54         try:
55             optionf = open(filename_bytes)
56         except IOError:
57             return [] # silently skip if file is not present
58         try:
59             res = []
60             for l in optionf:
61                 res += shlex.split(l, comments=True)
62         finally:
63             optionf.close()
64         return res
65
66     def _format_option_string(option):
67         ''' ('-o', '--option') -> -o, --format METAVAR'''
68
69         opts = []
70
71         if option._short_opts:
72             opts.append(option._short_opts[0])
73         if option._long_opts:
74             opts.append(option._long_opts[0])
75         if len(opts) > 1:
76             opts.insert(1, ', ')
77
78         if option.takes_value(): opts.append(' %s' % option.metavar)
79
80         return "".join(opts)
81
82     def _find_term_columns():
83         columns = os.environ.get('COLUMNS', None)
84         if columns:
85             return int(columns)
86
87         try:
88             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
89             out,err = sp.communicate()
90             return int(out.split()[1])
91         except:
92             pass
93         return None
94
95     max_width = 80
96     max_help_position = 80
97
98     # No need to wrap help messages if we're on a wide console
99     columns = _find_term_columns()
100     if columns: max_width = columns
101
102     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
103     fmt.format_option_strings = _format_option_string
104
105     kw = {
106         'version'   : __version__,
107         'formatter' : fmt,
108         'usage' : '%prog [options] url [url...]',
109         'conflict_handler' : 'resolve',
110     }
111
112     parser = optparse.OptionParser(**kw)
113
114     # option groups
115     general        = optparse.OptionGroup(parser, 'General Options')
116     selection      = optparse.OptionGroup(parser, 'Video Selection')
117     authentication = optparse.OptionGroup(parser, 'Authentication Options')
118     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
119     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
120     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
121     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
122
123     general.add_option('-h', '--help',
124             action='help', help='print this help text and exit')
125     general.add_option('-v', '--version',
126             action='version', help='print program version and exit')
127     general.add_option('-U', '--update',
128             action='store_true', dest='update_self', help='update this program to latest version')
129     general.add_option('-i', '--ignore-errors',
130             action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
131     general.add_option('-r', '--rate-limit',
132             dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
133     general.add_option('-R', '--retries',
134             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
135     general.add_option('--buffer-size',
136             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
137     general.add_option('--no-resize-buffer',
138             action='store_true', dest='noresizebuffer',
139             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
140     general.add_option('--dump-user-agent',
141             action='store_true', dest='dump_user_agent',
142             help='display the current browser identification', default=False)
143     general.add_option('--user-agent',
144             dest='user_agent', help='specify a custom user agent', metavar='UA')
145     general.add_option('--referer',
146             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
147             metavar='REF', default=None)
148     general.add_option('--list-extractors',
149             action='store_true', dest='list_extractors',
150             help='List all supported extractors and the URLs they would handle', default=False)
151     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
152     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
153     general.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
154
155     selection.add_option('--playlist-start',
156             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
157     selection.add_option('--playlist-end',
158             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
159     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
160     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
161     selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
162     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)
163     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)
164     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
165     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
166     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
167
168
169     authentication.add_option('-u', '--username',
170             dest='username', metavar='USERNAME', help='account username')
171     authentication.add_option('-p', '--password',
172             dest='password', metavar='PASSWORD', help='account password')
173     authentication.add_option('-n', '--netrc',
174             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
175
176
177     video_format.add_option('-f', '--format',
178             action='store', dest='format', metavar='FORMAT',
179             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
180     video_format.add_option('--all-formats',
181             action='store_const', dest='format', help='download all available video formats', const='all')
182     video_format.add_option('--prefer-free-formats',
183             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
184     video_format.add_option('--max-quality',
185             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
186     video_format.add_option('-F', '--list-formats',
187             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
188     video_format.add_option('--write-sub', '--write-srt',
189             action='store_true', dest='writesubtitles',
190             help='write subtitle file (currently youtube only)', default=False)
191     video_format.add_option('--only-sub',
192             action='store_true', dest='skip_download',
193             help='[deprecated] alias of --skip-download', default=False)
194     video_format.add_option('--all-subs',
195             action='store_true', dest='allsubtitles',
196             help='downloads all the available subtitles of the video (currently youtube only)', default=False)
197     video_format.add_option('--list-subs',
198             action='store_true', dest='listsubtitles',
199             help='lists all available subtitles for the video (currently youtube only)', default=False)
200     video_format.add_option('--sub-format',
201             action='store', dest='subtitlesformat', metavar='FORMAT',
202             help='subtitle format [srt/sbv] (default=srt) (currently youtube only)', default='srt')
203     video_format.add_option('--sub-lang', '--srt-lang',
204             action='store', dest='subtitleslang', metavar='LANG',
205             help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
206
207     verbosity.add_option('-q', '--quiet',
208             action='store_true', dest='quiet', help='activates quiet mode', default=False)
209     verbosity.add_option('-s', '--simulate',
210             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
211     verbosity.add_option('--skip-download',
212             action='store_true', dest='skip_download', help='do not download the video', default=False)
213     verbosity.add_option('-g', '--get-url',
214             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
215     verbosity.add_option('-e', '--get-title',
216             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
217     verbosity.add_option('--get-id',
218             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
219     verbosity.add_option('--get-thumbnail',
220             action='store_true', dest='getthumbnail',
221             help='simulate, quiet but print thumbnail URL', default=False)
222     verbosity.add_option('--get-description',
223             action='store_true', dest='getdescription',
224             help='simulate, quiet but print video description', default=False)
225     verbosity.add_option('--get-filename',
226             action='store_true', dest='getfilename',
227             help='simulate, quiet but print output filename', default=False)
228     verbosity.add_option('--get-format',
229             action='store_true', dest='getformat',
230             help='simulate, quiet but print output format', default=False)
231     verbosity.add_option('--newline',
232             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
233     verbosity.add_option('--no-progress',
234             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
235     verbosity.add_option('--console-title',
236             action='store_true', dest='consoletitle',
237             help='display progress in console titlebar', default=False)
238     verbosity.add_option('-v', '--verbose',
239             action='store_true', dest='verbose', help='print various debugging information', default=False)
240     verbosity.add_option('--dump-intermediate-pages',
241             action='store_true', dest='dump_intermediate_pages', default=False,
242             help='print downloaded pages to debug problems(very verbose)')
243
244     filesystem.add_option('-t', '--title',
245             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
246     filesystem.add_option('--id',
247             action='store_true', dest='useid', help='use only video ID in file name', default=False)
248     filesystem.add_option('-l', '--literal',
249             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
250     filesystem.add_option('-A', '--auto-number',
251             action='store_true', dest='autonumber',
252             help='number downloaded files starting from 00000', default=False)
253     filesystem.add_option('-o', '--output',
254             dest='outtmpl', metavar='TEMPLATE',
255             help=('output filename template. Use %(title)s to get the title, '
256                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
257                   '%(autonumber)s to get an automatically incremented number, '
258                   '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
259                   '%(extractor)s for the provider (youtube, metacafe, etc), '
260                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
261                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
262                   'Use - to output to stdout. Can also be used to download to a different directory, '
263                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
264     filesystem.add_option('--autonumber-size',
265             dest='autonumber_size', metavar='NUMBER',
266             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
267     filesystem.add_option('--restrict-filenames',
268             action='store_true', dest='restrictfilenames',
269             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
270     filesystem.add_option('-a', '--batch-file',
271             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
272     filesystem.add_option('-w', '--no-overwrites',
273             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
274     filesystem.add_option('-c', '--continue',
275             action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
276     filesystem.add_option('--no-continue',
277             action='store_false', dest='continue_dl',
278             help='do not resume partially downloaded files (restart from beginning)')
279     filesystem.add_option('--cookies',
280             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
281     filesystem.add_option('--no-part',
282             action='store_true', dest='nopart', help='do not use .part files', default=False)
283     filesystem.add_option('--no-mtime',
284             action='store_false', dest='updatetime',
285             help='do not use the Last-modified header to set the file modification time', default=True)
286     filesystem.add_option('--write-description',
287             action='store_true', dest='writedescription',
288             help='write video description to a .description file', default=False)
289     filesystem.add_option('--write-info-json',
290             action='store_true', dest='writeinfojson',
291             help='write video metadata to a .info.json file', default=False)
292     filesystem.add_option('--write-thumbnail',
293             action='store_true', dest='writethumbnail',
294             help='write thumbnail image to disk', default=False)
295
296
297     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
298             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
299     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
300             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
301     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
302             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)')
303     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
304             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
305     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
306             help='keeps the video file on disk after the post-processing; the video is erased by default')
307     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
308             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
309
310
311     parser.add_option_group(general)
312     parser.add_option_group(selection)
313     parser.add_option_group(filesystem)
314     parser.add_option_group(verbosity)
315     parser.add_option_group(video_format)
316     parser.add_option_group(authentication)
317     parser.add_option_group(postproc)
318
319     if overrideArguments is not None:
320         opts, args = parser.parse_args(overrideArguments)
321         if opts.verbose:
322             sys.stderr.write(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
323     else:
324         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
325         if xdg_config_home:
326             userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
327         else:
328             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
329         systemConf = _readOptions('/etc/youtube-dl.conf')
330         userConf = _readOptions(userConfFile)
331         commandLineConf = sys.argv[1:] 
332         argv = systemConf + userConf + commandLineConf
333         opts, args = parser.parse_args(argv)
334         if opts.verbose:
335             sys.stderr.write(u'[debug] System config: ' + repr(systemConf) + '\n')
336             sys.stderr.write(u'[debug] User config: ' + repr(userConf) + '\n')
337             sys.stderr.write(u'[debug] Command-line args: ' + repr(commandLineConf) + '\n')
338
339     return parser, opts, args
340
341 def _real_main(argv=None):
342     # Compatibility fixes for Windows
343     if sys.platform == 'win32':
344         # https://github.com/rg3/youtube-dl/issues/820
345         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
346
347     parser, opts, args = parseOpts(argv)
348
349     # Open appropriate CookieJar
350     if opts.cookiefile is None:
351         jar = compat_cookiejar.CookieJar()
352     else:
353         try:
354             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
355             if os.access(opts.cookiefile, os.R_OK):
356                 jar.load()
357         except (IOError, OSError) as err:
358             if opts.verbose:
359                 traceback.print_exc()
360             sys.stderr.write(u'ERROR: unable to open cookie file\n')
361             sys.exit(101)
362     # Set user agent
363     if opts.user_agent is not None:
364         std_headers['User-Agent'] = opts.user_agent
365     
366     # Set referer
367     if opts.referer is not None:
368         std_headers['Referer'] = opts.referer
369
370     # Dump user agent
371     if opts.dump_user_agent:
372         compat_print(std_headers['User-Agent'])
373         sys.exit(0)
374
375     # Batch file verification
376     batchurls = []
377     if opts.batchfile is not None:
378         try:
379             if opts.batchfile == '-':
380                 batchfd = sys.stdin
381             else:
382                 batchfd = open(opts.batchfile, 'r')
383             batchurls = batchfd.readlines()
384             batchurls = [x.strip() for x in batchurls]
385             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
386         except IOError:
387             sys.exit(u'ERROR: batch file could not be read')
388     all_urls = batchurls + args
389     all_urls = [url.strip() for url in all_urls]
390
391     # General configuration
392     cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
393     if opts.proxy is not None:
394         if opts.proxy == '':
395             proxies = {}
396         else:
397             proxies = {'http': opts.proxy, 'https': opts.proxy}
398     else:
399         proxies = compat_urllib_request.getproxies()
400         # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
401         if 'http' in proxies and 'https' not in proxies:
402             proxies['https'] = proxies['http']
403     proxy_handler = compat_urllib_request.ProxyHandler(proxies)
404     https_handler = make_HTTPS_handler(opts)
405     opener = compat_urllib_request.build_opener(https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
406     compat_urllib_request.install_opener(opener)
407     socket.setdefaulttimeout(300) # 5 minutes should be enough (famous last words)
408
409     extractors = gen_extractors()
410
411     if opts.list_extractors:
412         for ie in extractors:
413             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
414             matchedUrls = [url for url in all_urls if ie.suitable(url)]
415             all_urls = [url for url in all_urls if url not in matchedUrls]
416             for mu in matchedUrls:
417                 compat_print(u'  ' + mu)
418         sys.exit(0)
419
420     # Conflicting, missing and erroneous options
421     if opts.usenetrc and (opts.username is not None or opts.password is not None):
422         parser.error(u'using .netrc conflicts with giving username/password')
423     if opts.password is not None and opts.username is None:
424         sys.stderr.write(u'WARNING: account username missing\n')
425     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
426         parser.error(u'using output template conflicts with using title, video ID or auto number')
427     if opts.usetitle and opts.useid:
428         parser.error(u'using title conflicts with using video ID')
429     if opts.username is not None and opts.password is None:
430         opts.password = getpass.getpass(u'Type account password and press return:')
431     if opts.ratelimit is not None:
432         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
433         if numeric_limit is None:
434             parser.error(u'invalid rate limit specified')
435         opts.ratelimit = numeric_limit
436     if opts.min_filesize is not None:
437         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
438         if numeric_limit is None:
439             parser.error(u'invalid min_filesize specified')
440         opts.min_filesize = numeric_limit
441     if opts.max_filesize is not None:
442         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
443         if numeric_limit is None:
444             parser.error(u'invalid max_filesize specified')
445         opts.max_filesize = numeric_limit
446     if opts.retries is not None:
447         try:
448             opts.retries = int(opts.retries)
449         except (TypeError, ValueError) as err:
450             parser.error(u'invalid retry count specified')
451     if opts.buffersize is not None:
452         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
453         if numeric_buffersize is None:
454             parser.error(u'invalid buffer size specified')
455         opts.buffersize = numeric_buffersize
456     try:
457         opts.playliststart = int(opts.playliststart)
458         if opts.playliststart <= 0:
459             raise ValueError(u'Playlist start must be positive')
460     except (TypeError, ValueError) as err:
461         parser.error(u'invalid playlist start number specified')
462     try:
463         opts.playlistend = int(opts.playlistend)
464         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
465             raise ValueError(u'Playlist end must be greater than playlist start')
466     except (TypeError, ValueError) as err:
467         parser.error(u'invalid playlist end number specified')
468     if opts.extractaudio:
469         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
470             parser.error(u'invalid audio format specified')
471     if opts.audioquality:
472         opts.audioquality = opts.audioquality.strip('k').strip('K')
473         if not opts.audioquality.isdigit():
474             parser.error(u'invalid audio quality specified')
475     if opts.recodevideo is not None:
476         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
477             parser.error(u'invalid video recode format specified')
478     if opts.date is not None:
479         date = DateRange.day(opts.date)
480     else:
481         date = DateRange(opts.dateafter, opts.datebefore)
482
483     if sys.version_info < (3,):
484         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
485         if opts.outtmpl is not None:
486             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
487     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
488             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
489             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
490             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
491             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
492             or (opts.useid and u'%(id)s.%(ext)s')
493             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
494             or u'%(title)s-%(id)s.%(ext)s')
495
496     # YoutubeDL
497     ydl = YoutubeDL({
498         'usenetrc': opts.usenetrc,
499         'username': opts.username,
500         'password': opts.password,
501         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
502         'forceurl': opts.geturl,
503         'forcetitle': opts.gettitle,
504         'forceid': opts.getid,
505         'forcethumbnail': opts.getthumbnail,
506         'forcedescription': opts.getdescription,
507         'forcefilename': opts.getfilename,
508         'forceformat': opts.getformat,
509         'simulate': opts.simulate,
510         'skip_download': (opts.skip_download or opts.simulate or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
511         'format': opts.format,
512         'format_limit': opts.format_limit,
513         'listformats': opts.listformats,
514         'outtmpl': outtmpl,
515         'autonumber_size': opts.autonumber_size,
516         'restrictfilenames': opts.restrictfilenames,
517         'ignoreerrors': opts.ignoreerrors,
518         'ratelimit': opts.ratelimit,
519         'nooverwrites': opts.nooverwrites,
520         'retries': opts.retries,
521         'buffersize': opts.buffersize,
522         'noresizebuffer': opts.noresizebuffer,
523         'continuedl': opts.continue_dl,
524         'noprogress': opts.noprogress,
525         'progress_with_newline': opts.progress_with_newline,
526         'playliststart': opts.playliststart,
527         'playlistend': opts.playlistend,
528         'logtostderr': opts.outtmpl == '-',
529         'consoletitle': opts.consoletitle,
530         'nopart': opts.nopart,
531         'updatetime': opts.updatetime,
532         'writedescription': opts.writedescription,
533         'writeinfojson': opts.writeinfojson,
534         'writethumbnail': opts.writethumbnail,
535         'writesubtitles': opts.writesubtitles,
536         'allsubtitles': opts.allsubtitles,
537         'listsubtitles': opts.listsubtitles,
538         'subtitlesformat': opts.subtitlesformat,
539         'subtitleslang': opts.subtitleslang,
540         'matchtitle': decodeOption(opts.matchtitle),
541         'rejecttitle': decodeOption(opts.rejecttitle),
542         'max_downloads': opts.max_downloads,
543         'prefer_free_formats': opts.prefer_free_formats,
544         'verbose': opts.verbose,
545         'dump_intermediate_pages': opts.dump_intermediate_pages,
546         'test': opts.test,
547         'keepvideo': opts.keepvideo,
548         'min_filesize': opts.min_filesize,
549         'max_filesize': opts.max_filesize,
550         'daterange': date,
551         })
552
553     if opts.verbose:
554         ydl.to_screen(u'[debug] youtube-dl version ' + __version__)
555         try:
556             sp = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
557                                   cwd=os.path.dirname(os.path.abspath(__file__)))
558             out, err = sp.communicate()
559             out = out.decode().strip()
560             if re.match('[0-9a-f]+', out):
561                 ydl.to_screen(u'[debug] Git HEAD: ' + out)
562         except:
563             pass
564         ydl.to_screen(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()))
565         ydl.to_screen(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
566
567     for extractor in extractors:
568         ydl.add_info_extractor(extractor)
569
570     # PostProcessors
571     if opts.extractaudio:
572         ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
573     if opts.recodevideo:
574         ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
575
576     # Update version
577     if opts.update_self:
578         update_self(ydl.to_screen, opts.verbose, sys.argv[0])
579
580     # Maybe do nothing
581     if len(all_urls) < 1:
582         if not opts.update_self:
583             parser.error(u'you must provide at least one URL')
584         else:
585             sys.exit()
586
587     try:
588         retcode = ydl.download(all_urls)
589     except MaxDownloadsReached:
590         ydl.to_screen(u'--max-download limit reached, aborting.')
591         retcode = 101
592
593     # Dump cookie jar if requested
594     if opts.cookiefile is not None:
595         try:
596             jar.save()
597         except (IOError, OSError) as err:
598             sys.exit(u'ERROR: unable to save cookie jar')
599
600     sys.exit(retcode)
601
602 def main(argv=None):
603     try:
604         _real_main(argv)
605     except DownloadError:
606         sys.exit(1)
607     except SameFileError:
608         sys.exit(u'ERROR: fixed output name but more than one file to download')
609     except KeyboardInterrupt:
610         sys.exit(u'\nERROR: Interrupted by user')