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