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