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