Skip to content

Output & naming

Keys that control the output filename, the per-title subfolder, release-group tagging, and filename character handling. For template cookbook material and worked naming examples, see the Output & naming guide.

output_template

  • 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, 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.

unshackle.yaml
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, 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 values, filesystem-unsafe characters (< > : " / \ | ? *), empty templates, and unknown folder-kind keys.

All valid template variables

title, year, season, episode, season_episode, episode_name, part, absolute, date, quality, resolution, source, tag, track_number, artist, album_artist, album, disc, track_total, disc_total, release_type, genre, explicit, isrc, upc, label, audio, audio_channels, audio_full, atmos, dual, multi, dubbed, video, hdr, hfr, edition, repack, lang_tag, title_type.

{part?} is already inside {season_episode}

part holds the bare part index of a split episode (2) and is empty on every other title. unshackle folds it into {episode} and {season_episode}, so the shipped series template names split episodes correctly with no edit. Putting {part?} next to either of them renders the part twice (S01E01.Part.2.2). Use the standalone variable only in a template that names neither {episode} nor {season_episode}, and note that it is always empty in a folder template, since folders do not carry the part.

{absolute} counts episodes across seasons

absolute holds the absolute episode number, zero-padded to 3 digits (007), and is empty on titles that have none. You add it to the name yourself, and it never replaces {season} or {episode}. Any series with a TVDB absolute order can use it, anime most often. Services can supply it, and --enrich fills it in from TVDB. Use {absolute?} so the name stays clean when it is unknown. To keep the season and continue the episode number instead (S02E05), use --continuous-episodes.

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.

Tagging & naming keys

Key Type Default Description
tag str "" Release-group tag. Fills the {tag} template variable and is written into MKV/audio tags.
tag_group_name bool true Include the group name (tag) in the MKV Group tag.
tag_imdb_tmdb bool true Write IMDb/TMDB/TVDB external-ID tags into the MKV (needs metadata providers).
chapter_fallback_name str "" Fallback template for chapter names, e.g. "Chapter {i:02}".
unicode_filenames bool false Allow Unicode in filenames; when false, names are ASCII-sanitised.

codec_names

  • Type: dict  ·  Default: {}

Renames the codec and HDR names in the filename. Each map key is a name that unshackle writes by default, and its value is the name to write instead. The map applies to the video, audio, and hdr template variables, and so also to audio_full. A name that is not in the map stays as it is, and an empty value removes the name. You can also set codec_names for one service under services.

unshackle.yaml
codec_names:
  DDP: EAC3      # DDP5.1  -> EAC3.5.1
  DD: AC3        # DD5.1   -> AC3.5.1
  H.265: HEVC    # H.265   -> HEVC
  HDR10P: HDR10+ # DV.HDR10P -> DV.HDR10+

For hdr, unshackle renames each part of a Dolby Vision label separately, so HDR10P also changes DV.HDR10P to DV.HDR10+. When an audio name ends in a digit, audio_full puts a separator before the channels: EAC3.5.1, not EAC35.1.

The REST API fields codec_display and range_display use the same names and the same map. The dl --export file name does not use codec_names.

tag_rules see the new names

unshackle evaluates tag_rules after the rename. With the example above, a rule must match audio: EAC3, not audio: DDP.

tag_rules

  • Type: list  ·  Default: []

Conditionally replaces tag for a given download. Each rule pairs a when dict of conditions with the tag to use when they hold. unshackle evaluates the rules in order and the first match wins. If no rule matches, the global tag stays.

unshackle.yaml
tag_rules:
  - when: { title_type: movie, lang_tag: SUBBED }
    tag: SUBMOVIES
  - when: { quality: 2160p, hdr: [DV, DV.HDR, DV.HDR10P, HDR, HDR10P] }
    tag: UHDGROUP

Rule semantics:

  • Every condition in when must hold (they are AND-ed).
  • A value can be a scalar or a list. A list matches if any entry matches.
  • Comparison is case-insensitive string equality.
  • The keys of when are the filename template variables for the release itself: title_type, quality, resolution, source, video, hdr, hfr, audio, audio_channels, audio_full, atmos, dual, multi, dubbed, edition, repack, and lang_tag. Only these are available. unshackle adds the title's own fields (title, year, season, episode, and so on) after it evaluates the rules, so a condition cannot use them.
  • An unknown key in when is a mistake: unshackle logs a warning that names the key and skips that rule. unshackle also warns about a rule without conditions or without a tag, and skips it.

Put the more specific rules first, because unshackle stops at the first match.

Match hdr on the exact value

Matching is exact, and hdr is a composite label for Dolby Vision titles: a DV title with an HDR10 base layer gives DV.HDR, and with an HDR10+ base layer DV.HDR10P. Plain DV does not match those. Name every variant you want, as the example above does. Note also that HDR10 gives HDR, not HDR10, and so does a PQ video track with no HDR10 metadata. The full set of values is HDR, HDR10P, DV, DV.HDR, DV.HDR10P, and HLG, as listed in the variable table.

Operators

A condition value can start with a comparison operator, which unshackle applies to the rest of the value:

unshackle.yaml
tag_rules:
  - when: { resolution: "<1080" }
    tag: SDGROUP
  - when: { quality: ">=2160" }
    tag: UHDGROUP
  - when: { video: "!=H.265" }
    tag: AVCGROUP
  • >, <, >=, <= compare numbers. unshackle reads the first number out of the actual value, so ">=2160" matches a quality of 2160p. If the actual value has no number, the condition fails.
  • =, ==, and != compare text, case-insensitively, when the operand is not a number. With a numeric operand they compare numbers like the operators above. A value with no number in it is never equal to a number, so "!=2160" holds for it and "==2160" does not.
  • An ordering operator with a text operand (for example ">DV") is a mistake: unshackle logs a warning and the condition fails. So does an operator with nothing after it (">=").
  • A value with no operator keeps the plain equality behaviour described above.

Quote operator values in YAML

Two of these operators break an unquoted YAML value, and both stop the config from loading:

  • > opens a folded block scalar, so quality: >=2160 fails with a "while scanning a block scalar" error.
  • ! starts a tag, so hdr: !=DV fails with a "could not determine a constructor" error.

Quote every operator value: quality: ">=2160", resolution: "<1080", video: "!=H.265".

Keep a negation out of lists

A list matches if any entry matches, so two or more != entries in one list are always true. Give a negation as a single value, not as a list entry.

title_type is the media kind of the title: movie, series, or music. It is useful to give each kind its own group:

tag_rules:
  - when: { title_type: movie }
    tag: MOVIEGRP
  - when: { title_type: series }
    tag: TVGRP

The resolved tag applies to the {tag} filename variable only. The Group metadata tag written into MKV and music files always uses tag.

--tag wins

An explicit dl --tag on the command line disables the rules completely and uses the given tag.