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