diff --git a/README.md b/README.md
index db07301313..320aecc800 100644
--- a/README.md
+++ b/README.md
@@ -773,6 +773,8 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
                                      downloaded file is also available. If no
                                      fields are passed, "%(filepath)s" is
                                      appended to the end of the command
+    --exec-before-download CMD       Execute a command before the actual
+                                     download. The syntax is the same as --exec
     --convert-subs FORMAT            Convert the subtitles to another format
                                      (currently supported: srt|vtt|ass|lrc)
                                      (Alias: --convert-subtitles)
diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py
index 6f8f38b85d..30482e6c3e 100644
--- a/yt_dlp/__init__.py
+++ b/yt_dlp/__init__.py
@@ -415,6 +415,13 @@ 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': 'ExecAfterDownload',
+            'exec_cmd': opts.exec_before_dl_cmd,
+            'when': 'before_dl'
+        })
     if opts.extractaudio:
         postprocessors.append({
             'key': 'FFmpegExtractAudio',
diff --git a/yt_dlp/options.py b/yt_dlp/options.py
index 64bc380e15..2a42712b6f 100644
--- a/yt_dlp/options.py
+++ b/yt_dlp/options.py
@@ -1265,6 +1265,10 @@ def parseOpts(overrideArguments=None):
             'Similar syntax to 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'))
+    postproc.add_option(
+        '--exec-before-download',
+        metavar='CMD', dest='exec_before_dl_cmd',
+        help='Execute a command before the actual download. The syntax is the same as --exec')
     postproc.add_option(
         '--convert-subs', '--convert-sub', '--convert-subtitles',
         metavar='FORMAT', dest='convertsubtitles', default=None,
diff --git a/yt_dlp/postprocessor/execafterdownload.py b/yt_dlp/postprocessor/execafterdownload.py
index 948b3ffb35..336671d14a 100644
--- a/yt_dlp/postprocessor/execafterdownload.py
+++ b/yt_dlp/postprocessor/execafterdownload.py
@@ -28,7 +28,8 @@ class ExecAfterDownloadPP(PostProcessor):
         # If no replacements are found, replace {} for backard compatibility
         if '{}' not in cmd:
             cmd += ' {}'
-        return cmd.replace('{}', compat_shlex_quote(info['filepath']))
+        return cmd.replace('{}', compat_shlex_quote(
+            info.get('filepath') or info['_filename']))
 
     def run(self, info):
         cmd = self.parse_cmd(self.exec_cmd, info)