]> 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 )
29
30 __license__ = 'Public Domain'
31
32 import codecs
33 import getpass
34 import optparse
35 import os
36 import re
37 import shlex
38 import socket
39 import subprocess
40 import sys
41 import warnings
42 import platform
43
44 from .utils import *
45 from .update import update_self
46 from .version import __version__
47 from .FileDownloader import *
48 from .extractor import gen_extractors
49 from .PostProcessor import *
50
51 def parseOpts(overrideArguments=None):
52 def _readOptions(filename_bytes):
53 try:
54 optionf = open(filename_bytes)
55 except IOError:
56 return [] # silently skip if file is not present
57 try:
58 res = []
59 for l in optionf:
60 res += shlex.split(l, comments=True)
61 finally:
62 optionf.close()
63 return res
64
65 def _format_option_string(option):
66 ''' ('-o', '--option') -> -o, --format METAVAR'''
67
68 opts = []
69
70 if option._short_opts:
71 opts.append(option._short_opts[0])
72 if option._long_opts:
73 opts.append(option._long_opts[0])
74 if len(opts) > 1:
75 opts.insert(1, ', ')
76
77 if option.takes_value(): opts.append(' %s' % option.metavar)
78
79 return "".join(opts)
80
81 def _find_term_columns():
82 columns = os.environ.get('COLUMNS', None)
83 if columns:
84 return int(columns)
85
86 try:
87 sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
88 out,err = sp.communicate()
89 return int(out.split()[1])
90 except:
91 pass
92 return None
93
94 max_width = 80
95 max_help_position = 80
96
97 # No need to wrap help messages if we're on a wide console
98 columns = _find_term_columns()
99 if columns: max_width = columns
100
101 fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
102 fmt.format_option_strings = _format_option_string
103
104 kw = {
105 'version' : __version__,
106 'formatter' : fmt,
107 'usage' : '%prog [options] url [url...]',
108 'conflict_handler' : 'resolve',
109 }
110
111 parser = optparse.OptionParser(**kw)
112
113 # option groups
114 general = optparse.OptionGroup(parser, 'General Options')
115 selection = optparse.OptionGroup(parser, 'Video Selection')
116 authentication = optparse.OptionGroup(parser, 'Authentication Options')
117 video_format = optparse.OptionGroup(parser, 'Video Format Options')
118 postproc = optparse.OptionGroup(parser, 'Post-processing Options')
119 filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
120 verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
121
122 general.add_option('-h', '--help',
123 action='help', help='print this help text and exit')
124 general.add_option('-v', '--version',
125 action='version', help='print program version and exit')
126 general.add_option('-U', '--update',
127 action='store_true', dest='update_self', help='update this program to latest version')
128 general.add_option('-i', '--ignore-errors',
129 action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
130 general.add_option('-r', '--rate-limit',
131 dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
132 general.add_option('-R', '--retries',
133 dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
134 general.add_option('--buffer-size',
135 dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
136 general.add_option('--no-resize-buffer',
137 action='store_true', dest='noresizebuffer',
138 help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
139 general.add_option('--dump-user-agent',
140 action='store_true', dest='dump_user_agent',
141 help='display the current browser identification', default=False)
142 general.add_option('--user-agent',
143 dest='user_agent', help='specify a custom user agent', metavar='UA')
144 general.add_option('--referer',
145 dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
146 metavar='REF', default=None)
147 general.add_option('--list-extractors',
148 action='store_true', dest='list_extractors',
149 help='List all supported extractors and the URLs they would handle', default=False)
150 general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
151 general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
152 general.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
153
154 selection.add_option('--playlist-start',
155 dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
156 selection.add_option('--playlist-end',
157 dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
158 selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
159 selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
160 selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
161 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)
162 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)
163 selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
164 selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
165 selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
166
167
168 authentication.add_option('-u', '--username',
169 dest='username', metavar='USERNAME', help='account username')
170 authentication.add_option('-p', '--password',
171 dest='password', metavar='PASSWORD', help='account password')
172 authentication.add_option('-n', '--netrc',
173 action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
174
175
176 video_format.add_option('-f', '--format',
177 action='store', dest='format', metavar='FORMAT',
178 help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
179 video_format.add_option('--all-formats',
180 action='store_const', dest='format', help='download all available video formats', const='all')
181 video_format.add_option('--prefer-free-formats',
182 action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
183 video_format.add_option('--max-quality',
184 action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
185 video_format.add_option('-F', '--list-formats',
186 action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
187 video_format.add_option('--write-sub', '--write-srt',
188 action='store_true', dest='writesubtitles',
189 help='write subtitle file (currently youtube only)', default=False)
190 video_format.add_option('--only-sub',
191 action='store_true', dest='skip_download',
192 help='[deprecated] alias of --skip-download', default=False)
193 video_format.add_option('--all-subs',
194 action='store_true', dest='allsubtitles',
195 help='downloads all the available subtitles of the video (currently youtube only)', default=False)
196 video_format.add_option('--list-subs',
197 action='store_true', dest='listsubtitles',
198 help='lists all available subtitles for the video (currently youtube only)', default=False)
199 video_format.add_option('--sub-format',
200 action='store', dest='subtitlesformat', metavar='FORMAT',
201 help='subtitle format [srt/sbv] (default=srt) (currently youtube only)', default='srt')
202 video_format.add_option('--sub-lang', '--srt-lang',
203 action='store', dest='subtitleslang', metavar='LANG',
204 help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
205
206 verbosity.add_option('-q', '--quiet',
207 action='store_true', dest='quiet', help='activates quiet mode', default=False)
208 verbosity.add_option('-s', '--simulate',
209 action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
210 verbosity.add_option('--skip-download',
211 action='store_true', dest='skip_download', help='do not download the video', default=False)
212 verbosity.add_option('-g', '--get-url',
213 action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
214 verbosity.add_option('-e', '--get-title',
215 action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
216 verbosity.add_option('--get-id',
217 action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
218 verbosity.add_option('--get-thumbnail',
219 action='store_true', dest='getthumbnail',
220 help='simulate, quiet but print thumbnail URL', default=False)
221 verbosity.add_option('--get-description',
222 action='store_true', dest='getdescription',
223 help='simulate, quiet but print video description', default=False)
224 verbosity.add_option('--get-filename',
225 action='store_true', dest='getfilename',
226 help='simulate, quiet but print output filename', default=False)
227 verbosity.add_option('--get-format',
228 action='store_true', dest='getformat',
229 help='simulate, quiet but print output format', default=False)
230 verbosity.add_option('--newline',
231 action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
232 verbosity.add_option('--no-progress',
233 action='store_true', dest='noprogress', help='do not print progress bar', default=False)
234 verbosity.add_option('--console-title',
235 action='store_true', dest='consoletitle',
236 help='display progress in console titlebar', default=False)
237 verbosity.add_option('-v', '--verbose',
238 action='store_true', dest='verbose', help='print various debugging information', default=False)
239 verbosity.add_option('--dump-intermediate-pages',
240 action='store_true', dest='dump_intermediate_pages', default=False,
241 help='print downloaded pages to debug problems(very verbose)')
242
243 filesystem.add_option('-t', '--title',
244 action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
245 filesystem.add_option('--id',
246 action='store_true', dest='useid', help='use only video ID in file name', default=False)
247 filesystem.add_option('-l', '--literal',
248 action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
249 filesystem.add_option('-A', '--auto-number',
250 action='store_true', dest='autonumber',
251 help='number downloaded files starting from 00000', default=False)
252 filesystem.add_option('-o', '--output',
253 dest='outtmpl', metavar='TEMPLATE',
254 help=('output filename template. Use %(title)s to get the title, '
255 '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
256 '%(autonumber)s to get an automatically incremented number, '
257 '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
258 '%(extractor)s for the provider (youtube, metacafe, etc), '
259 '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
260 '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
261 'Use - to output to stdout. Can also be used to download to a different directory, '
262 'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
263 filesystem.add_option('--autonumber-size',
264 dest='autonumber_size', metavar='NUMBER',
265 help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
266 filesystem.add_option('--restrict-filenames',
267 action='store_true', dest='restrictfilenames',
268 help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
269 filesystem.add_option('-a', '--batch-file',
270 dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
271 filesystem.add_option('-w', '--no-overwrites',
272 action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
273 filesystem.add_option('-c', '--continue',
274 action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
275 filesystem.add_option('--no-continue',
276 action='store_false', dest='continue_dl',
277 help='do not resume partially downloaded files (restart from beginning)')
278 filesystem.add_option('--cookies',
279 dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
280 filesystem.add_option('--no-part',
281 action='store_true', dest='nopart', help='do not use .part files', default=False)
282 filesystem.add_option('--no-mtime',
283 action='store_false', dest='updatetime',
284 help='do not use the Last-modified header to set the file modification time', default=True)
285 filesystem.add_option('--write-description',
286 action='store_true', dest='writedescription',
287 help='write video description to a .description file', default=False)
288 filesystem.add_option('--write-info-json',
289 action='store_true', dest='writeinfojson',
290 help='write video metadata to a .info.json file', default=False)
291 filesystem.add_option('--write-thumbnail',
292 action='store_true', dest='writethumbnail',
293 help='write thumbnail image to disk', default=False)
294
295
296 postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
297 help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
298 postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
299 help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
300 postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
301 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)')
302 postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
303 help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
304 postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
305 help='keeps the video file on disk after the post-processing; the video is erased by default')
306 postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
307 help='do not overwrite post-processed files; the post-processed files are overwritten by default')
308
309
310 parser.add_option_group(general)
311 parser.add_option_group(selection)
312 parser.add_option_group(filesystem)
313 parser.add_option_group(verbosity)
314 parser.add_option_group(video_format)
315 parser.add_option_group(authentication)
316 parser.add_option_group(postproc)
317
318 if overrideArguments is not None:
319 opts, args = parser.parse_args(overrideArguments)
320 if opts.verbose:
321 print(u'[debug] Override config: ' + repr(overrideArguments))
322 else:
323 xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
324 if xdg_config_home:
325 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
326 else:
327 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
328 systemConf = _readOptions('/etc/youtube-dl.conf')
329 userConf = _readOptions(userConfFile)
330 commandLineConf = sys.argv[1:]
331 argv = systemConf + userConf + commandLineConf
332 opts, args = parser.parse_args(argv)
333 if opts.verbose:
334 print(u'[debug] System config: ' + repr(systemConf))
335 print(u'[debug] User config: ' + repr(userConf))
336 print(u'[debug] Command-line args: ' + repr(commandLineConf))
337
338 return parser, opts, args
339
340 def _real_main(argv=None):
341 # Compatibility fixes for Windows
342 if sys.platform == 'win32':
343 # https://github.com/rg3/youtube-dl/issues/820
344 codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
345
346 parser, opts, args = parseOpts(argv)
347
348 # Open appropriate CookieJar
349 if opts.cookiefile is None:
350 jar = compat_cookiejar.CookieJar()
351 else:
352 try:
353 jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
354 if os.access(opts.cookiefile, os.R_OK):
355 jar.load()
356 except (IOError, OSError) as err:
357 if opts.verbose:
358 traceback.print_exc()
359 sys.stderr.write(u'ERROR: unable to open cookie file\n')
360 sys.exit(101)
361 # Set user agent
362 if opts.user_agent is not None:
363 std_headers['User-Agent'] = opts.user_agent
364
365 # Set referer
366 if opts.referer is not None:
367 std_headers['Referer'] = opts.referer
368
369 # Dump user agent
370 if opts.dump_user_agent:
371 print(std_headers['User-Agent'])
372 sys.exit(0)
373
374 # Batch file verification
375 batchurls = []
376 if opts.batchfile is not None:
377 try:
378 if opts.batchfile == '-':
379 batchfd = sys.stdin
380 else:
381 batchfd = open(opts.batchfile, 'r')
382 batchurls = batchfd.readlines()
383 batchurls = [x.strip() for x in batchurls]
384 batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
385 except IOError:
386 sys.exit(u'ERROR: batch file could not be read')
387 all_urls = batchurls + args
388 all_urls = [url.strip() for url in all_urls]
389
390 # General configuration
391 cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
392 if opts.proxy is not None:
393 if opts.proxy == '':
394 proxies = {}
395 else:
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 print(u'WARNING: 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')