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