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