docs(post-scripts): use post-script as the one term for hooks

Add the post-script row to the ste-writing terminology contract and
replace hook/postscript/post-download script across docs and docstrings.
This commit is contained in:
imSp4rky
2026-08-25 19:57:41 -06:00
parent a13081b14f
commit b94f338619
11 changed files with 57 additions and 57 deletions
+2 -2
View File
@@ -425,9 +425,9 @@ Make a download job. It requires `service` and `title_id`. Every other field is
!!! danger "Rejected parameters" !!! danger "Rejected parameters"
`postscript`, `post_script` and `post_scripts` are never accepted. A body containing any `postscript`, `post_script` and `post_scripts` are never accepted. A body containing any
of them gets `400 INVALID_PARAMETERS`, because a command string that arrives from of them gets `400 INVALID_PARAMETERS`, because a command string that arrives from
an HTTP caller would be remote code execution. You configure post-download hooks only in an HTTP caller would be remote code execution. You configure post-scripts only in
`unshackle.yaml`, where they still operate for API jobs. See `unshackle.yaml`, where they still operate for API jobs. See
[Post-download scripts](../../reference/configuration/post-scripts.md). [Post-scripts](../../reference/configuration/post-scripts.md).
!!! warning "Gated parameters (developer)" !!! warning "Gated parameters (developer)"
The server accepts a few keys, but permits them only when the server config opts in. Otherwise the server rejects the request with `403 FORBIDDEN`: The server accepts a few keys, but permits them only when the server config opts in. Otherwise the server rejects the request with `403 FORBIDDEN`:
+1 -1
View File
@@ -87,7 +87,7 @@ The top-level keys group loosely into these areas:
| Naming & tagging | `tag`, `output_template`, `chapter_fallback_name` | | Naming & tagging | `tag`, `output_template`, `chapter_fallback_name` |
| External API keys | `tmdb_api_key`, `tvdb_api_key`, `simkl_client_id`, `ipinfo_api_key`, `metadata_providers` | | External API keys | `tmdb_api_key`, `tvdb_api_key`, `simkl_client_id`, `ipinfo_api_key`, `metadata_providers` |
| Behaviour & logging | `update_checks`, `redact_paths`, `debug`, `unicode_filenames` | | Behaviour & logging | `update_checks`, `redact_paths`, `debug`, `unicode_filenames` |
| Post-download scripts | `post_scripts` | | Post-scripts | `post_scripts` |
| Paths | `directories`, `filenames` | | Paths | `directories`, `filenames` |
For the full list with types and defaults, see the [Configuration Reference](../reference/configuration/index.md). For the full list with types and defaults, see the [Configuration Reference](../reference/configuration/index.md).
+1 -1
View File
@@ -148,7 +148,7 @@ Keep only certain track types, or skip certain track types.
| `--no-mux` | Do not mux; keep individual track files. | | `--no-mux` | Do not mux; keep individual track files. |
| `--tag` | Group tag override. | | `--tag` | Group tag override. |
| `--repack` | Add a `REPACK` tag to the filename. | | `--repack` | Add a `REPACK` tag to the filename. |
| `--postscript` | Run a command after each output file, with `{variable}` placeholders substituted. Repeatable. Replaces the `post_scripts` config for this run. See [Post-download scripts](../reference/configuration/post-scripts.md). | | `--postscript` | Run a command after each output file, with `{variable}` placeholders substituted. Repeatable. Replaces the `post_scripts` config for this run. See [Post-scripts](../reference/configuration/post-scripts.md). |
### Metadata & tagging ### Metadata & tagging
+5 -5
View File
@@ -686,16 +686,16 @@ By default, `mkvmerge` muxes the tracks of a movie or an episode into a single M
`--postscript "<command>"` runs your own command once per output file, with unshackle's `--postscript "<command>"` runs your own command once per output file, with unshackle's
metadata substituted into `{variable}` placeholders. It is repeatable, and it replaces the metadata substituted into `{variable}` placeholders. It is repeatable, and it replaces the
`post_scripts` config for that run. No `success` hook operates under `--no-mux`, because `post_scripts` config for that run. No `success` post-script operates under `--no-mux`, because
that run writes no muxed output. A `failure` hook still operates if the download fails. that run writes no muxed output. A `failure` post-script still operates if the download fails.
```shell title="Hand each finished file to an uploader" ```shell title="Hand each finished file to an uploader"
unshackle dl --postscript "python /opt/upload.py {filepath} --service={service}" EXAMPLE 81234567 unshackle dl --postscript "python /opt/upload.py {filepath} --service={service}" EXAMPLE 81234567
``` ```
For hooks that continue across runs, for the `season` and `run` modes, for `failure` hooks For post-scripts that continue across runs, for the `season` and `run` modes, for `failure`
and for the full variable list, see post-scripts and for the full variable list, see
[Post-download scripts](../reference/configuration/post-scripts.md). [Post-scripts](../reference/configuration/post-scripts.md).
### Naming tags ### Naming tags
+1 -1
View File
@@ -14,6 +14,6 @@ This page has moved. The configuration reference is now split by area under
| DRM & CDM | [configuration/drm.md](configuration/drm.md) | | DRM & CDM | [configuration/drm.md](configuration/drm.md) |
| Network & proxy | [configuration/network.md](configuration/network.md) | | Network & proxy | [configuration/network.md](configuration/network.md) |
| Key vaults | [configuration/vaults.md](configuration/vaults.md) | | Key vaults | [configuration/vaults.md](configuration/vaults.md) |
| Post-download scripts | [configuration/post-scripts.md](configuration/post-scripts.md) | | Post-scripts | [configuration/post-scripts.md](configuration/post-scripts.md) |
| Other settings | [configuration/misc.md](configuration/misc.md) | | Other settings | [configuration/misc.md](configuration/misc.md) |
| Complete annotated example | [configuration/example.md](configuration/example.md) | | Complete annotated example | [configuration/example.md](configuration/example.md) |
+1 -1
View File
@@ -36,7 +36,7 @@ Where the file lives, how unshackle discovers it, and how to edit it:
| [DRM & CDM](drm.md) | `cdm`, `remote_cdm`, `decryption` | | [DRM & CDM](drm.md) | `cdm`, `remote_cdm`, `decryption` |
| [Network & proxy](network.md) | `network`, `headers`, `proxy_providers` | | [Network & proxy](network.md) | `network`, `headers`, `proxy_providers` |
| [Key vaults](vaults.md) | `key_vaults`, `vault_timeout` | | [Key vaults](vaults.md) | `key_vaults`, `vault_timeout` |
| [Post-download scripts](post-scripts.md) | `post_scripts` | | [Post-scripts](post-scripts.md) | `post_scripts` |
| [External API keys](misc.md#external-api-keys) | `omdb_api_key`, `tmdb_api_key`, `tvdb_api_key`, `tvdb_pin`, `tvdb_order`, `simkl_client_id`, `metadata_providers`, `anilist_title_language`, `disable_metadata`, `decrypt_labs_api_key`, `ipinfo_api_key` | | [External API keys](misc.md#external-api-keys) | `omdb_api_key`, `tmdb_api_key`, `tvdb_api_key`, `tvdb_pin`, `tvdb_order`, `simkl_client_id`, `metadata_providers`, `anilist_title_language`, `disable_metadata`, `decrypt_labs_api_key`, `ipinfo_api_key` |
| [Caching & updates](misc.md#caching-updates) | `title_cache_enabled`, `title_cache_time`, `title_cache_max_retention`, `update_checks`, `update_check_interval` | | [Caching & updates](misc.md#caching-updates) | `title_cache_enabled`, `title_cache_time`, `title_cache_max_retention`, `update_checks`, `update_check_interval` |
| [Appearance](misc.md#appearance) | `theme` | | [Appearance](misc.md#appearance) | `theme` |
+32 -32
View File
@@ -1,4 +1,4 @@
# Post-download scripts { #post-scripts } # Post-scripts { #post-scripts }
Operate your own script when a download finishes, with unshackle's metadata passed in as Operate your own script when a download finishes, with unshackle's metadata passed in as
`{variable}` placeholders. Use it to hand a finished file to an uploader, send a `{variable}` placeholders. Use it to hand a finished file to an uploader, send a
@@ -87,7 +87,7 @@ post_scripts:
``` ```
With `wait: true`, unshackle waits until the script exits, then writes the exit code to the With `wait: true`, unshackle waits until the script exits, then writes the exit code to the
debug log and carries on. Because the `file` hook runs between titles, unshackle runs one debug log and carries on. Because the `file` post-script runs between titles, unshackle runs one
script at a time over a season pack instead of starting them all at once. unshackle only script at a time over a season pack instead of starting them all at once. unshackle only
logs the exit code: a failing script does not fail the download or change unshackle's own logs the exit code: a failing script does not fail the download or change unshackle's own
exit code. `--postscript` entries never wait. exit code. `--postscript` entries never wait.
@@ -132,7 +132,7 @@ Every variable from your `output_template` is available here as well, including
file, because SDR is the absence of an HDR tag in a filename rather than a tag that file, because SDR is the absence of an HDR tag in a filename rather than a tag that
reads `SDR`. `{edition}`, `{atmos}`, `{multi}`, `{dual}` and `{hfr}` behave the same reads `SDR`. `{edition}`, `{atmos}`, `{multi}`, `{dual}` and `{hfr}` behave the same
way. If your script needs the word `SDR`, derive it from an empty `{hdr}` yourself. way. If your script needs the word `SDR`, derive it from an empty `{hdr}` yourself.
- The hook is a `failure` hook. A failed download has no output file to read metadata - The post-script is a `failure` one. A failed download has no output file to read metadata
from, so everything that comes from the naming context is empty. See from, so everything that comes from the naming context is empty. See
[Events](#events). [Events](#events).
@@ -146,7 +146,7 @@ Every variable from your `output_template` is available here as well, including
### Music variables ### Music variables
A music download builds its variables from the music naming context, so a hook gets the A music download builds its variables from the music naming context, so a post-script gets the
release fields instead of the season and episode ones. `{season}`, `{episode}` and release fields instead of the season and episode ones. `{season}`, `{episode}` and
`{episode_name}` are always empty for music. `{episode_name}` are always empty for music.
@@ -161,7 +161,7 @@ release fields instead of the season and episode ones. `{season}`, `{episode}` a
| `{release_type}` | `album`, `single`, `ep`, and so on. A service that reports nothing gives `album` | | `{release_type}` | `album`, `single`, `ep`, and so on. A service that reports nothing gives `album` |
| `{explicit}` | The word `Explicit` when the track is flagged, otherwise empty | | `{explicit}` | The word `Explicit` when the track is flagged, otherwise empty |
In a `file` hook `{title}` is the track name. See [Modes](#modes) for what an album hook In a `file` post-script `{title}` is the track name. See [Modes](#modes) for what an album post-script
puts in `{title}`. puts in `{title}`.
`{year}` is empty when the service gives the release no year. `{ext}` is the container the `{year}` is empty when the service gives the release no year. `{ext}` is the container the
@@ -170,11 +170,11 @@ track arrived in, such as `.flac`, because a music download is not muxed.
### Tagging IDs { #tagging-ids } ### Tagging IDs { #tagging-ids }
`{tmdb}`, `{imdb}` and `{tvdb}` carry the IDs unshackle tags the file with. unshackle reads `{tmdb}`, `{imdb}` and `{tvdb}` carry the IDs unshackle tags the file with. unshackle reads
them at the moment it sends the hook, and not at the start of the run. The title search inside them at the moment it dispatches the post-script, and not at the start of the run. The title search
the download loop finds an episode's TMDB ID, so a hook fires with it already filled in. inside the download loop finds an episode's TMDB ID, so a post-script fires with it already filled in.
They hold an ID you passed with `--tmdb`, `--imdb` or `--tvdb`, plus a TMDB ID the episode They hold an ID you passed with `--tmdb`, `--imdb` or `--tvdb`, plus a TMDB ID the episode
search resolved. No such search runs for a movie, so a movie hook gets them empty unless you search resolved. No such search runs for a movie, so a movie post-script gets them empty unless you
passed one. passed one.
### Sidecar files ### Sidecar files
@@ -206,19 +206,19 @@ subs = [p for p in sys.argv[i].removeprefix("--subs=").split("\n") if p]
| `run` | Once per folder written, at the end of the run | Empty | Empty | | `run` | Once per folder written, at the end of the run | Empty | Empty |
!!! warning "`season` means everything this run asked for" !!! warning "`season` means everything this run asked for"
A `season` hook fires when the last title **this run queued** for that season finishes. A `season` post-script fires when the last title **this run queued** for that season
With `-w S01-S02` the S01 hook runs while S02 is still downloading. It says nothing finishes. With `-w S01-S02` the S01 post-script runs while S02 is still downloading. It says
about whether the season is complete on disk. Downloading a single episode fires the nothing about whether the season is complete on disk. Downloading a single episode fires
hook for that season as soon as the episode lands. the post-script for that season as soon as the episode lands.
A title that fails stops the whole run. unshackle dispatches the `failure` hook for A title that fails stops the whole run. unshackle dispatches the `failure` post-script for
that title and then returns. It downloads no further title, and no `season` or `run` that title and then returns. It downloads no further title, and no `season` or `run`
hook fires after that point. This applies to every title type. If one episode of S01 post-script fires after that point. This applies to every title type. If one episode of S01
fails, the S01 hook does not fire at all. fails, the S01 post-script does not fire at all.
unshackle attaches the hook to the folder, not to the season, so one season landing in several unshackle attaches the post-script to the folder, not to the season, so one season landing in
folders (`-q 1080,720` with a quality-dependent folder template) fires it once per folder, several folders (`-q 1080,720` with a quality-dependent folder template) fires it once per
each with its own `{folder}`. A movie is a group of its own: a `season` hook fires for a folder, each with its own `{folder}`. A movie is a group of its own: a `season` post-script fires for a
movie's folder as soon as the movie finishes. movie's folder as soon as the movie finishes.
In `run` mode every variable except `{folder}` is empty, because one run can cover several In `run` mode every variable except `{folder}` is empty, because one run can cover several
@@ -235,27 +235,27 @@ Music uses the same three modes, with the album standing in for the season.
| `season` | Once per album folder, after every queued track of that album has landed | | `season` | Once per album folder, after every queued track of that album has landed |
| `run` | Once per folder written, at the end of the run | | `run` | Once per folder written, at the end of the run |
In a `file` hook `{title}` and `{title_raw}` are the track name. In an album hook they are In a `file` post-script `{title}` and `{title_raw}` are the track name. In an album post-script they
the album name, and the per-track variables `{track_number}`, `{disc}` and `{isrc}` are are the album name, and the per-track variables `{track_number}`, `{disc}` and `{isrc}` are
empty, in the same way that `{episode}` is empty in a season hook. empty, in the same way that `{episode}` is empty in a season post-script.
An album hook obeys the same rule as a season hook. It fires when the last track **this run An album post-script obeys the same rule as a season post-script. It fires when the last track
queued** for that album lands. This does not mean that the album is complete on disk. A **this run queued** for that album lands. This does not mean that the album is complete on disk.
one-track download fires the album hook as soon as that track lands. If a track fails, the A one-track download fires the album post-script as soon as that track lands. If a track fails,
run stops there, so the album hook never fires, in the same way as an episode and its the run stops there, so the album post-script never fires, in the same way as an episode and its
season. season.
## Events { #events } ## Events { #events }
`success` runs after the file has moved to its final path. `failure` runs when the download `success` runs after the file has moved to its final path. `failure` runs when the download
fails, with `{filepath}` empty and `{error}` set. Each track of an album is its own title. fails, with `{filepath}` empty and `{error}` set. Each track of an album is its own title.
A music `failure` hook therefore describes the track that failed, not the release. A music `failure` post-script therefore describes the track that failed, not the release.
!!! warning "`failure` only fires in `file` mode" !!! warning "`failure` only fires in `file` mode"
A `failure` entry with `mode: season` or `mode: run` never runs. Leave `mode` at its A `failure` entry with `mode: season` or `mode: run` never runs. Leave `mode` at its
default on a failure entry. default on a failure entry.
A `failure` hook has no output file to read metadata from, so it carries only what the A `failure` post-script has no output file to read metadata from, so it carries only what the
title object already knew: `{title}`, `{title_raw}`, `{title_id}`, `{year}`, `{season}`, title object already knew: `{title}`, `{title_raw}`, `{title_id}`, `{year}`, `{season}`,
`{episode}`, `{episode_name}`, `{service}`, the tagging IDs and `{error}`. Everything that `{episode}`, `{episode_name}`, `{service}`, the tagging IDs and `{error}`. Everything that
comes from the naming context, such as `{quality}`, `{hdr}`, `{artist}` and `{album}`, is comes from the naming context, such as `{quality}`, `{hdr}`, `{artist}` and `{album}`, is
@@ -266,7 +266,7 @@ sees your script's exit code only when that entry sets `wait: true`, and even th
writes the code to the debug log. Nothing else reports a failing script. Your script owns writes the code to the debug log. Nothing else reports a failing script. Your script owns
its own error handling and logging. its own error handling and logging.
A `success` hook always names a file this run wrote. There is no skip-if-exists path in A `success` post-script always names a file this run wrote. There is no skip-if-exists path in
`dl` today, so nothing fires for a title that was not downloaded. `dl` today, so nothing fires for a title that was not downloaded.
## `--postscript` ## `--postscript`
@@ -300,7 +300,7 @@ unshackle logs the command it operated twice: at `DEBUG` level on the console, a
when that log is on. when that log is on.
unshackle masks both the same way, and honours [`redact_paths`](misc.md), which is on by default. unshackle masks both the same way, and honours [`redact_paths`](misc.md), which is on by default.
Debug logs get shared in issue reports, and a hook command line is mostly paths. URL Debug logs get shared in issue reports, and a post-script command line is mostly paths. URL
credentials and `token=` / `api_key=` query parameters are also masked. credentials and `token=` / `api_key=` query parameters are also masked.
!!! warning "Do not hardcode secrets in the command" !!! warning "Do not hardcode secrets in the command"
@@ -310,8 +310,8 @@ credentials and `token=` / `api_key=` query parameters are also masked.
## Limitations ## Limitations
- No `success` hook operates under `--no-mux` or `--skip-dl`, because neither writes a muxed - No `success` post-script operates under `--no-mux` or `--skip-dl`, because neither writes a
output. A `failure` hook still runs under `--no-mux` if the download itself fails. muxed output. A `failure` post-script still runs under `--no-mux` if the download itself fails.
- `failure` hooks only operate in `file` mode. - `failure` post-scripts only operate in `file` mode.
- There is no webhook sender. Call `curl` from a script instead. - There is no webhook sender. Call `curl` from a script instead.
- Script output is not captured. Redirect it inside your own script if you want a log. - Script output is not captured. Redirect it inside your own script if you want a log.
+1 -1
View File
@@ -128,7 +128,7 @@ nav:
- DRM & CDM: reference/configuration/drm.md - DRM & CDM: reference/configuration/drm.md
- Network & Proxy: reference/configuration/network.md - Network & Proxy: reference/configuration/network.md
- Key Vaults: reference/configuration/vaults.md - Key Vaults: reference/configuration/vaults.md
- Post-Download Scripts: reference/configuration/post-scripts.md - Post-Scripts: reference/configuration/post-scripts.md
- Other Settings: reference/configuration/misc.md - Other Settings: reference/configuration/misc.md
- Annotated Example: reference/configuration/example.md - Annotated Example: reference/configuration/example.md
- Developer: - Developer:
+11 -11
View File
@@ -1,9 +1,9 @@
"""Music post-script hooks, which no live service was available to test against. """Music post-scripts, which no live service was available to test against.
A Song runs through the same title loop as an Episode, so its hooks come from the same A Song runs through the same title loop as an Episode, so its post-scripts come from the same
two functions: ``build_context`` for a file and ``season_context`` for the release folder. two functions: ``build_context`` for a file and ``season_context`` for the release folder.
These check what those two feed a script: that a Song builds a usable context, that an These check what those two feed a script: that a Song builds a usable context, that an
album groups the way a season does, and that the album hook describes the album rather album groups the way a season does, and that the album post-script describes the album rather
than whichever track landed last. than whichever track landed last.
""" """
@@ -18,7 +18,7 @@ from unshackle.core.utils.post_scripts import build_context, dispatch, season_co
class FakeSong(SimpleNamespace): class FakeSong(SimpleNamespace):
"""A Song as the hook sees it: name/artist/album, no season or episode.""" """A Song as the post-script sees it: name/artist/album, no season or episode."""
def build_template_context(self, media_info, show_service=True): def build_template_context(self, media_info, show_service=True):
return { return {
@@ -45,7 +45,7 @@ def song(**kwargs):
class FakeEpisode(SimpleNamespace): class FakeEpisode(SimpleNamespace):
"""An Episode as the hook sees it: a show title, a season, and a number.""" """An Episode as the post-script sees it: a show title, a season, and a number."""
def build_template_context(self, media_info, show_service=True): def build_template_context(self, media_info, show_service=True):
return {"title": self.title, "season": f"{self.season:02}", "audio": "EAC3", "video": "H.265"} return {"title": self.title, "season": f"{self.season:02}", "audio": "EAC3", "video": "H.265"}
@@ -109,7 +109,7 @@ def test_album_grouping_matches_the_season_grouping_rule():
@pytest.mark.parametrize("mode", ["season", "run"]) @pytest.mark.parametrize("mode", ["season", "run"])
def test_album_and_run_contexts_blank_the_file_variables(mode): def test_album_and_run_contexts_blank_the_file_variables(mode):
"""Mirrors the blanking dl.py applies before dispatching an album or run hook.""" """Mirrors the blanking dl.py applies before dispatching an album or run post-script."""
base = build_context( base = build_context(
song(), song(),
media_info=object(), media_info=object(),
@@ -133,7 +133,7 @@ def test_album_and_run_contexts_blank_the_file_variables(mode):
assert context["album"] == "Example Album, Live & Remastered" assert context["album"] == "Example Album, Live & Remastered"
def test_a_music_hook_command_builds_the_argv_a_script_would_get(monkeypatch, tmp_path): def test_a_music_post_script_command_builds_the_argv_a_script_would_get(monkeypatch, tmp_path):
"""End to end through the real dispatcher: config entry in, argv out.""" """End to end through the real dispatcher: config entry in, argv out."""
from unshackle.core.config import config from unshackle.core.config import config
@@ -163,7 +163,7 @@ def test_a_music_hook_command_builds_the_argv_a_script_would_get(monkeypatch, tm
import time import time
time.sleep(0.05) time.sleep(0.05)
assert marker.exists(), "the hook process never ran" assert marker.exists(), "the post-script process never ran"
argv = marker.read_text().splitlines() argv = marker.read_text().splitlines()
assert "--album=Example Album, Live & Remastered" in argv assert "--album=Example Album, Live & Remastered" in argv
assert "--artist=Example Artist" in argv assert "--artist=Example Artist" in argv
@@ -172,7 +172,7 @@ def test_a_music_hook_command_builds_the_argv_a_script_would_get(monkeypatch, tm
def test_season_context_blanks_the_file_variables_and_sets_the_folder(): def test_season_context_blanks_the_file_variables_and_sets_the_folder():
"""An album hook describes the release folder, so no track's file may leak into it.""" """An album post-script describes the release folder, so no track's file may leak into it."""
folder = Path("/dl/Example Artist - Example Album, Live & Remastered (1983)") folder = Path("/dl/Example Artist - Example Album, Live & Remastered (1983)")
context = build_context( context = build_context(
song(), song(),
@@ -194,7 +194,7 @@ def test_season_context_blanks_the_file_variables_and_sets_the_folder():
def test_season_context_identifies_the_album_not_the_last_track(): def test_season_context_identifies_the_album_not_the_last_track():
"""A Song's ``{title}`` is the song, so blanking only the file fields is not enough. """A Song's ``{title}`` is the song, so blanking only the file fields is not enough.
Guards a regression where an album hook was handed whichever track landed last: Guards a regression where an album post-script was handed whichever track landed last:
``{title}`` was a song name and ``{track_number}``/``{isrc}`` were that track's. ``{title}`` was a song name and ``{track_number}``/``{isrc}`` were that track's.
""" """
folder = Path("/dl/Example Artist - Example Album (1983)") folder = Path("/dl/Example Artist - Example Album (1983)")
@@ -219,7 +219,7 @@ def test_season_context_identifies_the_album_not_the_last_track():
def test_season_context_leaves_a_non_music_context_untouched(): def test_season_context_leaves_a_non_music_context_untouched():
"""The music branch is gated on ``{album}``; a season hook must not lose its own keys.""" """The music branch is gated on ``{album}``; a season post-script must not lose its own keys."""
folder = Path("/dl/Some Show/Season 1") folder = Path("/dl/Some Show/Season 1")
context = build_context( context = build_context(
episode(), episode(),
+1 -1
View File
@@ -597,7 +597,7 @@ async def download(request: web.Request) -> web.Response:
description: >- description: >-
Download a video title based on the specified parameters. Download a video title based on the specified parameters.
'postscript', 'post_script' and 'post_scripts' are never accepted and return 400. 'postscript', 'post_script' and 'post_scripts' are never accepted and return 400.
You configure post-download hooks only in unshackle.yaml. You configure post-scripts only in unshackle.yaml.
requestBody: requestBody:
required: true required: true
content: content:
+1 -1
View File
@@ -142,7 +142,7 @@ def build_context(
def season_context(context: dict[str, str], folder: Path) -> dict[str, str]: def season_context(context: dict[str, str], folder: Path) -> dict[str, str]:
"""Blank the file-level variables so a season/album hook describes the folder.""" """Blank the file-level variables so a season/album post-script describes the folder."""
out = dict(context) out = dict(context)
for key in ("filepath", "filename", "ext", "sidecars", "episode", "episode_name"): for key in ("filepath", "filename", "ext", "sidecars", "episode", "episode_name"):
out[key] = "" out[key] = ""