Credit @julienfr112 for Ina IE (#823)
[youtube-dl] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from __future__ import with_statement
5 from __future__ import absolute_import
6
7 __authors__  = (
8     'Ricardo Garcia Gonzalez',
9     'Danny Colligan',
10     'Benjamin Johnson',
11     'Vasyl\' Vavrychuk',
12     'Witold Baryluk',
13     'Paweł Paprota',
14     'Gergely Imreh',
15     'Rogério Brito',
16     'Philipp Hagemeister',
17     'Sören Schulze',
18     'Kevin Ngo',
19     'Ori Avtalion',
20     'shizeeg',
21     'Filippo Valsorda',
22     'Christian Albrecht',
23     'Dave Vasilevsky',
24     'Jaime Marquínez Ferrándiz',
25     'Jeff Crouse',
26     'Osama Khalid',
27     'Michael Walter',
28     'M. Yasoob Ullah Khalid',
29     'Julien Fraichard',
30     )
31
32 __license__ = 'Public Domain'
33
34 import codecs
35 import getpass
36 import optparse
37 import os
38 import re
39 import shlex
40 import socket
41 import subprocess
42 import sys
43 import warnings
44 import platform
45
46 from .utils import *
47 from .update import update_self
48 from .version import __version__
49 from .FileDownloader import *
50 from .InfoExtractors import gen_extractors
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
177
178     video_format.add_option('-f', '--format',
179             action='store', dest='format', metavar='FORMAT',
180             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
181     video_format.add_option('--all-formats',
182             action='store_const', dest='format', help='download all available video formats', const='all')
183     video_format.add_option('--prefer-free-formats',
184             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
185     video_format.add_option('--max-quality',
186             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
187     video_format.add_option('-F', '--list-formats',
188             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
189     video_format.add_option('--write-sub', '--write-srt',
190             action='store_true', dest='writesubtitles',
191             help='write subtitle file (currently youtube only)', default=False)
192     video_format.add_option('--only-sub',
193             action='store_true', dest='onlysubtitles',
194             help='downloads only the subtitles (no video)', default=False)
195     video_format.add_option('--all-subs',
196             action='store_true', dest='allsubtitles',
197             help='downloads all the available subtitles of the video (currently youtube only)', default=False)
198     video_format.add_option('--list-subs',
199             action='store_true', dest='listsubtitles',
200             help='lists all available subtitles for the video (currently youtube only)', default=False)
201     video_format.add_option('--sub-format',
202             action='store', dest='subtitlesformat', metavar='LANG',
203             help='subtitle format [srt/sbv] (default=srt) (currently youtube only)', default='srt')
204     video_format.add_option('--sub-lang', '--srt-lang',
205             action='store', dest='subtitleslang', metavar='LANG',
206             help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
207
208     verbosity.add_option('-q', '--quiet',
209             action='store_true', dest='quiet', help='activates quiet mode', default=False)
210     verbosity.add_option('-s', '--simulate',
211             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
212     verbosity.add_option('--skip-download',
213             action='store_true', dest='skip_download', help='do not download the video', default=False)
214     verbosity.add_option('-g', '--get-url',
215             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
216     verbosity.add_option('-e', '--get-title',
217             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
218     verbosity.add_option('--get-thumbnail',
219             action='store_true', dest='getthumbnail',
220             help='simulate, quiet but print thumbnail URL', default=False)
221     verbosity.add_option('--get-description',
222             action='store_true', dest='getdescription',
223             help='simulate, quiet but print video description', default=False)
224     verbosity.add_option('--get-filename',
225             action='store_true', dest='getfilename',
226             help='simulate, quiet but print output filename', default=False)
227     verbosity.add_option('--get-format',
228             action='store_true', dest='getformat',
229             help='simulate, quiet but print output format', default=False)
230     verbosity.add_option('--newline',
231             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
232     verbosity.add_option('--no-progress',
233             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
234     verbosity.add_option('--console-title',
235             action='store_true', dest='consoletitle',
236             help='display progress in console titlebar', default=False)
237     verbosity.add_option('-v', '--verbose',
238             action='store_true', dest='verbose', help='print various debugging information', default=False)
239     verbosity.add_option('--dump-intermediate-pages',
240             action='store_true', dest='dump_intermediate_pages', default=False,
241             help='print downloaded pages to debug problems(very verbose)')
242
243     filesystem.add_option('-t', '--title',
244             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
245     filesystem.add_option('--id',
246             action='store_true', dest='useid', help='use only video ID in file name', default=False)
247     filesystem.add_option('-l', '--literal',
248             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
249     filesystem.add_option('-A', '--auto-number',
250             action='store_true', dest='autonumber',
251             help='number downloaded files starting from 00000', default=False)
252     filesystem.add_option('-o', '--output',
253             dest='outtmpl', metavar='TEMPLATE',
254             help=('output filename template. Use %(title)s to get the title, '
255                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
256                   '%(autonumber)s to get an automatically incremented number, '
257                   '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
258                   '%(extractor)s for the provider (youtube, metacafe, etc), '
259                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
260                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
261                   'Use - to output to stdout. Can also be used to download to a different directory, '
262                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
263     filesystem.add_option('--autonumber-size',
264             dest='autonumber_size', metavar='NUMBER',
265             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
266     filesystem.add_option('--restrict-filenames',
267             action='store_true', dest='restrictfilenames',
268             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
269     filesystem.add_option('-a', '--batch-file',
270             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
271     filesystem.add_option('-w', '--no-overwrites',
272             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
273     filesystem.add_option('-c', '--continue',
274             action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
275     filesystem.add_option('--no-continue',
276             action='store_false', dest='continue_dl',
277             help='do not resume partially downloaded files (restart from beginning)')
278     filesystem.add_option('--cookies',
279             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
280     filesystem.add_option('--no-part',
281             action='store_true', dest='nopart', help='do not use .part files', default=False)
282     filesystem.add_option('--no-mtime',
283             action='store_false', dest='updatetime',
284             help='do not use the Last-modified header to set the file modification time', default=True)
285     filesystem.add_option('--write-description',
286             action='store_true', dest='writedescription',
287             help='write video description to a .description file', default=False)
288     filesystem.add_option('--write-info-json',
289             action='store_true', dest='writeinfojson',
290             help='write video metadata to a .info.json file', default=False)
291     filesystem.add_option('--write-thumbnail',
292             action='store_true', dest='writethumbnail',
293             help='write thumbnail image to disk', default=False)
294
295
296     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
297             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
298     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
299             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
300     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
301             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)')
302     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
303             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
304     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
305             help='keeps the video file on disk after the post-processing; the video is erased by default')
306     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
307             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
308
309
310     parser.add_option_group(general)
311     parser.add_option_group(selection)
312     parser.add_option_group(filesystem)
313     parser.add_option_group(verbosity)
314     parser.add_option_group(video_format)
315     parser.add_option_group(authentication)
316     parser.add_option_group(postproc)
317
318     if overrideArguments is not None:
319         opts, args = parser.parse_args(overrideArguments)
320         if opts.verbose:
321             print(u'[debug] Override config: ' + repr(overrideArguments))
322     else:
323         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
324         if xdg_config_home:
325             userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
326         else:
327             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
328         systemConf = _readOptions('/etc/youtube-dl.conf')
329         userConf = _readOptions(userConfFile)
330         commandLineConf = sys.argv[1:] 
331         argv = systemConf + userConf + commandLineConf
332         opts, args = parser.parse_args(argv)
333         if opts.verbose:
334             print(u'[debug] System config: ' + repr(systemConf))
335             print(u'[debug] User config: ' + repr(userConf))
336             print(u'[debug] Command-line args: ' + repr(commandLineConf))
337
338     return parser, opts, args
339
340 def _real_main(argv=None):
341     # Compatibility fixes for Windows
342     if sys.platform == 'win32':
343         # https://github.com/rg3/youtube-dl/issues/820
344         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
345
346     parser, opts, args = parseOpts(argv)
347
348     # Open appropriate CookieJar
349     if opts.cookiefile is None:
350         jar = compat_cookiejar.CookieJar()
351     else:
352         try:
353             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
354             if os.access(opts.cookiefile, os.R_OK):
355                 jar.load()
356         except (IOError, OSError) as err:
357             if opts.verbose:
358                 traceback.print_exc()
359             sys.stderr.write(u'ERROR: unable to open cookie file\n')
360             sys.exit(101)
361     # Set user agent
362     if opts.user_agent is not None:
363         std_headers['User-Agent'] = opts.user_agent
364     
365     # Set referer
366     if opts.referer is not None:
367         std_headers['Referer'] = opts.referer
368
369     # Dump user agent
370     if opts.dump_user_agent:
371         print(std_headers['User-Agent'])
372         sys.exit(0)
373
374     # Batch file verification
375     batchurls = []
376     if opts.batchfile is not None:
377         try:
378             if opts.batchfile == '-':
379                 batchfd = sys.stdin
380             else:
381                 batchfd = open(opts.batchfile, 'r')
382             batchurls = batchfd.readlines()
383             batchurls = [x.strip() for x in batchurls]
384             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
385         except IOError:
386             sys.exit(u'ERROR: batch file could not be read')
387     all_urls = batchurls + args
388     all_urls = [url.strip() for url in all_urls]
389
390     # General configuration
391     cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
392     if opts.proxy:
393         proxies = {'http': opts.proxy, 'https': opts.proxy}
394     else:
395         proxies = compat_urllib_request.getproxies()
396         # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
397         if 'http' in proxies and 'https' not in proxies:
398             proxies['https'] = proxies['http']
399     proxy_handler = compat_urllib_request.ProxyHandler(proxies)
400     https_handler = make_HTTPS_handler(opts)
401     opener = compat_urllib_request.build_opener(https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
402     compat_urllib_request.install_opener(opener)
403     socket.setdefaulttimeout(300) # 5 minutes should be enough (famous last words)
404
405     extractors = gen_extractors()
406
407     if opts.list_extractors:
408         for ie in extractors:
409             print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
410             matchedUrls = [url for url in all_urls if ie.suitable(url)]
411             all_urls = [url for url in all_urls if url not in matchedUrls]
412             for mu in matchedUrls:
413                 print(u'  ' + mu)
414         sys.exit(0)
415
416     # Conflicting, missing and erroneous options
417     if opts.usenetrc and (opts.username is not None or opts.password is not None):
418         parser.error(u'using .netrc conflicts with giving username/password')
419     if opts.password is not None and opts.username is None:
420         parser.error(u'account username missing')
421     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
422         parser.error(u'using output template conflicts with using title, video ID or auto number')
423     if opts.usetitle and opts.useid:
424         parser.error(u'using title conflicts with using video ID')
425     if opts.username is not None and opts.password is None:
426         opts.password = getpass.getpass(u'Type account password and press return:')
427     if opts.ratelimit is not None:
428         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
429         if numeric_limit is None:
430             parser.error(u'invalid rate limit specified')
431         opts.ratelimit = numeric_limit
432     if opts.min_filesize is not None:
433         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
434         if numeric_limit is None:
435             parser.error(u'invalid min_filesize specified')
436         opts.min_filesize = numeric_limit
437     if opts.max_filesize is not None:
438         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
439         if numeric_limit is None:
440             parser.error(u'invalid max_filesize specified')
441         opts.max_filesize = numeric_limit
442     if opts.retries is not None:
443         try:
444             opts.retries = int(opts.retries)
445         except (TypeError, ValueError) as err:
446             parser.error(u'invalid retry count specified')
447     if opts.buffersize is not None:
448         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
449         if numeric_buffersize is None:
450             parser.error(u'invalid buffer size specified')
451         opts.buffersize = numeric_buffersize
452     try:
453         opts.playliststart = int(opts.playliststart)
454         if opts.playliststart <= 0:
455             raise ValueError(u'Playlist start must be positive')
456     except (TypeError, ValueError) as err:
457         parser.error(u'invalid playlist start number specified')
458     try:
459         opts.playlistend = int(opts.playlistend)
460         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
461             raise ValueError(u'Playlist end must be greater than playlist start')
462     except (TypeError, ValueError) as err:
463         parser.error(u'invalid playlist end number specified')
464     if opts.extractaudio:
465         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
466             parser.error(u'invalid audio format specified')
467     if opts.audioquality:
468         opts.audioquality = opts.audioquality.strip('k').strip('K')
469         if not opts.audioquality.isdigit():
470             parser.error(u'invalid audio quality specified')
471     if opts.recodevideo is not None:
472         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
473             parser.error(u'invalid video recode format specified')
474     if opts.date is not None:
475         date = DateRange.day(opts.date)
476     else:
477         date = DateRange(opts.dateafter, opts.datebefore)
478
479     if sys.version_info < (3,):
480         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
481         if opts.outtmpl is not None:
482             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
483     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
484             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
485             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
486             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
487             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
488             or (opts.useid and u'%(id)s.%(ext)s')
489             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
490             or u'%(title)s-%(id)s.%(ext)s')
491
492     # File downloader
493     fd = FileDownloader({
494         'usenetrc': opts.usenetrc,
495         'username': opts.username,
496         'password': opts.password,
497         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
498         'forceurl': opts.geturl,
499         'forcetitle': opts.gettitle,
500         'forcethumbnail': opts.getthumbnail,
501         'forcedescription': opts.getdescription,
502         'forcefilename': opts.getfilename,
503         'forceformat': opts.getformat,
504         'simulate': opts.simulate,
505         '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),
506         'format': opts.format,
507         'format_limit': opts.format_limit,
508         'listformats': opts.listformats,
509         'outtmpl': outtmpl,
510         'autonumber_size': opts.autonumber_size,
511         'restrictfilenames': opts.restrictfilenames,
512         'ignoreerrors': opts.ignoreerrors,
513         'ratelimit': opts.ratelimit,
514         'nooverwrites': opts.nooverwrites,
515         'retries': opts.retries,
516         'buffersize': opts.buffersize,
517         'noresizebuffer': opts.noresizebuffer,
518         'continuedl': opts.continue_dl,
519         'noprogress': opts.noprogress,
520         'progress_with_newline': opts.progress_with_newline,
521         'playliststart': opts.playliststart,
522         'playlistend': opts.playlistend,
523         'logtostderr': opts.outtmpl == '-',
524         'consoletitle': opts.consoletitle,
525         'nopart': opts.nopart,
526         'updatetime': opts.updatetime,
527         'writedescription': opts.writedescription,
528         'writeinfojson': opts.writeinfojson,
529         'writethumbnail': opts.writethumbnail,
530         'writesubtitles': opts.writesubtitles,
531         'onlysubtitles': opts.onlysubtitles,
532         'allsubtitles': opts.allsubtitles,
533         'listsubtitles': opts.listsubtitles,
534         'subtitlesformat': opts.subtitlesformat,
535         'subtitleslang': opts.subtitleslang,
536         'matchtitle': decodeOption(opts.matchtitle),
537         'rejecttitle': decodeOption(opts.rejecttitle),
538         'max_downloads': opts.max_downloads,
539         'prefer_free_formats': opts.prefer_free_formats,
540         'verbose': opts.verbose,
541         'dump_intermediate_pages': opts.dump_intermediate_pages,
542         'test': opts.test,
543         'keepvideo': opts.keepvideo,
544         'min_filesize': opts.min_filesize,
545         'max_filesize': opts.max_filesize,
546         'daterange': date,
547         })
548
549     if opts.verbose:
550         fd.to_screen(u'[debug] youtube-dl version ' + __version__)
551         try:
552             sp = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
553                                   cwd=os.path.dirname(os.path.abspath(__file__)))
554             out, err = sp.communicate()
555             out = out.decode().strip()
556             if re.match('[0-9a-f]+', out):
557                 fd.to_screen(u'[debug] Git HEAD: ' + out)
558         except:
559             pass
560         fd.to_screen(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()))
561         fd.to_screen(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
562
563     for extractor in extractors:
564         fd.add_info_extractor(extractor)
565
566     # PostProcessors
567     if opts.extractaudio:
568         fd.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
569     if opts.recodevideo:
570         fd.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
571
572     # Update version
573     if opts.update_self:
574         update_self(fd.to_screen, opts.verbose, sys.argv[0])
575
576     # Maybe do nothing
577     if len(all_urls) < 1:
578         if not opts.update_self:
579             parser.error(u'you must provide at least one URL')
580         else:
581             sys.exit()
582
583     try:
584         retcode = fd.download(all_urls)
585     except MaxDownloadsReached:
586         fd.to_screen(u'--max-download limit reached, aborting.')
587         retcode = 101
588
589     # Dump cookie jar if requested
590     if opts.cookiefile is not None:
591         try:
592             jar.save()
593         except (IOError, OSError) as err:
594             sys.exit(u'ERROR: unable to save cookie jar')
595
596     sys.exit(retcode)
597
598 def main(argv=None):
599     try:
600         _real_main(argv)
601     except DownloadError:
602         sys.exit(1)
603     except SameFileError:
604         sys.exit(u'ERROR: fixed output name but more than one file to download')
605     except KeyboardInterrupt:
606         sys.exit(u'\nERROR: Interrupted by user')