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