Back to Libation

Naming Templates

docs/features/naming-templates.md

13.4.153.3 KB
Original Source

Naming Templates

File and Folder names can be customized using Libation's built-in tag template naming engine. To edit how folder and file names are created, go to Settings > Download/Decrypt and edit the naming templates. If you're splitting your audiobook into multiple files by chapter, you can also use a custom template to set each chapter's title metadata tag by editing the template in Settings > Audio File Options.

These templates apply to both GUI and CLI.

Template Tags

These are the naming template tags currently supported by Libation.

Property Tags

These tags will be replaced in the template with the audiobook's values.

TagDescriptionType
<id> Audible book ID (ASIN)Text
<title>Full title with subtitleText
<title short>Title. Stop at first colonText
<audible title>Audible's title (does not include subtitle)Text
<audible subtitle>Audible's subtitleText
<author>Author(s)Name List
<first author>First authorName
<narrator>Narrator(s)Name List
<first narrator>First narratorName
<series>All series to which the book belongs (if any)Series List
<first series>First seriesSeries
<series#>Number order in series (alias for <first series[{#}]>Number
<minutes>Duration of the audiobook in minutesTimeSpan
<bitrate>Bitrate (kbps) of the last downloaded audiobookNumber
<samplerate>Sample rate (Hz) of the last downloaded audiobookNumber
<channels>Number of audio channels in the last downloaded audiobookNumber
<codec>Audio codec of the last downloaded audiobookText
<file version>Audible's file version number of the last downloaded audiobookText
<libation version>Libation version used during last download of the audiobookText
<account>Audible account of this bookText
<account nickname>Audible account nickname of this bookText
<tag>Tag(s)Text List
<first tag>First tagText
<locale>Region/countryRegion
<year>Year publishedNumber
<language>Book's languageLanguage
<language short> Book's language abbreviated. Eg: ENGText
<os>Language currently set in the operating systemLanguage
<ui>User interface languageLanguage
<file date>File creation date/time.DateTime
<pub date>Audiobook publication dateDateTime
<date added>Date the book added to your Audible accountDateTime
<ch count> Number of chaptersNumber
<ch title> Chapter titleText
<ch#> Chapter numberNumber
<ch# 0> Chapter number with leading zerosNumber

Does not support custom formatting

Only valid for Chapter Filename and Chapter Tile Metadata

To change how these properties are displayed, read about custom formatters

Conditional Tags

Anything between the opening tag (<tagname->) and closing tag (<-tagname>) will only appear in the name if the condition evaluates to true.

TagDescriptionType
<if series->...<-if series>Only include if part of a book series or podcastConditional
<if podcast->...<-if podcast>Only include if part of a podcastConditional
<if bookseries->...<-if bookseries>Only include if part of a book seriesConditional
<if podcastparent->...<-if podcastparent> Only include if item is a podcast series parentConditional
<if abridged->...<-if abridged>Only include if item is abridgedConditional
<has PROPERTY->...<-has>Only include if the PROPERTY has a value (i.e. not null or empty)Conditional
<is PROPERTY[CHECK]->...<-is>Only include if the PROPERTY or a single value of a list PROPERTY satisfies the CHECKConditional
<is PROPERTY[FORMAT][CHECK]->...<-is>Only include if the formatted PROPERTY or a single value of a list PROPERTY satisfies the CHECKConditional
<is PROPERTY[...separator(...)...][CHECK]->...<-is>Only include if the joined form of all formatted values of a list PROPERTY satisfies the CHECKConditional
<cmp 1st-PROPERTY [CHECK] 2nd-PROPERTY->...<-cmp>Only include if two given PROPERTIES satisfy the CHECKConditional

Only affects the podcast series folder naming if "Save all podcast episodes to the series parent folder" option is checked.

For example, <if podcast-><series><-if podcast> will evaluate to the podcast's series name if the file is a podcast. For audiobooks that are not podcasts, that tag will be blank.

You can invert the condition (instead of displaying the text when the condition is true, display the text when it is false) by playing a ! symbol before the opening tag name.

Inverted TagDescriptionType
<!if series->...<-if series>Only include if not part of a book series or podcastConditional
<!if podcast->...<-if podcast>Only include if not part of a podcastConditional
<!if bookseries->...<-if bookseries>Only include if not part of a book seriesConditional
<!if podcastparent->...<-if podcastparent> Only include if item is not a podcast series parentConditional
<!has PROPERTY->...<-has>Only include if the PROPERTY does not have a value (i.e. is null or empty)Conditional
<!is PROPERTY[CHECK]->...<-is>Only include if neither the whole PROPERTY nor the values of a list PROPERTY satisfies the CHECKConditional
<!cmp 1st-PROPERTY [CHECK] 2nd-PROPERTY->...<-cmp>Only include if two given PROPERTIES do not satisfy the CHECKConditional

Only affects the podcast series folder naming if "Save all podcast episodes to the series parent folder" option is checked.

As an example, this folder template will place all Liberated podcasts into a "Podcasts" folder and all liberated books (not podcasts) into a "Books" folder.

<if podcast->Podcasts<-if podcast><!if podcast->Books<-if podcast><title>

This example will add a number if the <series#> tag has a value:

<has series#><series#><-has>

This example will put non-series books in a "Standalones" folder:

<!if series->Standalones/<-if series>

And this example will customize the title based on whether the book has a subtitle:

<audible title><has audible subtitle->-<audible subtitle><-has>

Tag Formatters

Text, Name, Series, Number, TimeSpan, DateTime, Region, Language and their List tags can be optionally formatted using format text in square brackets after the tag name. Below is a list of supported formatters for each tag type.

Text Formatters

Text formatting can change length and case of the text. Use <#>, <#><case> or <case> to specify one or both of these.

FormatterDescriptionExample UsageExample Result
#Cuts down the text to the specified number of characters<title[14]>A Study in Scar
LConverts text to lowercase<title[L]>a study in scarlet꞉ a sherlock holmes novel
UConverts text to uppercase<title short[U]>A STUDY IN SCARLET
tConverts text to title case<title[t]>The Abc Murders
TConverts text to title case where uppercase words are preserved<title[T]>The ABC Murders
<title[6T]>The AB

Text List Formatters

FormatterDescriptionExample UsageExample Result
separator()Specify the text used to join
multiple entries.

Default is ", " | <tag[separator(_)]> | Tag1_Tag2_Tag3_Tag4_Tag5 | | format({S}) | Formats the entries by placing their values into the specified template. Use {S:Text formatters} to place the entry and optionally apply a format. | <tag[format(Tag={S:l}) separator(;)]> | Tag=tag1;Tag=tag2;Tag=tag3;Tag=tag4;Tag=tag5 | | sort(S) | Sorts the elements by their value.

Sorting direction: uppercase = ascending lowercase = descending

Default is unsorted | <tag[sort(s) separator(;)]> | Tag5;Tag4;Tag3;Tag2;Tag1 | | max(#) | Only use the first # of entries | <tag[max(1)]> | Tag1 | | slice(#) | Only use the nth entry of the list | <tag[slice(2)]> | Tag2 | | slice(#..) | Only use entries of the list starting from # | <tag[slice(2..)]> | Tag2, Tag3, Tag4, Tag5 | | slice(..#) | Like max(#). Only use the first # of entries | <tag[slice(..1)]> | Tag1 | | slice(#..#) | Only use entries of the list starting from # and ending at # (inclusive) | <tag[slice(2..4)]> | Tag2, Tag3, Tag4 | | slice(-#..-#) | Numbers may be specified negative. In that case positions ar counted from the end with -1 pointing at the last member | <tag[slice(-3..-2)]> | Tag3, Tag4 |

For further information on format templates, please refer to the Format templates section.

Series Formatters

FormatterDescriptionExample UsageExample Result
{N | # | ID} Formats the series using
the series part tags.
{N:Text_Formatter} = Series Name
{#:Number_Formatter} = Number order in series
{ID:Text_Formatter} = Audible Series ID

Formatter parts are optional and introduced by the colon. If specified the string will be used to format the part using the corresponding formatter.

Default is {N} | <first series><hr><first series[{N:l}]><hr><first series[{N}, {#}, {ID}]><hr><first series[{N:10U}, {ID}, {#:00.0}]> | Sherlock Holmes<hr>sherlock holmes<hr>Sherlock Holmes, 1-6, B08376S3R2<hr>SHERLOCK H, B08376S3R2, 01.0-06.0 |

For further information on format templates, please refer to the Format templates section.

Series List Formatters

FormatterDescriptionExample UsageExample Result
separator()Specify the text used to join
multiple series names.

Default is ", " | <series[separator(; )]> | Sherlock Holmes; Some Other Series | | format({N | # | ID}) | Formats the series properties using the name series tags. See Series Formatter Usage above. | <series[format({N}, {#}) separator(; )]><hr><series[format({ID}-{N}, {#:00.0})]> | Sherlock Holmes, 1-6; Book Collection, 1<hr>B08376S3R2-Sherlock Holmes, 01.0-06.0, B000000000-Book Collection, 01.0 | | sort(N | # | ID) | Sorts the series by name, number or ID.

These terms define the primary, secondary, tertiary, … sorting order. You may combine multiple terms in sequence to specify multi‑level sorting.

Sorting direction: uppercase = ascending lowercase = descending

Default is unsorted | <series[sort(N) separator(; )]> | Book Collection, 1; Sherlock Holmes, 1-6 | | max(#) | Only use the first # of series | <series[max(1)]> | Sherlock Holmes | | slice(#..#) | Only use entries of the series list starting from # and ending at # (inclusive)

See Text List Formatter Usage above for details on all the variants of slice() | <series[slice(..-2)]> | Sherlock Holmes |

For further information on format templates, please refer to the Format templates section.

Name Formatters

FormatterDescriptionExample UsageExample Result
{T | F | M | L | S | ID} Formats the human name using
the name part tags.
{T:Text_Formatter} = Title (e.g. "Dr.")
{F:Text_Formatter} = First name
{M:Text_Formatter} = Middle name
{L:Text_Formatter} = Last Name
{S:Text_Formatter} = Suffix (e.g. "PhD")
{ID:Text_Formatter} = Audible Contributor ID

Formatter parts are optional and introduced by the colon. If specified the string will be used to format the part using the correspoing formatter.

Default is {T} {F} {M} {L} {S} | <first narrator[{L}, {F:1}.]><hr><first author[{L:u}, {F} _{ID}_]> | Fry, S.<hr>DOYLE, Arthur _B000AQ43GQ_ |

For further information on format templates, please refer to the Format templates section.

Name List Formatters

FormatterDescriptionExample UsageExample Result
separator()Specify the text used to join
multiple people's names.

Default is ", " | <author[separator(; )]> | Arthur Conan Doyle; Stephen Fry | | format({T | F | M | L | S | ID}) | Formats the human name using the name part tags. See Name Formatter Usage above. | <author[format({L:u}, {F}) separator(; )]><hr><author[format({L}, {F:1}. _{ID}_) separator(; )]> | DOYLE, Arthur; FRY, Stephen<hr>Doyle, A. _B000AQ43GQ_; Fry, S. _B000APAGVS_ | | sort(T | F | M | L | S | ID) | Sorts the names by title, first, middle, or last name, suffix or Audible Contributor ID

These terms define the primary, secondary, tertiary, … sorting order. You may combine multiple terms in sequence to specify multi‑level sorting.

Sorting direction: uppercase = ascending lowercase = descending

Default is unsorted | <author[sort(M)]><hr><author[sort(Fl)]><hr><author[sort(L FM ID)]> | Stephen Fry, Arthur Conan Doyle<hr>Stephen King, Stephen Fry<hr>John P. Smith _B000TTTBBB_, John P. Smith _B000TTTCCC_, John S. Smith _B000HHHVVV_ | | max(#) | Only use the first # of names

Default is all names | <author[max(1)]> | Arthur Conan Doyle | | slice(#..#) | Only use entries of the names list starting from # and ending at # (inclusive)

See Text List Formatter Usage above for details on all the variants of slice() | <author[slice(..-2)]> | Arthur Conan Doyle |

For further information on format templates, please refer to the Format templates section.

TimeSpan Formatters

For more custom formatters and examples, see this guide from Microsoft.

FormatterDescriptionExample UsageExample Result
dThe "d" custom format specifier outputs the value of the TimeSpan.Days property, which represents the number of whole days in the time interval. It outputs the full number of days in a TimeSpan value, even if the value has more than one digit. If the value of the TimeSpan.Days property is zero, the specifier outputs "0".

Use "dd"-"dddddddd" for zero padding up to the specified size. | <minutes[dd]> | 02 | | h | The "h" custom format specifier outputs the value of the TimeSpan.Hours property, which represents the number of whole hours in the time interval that isn't counted as part of its day component. It returns a one-digit string value if the value of the TimeSpan.Hours property is 0 through 9, and it returns a two-digit string value if the value of the TimeSpan.Hours property ranges from 10 to 23.

Use "hh" for zero padding. | <minutes[hh]> | 14 | | m | The "m" custom format specifier outputs the value of the TimeSpan.Minutes property, which represents the number of whole minutes in the time interval that isn't counted as part of its day component. It returns a one-digit string value if the value of the TimeSpan.Minutes property is 0 through 9, and it returns a two-digit string value if the value of the TimeSpan.Minutes property ranges from 10 to 59.

Use "mm" for zero padding. | <minutes[m]> | 42 | | 'string' | Literal string delimiter. | <minutes[d'd 'h'h 'm'm']> | 2d 14h 42m | | \ | The escape character. | <minutes[d\d h\h m\m]> | 2d 14h 42m |

These formatters have been enhanced to allow the display of days, hours or months beyond their usual limits. For example, the total number of hours, even if it exceeds 23. Here, a number format is inserted for the desired part in accordance with Microsoft's instructions. Unlike standard number formats, however, the letters D, H or M (uppercase) are used instead of zeros.

FormatterDescriptionExample UsageExample Result
DA number format with "D" instead of "0". Using this will output the total number of days and reduce the amount of minutes avalable for "H" and "M".<minutes[DD]>02
HA number format with "H" instead of "0". Using this will output the total number of hours and reduce the amount of minutes available for "M".<minutes[HH]>62
MA number format with "M" instead of "0". Using this will output the total number of minutes.<minutes[#,#MM]>3,762
D H MA combination of the above.<minutes[D'days 'MM'minutes']>02days 882minutes

Number Formatters

For more custom formatters and examples, see this guide from Microsoft.

FormatterDescriptionExample UsageExample Result
[integer]Zero-pads the number<bitrate[4]>
<series#[3]>
<samplerate[6]>0128
001
044100
0Replaces the zero with the corresponding digit if one
is present; otherwise, zero appears in the result string.<series#[000.0]>001.0
#Replaces the "#" symbol with the corresponding digit if one
is present; otherwise, no digit appears in the result string<series#[00.##]>01

Date Formatters

For more standard formatters, see this guide from Microsoft.

Standard DateTime Formatters

FormatterDescriptionExample UsageExample Result
sSortable date/time pattern.<file date[s]>2023-02-14T13:45:30
YYear month pattern.<file date[Y]>February 2023

Custom DateTime Formatters

You can use custom formatters to construct customized DateTime string. For more custom formatters and examples, see this guide from Microsoft.

FormatterDescriptionExample UsageExample Result
yyyy4-digit year<file date[yyyy]>2023
yy2-digit year<file date[yy]>23
MM2-digit month<file date[MM]>02
dd2-digit day of the month<file date[yyyy-MM-dd]>2023-02-14
HH
mmThe hour, using a 24-hour clock from 00 to 23
The minute, from 00 through 59.<file date[HH:mm]>14:45

Region Formatters

You can specify which part of a region you are interested in.

FormatterDescriptionExample UsageExample Result
{O | I | I2 | I3 | E | N | W | L | T | ID} Formats the region using
the region part tags.
{O:Text_Formatter} = Region as used in Libation
{I:Text_Formatter} = Two letter ISO code
{I2:Text_Formatter} = Two letter ISO code
{I3:Text_Formatter} = Three letter ISO code
{E:Text_Formatter} = English name
{N:Text_Formatter} = Native name - OS dependent
{W:Text_Formatter} = Unique Windows code
{L:Text_Formatter} = Lang code used for this region/store
{T:Text_Formatter} = TLD under which the audible store is hosted
{ID:Text_Formatter} = Region code

Formatter parts are optional and introduced by the colon. If specified the string will be used to format the part using the corresponding formatter.

Default is {O} | <locale[{I} ({E})]><hr>www.audible.<locale[{T}]> | US (United States)<hr>www.audible.com | | {D} , | Display name interpreted by the current language settings. To ensure output in a specific language the lang-code to use might be specified with a leading '@'. Formatter part is also optional and introduced by the colon. {D@LANG:Text_Formatter} | <locale[{D@es:u}]> | ESTADOS UNIDOS |

For further information on format templates, please refer to the Format templates section.

LANG may be any code from the ISO 639-1 standard like es for Spanish, en for English, de for German, etc. or even a IETF language tag like 'fr-CA'.

Language Formatters

You can specify which part of a language you are interested in.

FormatterDescriptionExample UsageExample Result
{O | I | I2 | I3 | E | N | W | ID} Formats the language using
the language part tags.
{O:Text_Formatter} = Language as provided by audible
{I:Text_Formatter} = Two letter ISO code
{I2:Text_Formatter} = Two letter ISO code
{I3:Text_Formatter} = Three letter ISO code
{E:Text_Formatter} = English name
{N:Text_Formatter} = Native name - OS dependent
{W:Text_Formatter} = Unique Windows code
{ID:Text_Formatter} = Lang code

Formatter parts are optional and introduced by the colon. If specified the string will be used to format the part using the corresponding formatter.

Default is {O} | <language[{I3:l} ({E})]> | fra (French) | | {D} , | Display name interpreted by the current language settings. To ensure output in a specific language the lang-code to use might be specified with a leading '@'. Formatter part is also optional and introduced by the colon. {D@LANG:Text_Formatter} | <language[{D@es}]> | francés |

For further information on format templates, please refer to the Format templates section.

LANG may be any code from the ISO 639-1 standard like es for Spanish, en for English, de for German, etc. or even a IETF language tag like 'fr-CA'.

Format Templates

Depending on which property is to be displayed, one or more placeholders can be used in a format template. The placeholders are defined in the form {A}:

<first author[{F} {U}]>

The format template must sometimes be enclosed in square brackets and sometimes in round brackets. In addition to placeholders, the format template may also contain arbitrary text. To prevent this text from being mistaken for a bracket at the end of the template or a placeholder, escapes can be used within the text:

  • \x - Escapes the next character.
  • \\ - Escapes a backslash.
  • "text" - encloses text that may contain special characters. To include a double quote in the text, escape it by doubling it: "She said ""Hello""" will output She said "Hello".
  • 'text'- encloses text that may contain special characters. To include a single quote in the text, escape it by doubling it: 'It''s a test' will output It's a test.

<series[separator(,) format('{Series:' {N}\})]>

Not all elements of a property are always present or have content. In this case, format templates would contain gaps after substitution. Groups of spaces are automatically merged. Other characters, however, remain unchanged. By doubling the curly brackets, you can specify text fragments before and after the placeholder, which are only used if the placeholder is replaced with content.

<!-- VitePress compiles each .md as a Vue SFC: a literal `{{` inside normal backtick `code` is treated as Vue interpolation and breaks the build. Elsewhere this doc uses backticks for inline examples; this line is HTML `code` with `v-pre` so `{{` can be written literally and still render like the other snippets, without additional hacks such as obscure invisible characters (like &#200B : 0-width space). -->

<code v-pre><narrator[format({{F} }{({M}') '}{L})]></code> -> <code>Neil Gaiman, Christopher (Evan) Welch</code>

Checks

There are two formats for checks, with slightly different syntax for specifying parameters:

<is PROPERTY[CHECK-with-value]->...<-is>

<cmp 1st-PROPERTY CHECK 2nd-PROPERTY->...<-cmp>

For CHECK-with-value, the value (2nd parameter) is specified directly after the check operator (e.g., =). This may be a number or a string with escaped characters like \]. Single backslashes must be doubled if they are part of the string.

1st-PROPERTY and 2nd-PROPERTY may be any of the properties listed in the Property tags section, or they may be string or number literals. Use digits only for numbers. To specify a string literal, enclose it in single or double quotes. If the string contains a single or double quote, escape it by doubling it. For example, to specify the string literal O'Reilly, you can use either 'O''Reilly' or "O'Reilly".

String ChecksUnicode OperatorDescriptionExamples
=Matches if values are equal (case-insensitive)<is tag[=Tag1]->
!=Matches if values are not equal (case-insensitive)<is first author[!=Arthur]->
<cmp "foo" != 'bar'->
~Matches if the first parameter matches the regular expression specified by the second parameter (case-insensitive)<is title[~([XYZ]).*\1]->
Number ChecksUnicode OperatorDescriptionExamples
#= Matches if the number value equals NUMBER<is channels[#=2]->
<cmp channels #= 1->
#!= Matches if the number value does not equal NUMBER<is author[#!=1]->
#>= Matches if the number value is greater than or equal to NUMBER<is bitrate[#>=128]->
<cmp 44100 #>= samplerate->
#> Matches if the number value is greater than NUMBER<is title[#>30]->
<cmp minutes #> 60->
#<= Matches if the number value is less than or equal to NUMBER<is first narrator[format({F})][#<=1]->
#< Matches if the number value is less than NUMBER<is author[#<3]->
List ChecksUnicode OperatorDescriptionExamples
== | :equals:Matches if both values contain the same elements<cmp author[slice(-2..-1)] == narrator[slice(..2)]->
>> | :contains:Matches if the first parameter contains the second parameter<is author[format({L})][∋King]->
!>> | :not_contains:Matches if the first parameter does not contain the second parameter<cmp series :not_contains: 'Harry Potter'->
<< | :in:Matches if the first parameter is contained in the second parameter<cmp first author << author[slice(2..)]->
!<< | :not_in:Matches if the first parameter is not contained in the second parameter<cmp author[slice(1)] ∉ narrator->
&& | :overlaps:Matches if both values share at least one element<cmp author && narrator->
&&! | :disjoint:⋂̸Matches if both values share no elements<cmp tag :disjoint: series->
<=< | :subset:Matches if all elements from the first parameter are found in the second parameter<cmp author[slice(-3..)] <=< author[slice(..-4)]->
>=> | :superset:Matches if the first parameter contains all elements from the second parameter<cmp author ⊇ narrator->
<-< | :proper_subset:Matches if all elements from the first parameter are found in the second parameter, and the second has additional elements<cmp author[slice(..2)] :proper_subset: author->
>-> | :proper_superset:Matches if the first parameter contains all elements from the second parameter plus at least one additional element<cmp author ⊃ narrator->

NUMBER checks on lists check the size of the list. For string values, the string length is used.

More Complex Examples

This example truncates the title to 4 characters and checks if its (trimmed) value equals "the" (case-insensitive):

<is title[4][=the]>

This example takes tags 2 through 4, joins them with a colon, and checks if the result equals "Tag2:Tag3:Tag4":

<is tag[separator(:)slice(2..4)][=Tag2:Tag3:Tag4]->