Allow `--exec` to be run at any post-processing stage

Deprecates `--exec-before-download`
This commit is contained in:
pukkandan 2022-01-03 16:43:54 +05:30
parent ca30f449a1
commit 1e43a6f733
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698
6 changed files with 52 additions and 45 deletions

View File

@ -896,23 +896,20 @@ You can also fork the project on github and run your fork's [build workflow](.gi
--ffmpeg-location PATH Location of the ffmpeg binary; either the
path to the binary or its containing
directory
--exec CMD Execute a command on the file after
downloading and post-processing. Same
syntax as the output template can be used
to pass any field as arguments to the
command. An additional field "filepath"
--exec [WHEN:]CMD Execute a command, optionally prefixed with
when to execute it (after_move if
unspecified), separated by a ":". Supported
values of "WHEN" are the same as that of
--use-postprocessor. Same syntax as the
output template can be used to pass any
field as arguments to the command. After
download, an additional field "filepath"
that contains the final path of the
downloaded file is also available. If no
fields are passed, %(filepath)q is appended
to the end of the command. This option can
be used multiple times
--no-exec Remove any previously defined --exec
--exec-before-download CMD Execute a command before the actual
download. The syntax is the same as --exec
but "filepath" is not available. This
downloaded file is also available, and if
no fields are passed, %(filepath)q is
appended to the end of the command. This
option can be used multiple times
--no-exec-before-download Remove any previously defined
--exec-before-download
--no-exec Remove any previously defined --exec
--convert-subs FORMAT Convert the subtitles to another format
(currently supported: srt|vtt|ass|lrc)
(Alias: --convert-subtitles)
@ -1800,6 +1797,8 @@ While these options are redundant, they are still expected to be used due to the
#### Not recommended
While these options still work, their use is not recommended since there are other alternatives to achieve the same
--exec-before-download CMD --exec "before_dl:CMD"
--no-exec-before-download --no-exec
--all-formats -f all
--all-subs --sub-langs all --write-subs
--print-json -j --no-simulate

View File

@ -91,6 +91,7 @@ from .utils import (
PerRequestProxyHandler,
platform_name,
Popen,
POSTPROCESS_WHEN,
PostProcessingError,
preferredencoding,
prepend_extension,
@ -507,7 +508,7 @@ class YoutubeDL(object):
params = None
_ies = {}
_pps = {'pre_process': [], 'before_dl': [], 'after_move': [], 'post_process': []}
_pps = {k: [] for k in POSTPROCESS_WHEN}
_printed_messages = set()
_first_webpage_request = True
_download_retcode = None
@ -525,7 +526,7 @@ class YoutubeDL(object):
params = {}
self._ies = {}
self._ies_instances = {}
self._pps = {'pre_process': [], 'before_dl': [], 'after_move': [], 'post_process': []}
self._pps = {k: [] for k in POSTPROCESS_WHEN}
self._printed_messages = set()
self._first_webpage_request = True
self._post_hooks = []

View File

@ -143,6 +143,8 @@ def _real_main(argv=None):
'"-f best" selects the best pre-merged format which is often not the best option',
'To let yt-dlp download and merge the best available formats, simply do not pass any format selection',
'If you know what you are doing and want only the best pre-merged format, use "-f b" instead to suppress this warning')))
if opts.exec_cmd.get('before_dl') and opts.exec_before_dl_cmd:
parser.error('using "--exec-before-download" conflicts with "--exec before_dl:"')
if opts.usenetrc and (opts.username is not None or opts.password is not None):
parser.error('using .netrc conflicts with giving username/password')
if opts.password is not None and opts.username is None:
@ -489,13 +491,6 @@ def _real_main(argv=None):
# Run this before the actual video download
'when': 'before_dl'
})
# Must be after all other before_dl
if opts.exec_before_dl_cmd:
postprocessors.append({
'key': 'Exec',
'exec_cmd': opts.exec_before_dl_cmd,
'when': 'before_dl'
})
if opts.extractaudio:
postprocessors.append({
'key': 'FFmpegExtractAudio',
@ -596,13 +591,15 @@ def _real_main(argv=None):
# XAttrMetadataPP should be run after post-processors that may change file contents
if opts.xattrs:
postprocessors.append({'key': 'XAttrMetadata'})
# Exec must be the last PP
if opts.exec_cmd:
# Exec must be the last PP of each category
if opts.exec_before_dl_cmd:
opts.exec_cmd.setdefault('before_dl', opts.exec_before_dl_cmd)
for when, exec_cmd in opts.exec_cmd.items():
postprocessors.append({
'key': 'Exec',
'exec_cmd': opts.exec_cmd,
'exec_cmd': exec_cmd,
# Run this only after the files have been moved to their final locations
'when': 'after_move'
'when': when,
})
def report_args_compat(arg, name):

View File

@ -16,6 +16,7 @@ from .utils import (
expand_path,
get_executable_path,
OUTTMPL_TYPES,
POSTPROCESS_WHEN,
preferredencoding,
remove_end,
write_string,
@ -1393,29 +1394,33 @@ def parseOpts(overrideArguments=None):
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',
action='append', dest='exec_cmd',
help=(
'Execute a command on the file after downloading and post-processing. '
'--exec',
metavar='[WHEN:]CMD', dest='exec_cmd', default={}, type='str',
action='callback', callback=_dict_from_options_callback,
callback_kwargs={
'allowed_keys': '|'.join(map(re.escape, POSTPROCESS_WHEN)),
'default_key': 'after_move',
'multiple_keys': False,
'append': True,
}, help=(
'Execute a command, optionally prefixed with when to execute it (after_move if unspecified), separated by a ":". '
'Supported values of "WHEN" are the same as that of --use-postprocessor. '
'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)q is appended to the end of the command. '
'After download, an additional field "filepath" that contains the final path of the downloaded file '
'is also available, and 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=[],
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'))
help=optparse.SUPPRESS_HELP)
postproc.add_option(
'--no-exec-before-download',
action='store_const', dest='exec_before_dl_cmd', const=[],
help='Remove any previously defined --exec-before-download')
help=optparse.SUPPRESS_HELP)
postproc.add_option(
'--convert-subs', '--convert-sub', '--convert-subtitles',
metavar='FORMAT', dest='convertsubtitles', default=None,

View File

@ -22,11 +22,13 @@ class ExecPP(PostProcessor):
if tmpl_dict: # if there are no replacements, tmpl_dict = {}
return self._downloader.escape_outtmpl(tmpl) % tmpl_dict
# If no replacements are found, replace {} for backard compatibility
if '{}' not in cmd:
cmd += ' {}'
return cmd.replace('{}', compat_shlex_quote(
info.get('filepath') or info['_filename']))
filepath = info.get('filepath', info.get('_filename'))
# If video, and no replacements are found, replace {} for backard compatibility
if filepath:
if '{}' not in cmd:
cmd += ' {}'
cmd = cmd.replace('{}', compat_shlex_quote(filepath))
return cmd
def run(self, info):
for tmpl in self.exec_cmd:

View File

@ -3036,6 +3036,9 @@ def qualities(quality_ids):
return q
POSTPROCESS_WHEN = {'pre_process', 'before_dl', 'after_move', 'post_process'}
DEFAULT_OUTTMPL = {
'default': '%(title)s [%(id)s].%(ext)s',
'chapter': '%(title)s - %(section_number)03d %(section_title)s [%(id)s].%(ext)s',