feat(titles): add a sports output and folder template kind

A sport episode uses output_template.sports with a {date} in the template's separator style; the flag survives --remote, the REST API and export.
This commit is contained in:
imSp4rky
2026-11-03 08:43:05 -07:00
parent 3027592e31
commit b710b5b0c9
9 changed files with 180 additions and 21 deletions
+1
View File
@@ -287,6 +287,7 @@ These keys are sent only when the title carries them, so a title without them se
| `air_date` | string | episode | ISO air date of [daily and date-based content](../../guide/downloading.md#daily-and-date-based-content). unshackle names the episode by date instead of `SxxExx`. |
| `absolute` | integer | episode | Absolute episode number across all seasons. |
| `daily` | boolean | episode | The episode is daily/date-based. Set from the title, or from the service's `DAILY` class attribute. |
| `sport` | boolean | episode | The episode is a sports event, so it uses the `sports` output template when one is set. Sent only when true. |
| `anime` | boolean | episode, movie | The title is anime, so metadata lookups prefer AniList. Set from the title, or from the service's `ANIME` class attribute. |
!!! info "`part` on a split episode"
+29 -2
View File
@@ -168,6 +168,33 @@ The same holds for a folder template of your own: `{season}` never picks up the
For custom templates there is also a standalone [`{part}`](../reference/configuration/output.md#output_template) variable. You rarely want it, see the caveat on that page.
### Sports events {#sports-events}
A service can mark an episode as a sports event. That episode then uses the `sports` output template and the `sports` folder template, if you set them. Without them it uses the `series` templates, as before.
```yaml title="unshackle.yaml"
output_template:
sports: "{title}.{year?}.{date?}.{episode_name}.{quality}.{source}.WEB-DL.{audio_full}.{video}-{tag}"
folder:
sports: "{title}.{year?}"
```
A `sports` template can use every series variable, with two differences:
- `{date}` holds the air date in the separator style of the template (`2026.11.01`), and is empty when the event has no air date.
- `{year}` is empty when the event has an air date, because the date holds the year.
An event with a year and no air date, and an event with an air date:
```text
League.2026/
└─ League.2026.City.Grand.Prix.Practice.One.1080p.EXAMPLE.WEB-DL.AAC2.0.H.264-TAG.mkv
Club.League.2026/
└─ Club.League.2026.11.01.Home.Club.vs.Away.Club.1080p.EXAMPLE.WEB-DL.AAC2.0.H.264-TAG.mkv
```
A `sports` folder template groups by `{year}`, or by the air year when the event has no year. `{season}`, `{episode}` and `{season_episode}` are not useful in a `sports` template. Use `-w S01E02` to select an event: the season and episode numbers stay on the title.
### Audio
| Variable | Meaning | Example |
@@ -222,12 +249,12 @@ Folder templates sit under a special `folder` config key inside `output_template
albums: "{artist} - {album} ({year})"
```
The per-kind folder config keys are `movies`, `series`, `songs`, and `albums`. Any other config key gives a startup warning. Folder templates permit path separators (`/` or `\`). unshackle formats each segment independently, so you can assemble nested directory structures like `Show/Season 01`. unshackle reads the separator style from the whole template, so it spaces every segment alike.
The per-kind folder config keys are `movies`, `series`, `sports`, `songs`, and `albums`. Any other config key gives a startup warning. Folder templates permit path separators (`/` or `\`). unshackle formats each segment independently, so you can assemble nested directory structures like `Show/Season 01`. unshackle reads the separator style from the whole template, so it spaces every segment alike.
**Fallback behaviour:**
- A per-kind folder template wins if present. If there is none, unshackle uses the single `folder` string. If there is no `folder` string either, unshackle falls back to a built-in default.
- Built-in defaults when no folder template is set. Movies get no folder at all unless a `movies` folder template (or a single-string `folder` template) exists. Series fall back to a folder *derived* from the `series` output template (stripping `{episode}`, `{episode_name}`, and collapsing `{season_episode}` down to `{season}`). Music albums fall back to `{artist} - {album} ({year})`. If the song has no year, the folder name is only `{artist} - {album}`.
- Built-in defaults when no folder template is set. Movies get no folder at all unless a `movies` folder template (or a single-string `folder` template) exists. Series fall back to a folder *derived* from the `series` output template (stripping `{episode}`, `{episode_name}`, and collapsing `{season_episode}` down to `{season}`). A sports event with no `sports` folder template uses the `series` folder template, or derives its folder from the `sports` output template when there is no folder template. Music albums fall back to `{artist} - {album} ({year})`. If the song has no year, the folder name is only `{artist} - {album}`.
!!! note "Movies are flat by default"
Episodes and songs are always foldered. unshackle writes movies directly into the output directory *unless* you define a `movies` folder template (or a single-string `folder` template, which folders every kind). Set one if you want each movie in its own directory.
+9 -2
View File
@@ -9,7 +9,7 @@ the [Output & naming guide](../../guide/output-and-naming.md).
- **Type:** `dict`  ·  **Required** (no usable default; `dl` exits with an error if this is missing)
Filename templates keyed by media kind, using `{variable}` placeholders. Recognised kinds are
`movies`, `series`, and `songs` (and `albums` for folder templates). A trailing `?` on a
`movies`, `series`, `sports`, and `songs` (and `albums` for folder templates). A trailing `?` on a
variable (e.g. `{quality?}`) marks it optional: if empty, it and one adjacent separator are
dropped.
@@ -17,16 +17,18 @@ dropped.
output_template:
movies: "{title}.{year}.{quality?}.{source}-{tag}"
series: "{title}.{season_episode}.{episode_name?}.{quality?}.{source}-{tag}"
sports: "{title}.{year?}.{date?}.{episode_name}.{quality?}.{source}-{tag}"
songs: "{track_number}. {title}"
folder: # special nested key, see below
movies: "{title} ({year})"
series: "{title} ({year})"
sports: "{title}.{year?}"
```
**The nested `folder` sub-key** controls output subfolders, and unshackle pops it out of
`output_template`:
- A **dict** sets per-kind folder templates (kinds: `movies`, `series`, `songs`, `albums`).
- A **dict** sets per-kind folder templates (kinds: `movies`, `series`, `sports`, `songs`, `albums`).
- A **str** sets a single folder template for everything.
unshackle validates templates on load and emits warnings for unknown variables, non-string
@@ -59,6 +61,11 @@ folder-kind keys.
[`--enrich`](../../guide/downloading.md#metadata-and-tagging) fills it in from TVDB.
Use `{absolute?}` so the name stays clean when it is unknown.
!!! tip "`sports` names an event by year or date"
A service marks an event episode as sport, and that episode then uses the `sports`
templates. Without them it uses the `series` templates. For the variables and
examples, see [Sports events](../../guide/output-and-naming.md#sports-events).
## Tagging & naming keys
| Key | Type | Default | Description |