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