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