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