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