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