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