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