mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-21 20:46:36 -05:00
Allow --exec
to be run at any post-processing stage
Deprecates `--exec-before-download`
This commit is contained in:
parent
ca30f449a1
commit
1e43a6f733
6 changed files with 52 additions and 45 deletions
29
README.md
29
README.md
|
@ -896,23 +896,20 @@ ## Post-Processing Options:
|
||||||
--ffmpeg-location PATH Location of the ffmpeg binary; either the
|
--ffmpeg-location PATH Location of the ffmpeg binary; either the
|
||||||
path to the binary or its containing
|
path to the binary or its containing
|
||||||
directory
|
directory
|
||||||
--exec CMD Execute a command on the file after
|
--exec [WHEN:]CMD Execute a command, optionally prefixed with
|
||||||
downloading and post-processing. Same
|
when to execute it (after_move if
|
||||||
syntax as the output template can be used
|
unspecified), separated by a ":". Supported
|
||||||
to pass any field as arguments to the
|
values of "WHEN" are the same as that of
|
||||||
command. An additional field "filepath"
|
--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
|
that contains the final path of the
|
||||||
downloaded file is also available. If no
|
downloaded file is also available, and if
|
||||||
fields are passed, %(filepath)q is appended
|
no fields are passed, %(filepath)q is
|
||||||
to the end of the command. This option can
|
appended to the end of the command. This
|
||||||
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
|
|
||||||
option can be used multiple times
|
option can be used multiple times
|
||||||
--no-exec-before-download Remove any previously defined
|
--no-exec Remove any previously defined --exec
|
||||||
--exec-before-download
|
|
||||||
--convert-subs FORMAT Convert the subtitles to another format
|
--convert-subs FORMAT Convert the subtitles to another format
|
||||||
(currently supported: srt|vtt|ass|lrc)
|
(currently supported: srt|vtt|ass|lrc)
|
||||||
(Alias: --convert-subtitles)
|
(Alias: --convert-subtitles)
|
||||||
|
@ -1800,6 +1797,8 @@ #### Redundant options
|
||||||
#### Not recommended
|
#### Not recommended
|
||||||
While these options still work, their use is not recommended since there are other alternatives to achieve the same
|
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-formats -f all
|
||||||
--all-subs --sub-langs all --write-subs
|
--all-subs --sub-langs all --write-subs
|
||||||
--print-json -j --no-simulate
|
--print-json -j --no-simulate
|
||||||
|
|
|
@ -91,6 +91,7 @@
|
||||||
PerRequestProxyHandler,
|
PerRequestProxyHandler,
|
||||||
platform_name,
|
platform_name,
|
||||||
Popen,
|
Popen,
|
||||||
|
POSTPROCESS_WHEN,
|
||||||
PostProcessingError,
|
PostProcessingError,
|
||||||
preferredencoding,
|
preferredencoding,
|
||||||
prepend_extension,
|
prepend_extension,
|
||||||
|
@ -507,7 +508,7 @@ class YoutubeDL(object):
|
||||||
|
|
||||||
params = None
|
params = None
|
||||||
_ies = {}
|
_ies = {}
|
||||||
_pps = {'pre_process': [], 'before_dl': [], 'after_move': [], 'post_process': []}
|
_pps = {k: [] for k in POSTPROCESS_WHEN}
|
||||||
_printed_messages = set()
|
_printed_messages = set()
|
||||||
_first_webpage_request = True
|
_first_webpage_request = True
|
||||||
_download_retcode = None
|
_download_retcode = None
|
||||||
|
@ -525,7 +526,7 @@ def __init__(self, params=None, auto_init=True):
|
||||||
params = {}
|
params = {}
|
||||||
self._ies = {}
|
self._ies = {}
|
||||||
self._ies_instances = {}
|
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._printed_messages = set()
|
||||||
self._first_webpage_request = True
|
self._first_webpage_request = True
|
||||||
self._post_hooks = []
|
self._post_hooks = []
|
||||||
|
|
|
@ -143,6 +143,8 @@ def _real_main(argv=None):
|
||||||
'"-f best" selects the best pre-merged format which is often not the best option',
|
'"-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',
|
'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 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):
|
if opts.usenetrc and (opts.username is not None or opts.password is not None):
|
||||||
parser.error('using .netrc conflicts with giving username/password')
|
parser.error('using .netrc conflicts with giving username/password')
|
||||||
if opts.password is not None and opts.username is None:
|
if opts.password is not None and opts.username is None:
|
||||||
|
@ -489,13 +491,6 @@ def report_unplayable_conflict(opt_name, arg, default=False, allowed=None):
|
||||||
# Run this before the actual video download
|
# Run this before the actual video download
|
||||||
'when': 'before_dl'
|
'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:
|
if opts.extractaudio:
|
||||||
postprocessors.append({
|
postprocessors.append({
|
||||||
'key': 'FFmpegExtractAudio',
|
'key': 'FFmpegExtractAudio',
|
||||||
|
@ -596,13 +591,15 @@ def report_unplayable_conflict(opt_name, arg, default=False, allowed=None):
|
||||||
# XAttrMetadataPP should be run after post-processors that may change file contents
|
# XAttrMetadataPP should be run after post-processors that may change file contents
|
||||||
if opts.xattrs:
|
if opts.xattrs:
|
||||||
postprocessors.append({'key': 'XAttrMetadata'})
|
postprocessors.append({'key': 'XAttrMetadata'})
|
||||||
# Exec must be the last PP
|
# Exec must be the last PP of each category
|
||||||
if opts.exec_cmd:
|
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({
|
postprocessors.append({
|
||||||
'key': 'Exec',
|
'key': 'Exec',
|
||||||
'exec_cmd': opts.exec_cmd,
|
'exec_cmd': exec_cmd,
|
||||||
# Run this only after the files have been moved to their final locations
|
# Run this only after the files have been moved to their final locations
|
||||||
'when': 'after_move'
|
'when': when,
|
||||||
})
|
})
|
||||||
|
|
||||||
def report_args_compat(arg, name):
|
def report_args_compat(arg, name):
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
expand_path,
|
expand_path,
|
||||||
get_executable_path,
|
get_executable_path,
|
||||||
OUTTMPL_TYPES,
|
OUTTMPL_TYPES,
|
||||||
|
POSTPROCESS_WHEN,
|
||||||
preferredencoding,
|
preferredencoding,
|
||||||
remove_end,
|
remove_end,
|
||||||
write_string,
|
write_string,
|
||||||
|
@ -1393,29 +1394,33 @@ def _dict_from_options_callback(
|
||||||
dest='ffmpeg_location',
|
dest='ffmpeg_location',
|
||||||
help='Location of the ffmpeg binary; either the path to the binary or its containing directory')
|
help='Location of the ffmpeg binary; either the path to the binary or its containing directory')
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'--exec', metavar='CMD',
|
'--exec',
|
||||||
action='append', dest='exec_cmd',
|
metavar='[WHEN:]CMD', dest='exec_cmd', default={}, type='str',
|
||||||
help=(
|
action='callback', callback=_dict_from_options_callback,
|
||||||
'Execute a command on the file after downloading and post-processing. '
|
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. '
|
'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. '
|
'After download, an additional field "filepath" that contains the final path of the downloaded file '
|
||||||
'If no fields are passed, %(filepath)q is appended to the end of the command. '
|
'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'))
|
'This option can be used multiple times'))
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'--no-exec',
|
'--no-exec',
|
||||||
action='store_const', dest='exec_cmd', const=[],
|
action='store_const', dest='exec_cmd', const={},
|
||||||
help='Remove any previously defined --exec')
|
help='Remove any previously defined --exec')
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'--exec-before-download', metavar='CMD',
|
'--exec-before-download', metavar='CMD',
|
||||||
action='append', dest='exec_before_dl_cmd',
|
action='append', dest='exec_before_dl_cmd',
|
||||||
help=(
|
help=optparse.SUPPRESS_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(
|
postproc.add_option(
|
||||||
'--no-exec-before-download',
|
'--no-exec-before-download',
|
||||||
action='store_const', dest='exec_before_dl_cmd', const=[],
|
action='store_const', dest='exec_before_dl_cmd', const=[],
|
||||||
help='Remove any previously defined --exec-before-download')
|
help=optparse.SUPPRESS_HELP)
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'--convert-subs', '--convert-sub', '--convert-subtitles',
|
'--convert-subs', '--convert-sub', '--convert-subtitles',
|
||||||
metavar='FORMAT', dest='convertsubtitles', default=None,
|
metavar='FORMAT', dest='convertsubtitles', default=None,
|
||||||
|
|
|
@ -22,11 +22,13 @@ def parse_cmd(self, cmd, info):
|
||||||
if tmpl_dict: # if there are no replacements, tmpl_dict = {}
|
if tmpl_dict: # if there are no replacements, tmpl_dict = {}
|
||||||
return self._downloader.escape_outtmpl(tmpl) % tmpl_dict
|
return self._downloader.escape_outtmpl(tmpl) % tmpl_dict
|
||||||
|
|
||||||
# If no replacements are found, replace {} for backard compatibility
|
filepath = info.get('filepath', info.get('_filename'))
|
||||||
if '{}' not in cmd:
|
# If video, and no replacements are found, replace {} for backard compatibility
|
||||||
cmd += ' {}'
|
if filepath:
|
||||||
return cmd.replace('{}', compat_shlex_quote(
|
if '{}' not in cmd:
|
||||||
info.get('filepath') or info['_filename']))
|
cmd += ' {}'
|
||||||
|
cmd = cmd.replace('{}', compat_shlex_quote(filepath))
|
||||||
|
return cmd
|
||||||
|
|
||||||
def run(self, info):
|
def run(self, info):
|
||||||
for tmpl in self.exec_cmd:
|
for tmpl in self.exec_cmd:
|
||||||
|
|
|
@ -3036,6 +3036,9 @@ def q(qid):
|
||||||
return q
|
return q
|
||||||
|
|
||||||
|
|
||||||
|
POSTPROCESS_WHEN = {'pre_process', 'before_dl', 'after_move', 'post_process'}
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_OUTTMPL = {
|
DEFAULT_OUTTMPL = {
|
||||||
'default': '%(title)s [%(id)s].%(ext)s',
|
'default': '%(title)s [%(id)s].%(ext)s',
|
||||||
'chapter': '%(title)s - %(section_number)03d %(section_title)s [%(id)s].%(ext)s',
|
'chapter': '%(title)s - %(section_number)03d %(section_title)s [%(id)s].%(ext)s',
|
||||||
|
|
Loading…
Reference in a new issue