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