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