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