import re
import sys
-from .downloader.external import list_external_downloaders
from .compat import (
compat_expanduser,
compat_get_terminal_size,
get_executable_path,
OUTTMPL_TYPES,
preferredencoding,
- REMUX_EXTENSIONS,
write_string,
)
from .version import __version__
+from .downloader.external import list_external_downloaders
+from .postprocessor.ffmpeg import (
+ FFmpegExtractAudioPP,
+ FFmpegSubtitlesConvertorPP,
+ FFmpegThumbnailsConvertorPP,
+ FFmpegVideoRemuxerPP,
+)
+
def _hide_login_info(opts):
PRIVATE_OPTS = set(['-p', '--password', '-u', '--username', '--video-password', '--ap-password', '--ap-username'])
return ''.join(opts)
- def _comma_separated_values_options_callback(option, opt_str, value, parser, prepend=True):
+ def _list_from_options_callback(option, opt_str, value, parser, append=True, delim=','):
+ # append can be True, False or -1 (prepend)
+ current = getattr(parser.values, option.dest) if append else []
+ value = [value] if delim is None else value.split(delim)
setattr(
parser.values, option.dest,
- value.split(',') if not prepend
- else value.split(',') + getattr(parser.values, option.dest))
+ current + value if append is True else value + current)
- def _dict_from_multiple_values_options_callback(
+ def _dict_from_options_callback(
option, opt_str, value, parser,
allowed_keys=r'[\w-]+', delimiter=':', default_key=None, process=None, multiple_keys=True):
else:
raise optparse.OptionValueError(
'wrong %s formatting; it should be %s, not "%s"' % (opt_str, option.metavar, value))
- val = process(val) if callable(process) else val
+ try:
+ val = process(val) if process else val
+ except Exception as err:
+ raise optparse.OptionValueError(
+ 'wrong %s formatting; %s' % (opt_str, err))
for key in keys:
out_dict[key] = val
help='Update this program to latest version. Make sure that you have sufficient permissions (run with sudo if needed)')
general.add_option(
'-i', '--ignore-errors', '--no-abort-on-error',
- action='store_true', dest='ignoreerrors', default=True,
+ action='store_true', dest='ignoreerrors', default=None,
help='Continue on download errors, for example to skip unavailable videos in a playlist (default) (Alias: --no-abort-on-error)')
general.add_option(
'--abort-on-error', '--no-ignore-errors',
'--no-colors',
action='store_true', dest='no_color', default=False,
help='Do not emit color codes in output')
+ general.add_option(
+ '--compat-options',
+ metavar='OPTS', dest='compat_opts', default=[],
+ action='callback', callback=_list_from_options_callback, type='str',
+ help=(
+ 'Options that can help keep compatibility with youtube-dl and youtube-dlc '
+ 'configurations by reverting some of the changes made in yt-dlp. '
+ 'See "Differences in default behavior" for details'))
network = optparse.OptionGroup(parser, 'Network Options')
network.add_option(
'--break-on-reject',
action='store_true', dest='break_on_reject', default=False,
help='Stop the download process when encountering a file that has been filtered out')
+ selection.add_option(
+ '--skip-playlist-after-errors', metavar='N',
+ dest='skip_playlist_after_errors', default=None, type=int,
+ help='Number of allowed failures until the rest of the playlist is skipped')
selection.add_option(
'--no-download-archive',
dest='download_archive', action="store_const", const=None,
help='Video format code, see "FORMAT SELECTION" for more details')
video_format.add_option(
'-S', '--format-sort', metavar='SORTORDER',
- dest='format_sort', default=[],
- action='callback', callback=_comma_separated_values_options_callback, type='str',
+ dest='format_sort', default=[], type='str', action='callback',
+ callback=_list_from_options_callback, callback_kwargs={'append': -1},
help='Sort the formats by the fields given, see "Sorting Formats" for more details')
video_format.add_option(
'--format-sort-force', '--S-force',
'see "Sorting Formats" for more details'))
video_format.add_option(
'--video-multistreams',
- action='store_true', dest='allow_multiple_video_streams', default=False,
+ action='store_true', dest='allow_multiple_video_streams', default=None,
help='Allow multiple video streams to be merged into a single file')
video_format.add_option(
'--no-video-multistreams',
help='Only one video stream is downloaded for each output file (default)')
video_format.add_option(
'--audio-multistreams',
- action='store_true', dest='allow_multiple_audio_streams', default=False,
+ action='store_true', dest='allow_multiple_audio_streams', default=None,
help='Allow multiple audio streams to be merged into a single file')
video_format.add_option(
'--no-audio-multistreams',
'--no-prefer-free-formats',
action='store_true', dest='prefer_free_formats', default=False,
help="Don't give any special preference to free containers (default)")
+ video_format.add_option(
+ '--check-formats',
+ action='store_true', dest='check_formats', default=None,
+ help='Check that the formats selected are actually downloadable')
+ video_format.add_option(
+ '--no-check-formats',
+ action='store_false', dest='check_formats',
+ help='Do not check that the formats selected are actually downloadable')
video_format.add_option(
'-F', '--list-formats',
action='store_true', dest='listformats',
video_format.add_option(
'--list-formats-as-table',
action='store_true', dest='listformats_table', default=True,
- help='Present the output of -F in tabular form (default)')
+ help=optparse.SUPPRESS_HELP)
video_format.add_option(
'--list-formats-old', '--no-list-formats-as-table',
action='store_false', dest='listformats_table',
- help='Present the output of -F in the old form (Alias: --no-list-formats-as-table)')
+ help=optparse.SUPPRESS_HELP)
video_format.add_option(
'--merge-output-format',
action='store', dest='merge_output_format', metavar='FORMAT', default=None,
action='store_true', dest='allow_unplayable_formats', default=False,
help=(
'Allow unplayable formats to be listed and downloaded. '
- 'All video postprocessing will also be turned off'))
+ 'All video post-processing will also be turned off'))
video_format.add_option(
'--no-allow-unplayable-formats',
action='store_false', dest='allow_unplayable_formats',
subtitles.add_option(
'--all-subs',
action='store_true', dest='allsubtitles', default=False,
- help='Download all the available subtitles of the video')
+ help=optparse.SUPPRESS_HELP)
subtitles.add_option(
'--list-subs',
action='store_true', dest='listsubtitles', default=False,
subtitles.add_option(
'--sub-langs', '--srt-langs',
action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
- default=[], callback=_comma_separated_values_options_callback,
- help='Languages of the subtitles to download (optional) separated by commas, use --list-subs for available language tags')
+ default=[], callback=_list_from_options_callback,
+ help=(
+ 'Languages of the subtitles to download (can be regex) or "all" separated by commas. (Eg: --sub-langs en.*,ja) '
+ 'You can prefix the language code with a "-" to exempt it from the requested languages. (Eg: --sub-langs all,-live_chat) '
+ 'Use --list-subs for a list of available language tags'))
downloader = optparse.OptionGroup(parser, 'Download Options')
downloader.add_option(
'-r', '--limit-rate', '--rate-limit',
dest='ratelimit', metavar='RATE',
help='Maximum download rate in bytes per second (e.g. 50K or 4.2M)')
+ downloader.add_option(
+ '--throttled-rate',
+ dest='throttledratelimit', metavar='RATE',
+ help='Minimum download rate in bytes per second below which throttling is assumed and the video data is re-extracted (e.g. 100K)')
downloader.add_option(
'-R', '--retries',
dest='retries', metavar='RETRIES', default=10,
downloader.add_option(
'--downloader', '--external-downloader',
dest='external_downloader', metavar='[PROTO:]NAME', default={}, type='str',
- action='callback', callback=_dict_from_multiple_values_options_callback,
+ action='callback', callback=_dict_from_options_callback,
callback_kwargs={
'allowed_keys': 'http|ftp|m3u8|dash|rtsp|rtmp|mms',
- 'default_key': 'default', 'process': lambda x: x.strip()},
+ 'default_key': 'default',
+ 'process': lambda x: x.strip()
+ },
help=(
'Name or path of the external downloader to use (optionally) prefixed by '
'the protocols (http, ftp, m3u8, dash, rstp, rtmp, mms) to use it for. '
downloader.add_option(
'--downloader-args', '--external-downloader-args',
metavar='NAME:ARGS', dest='external_downloader_args', default={}, type='str',
- action='callback', callback=_dict_from_multiple_values_options_callback,
+ action='callback', callback=_dict_from_options_callback,
callback_kwargs={
'allowed_keys': '|'.join(list_external_downloaders()),
- 'default_key': 'default', 'process': compat_shlex_split},
+ 'default_key': 'default',
+ 'process': compat_shlex_split
+ },
help=(
'Give these arguments to the external downloader. '
'Specify the downloader name and the arguments separated by a colon ":". '
- 'You can use this option multiple times (Alias: --external-downloader-args)'))
+ 'You can use this option multiple times to give different arguments to different downloaders '
+ '(Alias: --external-downloader-args)'))
workarounds = optparse.OptionGroup(parser, 'Workarounds')
workarounds.add_option(
workarounds.add_option(
'--add-header',
metavar='FIELD:VALUE', dest='headers', default={}, type='str',
- action='callback', callback=_dict_from_multiple_values_options_callback,
+ action='callback', callback=_dict_from_options_callback,
callback_kwargs={'multiple_keys': False},
help='Specify a custom HTTP header and its value, separated by a colon ":". You can use this option multiple times',
)
'--skip-download', '--no-download',
action='store_true', dest='skip_download', default=False,
help='Do not download the video but write all related files (Alias: --no-download)')
+ verbosity.add_option(
+ '-O', '--print', metavar='TEMPLATE',
+ action='callback', dest='forceprint', type='str', default=[],
+ callback=_list_from_options_callback, callback_kwargs={'delim': None},
+ help=(
+ 'Simulate, quiet but print the given fields. Either a field name '
+ 'or similar formatting as the output template can be used'))
verbosity.add_option(
'-g', '--get-url',
action='store_true', dest='geturl', default=False,
- help='Simulate, quiet but print URL')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'-e', '--get-title',
action='store_true', dest='gettitle', default=False,
- help='Simulate, quiet but print title')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--get-id',
action='store_true', dest='getid', default=False,
- help='Simulate, quiet but print id')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--get-thumbnail',
action='store_true', dest='getthumbnail', default=False,
- help='Simulate, quiet but print thumbnail URL')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--get-description',
action='store_true', dest='getdescription', default=False,
- help='Simulate, quiet but print video description')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--get-duration',
action='store_true', dest='getduration', default=False,
- help='Simulate, quiet but print video length')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--get-filename',
action='store_true', dest='getfilename', default=False,
- help='Simulate, quiet but print output filename')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--get-format',
action='store_true', dest='getformat', default=False,
- help='Simulate, quiet but print output format')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'-j', '--dump-json',
action='store_true', dest='dumpjson', default=False,
'--force-write-archive', '--force-write-download-archive', '--force-download-archive',
action='store_true', dest='force_write_download_archive', default=False,
help=(
- 'Force download archive entries to be written as far as no errors occur,'
- 'even if -s or another simulation switch is used (Alias: --force-download-archive)'))
+ 'Force download archive entries to be written as far as no errors occur, '
+ 'even if -s or another simulation option is used (Alias: --force-download-archive)'))
verbosity.add_option(
'--newline',
action='store_true', dest='progress_with_newline', default=False,
filesystem.add_option(
'-P', '--paths',
metavar='TYPES:PATH', dest='paths', default={}, type='str',
- action='callback', callback=_dict_from_multiple_values_options_callback,
- callback_kwargs={
- 'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys()),
- 'process': lambda x: x.strip()},
+ action='callback', callback=_dict_from_options_callback,
+ callback_kwargs={'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys())},
help=(
'The paths where the files should be downloaded. '
'Specify the type of file and the path separated by a colon ":". '
filesystem.add_option(
'-o', '--output',
metavar='[TYPES:]TEMPLATE', dest='outtmpl', default={}, type='str',
- action='callback', callback=_dict_from_multiple_values_options_callback,
+ action='callback', callback=_dict_from_options_callback,
callback_kwargs={
'allowed_keys': '|'.join(OUTTMPL_TYPES.keys()),
- 'default_key': 'default', 'process': lambda x: x.strip()},
+ 'default_key': 'default'
+ },
help='Output filename template; see "OUTPUT TEMPLATE" for details')
filesystem.add_option(
'--output-na-placeholder',
filesystem.add_option(
'--autonumber-start',
dest='autonumber_start', metavar='NUMBER', default=1, type=int,
- help='Specify the start value for %(autonumber)s (default is %default)')
+ help=optparse.SUPPRESS_HELP)
filesystem.add_option(
'--restrict-filenames',
action='store_true', dest='restrictfilenames', default=False,
dest='trim_file_name', default=0, type=int,
help='Limit the filename length (excluding extension) to the specified number of characters')
filesystem.add_option(
- '-A', '--auto-number',
+ '--auto-number',
action='store_true', dest='autonumber', default=False,
help=optparse.SUPPRESS_HELP)
filesystem.add_option(
- '-t', '--title',
+ '--title',
action='store_true', dest='usetitle', default=False,
help=optparse.SUPPRESS_HELP)
filesystem.add_option(
- '-l', '--literal', default=False,
+ '--literal', default=False,
action='store_true', dest='usetitle',
help=optparse.SUPPRESS_HELP)
filesystem.add_option(
action='store_false', dest='continue_dl',
help=(
'Do not resume partially downloaded fragments. '
- 'If the file is unfragmented, restart download of the entire file'))
+ 'If the file is not fragmented, restart download of the entire file'))
filesystem.add_option(
'--part',
action='store_false', dest='nopart', default=False,
help='Do not write video annotations (default)')
filesystem.add_option(
'--write-playlist-metafiles',
- action='store_true', dest='allow_playlist_files', default=True,
+ action='store_true', dest='allow_playlist_files', default=None,
help=(
'Write playlist metadata in addition to the video metadata '
'when using --write-info-json, --write-description etc. (default)'))
action='store_false', dest='clean_infojson',
help='Write all fields to the infojson')
filesystem.add_option(
- '--get-comments',
+ '--write-comments', '--get-comments',
action='store_true', dest='getcomments', default=False,
help=(
- 'Retrieve video comments to be placed in the .info.json file. '
- 'The comments are fetched even without this option if the extraction is known to be quick'))
+ 'Retrieve video comments to be placed in the infojson. '
+ 'The comments are fetched even without this option if the extraction is known to be quick (Alias: --get-comments)'))
+ filesystem.add_option(
+ '--no-write-comments', '--no-get-comments',
+ action='store_true', dest='getcomments', default=False,
+ help='Do not retrieve video comments unless the extraction is known to be quick (Alias: --no-get-comments)')
filesystem.add_option(
'--load-info-json', '--load-info',
dest='load_info_filename', metavar='FILE',
help='Do not read/dump cookies (default)')
filesystem.add_option(
'--cache-dir', dest='cachedir', default=None, metavar='DIR',
- help='Location in the filesystem where youtube-dl can store some downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl . At the moment, only YouTube player files (for videos with obfuscated signatures) are cached, but that may change')
+ help='Location in the filesystem where youtube-dl can store some downloaded information (such as client ids and signatures) permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl')
filesystem.add_option(
'--no-cache-dir', action='store_false', dest='cachedir',
help='Disable filesystem caching')
help='Convert video files to audio-only files (requires ffmpeg and ffprobe)')
postproc.add_option(
'--audio-format', metavar='FORMAT', dest='audioformat', default='best',
- help='Specify audio format: "best", "aac", "flac", "mp3", "m4a", "opus", "vorbis", or "wav"; "%default" by default; No effect without -x')
+ help=(
+ 'Specify audio format to convert the audio to when -x is used. Currently supported formats are: '
+ 'best (default) or one of %s' % '|'.join(FFmpegExtractAudioPP.SUPPORTED_EXTS)))
postproc.add_option(
'--audio-quality', metavar='QUALITY',
dest='audioquality', default='5',
help=(
'Remux the video into another container if necessary (currently supported: %s). '
'If target container does not support the video/audio codec, remuxing will fail. '
- 'You can specify multiple rules; eg. "aac>m4a/mov>mp4/mkv" will remux aac to m4a, mov to mp4 '
- 'and anything else to mkv.' % '|'.join(REMUX_EXTENSIONS)))
+ 'You can specify multiple rules; Eg. "aac>m4a/mov>mp4/mkv" will remux aac to m4a, mov to mp4 '
+ 'and anything else to mkv.' % '|'.join(FFmpegVideoRemuxerPP.SUPPORTED_EXTS)))
postproc.add_option(
'--recode-video',
metavar='FORMAT', dest='recodevideo', default=None,
help=(
'Re-encode the video into another format if re-encoding is necessary. '
- 'The supported formats are the same as --remux-video'))
+ 'The syntax and supported formats are the same as --remux-video'))
postproc.add_option(
'--postprocessor-args', '--ppa',
metavar='NAME:ARGS', dest='postprocessor_args', default={}, type='str',
- action='callback', callback=_dict_from_multiple_values_options_callback,
+ action='callback', callback=_dict_from_options_callback,
callback_kwargs={
'allowed_keys': r'\w+(?:\+\w+)?', 'default_key': 'default-compat',
- 'process': compat_shlex_split, 'multiple_keys': False},
+ 'process': compat_shlex_split,
+ 'multiple_keys': False
+ },
help=(
'Give these arguments to the postprocessors. '
'Specify the postprocessor/executable name and the arguments separated by a colon ":" '
'to give the argument to the specified postprocessor/executable. Supported PP are: '
'Merger, ExtractAudio, SplitChapters, Metadata, EmbedSubtitle, EmbedThumbnail, '
'SubtitlesConvertor, ThumbnailsConvertor, VideoRemuxer, VideoConvertor, '
- 'SponSkrub, FixupStretched, FixupM4a and FixupM3u8. '
+ 'SponSkrub, FixupStretched, FixupM4a, FixupM3u8, FixupTimestamp and FixupDuration. '
'The supported executables are: AtomicParsley, FFmpeg, FFprobe, and SponSkrub. '
'You can also specify "PP+EXE:ARGS" to give the arguments to the specified executable '
'only when being used by the specified postprocessor. Additionally, for ffmpeg/ffprobe, '
postproc.add_option(
'--embed-thumbnail',
action='store_true', dest='embedthumbnail', default=False,
- help='Embed thumbnail in the audio as cover art')
+ help='Embed thumbnail in the video as cover art')
postproc.add_option(
'--no-embed-thumbnail',
action='store_false', dest='embedthumbnail',
help='Do not embed thumbnail (default)')
postproc.add_option(
- '--add-metadata',
+ '--embed-metadata', '--add-metadata',
action='store_true', dest='addmetadata', default=False,
- help='Write metadata to the video file')
+ help='Embed metadata including chapter markers (if supported by the format) to the video file (Alias: --add-metadata)')
postproc.add_option(
- '--no-add-metadata',
+ '--no-embed-metadata', '--no-add-metadata',
action='store_false', dest='addmetadata',
- help='Do not write metadata (default)')
+ help='Do not write metadata (default) (Alias: --no-add-metadata)')
postproc.add_option(
'--metadata-from-title',
metavar='FORMAT', dest='metafromtitle',
postproc.add_option(
'--fixup',
metavar='POLICY', dest='fixup', default=None,
+ choices=('never', 'ignore', 'warn', 'detect_or_warn', 'force'),
help=(
'Automatically correct known faults of the file. '
'One of never (do nothing), warn (only emit a warning), '
- 'detect_or_warn (the default; fix file if we can, warn otherwise)'))
+ 'detect_or_warn (the default; fix file if we can, warn otherwise), '
+ 'force (try fixing even if file already exists'))
postproc.add_option(
'--prefer-avconv', '--no-prefer-ffmpeg',
action='store_false', dest='prefer_ffmpeg',
'Similar syntax to the output template can be used to pass any field as arguments to the command. '
'An additional field "filepath" that contains the final path of the downloaded file is also available. '
'If no fields are passed, "%(filepath)s" is appended to the end of the command'))
+ postproc.add_option(
+ '--exec-before-download',
+ metavar='CMD', dest='exec_before_dl_cmd',
+ help='Execute a command before the actual download. The syntax is the same as --exec')
postproc.add_option(
'--convert-subs', '--convert-sub', '--convert-subtitles',
metavar='FORMAT', dest='convertsubtitles', default=None,
- help='Convert the subtitles to another format (currently supported: srt|ass|vtt|lrc) (Alias: --convert-subtitles)')
+ help=(
+ 'Convert the subtitles to another format (currently supported: %s) '
+ '(Alias: --convert-subtitles)' % '|'.join(FFmpegSubtitlesConvertorPP.SUPPORTED_EXTS)))
postproc.add_option(
'--convert-thumbnails',
metavar='FORMAT', dest='convertthumbnails', default=None,
- help='Convert the thumbnails to another format (currently supported: jpg)')
+ help=(
+ 'Convert the thumbnails to another format '
+ '(currently supported: %s) ' % '|'.join(FFmpegThumbnailsConvertorPP.SUPPORTED_EXTS)))
postproc.add_option(
'--split-chapters', '--split-tracks',
dest='split_chapters', action='store_true', default=False,
'--no-hls-split-discontinuity',
dest='hls_split_discontinuity', action='store_false',
help='Do not split HLS playlists to different formats at discontinuities such as ad breaks (default)')
+ _extractor_arg_parser = lambda key, vals='': (key.strip().lower(), [val.strip() for val in vals.split(',')])
+ extractor.add_option(
+ '--extractor-args',
+ metavar='KEY:ARGS', dest='extractor_args', default={}, type='str',
+ action='callback', callback=_dict_from_options_callback,
+ callback_kwargs={
+ 'multiple_keys': False,
+ 'process': lambda val: dict(
+ _extractor_arg_parser(*arg.split('=', 1)) for arg in val.split(';'))
+ },
+ help=(
+ 'Pass these arguments to the extractor. See "EXTRACTOR ARGUMENTS" for details. '
+ 'You can use this option multiple times to give arguments for different extractors'))
extractor.add_option(
'--youtube-include-dash-manifest', '--no-youtube-skip-dash-manifest',
action='store_true', dest='youtube_include_dash_manifest', default=True,
- help='Download the DASH manifests and related data on YouTube videos (default) (Alias: --no-youtube-skip-dash-manifest)')
+ help=optparse.SUPPRESS_HELP)
extractor.add_option(
'--youtube-skip-dash-manifest', '--no-youtube-include-dash-manifest',
action='store_false', dest='youtube_include_dash_manifest',
- help='Do not download the DASH manifests and related data on YouTube videos (Alias: --no-youtube-include-dash-manifest)')
+ help=optparse.SUPPRESS_HELP)
extractor.add_option(
'--youtube-include-hls-manifest', '--no-youtube-skip-hls-manifest',
action='store_true', dest='youtube_include_hls_manifest', default=True,
- help='Download the HLS manifests and related data on YouTube videos (default) (Alias: --no-youtube-skip-hls-manifest)')
+ help=optparse.SUPPRESS_HELP)
extractor.add_option(
'--youtube-skip-hls-manifest', '--no-youtube-include-hls-manifest',
action='store_false', dest='youtube_include_hls_manifest',
- help='Do not download the HLS manifests and related data on YouTube videos (Alias: --no-youtube-include-hls-manifest)')
+ help=optparse.SUPPRESS_HELP)
parser.add_option_group(general)
parser.add_option_group(network)