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