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