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