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