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