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