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