preferredencoding,
write_string,
)
+from .cookies import SUPPORTED_BROWSERS
from .version import __version__
from .downloader.external import list_external_downloaders
-from .postprocessor.ffmpeg import (
+from .postprocessor import (
FFmpegExtractAudioPP,
FFmpegSubtitlesConvertorPP,
FFmpegThumbnailsConvertorPP,
parser.values, option.dest,
current + value if append is True else value + current)
+ def _set_from_options_callback(
+ option, opt_str, value, parser,
+ delim=',', allowed_values=None, process=str.lower, aliases={}):
+ current = getattr(parser.values, option.dest)
+ values = [process(value)] if delim is None else process(value).split(delim)[::-1]
+ while values:
+ actual_val = val = values.pop()
+ if val == 'all':
+ current.update(allowed_values)
+ elif val == '-all':
+ current = set()
+ elif val in aliases:
+ values.extend(aliases[val])
+ else:
+ if val[0] == '-':
+ val = val[1:]
+ current.discard(val)
+ else:
+ current.update([val])
+ if allowed_values is not None and val not in allowed_values:
+ raise optparse.OptionValueError(f'wrong {option.metavar} for {opt_str}: {actual_val}')
+
+ setattr(parser.values, option.dest, current)
+
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
# No need to wrap help messages if we're on a wide console
columns = compat_get_terminal_size().columns
max_width = columns if columns else 80
- max_help_position = 80
+ # 47% is chosen because that is how README.md is currently formatted
+ # and moving help text even further to the right is undesirable.
+ # This can be reduced in the future to get a prettier output
+ max_help_position = int(0.47 * max_width)
fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
fmt.format_option_strings = _format_option_string
general.add_option(
'--dump-user-agent',
action='store_true', dest='dump_user_agent', default=False,
- help='Display the current browser identification')
+ help='Display the current user-agent and exit')
general.add_option(
'--list-extractors',
action='store_true', dest='list_extractors', default=False,
- help='List all supported extractors')
+ help='List all supported extractors and exit')
general.add_option(
'--extractor-descriptions',
action='store_true', dest='list_extractor_descriptions', default=False,
- help='Output descriptions of all supported extractors')
+ help='Output descriptions of all supported extractors and exit')
general.add_option(
'--force-generic-extractor',
action='store_true', dest='force_generic_extractor', default=False,
'--flat-playlist',
action='store_const', dest='extract_flat', const='in_playlist', default=False,
help='Do not extract the videos of a playlist, only list them')
- general.add_option(
- '--flat-videos',
- action='store_true', dest='extract_flat',
- # help='Do not resolve the video urls')
- # doesn't work
- help=optparse.SUPPRESS_HELP)
general.add_option(
'--no-flat-playlist',
action='store_false', dest='extract_flat',
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 '
+ metavar='OPTS', dest='compat_opts', default=set(), type='str',
+ action='callback', callback=_set_from_options_callback,
+ callback_kwargs={
+ 'allowed_values': {
+ 'filename', 'format-sort', 'abort-on-error', 'format-spec', 'no-playlist-metafiles',
+ 'multistreams', 'no-live-chat', 'playlist-index', 'list-formats', 'no-direct-merge',
+ 'no-youtube-channel-redirect', 'no-youtube-unavailable-videos', 'no-attach-info-json',
+ 'embed-thumbnail-atomicparsley', 'seperate-video-versions', 'no-clean-infojson', 'no-keep-subs',
+ },
+ 'aliases': {
+ 'youtube-dl': ['-multistreams', 'all'],
+ 'youtube-dlc': ['-no-youtube-channel-redirect', '-no-live-chat', 'all'],
+ }
+ }, help=(
+ 'Options that can help keep compatibility with youtube-dl or youtube-dlc '
'configurations by reverting some of the changes made in yt-dlp. '
'See "Differences in default behavior" for details'))
selection.add_option(
'--match-title',
dest='matchtitle', metavar='REGEX',
- help='Download only matching titles (regex or caseless sub-string)')
+ help=optparse.SUPPRESS_HELP)
selection.add_option(
'--reject-title',
dest='rejecttitle', metavar='REGEX',
- help='Skip download for matching titles (regex or caseless sub-string)')
+ help=optparse.SUPPRESS_HELP)
selection.add_option(
'--max-downloads',
dest='max_downloads', metavar='NUMBER', type=int, default=None,
selection.add_option(
'--min-views',
metavar='COUNT', dest='min_views', default=None, type=int,
- help='Do not download any videos with less than COUNT views')
+ help=optparse.SUPPRESS_HELP)
selection.add_option(
'--max-views',
metavar='COUNT', dest='max_views', default=None, type=int,
- help='Do not download any videos with more than COUNT views')
+ help=optparse.SUPPRESS_HELP)
selection.add_option(
'--match-filter',
metavar='FILTER', dest='match_filter', default=None,
help=(
- 'Generic video filter. '
- 'Specify any key (see "OUTPUT TEMPLATE" for a list of available keys) to '
- 'match if the key is present, '
- '!key to check if the key is not present, '
- 'key>NUMBER (like "view_count > 12", also works with '
- '>=, <, <=, !=, =) to compare against a number, '
- 'key = \'LITERAL\' (like "uploader = \'Mike Smith\'", also works with !=) '
- 'to match against a string literal '
- 'and & to require multiple matches. '
- 'Values which are not known are excluded unless you '
- 'put a question mark (?) after the operator. '
- 'For example, to only match videos that have been liked more than '
- '100 times and disliked less than 50 times (or the dislike '
- 'functionality is not available at the given service), but who '
- 'also have a description, use --match-filter '
- '"like_count > 100 & dislike_count <? 50 & description"'))
+ 'Generic video filter. Any field (see "OUTPUT TEMPLATE") can be compared with a '
+ 'number or a string using the operators defined in "Filtering formats". '
+ 'You can also simply specify a field to match if the field is present '
+ 'and "!field" to check if the field is not present. In addition, '
+ 'Python style regular expression matching can be done using "~=", '
+ 'and multiple filters can be checked with "&". '
+ 'Use a "\\" to escape "&" or quotes if needed. Eg: --match-filter '
+ r'"!is_live & like_count>?100 & description~=\'(?i)\bcats \& dogs\b\'" '
+ 'matches only videos that are not live, has a like count more than 100 '
+ '(or the like field is not available), and also has a description '
+ 'that contains the phrase "cats & dogs" (ignoring case)'))
selection.add_option(
'--no-match-filter',
metavar='FILTER', dest='match_filter', action='store_const', const=None,
help="Don't give any special preference to free containers (default)")
video_format.add_option(
'--check-formats',
- action='store_true', dest='check_formats', default=False,
- help="Check that the formats selected are actually downloadable (Experimental)")
+ 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',
- help='List all available formats of requested videos')
+ help='List available formats of each video. Simulate unless --no-simulate is used')
video_format.add_option(
'--list-formats-as-table',
action='store_true', dest='listformats_table', default=True,
subtitles.add_option(
'--list-subs',
action='store_true', dest='listsubtitles', default=False,
- help='List all available subtitles for the video')
+ help='List available subtitles of each video. Simulate unless --no-simulate is used')
subtitles.add_option(
'--sub-format',
action='store', dest='subtitlesformat', metavar='FORMAT', default='best',
'-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,
callback_kwargs={
'allowed_keys': 'http|ftp|m3u8|dash|rtsp|rtmp|mms',
'default_key': 'default',
- 'process': lambda x: x.strip()
- },
- help=(
+ 'process': str.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. '
'Currently supports native, %s (Recommended: aria2c). '
'allowed_keys': '|'.join(list_external_downloaders()),
'default_key': 'default',
'process': compat_shlex_split
- },
- help=(
+ }, 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(
verbosity.add_option(
'-q', '--quiet',
action='store_true', dest='quiet', default=False,
- help='Activate quiet mode')
+ help='Activate quiet mode. If used with --verbose, print the log to stderr')
verbosity.add_option(
'--no-warnings',
dest='no_warnings', action='store_true', default=False,
help='Ignore warnings')
verbosity.add_option(
'-s', '--simulate',
- action='store_true', dest='simulate', default=False,
+ action='store_true', dest='simulate', default=None,
help='Do not download the video and do not write anything to disk')
+ verbosity.add_option(
+ '--no-simulate',
+ action='store_false', dest='simulate',
+ help='Download the video even if printing/listing options are used')
verbosity.add_option(
'--ignore-no-formats-error',
action='store_true', dest='ignore_no_formats_error', default=False,
help=(
'Ignore "No video formats" error. Usefull for extracting metadata '
- 'even if the video is not actually available for download (experimental)'))
+ 'even if the videos are not actually available for download (experimental)'))
verbosity.add_option(
'--no-ignore-no-formats-error',
action='store_false', dest='ignore_no_formats_error',
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},
+ '-O', '--print',
+ metavar='TEMPLATE', action='append', dest='forceprint',
help=(
- 'Simulate, quiet but print the given fields. Either a field name '
- 'or similar formatting as the output template can be used'))
+ 'Quiet, but print the given fields for each video. Simulate unless --no-simulate is used. '
+ 'Either a field name or same syntax as the output template can be used'))
verbosity.add_option(
'-g', '--get-url',
action='store_true', dest='geturl', default=False,
verbosity.add_option(
'-j', '--dump-json',
action='store_true', dest='dumpjson', default=False,
- help='Simulate, quiet but print JSON information. See "OUTPUT TEMPLATE" for a description of available keys')
+ help='Quiet, but print JSON information for each video. Simulate unless --no-simulate is used. See "OUTPUT TEMPLATE" for a description of available keys')
verbosity.add_option(
'-J', '--dump-single-json',
action='store_true', dest='dump_single_json', default=False,
help=(
- 'Simulate, quiet but print JSON information for each command-line argument. '
- 'If the URL refers to a playlist, dump the whole playlist information in a single line'))
+ 'Quiet, but print JSON information for each url or infojson passed. Simulate unless --no-simulate is used. '
+ 'If the URL refers to a playlist, the whole playlist information is dumped in a single line'))
verbosity.add_option(
'--print-json',
action='store_true', dest='print_json', default=False,
- help='Be quiet and print the video information as JSON (video is still being downloaded)')
+ help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--force-write-archive', '--force-write-download-archive', '--force-download-archive',
action='store_true', dest='force_write_download_archive', default=False,
action='store_true', dest='useid', help=optparse.SUPPRESS_HELP)
filesystem.add_option(
'-P', '--paths',
- metavar='TYPES:PATH', dest='paths', default={}, type='str',
+ metavar='[TYPES:]PATH', dest='paths', default={}, type='str',
action='callback', callback=_dict_from_options_callback,
- callback_kwargs={'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys())},
- help=(
+ callback_kwargs={
+ 'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys()),
+ 'default_key': 'home'
+ }, help=(
'The paths where the files should be downloaded. '
'Specify the type of file and the path separated by a colon ":". '
'All the same types as --output are supported. '
- 'Additionally, you can also provide "home" and "temp" paths. '
+ 'Additionally, you can also provide "home" (default) and "temp" paths. '
'All intermediary files are first downloaded to the temp path and '
'then the final files are moved over to the home path after download is finished. '
'This option is ignored if --output is an absolute path'))
callback_kwargs={
'allowed_keys': '|'.join(OUTTMPL_TYPES.keys()),
'default_key': 'default'
- },
- help='Output filename template; see "OUTPUT TEMPLATE" for details')
+ }, help='Output filename template; see "OUTPUT TEMPLATE" for details')
filesystem.add_option(
'--output-na-placeholder',
dest='outtmpl_na_placeholder', metavar='TEXT', default='NA',
help='Do not write playlist metadata when using --write-info-json, --write-description etc.')
filesystem.add_option(
'--clean-infojson',
- action='store_true', dest='clean_infojson', default=True,
+ action='store_true', dest='clean_infojson', default=None,
help=(
'Remove some private fields such as filenames from the infojson. '
'Note that it could still contain some personal information (default)'))
filesystem.add_option(
'--no-cookies',
action='store_const', const=None, dest='cookiefile', metavar='FILE',
- help='Do not read/dump cookies (default)')
+ help='Do not read/dump cookies from/to file (default)')
+ filesystem.add_option(
+ '--cookies-from-browser',
+ dest='cookiesfrombrowser', metavar='BROWSER[:PROFILE]',
+ help=(
+ 'Load cookies from a user profile of the given web browser. '
+ 'Currently supported browsers are: {}. '
+ 'You can specify the user profile name or directory using '
+ '"BROWSER:PROFILE_NAME" or "BROWSER:PROFILE_PATH". '
+ 'If no profile is given, the most recently accessed one is used'.format(
+ '|'.join(sorted(SUPPORTED_BROWSERS)))))
+ filesystem.add_option(
+ '--no-cookies-from-browser',
+ action='store_const', const=None, dest='cookiesfrombrowser',
+ help='Do not load cookies from browser (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 (such as client ids and signatures) permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl')
thumbnail.add_option(
'--list-thumbnails',
action='store_true', dest='list_thumbnails', default=False,
- help='Simulate and list all available thumbnail formats')
+ help='List available thumbnails of each video. Simulate unless --no-simulate is used')
link = optparse.OptionGroup(parser, 'Internet Shortcut Options')
link.add_option(
'allowed_keys': r'\w+(?:\+\w+)?', 'default_key': 'default-compat',
'process': compat_shlex_split,
'multiple_keys': False
- },
- help=(
+ }, 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: '
postproc.add_option(
'--embed-thumbnail',
action='store_true', dest='embedthumbnail', default=False,
- help='Embed thumbnail in the video/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=optparse.SUPPRESS_HELP)
postproc.add_option(
'--parse-metadata',
- metavar='FROM:TO', dest='metafromfield', action='append',
+ metavar='FROM:TO', dest='parse_metadata', action='append',
help=(
'Parse additional metadata like title/artist from other fields; '
'see "MODIFYING METADATA" for details'))
+ postproc.add_option(
+ '--replace-in-metadata',
+ dest='parse_metadata', metavar='FIELDS REGEX REPLACE', action='append', nargs=3,
+ help='Replace text in a metadata field using the given regex. This option can be used multiple times')
postproc.add_option(
'--xattrs',
action='store_true', dest='xattrs', default=False,
dest='ffmpeg_location',
help='Location of the ffmpeg binary; either the path to the binary or its containing directory')
postproc.add_option(
- '--exec',
- metavar='CMD', dest='exec_cmd',
+ '--exec', metavar='CMD',
+ action='append', dest='exec_cmd',
help=(
'Execute a command on the file after downloading and post-processing. '
- 'Similar syntax to the output template can be used to pass any field as arguments to the command. '
+ 'Same syntax as 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'))
+ 'If no fields are passed, %(filepath)q is appended to the end of the command. '
+ 'This option can be used multiple times'))
+ postproc.add_option(
+ '--no-exec',
+ action='store_const', dest='exec_cmd', const=[],
+ help='Remove any previously defined --exec')
+ postproc.add_option(
+ '--exec-before-download', metavar='CMD',
+ action='append', dest='exec_before_dl_cmd',
+ help=(
+ 'Execute a command before the actual download. '
+ 'The syntax is the same as --exec but "filepath" is not available. '
+ 'This option can be used multiple times'))
+ postproc.add_option(
+ '--no-exec-before-download',
+ action='store_const', dest='exec_before_dl_cmd', const=[],
+ help='Remove any previously defined --exec-before-download')
postproc.add_option(
'--convert-subs', '--convert-sub', '--convert-subtitles',
metavar='FORMAT', dest='convertsubtitles', default=None,
'--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().replace('-', '_'), [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)