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