Upgrade yt_dlp and download script
This commit is contained in:
@@ -40,7 +40,7 @@ from .utils import (
|
||||
from .version import CHANNEL, __version__
|
||||
|
||||
|
||||
def parseOpts(overrideArguments=None, ignore_config_files='if_override'):
|
||||
def parseOpts(overrideArguments=None, ignore_config_files='if_override'): # noqa: N803
|
||||
PACKAGE_NAME = 'yt-dlp'
|
||||
|
||||
root = Config(create_parser())
|
||||
@@ -150,8 +150,17 @@ class _YoutubeDLHelpFormatter(optparse.IndentedHelpFormatter):
|
||||
return opts
|
||||
|
||||
|
||||
_PRESET_ALIASES = {
|
||||
'mp3': ['-f', 'ba[acodec^=mp3]/ba/b', '-x', '--audio-format', 'mp3'],
|
||||
'aac': ['-f', 'ba[acodec^=aac]/ba[acodec^=mp4a.40.]/ba/b', '-x', '--audio-format', 'aac'],
|
||||
'mp4': ['--merge-output-format', 'mp4', '--remux-video', 'mp4', '-S', 'vcodec:h264,lang,quality,res,fps,hdr:12,acodec:aac'],
|
||||
'mkv': ['--merge-output-format', 'mkv', '--remux-video', 'mkv'],
|
||||
'sleep': ['--sleep-subtitles', '5', '--sleep-requests', '0.75', '--sleep-interval', '10', '--max-sleep-interval', '20'],
|
||||
}
|
||||
|
||||
|
||||
class _YoutubeDLOptionParser(optparse.OptionParser):
|
||||
# optparse is deprecated since python 3.2. So assume a stable interface even for private methods
|
||||
# optparse is deprecated since Python 3.2. So assume a stable interface even for private methods
|
||||
ALIAS_DEST = '_triggered_aliases'
|
||||
ALIAS_TRIGGER_LIMIT = 100
|
||||
|
||||
@@ -196,9 +205,12 @@ class _YoutubeDLOptionParser(optparse.OptionParser):
|
||||
raise
|
||||
return self.check_values(self.values, self.largs)
|
||||
|
||||
def error(self, msg):
|
||||
def _generate_error_message(self, msg):
|
||||
msg = f'{self.get_prog_name()}: error: {str(msg).strip()}\n'
|
||||
raise optparse.OptParseError(f'{self.get_usage()}\n{msg}' if self.usage else msg)
|
||||
return f'{self.get_usage()}\n{msg}' if self.usage else msg
|
||||
|
||||
def error(self, msg):
|
||||
raise optparse.OptParseError(self._generate_error_message(msg))
|
||||
|
||||
def _get_args(self, args):
|
||||
return sys.argv[1:] if args is None else list(args)
|
||||
@@ -212,6 +224,22 @@ class _YoutubeDLOptionParser(optparse.OptionParser):
|
||||
return e.possibilities[0]
|
||||
raise
|
||||
|
||||
def format_option_help(self, formatter=None):
|
||||
assert formatter, 'Formatter can not be None'
|
||||
formatted_help = super().format_option_help(formatter=formatter)
|
||||
formatter.indent()
|
||||
heading = formatter.format_heading('Preset Aliases')
|
||||
formatter.indent()
|
||||
result = []
|
||||
for name, args in _PRESET_ALIASES.items():
|
||||
option = optparse.Option('-t', help=shlex.join(args))
|
||||
formatter.option_strings[option] = f'-t {name}'
|
||||
result.append(formatter.format_option(option))
|
||||
formatter.dedent()
|
||||
formatter.dedent()
|
||||
help_lines = '\n'.join(result)
|
||||
return f'{formatted_help}\n{heading}{help_lines}'
|
||||
|
||||
|
||||
def create_parser():
|
||||
def _list_from_options_callback(option, opt_str, value, parser, append=True, delim=',', process=str.strip):
|
||||
@@ -261,7 +289,7 @@ def create_parser():
|
||||
except Exception as err:
|
||||
raise optparse.OptionValueError(f'wrong {opt_str} formatting; {err}')
|
||||
for key in keys:
|
||||
out_dict[key] = out_dict.get(key, []) + [val] if append else val
|
||||
out_dict[key] = [*out_dict.get(key, []), val] if append else val
|
||||
setattr(parser.values, option.dest, out_dict)
|
||||
|
||||
def when_prefix(default):
|
||||
@@ -314,6 +342,13 @@ def create_parser():
|
||||
parser.rargs[:0] = shlex.split(
|
||||
opts if value is None else opts.format(*map(shlex.quote, value)))
|
||||
|
||||
def _preset_alias_callback(option, opt_str, value, parser):
|
||||
if not value:
|
||||
return
|
||||
if value not in _PRESET_ALIASES:
|
||||
raise optparse.OptionValueError(f'Unknown preset alias: {value}')
|
||||
parser.rargs[:0] = _PRESET_ALIASES[value]
|
||||
|
||||
general = optparse.OptionGroup(parser, 'General Options')
|
||||
general.add_option(
|
||||
'-h', '--help', dest='print_help', action='store_true',
|
||||
@@ -390,12 +425,12 @@ def create_parser():
|
||||
'--ignore-config', '--no-config',
|
||||
action='store_true', dest='ignoreconfig',
|
||||
help=(
|
||||
'Don\'t load any more configuration files except those given by --config-locations. '
|
||||
'Don\'t load any more configuration files except those given to --config-locations. '
|
||||
'For backward compatibility, if this option is found inside the system configuration file, the user configuration is not loaded. '
|
||||
'(Alias: --no-config)'))
|
||||
general.add_option(
|
||||
'--no-config-locations',
|
||||
action='store_const', dest='config_locations', const=[],
|
||||
action='store_const', dest='config_locations', const=None,
|
||||
help=(
|
||||
'Do not load any custom configuration files (default). When given inside a '
|
||||
'configuration file, ignore all previous --config-locations defined in the current file'))
|
||||
@@ -405,10 +440,29 @@ def create_parser():
|
||||
help=(
|
||||
'Location of the main configuration file; either the path to the config or its containing directory '
|
||||
'("-" for stdin). Can be used multiple times and inside other configuration files'))
|
||||
general.add_option(
|
||||
'--plugin-dirs',
|
||||
metavar='PATH',
|
||||
dest='plugin_dirs',
|
||||
action='callback',
|
||||
callback=_list_from_options_callback,
|
||||
type='str',
|
||||
callback_kwargs={'delim': None},
|
||||
default=['default'],
|
||||
help=(
|
||||
'Path to an additional directory to search for plugins. '
|
||||
'This option can be used multiple times to add multiple directories. '
|
||||
'Use "default" to search the default plugin directories (default)'))
|
||||
general.add_option(
|
||||
'--no-plugin-dirs',
|
||||
dest='plugin_dirs', action='store_const', const=[],
|
||||
help='Clear plugin directories to search, including defaults and those provided by previous --plugin-dirs')
|
||||
general.add_option(
|
||||
'--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')
|
||||
help=(
|
||||
'Do not extract a playlist\'s URL result entries; '
|
||||
'some entry metadata may be missing and downloading may be bypassed'))
|
||||
general.add_option(
|
||||
'--no-flat-playlist',
|
||||
action='store_false', dest='extract_flat',
|
||||
@@ -459,6 +513,7 @@ def create_parser():
|
||||
'the STREAM (stdout or stderr) to apply the setting to. '
|
||||
'Can be one of "always", "auto" (default), "never", or '
|
||||
'"no_color" (use non color terminal sequences). '
|
||||
'Use "auto-tty" or "no_color-tty" to decide based on terminal support only. '
|
||||
'Can be used multiple times'))
|
||||
general.add_option(
|
||||
'--compat-options',
|
||||
@@ -471,12 +526,15 @@ def create_parser():
|
||||
'no-attach-info-json', 'embed-thumbnail-atomicparsley', 'no-external-downloader-progress',
|
||||
'embed-metadata', 'seperate-video-versions', 'no-clean-infojson', 'no-keep-subs', 'no-certifi',
|
||||
'no-youtube-channel-redirect', 'no-youtube-unavailable-videos', 'no-youtube-prefer-utc-upload-date',
|
||||
'prefer-legacy-http-handler', 'manifest-filesize-approx', 'allow-unsafe-ext', 'prefer-vp9-sort',
|
||||
}, 'aliases': {
|
||||
'youtube-dl': ['all', '-multistreams', '-playlist-match-filter'],
|
||||
'youtube-dlc': ['all', '-no-youtube-channel-redirect', '-no-live-chat', '-playlist-match-filter'],
|
||||
'2021': ['2022', 'no-certifi', 'filename-sanitization', 'no-youtube-prefer-utc-upload-date'],
|
||||
'2022': ['no-external-downloader-progress', 'playlist-match-filter'],
|
||||
}
|
||||
'youtube-dl': ['all', '-multistreams', '-playlist-match-filter', '-manifest-filesize-approx', '-allow-unsafe-ext', '-prefer-vp9-sort'],
|
||||
'youtube-dlc': ['all', '-no-youtube-channel-redirect', '-no-live-chat', '-playlist-match-filter', '-manifest-filesize-approx', '-allow-unsafe-ext', '-prefer-vp9-sort'],
|
||||
'2021': ['2022', 'no-certifi', 'filename-sanitization'],
|
||||
'2022': ['2023', 'no-external-downloader-progress', 'playlist-match-filter', 'prefer-legacy-http-handler', 'manifest-filesize-approx'],
|
||||
'2023': ['2024', 'prefer-vp9-sort'],
|
||||
'2024': [],
|
||||
},
|
||||
}, help=(
|
||||
'Options that can help keep compatibility with youtube-dl or youtube-dlc '
|
||||
'configurations by reverting some of the changes made in yt-dlp. '
|
||||
@@ -493,6 +551,15 @@ def create_parser():
|
||||
'Alias options can trigger more aliases; so be careful to avoid defining recursive options. '
|
||||
f'As a safety measure, each alias may be triggered a maximum of {_YoutubeDLOptionParser.ALIAS_TRIGGER_LIMIT} times. '
|
||||
'This option can be used multiple times'))
|
||||
general.add_option(
|
||||
'-t', '--preset-alias',
|
||||
metavar='PRESET', dest='_', type='str',
|
||||
action='callback', callback=_preset_alias_callback,
|
||||
help=(
|
||||
'Applies a predefined set of options. e.g. --preset-alias mp3. '
|
||||
f'The following presets are available: {", ".join(_PRESET_ALIASES)}. '
|
||||
'See the "Preset Aliases" section at the end for more info. '
|
||||
'This option can be used multiple times'))
|
||||
|
||||
network = optparse.OptionGroup(parser, 'Network Options')
|
||||
network.add_option(
|
||||
@@ -510,6 +577,19 @@ def create_parser():
|
||||
metavar='IP', dest='source_address', default=None,
|
||||
help='Client-side IP address to bind to',
|
||||
)
|
||||
network.add_option(
|
||||
'--impersonate',
|
||||
metavar='CLIENT[:OS]', dest='impersonate', default=None,
|
||||
help=(
|
||||
'Client to impersonate for requests. E.g. chrome, chrome-110, chrome:windows-10. '
|
||||
'Pass --impersonate="" to impersonate any client. Note that forcing impersonation '
|
||||
'for all requests may have a detrimental impact on download speed and stability'),
|
||||
)
|
||||
network.add_option(
|
||||
'--list-impersonate-targets',
|
||||
dest='list_impersonate_targets', default=False, action='store_true',
|
||||
help='List available clients to impersonate.',
|
||||
)
|
||||
network.add_option(
|
||||
'-4', '--force-ipv4',
|
||||
action='store_const', const='0.0.0.0', dest='source_address',
|
||||
@@ -523,7 +603,7 @@ def create_parser():
|
||||
network.add_option(
|
||||
'--enable-file-urls', action='store_true',
|
||||
dest='enable_file_urls', default=False,
|
||||
help='Enable file:// URLs. This is disabled by default for security reasons.'
|
||||
help='Enable file:// URLs. This is disabled by default for security reasons.',
|
||||
)
|
||||
|
||||
geo = optparse.OptionGroup(parser, 'Geo-restriction')
|
||||
@@ -604,13 +684,13 @@ def create_parser():
|
||||
metavar='DATE', dest='datebefore', default=None,
|
||||
help=(
|
||||
'Download only videos uploaded on or before this date. '
|
||||
'The date formats accepted is the same as --date'))
|
||||
'The date formats accepted are the same as --date'))
|
||||
selection.add_option(
|
||||
'--dateafter',
|
||||
metavar='DATE', dest='dateafter', default=None,
|
||||
help=(
|
||||
'Download only videos uploaded on or after this date. '
|
||||
'The date formats accepted is the same as --date'))
|
||||
'The date formats accepted are the same as --date'))
|
||||
selection.add_option(
|
||||
'--min-views',
|
||||
metavar='COUNT', dest='min_views', default=None, type=int,
|
||||
@@ -628,16 +708,16 @@ def create_parser():
|
||||
'You can also simply specify a field to match if the field is present, '
|
||||
'use "!field" to check if the field is not present, and "&" to check multiple conditions. '
|
||||
'Use a "\\" to escape "&" or quotes if needed. If used multiple times, '
|
||||
'the filter matches if atleast one of the conditions are met. E.g. --match-filter '
|
||||
'!is_live --match-filter "like_count>?100 & description~=\'(?i)\\bcats \\& dogs\\b\'" '
|
||||
'the filter matches if at least one of the conditions is met. E.g. --match-filters '
|
||||
'!is_live --match-filters "like_count>?100 & description~=\'(?i)\\bcats \\& dogs\\b\'" '
|
||||
'matches only videos that are not live OR those that have a like count more than 100 '
|
||||
'(or the like field is not available) and also has a description '
|
||||
'that contains the phrase "cats & dogs" (caseless). '
|
||||
'Use "--match-filter -" to interactively ask whether to download each video'))
|
||||
'Use "--match-filters -" to interactively ask whether to download each video'))
|
||||
selection.add_option(
|
||||
'--no-match-filters',
|
||||
dest='match_filter', action='store_const', const=None,
|
||||
help='Do not use any --match-filter (default)')
|
||||
help='Do not use any --match-filters (default)')
|
||||
selection.add_option(
|
||||
'--break-match-filters',
|
||||
metavar='FILTER', dest='breaking_match_filter', action='append',
|
||||
@@ -664,7 +744,7 @@ def create_parser():
|
||||
help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it')
|
||||
selection.add_option(
|
||||
'--no-download-archive',
|
||||
dest='download_archive', action="store_const", const=None,
|
||||
dest='download_archive', action='store_const', const=None,
|
||||
help='Do not use archive file (default)')
|
||||
selection.add_option(
|
||||
'--max-downloads',
|
||||
@@ -673,7 +753,12 @@ def create_parser():
|
||||
selection.add_option(
|
||||
'--break-on-existing',
|
||||
action='store_true', dest='break_on_existing', default=False,
|
||||
help='Stop the download process when encountering a file that is in the archive')
|
||||
help='Stop the download process when encountering a file that is in the archive '
|
||||
'supplied with the --download-archive option')
|
||||
selection.add_option(
|
||||
'--no-break-on-existing',
|
||||
action='store_false', dest='break_on_existing',
|
||||
help='Do not stop the download process when encountering a file that is in the archive (default)')
|
||||
selection.add_option(
|
||||
'--break-on-reject',
|
||||
action='store_true', dest='break_on_reject', default=False,
|
||||
@@ -681,7 +766,7 @@ def create_parser():
|
||||
selection.add_option(
|
||||
'--break-per-input',
|
||||
action='store_true', dest='break_per_url', default=False,
|
||||
help='Alters --max-downloads, --break-on-existing, --break-match-filter, and autonumber to reset per input URL')
|
||||
help='Alters --max-downloads, --break-on-existing, --break-match-filters, and autonumber to reset per input URL')
|
||||
selection.add_option(
|
||||
'--no-break-per-input',
|
||||
action='store_false', dest='break_per_url',
|
||||
@@ -727,7 +812,7 @@ def create_parser():
|
||||
authentication.add_option(
|
||||
'--video-password',
|
||||
dest='videopassword', metavar='PASSWORD',
|
||||
help='Video password (vimeo, youku)')
|
||||
help='Video-specific password')
|
||||
authentication.add_option(
|
||||
'--ap-mso',
|
||||
dest='ap_mso', metavar='MSO',
|
||||
@@ -802,7 +887,7 @@ def create_parser():
|
||||
'--prefer-free-formats',
|
||||
action='store_true', dest='prefer_free_formats', default=False,
|
||||
help=(
|
||||
'Prefer video formats with free containers over non-free ones of same quality. '
|
||||
'Prefer video formats with free containers over non-free ones of the same quality. '
|
||||
'Use with "-S ext" to strictly prefer free containers irrespective of quality'))
|
||||
video_format.add_option(
|
||||
'--no-prefer-free-formats',
|
||||
@@ -876,13 +961,14 @@ def create_parser():
|
||||
subtitles.add_option(
|
||||
'--sub-format',
|
||||
action='store', dest='subtitlesformat', metavar='FORMAT', default='best',
|
||||
help='Subtitle format; accepts formats preference, e.g. "srt" or "ass/srt/best"')
|
||||
help='Subtitle format; accepts formats preference separated by "/", e.g. "srt" or "ass/srt/best"')
|
||||
subtitles.add_option(
|
||||
'--sub-langs', '--srt-langs',
|
||||
action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
|
||||
default=[], callback=_list_from_options_callback,
|
||||
help=(
|
||||
'Languages of the subtitles to download (can be regex) or "all" separated by commas, e.g. --sub-langs "en.*,ja". '
|
||||
'Languages of the subtitles to download (can be regex) or "all" separated by commas, e.g. --sub-langs "en.*,ja" '
|
||||
'(where "en.*" is a regex pattern that matches "en" followed by 0 or more of any character). '
|
||||
'You can prefix the language code with a "-" to exclude it from the requested languages, e.g. --sub-langs all,-live_chat. '
|
||||
'Use --list-subs for a list of available language tags'))
|
||||
|
||||
@@ -1024,7 +1110,7 @@ def create_parser():
|
||||
callback_kwargs={
|
||||
'allowed_keys': 'http|ftp|m3u8|dash|rtsp|rtmp|mms',
|
||||
'default_key': 'default',
|
||||
'process': str.strip
|
||||
'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. '
|
||||
@@ -1038,9 +1124,9 @@ def create_parser():
|
||||
metavar='NAME:ARGS', dest='external_downloader_args', default={}, type='str',
|
||||
action='callback', callback=_dict_from_options_callback,
|
||||
callback_kwargs={
|
||||
'allowed_keys': r'ffmpeg_[io]\d*|%s' % '|'.join(map(re.escape, list_external_downloaders())),
|
||||
'allowed_keys': r'ffmpeg_[io]\d*|{}'.format('|'.join(map(re.escape, list_external_downloaders()))),
|
||||
'default_key': 'default',
|
||||
'process': shlex.split
|
||||
'process': shlex.split,
|
||||
}, help=(
|
||||
'Give these arguments to the external downloader. '
|
||||
'Specify the downloader name and the arguments separated by a colon ":". '
|
||||
@@ -1151,7 +1237,7 @@ def create_parser():
|
||||
'--print-to-file',
|
||||
metavar='[WHEN:]TEMPLATE FILE', dest='print_to_file', nargs=2, **when_prefix('video'),
|
||||
help=(
|
||||
'Append given template to the file. The values of WHEN and TEMPLATE are same as that of --print. '
|
||||
'Append given template to the file. The values of WHEN and TEMPLATE are the same as that of --print. '
|
||||
'FILE uses the same syntax as the output template. This option can be used multiple times'))
|
||||
verbosity.add_option(
|
||||
'-g', '--get-url',
|
||||
@@ -1188,12 +1274,14 @@ def create_parser():
|
||||
verbosity.add_option(
|
||||
'-j', '--dump-json',
|
||||
action='store_true', dest='dumpjson', default=False,
|
||||
help='Quiet, but print JSON information for each video. Simulate unless --no-simulate is used. 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=(
|
||||
'Quiet, but print JSON information for each url or infojson passed. Simulate unless --no-simulate is used. '
|
||||
'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',
|
||||
@@ -1227,7 +1315,7 @@ def create_parser():
|
||||
action='callback', callback=_dict_from_options_callback,
|
||||
callback_kwargs={
|
||||
'allowed_keys': '(download|postprocess)(-title)?',
|
||||
'default_key': 'download'
|
||||
'default_key': 'download',
|
||||
}, help=(
|
||||
'Template for progress outputs, optionally prefixed with one of "download:" (default), '
|
||||
'"download-title:" (the console title), "postprocess:", or "postprocess-title:". '
|
||||
@@ -1235,6 +1323,10 @@ def create_parser():
|
||||
'the progress attributes are accessible under "progress" key. E.g. '
|
||||
# TODO: Document the fields inside "progress"
|
||||
'--console-title --progress-template "download-title:%(info.id)s-%(progress.eta)s"'))
|
||||
verbosity.add_option(
|
||||
'--progress-delta',
|
||||
metavar='SECONDS', action='store', dest='progress_delta', type=float, default=0,
|
||||
help='Time between progress output (default: 0)')
|
||||
verbosity.add_option(
|
||||
'-v', '--verbose',
|
||||
action='store_true', dest='verbose', default=False,
|
||||
@@ -1289,8 +1381,8 @@ def create_parser():
|
||||
metavar='[TYPES:]PATH', dest='paths', default={}, type='str',
|
||||
action='callback', callback=_dict_from_options_callback,
|
||||
callback_kwargs={
|
||||
'allowed_keys': 'home|temp|%s' % '|'.join(map(re.escape, OUTTMPL_TYPES.keys())),
|
||||
'default_key': 'home'
|
||||
'allowed_keys': 'home|temp|{}'.format('|'.join(map(re.escape, 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 ":". '
|
||||
@@ -1305,12 +1397,12 @@ def create_parser():
|
||||
action='callback', callback=_dict_from_options_callback,
|
||||
callback_kwargs={
|
||||
'allowed_keys': '|'.join(map(re.escape, OUTTMPL_TYPES.keys())),
|
||||
'default_key': 'default'
|
||||
'default_key': 'default',
|
||||
}, help='Output filename template; see "OUTPUT TEMPLATE" for details')
|
||||
filesystem.add_option(
|
||||
'--output-na-placeholder',
|
||||
dest='outtmpl_na_placeholder', metavar='TEXT', default='NA',
|
||||
help=('Placeholder for unavailable fields in "OUTPUT TEMPLATE" (default: "%default")'))
|
||||
help=('Placeholder for unavailable fields in --output (default: "%default")'))
|
||||
filesystem.add_option(
|
||||
'--autonumber-size',
|
||||
dest='autonumber_size', metavar='NUMBER', type=int,
|
||||
@@ -1329,12 +1421,12 @@ def create_parser():
|
||||
help='Allow Unicode characters, "&" and spaces in filenames (default)')
|
||||
filesystem.add_option(
|
||||
'--windows-filenames',
|
||||
action='store_true', dest='windowsfilenames', default=False,
|
||||
action='store_true', dest='windowsfilenames', default=None,
|
||||
help='Force filenames to be Windows-compatible')
|
||||
filesystem.add_option(
|
||||
'--no-windows-filenames',
|
||||
action='store_false', dest='windowsfilenames',
|
||||
help='Make filenames Windows-compatible only if using Windows (default)')
|
||||
help='Sanitize filenames only minimally')
|
||||
filesystem.add_option(
|
||||
'--trim-filenames', '--trim-file-names', metavar='LENGTH',
|
||||
dest='trim_file_name', default=0, type=int,
|
||||
@@ -1451,7 +1543,7 @@ def create_parser():
|
||||
'Optionally, the KEYRING used for decrypting Chromium cookies on Linux, '
|
||||
'the name/path of the PROFILE to load cookies from, '
|
||||
'and the CONTAINER name (if Firefox) ("none" for no container) '
|
||||
'can be given with their respective seperators. '
|
||||
'can be given with their respective separators. '
|
||||
'By default, all containers of the most recently accessed profile are used. '
|
||||
f'Currently supported keyrings are: {", ".join(map(str.lower, sorted(SUPPORTED_KEYRINGS)))}'))
|
||||
filesystem.add_option(
|
||||
@@ -1533,7 +1625,7 @@ def create_parser():
|
||||
help=(
|
||||
'Remux the video into another container if necessary '
|
||||
f'(currently supported: {", ".join(FFmpegVideoRemuxerPP.SUPPORTED_EXTS)}). '
|
||||
'If target container does not support the video/audio codec, remuxing will fail. You can specify multiple rules; '
|
||||
'If the target container does not support the video/audio codec, remuxing will fail. You can specify multiple rules; '
|
||||
'e.g. "aac>m4a/mov>mp4/mkv" will remux aac to m4a, mov to mp4 and anything else to mkv'))
|
||||
postproc.add_option(
|
||||
'--recode-video',
|
||||
@@ -1547,7 +1639,7 @@ def create_parser():
|
||||
'allowed_keys': r'\w+(?:\+\w+)?',
|
||||
'default_key': 'default-compat',
|
||||
'process': shlex.split,
|
||||
'multiple_keys': False
|
||||
'multiple_keys': False,
|
||||
}, help=(
|
||||
'Give these arguments to the postprocessors. '
|
||||
'Specify the postprocessor/executable name and the arguments separated by a colon ":" '
|
||||
@@ -1639,7 +1731,7 @@ def create_parser():
|
||||
postproc.add_option(
|
||||
'--xattrs', '--xattr',
|
||||
action='store_true', dest='xattrs', default=False,
|
||||
help='Write metadata to the video file\'s xattrs (using dublin core and xdg standards)')
|
||||
help='Write metadata to the video file\'s xattrs (using Dublin Core and XDG standards)')
|
||||
postproc.add_option(
|
||||
'--concat-playlist',
|
||||
metavar='POLICY', dest='concat_playlist', default='multi_video',
|
||||
@@ -1647,7 +1739,7 @@ def create_parser():
|
||||
help=(
|
||||
'Concatenate videos in a playlist. One of "never", "always", or '
|
||||
'"multi_video" (default; only when the videos form a single show). '
|
||||
'All the video files must have same codecs and number of streams to be concatable. '
|
||||
'All the video files must have the same codecs and number of streams to be concatenable. '
|
||||
'The "pl_video:" prefix can be used with "--paths" and "--output" to '
|
||||
'set the output filename for the concatenated files. See "OUTPUT TEMPLATE" for details'))
|
||||
postproc.add_option(
|
||||
@@ -1657,8 +1749,8 @@ def create_parser():
|
||||
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), '
|
||||
'force (try fixing even if file already exists)'))
|
||||
'detect_or_warn (the default; fix the file if we can, warn otherwise), '
|
||||
'force (try fixing even if the file already exists)'))
|
||||
postproc.add_option(
|
||||
'--prefer-avconv', '--no-prefer-ffmpeg',
|
||||
action='store_false', dest='prefer_ffmpeg',
|
||||
@@ -1677,7 +1769,7 @@ def create_parser():
|
||||
help=(
|
||||
'Execute a command, optionally prefixed with when to execute it, separated by a ":". '
|
||||
'Supported values of "WHEN" are the same as that of --use-postprocessor (default: after_move). '
|
||||
'Same syntax as the output template can be used to pass any field as arguments to the command. '
|
||||
'The same syntax as the output template can be used to pass any field as arguments to the command. '
|
||||
'If no fields are passed, %(filepath,_filename|)q is appended to the end of the command. '
|
||||
'This option can be used multiple times'))
|
||||
postproc.add_option(
|
||||
@@ -1696,15 +1788,17 @@ def create_parser():
|
||||
'--convert-subs', '--convert-sub', '--convert-subtitles',
|
||||
metavar='FORMAT', dest='convertsubtitles', default=None,
|
||||
help=(
|
||||
'Convert the subtitles to another format (currently supported: %s) '
|
||||
'(Alias: --convert-subtitles)' % ', '.join(sorted(FFmpegSubtitlesConvertorPP.SUPPORTED_EXTS))))
|
||||
'Convert the subtitles to another format '
|
||||
f'(currently supported: {", ".join(sorted(FFmpegSubtitlesConvertorPP.SUPPORTED_EXTS))}). '
|
||||
'Use "--convert-subs none" to disable conversion (default) (Alias: --convert-subtitles)'))
|
||||
postproc.add_option(
|
||||
'--convert-thumbnails',
|
||||
metavar='FORMAT', dest='convertthumbnails', default=None,
|
||||
help=(
|
||||
'Convert the thumbnails to another format '
|
||||
f'(currently supported: {", ".join(sorted(FFmpegThumbnailsConvertorPP.SUPPORTED_EXTS))}). '
|
||||
'You can specify multiple rules using similar syntax as --remux-video'))
|
||||
'You can specify multiple rules using similar syntax as "--remux-video". '
|
||||
'Use "--convert-thumbnails none" to disable conversion (default)'))
|
||||
postproc.add_option(
|
||||
'--split-chapters', '--split-tracks',
|
||||
dest='split_chapters', action='store_true', default=False,
|
||||
@@ -1744,16 +1838,16 @@ def create_parser():
|
||||
action='callback', callback=_list_from_options_callback,
|
||||
callback_kwargs={
|
||||
'delim': None,
|
||||
'process': lambda val: dict(_postprocessor_opts_parser(*val.split(':', 1)))
|
||||
'process': lambda val: dict(_postprocessor_opts_parser(*val.split(':', 1))),
|
||||
}, help=(
|
||||
'The (case sensitive) name of plugin postprocessors to be enabled, '
|
||||
'The (case-sensitive) name of plugin postprocessors to be enabled, '
|
||||
'and (optionally) arguments to be passed to it, separated by a colon ":". '
|
||||
'ARGS are a semicolon ";" delimited list of NAME=VALUE. '
|
||||
'The "when" argument determines when the postprocessor is invoked. '
|
||||
'It can be one of "pre_process" (after video extraction), "after_filter" (after video passes filter), '
|
||||
'"video" (after --format; before --print/--output), "before_dl" (before each video download), '
|
||||
'"post_process" (after each video download; default), '
|
||||
'"after_move" (after moving video file to it\'s final locations), '
|
||||
'"after_move" (after moving the video file to its final location), '
|
||||
'"after_video" (after downloading and processing all formats of a video), '
|
||||
'or "playlist" (at end of playlist). '
|
||||
'This option can be used multiple times to add different postprocessors'))
|
||||
@@ -1766,11 +1860,11 @@ def create_parser():
|
||||
dest='sponsorblock_mark', default=set(), action='callback', type='str',
|
||||
callback=_set_from_options_callback, callback_kwargs={
|
||||
'allowed_values': SponsorBlockPP.CATEGORIES.keys(),
|
||||
'aliases': {'default': ['all']}
|
||||
'aliases': {'default': ['all']},
|
||||
}, help=(
|
||||
'SponsorBlock categories to create chapters for, separated by commas. '
|
||||
f'Available categories are {", ".join(SponsorBlockPP.CATEGORIES.keys())}, all and default (=all). '
|
||||
'You can prefix the category with a "-" to exclude it. See [1] for description of the categories. '
|
||||
'You can prefix the category with a "-" to exclude it. See [1] for descriptions of the categories. '
|
||||
'E.g. --sponsorblock-mark all,-preview [1] https://wiki.sponsor.ajay.app/w/Segment_Categories'))
|
||||
sponsorblock.add_option(
|
||||
'--sponsorblock-remove', metavar='CATS',
|
||||
@@ -1780,7 +1874,7 @@ def create_parser():
|
||||
# Note: From https://wiki.sponsor.ajay.app/w/Types:
|
||||
# The filler category is very aggressive.
|
||||
# It is strongly recommended to not use this in a client by default.
|
||||
'aliases': {'default': ['all', '-filler']}
|
||||
'aliases': {'default': ['all', '-filler']},
|
||||
}, help=(
|
||||
'SponsorBlock categories to be removed from the video file, separated by commas. '
|
||||
'If a category is present in both mark and remove, remove takes precedence. '
|
||||
@@ -1851,12 +1945,12 @@ def create_parser():
|
||||
extractor.add_option(
|
||||
'--hls-split-discontinuity',
|
||||
dest='hls_split_discontinuity', action='store_true', default=False,
|
||||
help='Split HLS playlists to different formats at discontinuities such as ad breaks'
|
||||
help='Split HLS playlists to different formats at discontinuities such as ad breaks',
|
||||
)
|
||||
extractor.add_option(
|
||||
'--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)')
|
||||
help='Do not split HLS playlists into different formats at discontinuities such as ad breaks (default)')
|
||||
_extractor_arg_parser = lambda key, vals='': (key.strip().lower().replace('-', '_'), [
|
||||
val.replace(r'\,', ',').strip() for val in re.split(r'(?<!\\),', vals)])
|
||||
extractor.add_option(
|
||||
@@ -1866,7 +1960,7 @@ def create_parser():
|
||||
callback_kwargs={
|
||||
'multiple_keys': False,
|
||||
'process': lambda val: dict(
|
||||
_extractor_arg_parser(*arg.split('=', 1)) for arg in val.split(';'))
|
||||
_extractor_arg_parser(*arg.split('=', 1)) for arg in val.split(';')),
|
||||
}, help=(
|
||||
'Pass ARGS arguments to the IE_KEY extractor. See "EXTRACTOR ARGUMENTS" for details. '
|
||||
'You can use this option multiple times to give arguments for different extractors'))
|
||||
|
Reference in New Issue
Block a user