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