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