aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpukkandan <pukkandan.ytdlp@gmail.com>2022-01-03 16:43:54 +0530
committerpukkandan <pukkandan.ytdlp@gmail.com>2022-01-03 19:40:02 +0530
commit1e43a6f7336f4d9691dc52a1bc7cfe14ba7a936d (patch)
tree218655a09fd54a9c51f4db1d5bb7564c633b6f3e
parentca30f449a187addcdb99f4c39333e7a292756597 (diff)
downloadhypervideo-pre-1e43a6f7336f4d9691dc52a1bc7cfe14ba7a936d.tar.lz
hypervideo-pre-1e43a6f7336f4d9691dc52a1bc7cfe14ba7a936d.tar.xz
hypervideo-pre-1e43a6f7336f4d9691dc52a1bc7cfe14ba7a936d.zip
Allow `--exec` to be run at any post-processing stage
Deprecates `--exec-before-download`
-rw-r--r--README.md29
-rw-r--r--yt_dlp/YoutubeDL.py5
-rw-r--r--yt_dlp/__init__.py19
-rw-r--r--yt_dlp/options.py29
-rw-r--r--yt_dlp/postprocessor/exec.py12
-rw-r--r--yt_dlp/utils.py3
6 files changed, 52 insertions, 45 deletions
diff --git a/README.md b/README.md
index e032ea6e6..1b8680e33 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py
index faea85485..5b285e1a1 100644
--- a/yt_dlp/YoutubeDL.py
+++ b/yt_dlp/YoutubeDL.py
@@ -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 = []
diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py
index af7a4e195..85f000df4 100644
--- a/yt_dlp/__init__.py
+++ b/yt_dlp/__init__.py
@@ -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):
diff --git a/yt_dlp/options.py b/yt_dlp/options.py
index d48cd1457..f4e5d14df 100644
--- a/yt_dlp/options.py
+++ b/yt_dlp/options.py
@@ -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,
diff --git a/yt_dlp/postprocessor/exec.py b/yt_dlp/postprocessor/exec.py
index 28a7c3d70..63f4d23f2 100644
--- a/yt_dlp/postprocessor/exec.py
+++ b/yt_dlp/postprocessor/exec.py
@@ -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:
diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py
index ae23ec2a3..f56129aa5 100644
--- a/yt_dlp/utils.py
+++ b/yt_dlp/utils.py
@@ -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',