Язык шаблонов calibre

Язык шаблонов calibre — это специфичный для calibre язык, используемый в calibre для таких задач, как указание путей к файлам, форматирование значений и вычисление значений для столбцов, указанных пользователем. Примеры:

  • Укажите структуру папок и имена файлов при сохранении файлов из библиотеки calibre на диск или в читалку электронных книг

  • Определите правила добавления значков и цветов в список книг calibre.

  • Определите виртуальные столбцы, содержащие данные из других столбцов.

  • Расширенный поиск в библиотеке.

  • Расширенный поиск и замена метаданных.

Язык построен на понятии «шаблон», который определяет, какие метаданные книги использовать, вычисления над этими метаданными и способ их форматирования.

Базовые шаблоны

Базовый шаблон состоит из одного или нескольких шаблонных выражений. Шаблонное выражение состоит из текста и имен в фигурных скобках ({}), которые заменяются соответствующими метаданными из обрабатываемой книги. Например, шаблон по умолчанию в calibre, используемый для сохранения книг на устройство, имеет 4 шаблонных выражения:

{author_sort}/{title}/{title} - {authors}

Для книги Айзека Азимова «Основание» «The Foundation» by «Isaac Asimov» им станет:

Asimov, Isaac/The Foundation/The Foundation - Isaac Asimov

Косые черты не являются шаблонными выражениями, потому что они находятся между ними в {}. Такой текст остается там, где он появляется. Например, если шаблон:

{author_sort} Some Important Text {title}/{title} - {authors}

затем для книги «Основание» шаблон создает:

Asimov, Isaac Some Important Text The Foundation/The Foundation - Isaac Asimov

Шаблонное выражение может получить доступ ко всем метаданным, доступным в calibre, включая настраиваемые столбцы (столбцы, которые вы создаете самостоятельно), используя имя поиска столбца. Чтобы найти поисковое имя для столбца (иногда называемых полями), наведите указатель мыши на заголовок столбца в списке книг calibre. Имена подстановки для настраиваемых столбцов всегда начинаются с символа #. Для столбцов типа серии есть дополнительное поле с именем #lookup name_index, которое является индексом серии для этой книги в серии. Например, если у вас есть столбец настраиваемой серии с именем #myseries, также будет столбец с именем #myseries_index. Индекс столбца стандартной серии называется series_index.

В дополнение к стандартным полям на основе столбцов вы также можете использовать:

  • {formats}- Список форматов, доступных в библиотеке calibre для книги

  • {identifiers:select(isbn)} - ISBN книги

Если метаданные для поля для данной книги не определены, тогда поле в шаблоне заменяется пустой строкой (''). Например, рассмотрим следующий шаблон:

{author_sort}/{series}/{title} {series_index}

Если книга Азимова «Второе основание» входит в серию «Основание», то шаблон дает:

Asimov, Isaac/Foundation/Second Foundation 3

Если для книги не введена серия, то шаблон выдает:

Asimov, Isaac/Second Foundation

Обработчик шаблонов автоматически удаляет несколько косых черт и начальные или конечные пробелы.

Расширенное форматирование

Помимо подстановки метаданных, шаблоны могут условно включать дополнительный текст и управлять форматированием заменяемых данных.

Условно включая текст

Иногда вы хотите, чтобы текст отображался в выводе, только если поле не пустое. Обычный случай - это series и series_index, когда вы не хотите ничего или два значения, разделенные дефисом. calibre обрабатывает этот случай, используя специальный синтаксис шаблонного выражения.

Например, используя приведенный выше пример Foundation, предположим, что вы хотите, чтобы шаблон создавал Foundation - 3 - Second Foundation. Этот шаблон производит такой вывод:

{series} - {series_index} - {title}

Однако, если в книге нет серии, шаблон создаст - - title, что, вероятно, не то, что вам нужно. Обычно люди хотят, чтобы в результате получился заголовок без лишних дефисов. Вы можете сделать это, используя следующий синтаксис шаблона:

{field:|prefix_text|suffix_text}

Это шаблонное выражение говорит, что если field имеет значение XXXX, то результатом будет prefix_textXXXXXsuffix_text. Если поле пусто (не имеет значения), результатом будет пустая строка (ничего), потому что префикс и суффикс игнорируются. Префикс и суффикс могут содержать пробелы.

Не используйте подшаблоны (`{ … }`) или функции (см. Ниже) в префиксе или суффиксе.

Используя этот синтаксис, мы можем решить указанную выше проблему без серии с шаблоном:

{series}{series_index:| - | - }{title}

Дефисы будут добавлены только в том случае, если у книги есть индекс серии, который есть только в том случае, если в ней есть серия. Продолжая пример с Foundation снова, шаблон создаст Foundation - 1 - Second Foundation.

Примечания:

  • Вы должны включить двоеточие после имени поиска, если используете префикс или суффикс.

  • Вы должны использовать либо никакой, либо оба символа |. Использовать один, как в {field:| -}, не допускается.

  • Допускается отсутствие текста для префикса или суффикса, например, в {series:|| -}. Шаблон {title:||} такой же, как {title}.

Форматирование

Предположим, вы хотите, чтобы series_index был отформатирован как три цифры с ведущими нулями. Это помогает:

{series_index: 0>3s} - три цифры с ведущими нулями

Для завершающих нулей используйте:

{series_index: 0<3s}- три цифры с завершающими нулями

Если вы используете индексы серий с дробными значениями, например 1.1, и нужно чтобы десятичные точки совпадали. Например, чтобы индексы 1 и 2.5 отображались как 01.00 и 02.50 и правильно сортировались на устройстве, которое выполняет лексическую сортировку. Для этого используйте:

{series_index: 05.2f} - пять символов, состоящих из двух цифр с ведущими нулями, десятичной точкой и двумя цифрами после десятичной точки.

Если вам нужны только первые две буквы данных, используйте:

{author_sort:.2} - Только первые две буквы сортировочного имени автора

Большая часть форматирования языка шаблонов calibre из Python. Дополнительные сведения о синтаксисе расширенных операций форматирования см. в Python documentation.

Использование шаблонов для определения пользовательских столбцов

Шаблоны могут использоваться для отображения информации, которая не входит в метаданные calibre, или для отображения метаданных, отличных от обычного формата calibre. Например, чтобы отобразить ISBN, поле, которое штатно не отображается в calibre. Создайте настраиваемый столбец с типом Столбец, построенный из других столбцов (в дальнейшем называемый составные столбцы) и предоставьте шаблон для генерации отображаемого текста. В столбце отобразится результат оценки шаблона. Чтобы отобразить ISBN, создайте составной столбец и введите {identifiers:select (isbn)} в поле шаблона. Чтобы отобразить столбец, содержащий значения двух пользовательских столбцов серий, разделённых запятой, используйте {#series1:||,}{#series2}.

В составных столбцах можно использовать любой параметр шаблона, включая форматирование.

Примечание. Вы не можете редактировать данные, отображаемые в составном столбце. Вместо этого вы редактируете исходные столбцы. Если вы редактируете составной столбец, например, дважды щелкнув по нему, calibre откроет для редактирования шаблон, а не базовые данные.

Шаблоны и коммутации

Коммутационные панели используются для изменения метаданных, записанных в книги, во время операций отправки на устройство и сохранения на диск. Коммутационная панель позволяет указать шаблон предоставления данных для записи в метаданные книги. Вы можете использовать коммутационные панели для изменения следующих полей: authors, author_sort, language, publisher, tags, title, title_sort. Эта функция помогает в использовании разных метаданных в книгах на устройствах, решении проблем сортировки или отображения.

При создании коммутационной панели вы указываете формат и устройство, для которых она будет использоваться. Предоставляется специальное устройство save_to_disk, которое используется при сохранении форматов (в отличие от их отправки на устройство). После того, как вы выбрали формат и устройство, вы выбираете поля метаданных, которые нужно изменить, предоставляя шаблоны для предоставления новых значений. Эти шаблоны присоединены к своим полям назначения, отсюда и название plugboards. Конечно, в этих шаблонах можно использовать составные столбцы.

Плагборды довольно гибкие и могут быть написаны в режиме Single Function Mode, Template Program Mode, General Program Mode, или Python Template mode.

Когда может применяться коммутационная панель (контент-сервер, сохранение на диск или отправка на устройство), calibre выполняет поиск определенных подключаемых модулей, чтобы выбрать правильный вариант для данного формата и устройства. Например, чтобы найти подходящую коммутационную панель для книги EPUB, отправляемой на устройство ANDROID, calibre выполняет поиск в коммутационных панелях, используя следующий порядок поиска:

  • коммутационная панель с точным соответствием по формату и устройству, например, EPUB и ANDROID

  • коммутационная панель с точным соответствием по формату и специальным выбором any device, например, EPUB и any device

  • коммутационная панель со специальным выбором any format и точным соответствием на устройстве, например, any format и ANDROID

  • коммутационная панель с any format и any device

Поля тегов и авторов обрабатываются по-особому, потому что оба эти поля могут содержать более одного элемента. У книги может быть много тегов и много авторов. Когда вы указываете, что одно из этих двух полей должно быть изменено, результат шаблона проверяется, чтобы увидеть, есть ли там более одного элемента. Для тегов результат будет разделен на части, если calibre найдет запятую. Например, если в шаблоне выдается значение Thriller, Horror, результатом будут два тега: Thriller и Horror. Невозможно поставить запятую в середине тега.

То же самое происходит с авторами, но с использованием другого символа для сокращения, & (амперсанд) вместо запятой. Например, если в шаблоне указано значение Blogs, Joe&Posts, Susan, тогда в книге будет два автора: Blogs, Joe и Posts, Susan. Если шаблон выдает значение Blogs, Joe;Posts, Susan, то у книги будет один автор с довольно странным именем.

Плагины влияют на метаданные, записанные в книгу, когда они сохраняются на диск или записываются на устройство. Плагины не влияют на метаданные, используемые командами «сохранить на диск» и «отправить на устройство» для создания имен файлов. Вместо этого имена файлов создаются с использованием шаблонов, введенных в соответствующем окне настроек.

Использование функций в шаблонах - режим одной функции

Предположим, вы хотите отобразить значение поля в верхнем регистре, когда это поле обычно находится в регистре заголовков. Вы можете сделать это с помощью шаблонных функций. Например, чтобы отобразить заголовок в верхнем регистре, используйте функцию uppercase, как в {title:uppercase()}. Чтобы отобразить его в регистре заголовка, используйте {title:titlecase()}.

Функции входят в форматную часть шаблона после : и перед первым | или закрывающим }, если не используется префикс/суффикс. Если у вас есть и формат, и ссылка на функцию, функция появляется после второго :. Функции возвращают соответствующее измененное значение столбца, указанного в шаблоне.

Синтаксис использования функций - один из:

{lookup_name:function(arguments)}
{lookup_name:format:function(arguments)}
{lookup_name:function(arguments)|prefix|suffix}
{lookup_name:format:function(arguments)|prefix|suffix}

За именами функций всегда должны стоять открывающие и закрывающие круглые скобки. Некоторым функциям требуются дополнительные значения (аргументы), и они заключаются в круглые скобки. Аргументы разделяются запятыми. Буквальным запятым (запятым как тексту, а не разделителям аргументов) должна предшествовать обратная косая черта (\\). Последний (или единственный) аргумент не может содержать закрывающую текстовую скобку.

Функции оцениваются до спецификации формата и префикса/суффикса. См. Ниже пример использования формата и функции.

Важно: если у вас есть опыт программирования, обратите внимание, что синтаксис в Single Function Mode не соответствует вашим ожиданиям. Строки не заключаются в кавычки, а пробелы имеют значение. Все аргументы считаются константами; нет выражений.

Не используйте подшаблоны (`{ … }`) в качестве аргументов функции. Вместо этого используйте Template Program Mode и General Program Mode.

Notes on calling functions in Single Function Mode:

  • When functions are used in Single Function Mode, the first parameter, value, is automatically replaced by the content of the field specified in the template. For example, when the template {title:capitalize()} is processed, the content of the title field is passed as the parameter value to the capitalize function.

  • In the function documentation, the notation [something]* means that something can be repeated zero or more times. The notation [something]+ means that the something is repeated one or more times (must exist at least one time).

  • Some functions use regular expressions. In the template language regular expression matching is case-insensitive.

Functions are documented in Template function reference. The documentation tells you what arguments the functions require and what the functions do. For example, here is the documentation of the ifempty function.

  • ifempty(value, text_if_empty) – if the value is not empty then return that value, otherwise return text_if_empty.

You see that the function requires two arguments, value and text_if_empty. However, because we are using Single Function Mode, we omit the value argument, passing only text_if_empty. For example, this template:

{tags:ifempty(No tags on this book)}

shows the tags for a book, if any. If it has no tags then it show No tags on this book.

The following functions are usable in Single Function Mode because their first parameter is value.

  • capitalize(value) – returns the value with the first letter in upper case and the rest lower case.

  • ceiling(value) – returns the smallest integer greater than or equal to value.

  • cmp(value, y, lt, eq, gt) – compares value and y after converting both to numbers.

  • contains(value, pattern, text_if_match, text_if_not_match) – checks if the value is matched by the regular expression pattern

  • date_arithmetic(value, calc_spec, fmt) – Calculate a new date from value using calc_spec.

  • floor(value) – returns the largest integer less than or equal to value.

  • format_date(value, format_string) – format the value, which must be a date string, using the format_string, returning a string.

  • format_number(value, template) – interprets the value as a number and formats that number using a Python formatting template such as {0:5.2f} or {0:,d} or ${0:5,.2f}.

  • fractional_part(value) – returns the part of the value after the decimal point.

  • human_readable(value) – expects the value to be a number and returns a string representing that number in KB, MB, GB, etc.

  • ifempty(value, text_if_empty) – if the value is not empty then return that value, otherwise return text_if_empty.

  • language_strings(value, localize) – return the language names for the language codes (see here for names and codes) passed in value.

  • list_contains(value, separator, [ pattern, found_val, ]* not_found_val) – interpret the value as a list of items separated by separator, checking the pattern against each item in the list.

  • list_count(value, separator) – interprets the value as a list of items separated by separator and returns the number of items in the list.

  • list_count_matching(value, pattern, separator) – interprets value as a list of items separated by separator, returning the number of items in the list that match the regular expression pattern.

  • list_item(value, index, separator) – interpret the value as a list of items separated by separator, returning the „index’th item.

  • list_sort(value, direction, separator) – return value sorted using a case-insensitive lexical sort.

  • lookup(value, [ pattern, key, ]* else_key) – The patterns will be checked against the value in order

  • lowercase(value) – returns the value in lower case.

  • mod(value, y) – returns the floor of the remainder of value / y.

  • rating_to_stars(value, use_half_stars) – Returns the value as string of star () characters.

  • re(value, pattern, replacement) – return the value after applying the regular expression.

  • re_group(value, pattern [, template_for_group]*) – return a string made by applying the regular expression pattern to value and replacing each matched instance

  • round(value) – returns the nearest integer to value.

  • select(value, key) – interpret the value as a comma-separated list of items with each item having the form id:id_value (the calibre identifier format).

  • shorten(value, left_chars, middle_text, right_chars) – Return a shortened version of the value

  • str_in_list(value, separator, [ string, found_val, ]+ not_found_val) – interpret the value as a list of items separated by separator then compare string against each value in the list.

  • subitems(value, start_index, end_index) – This function breaks apart lists of tag-like hierarchical items such as genres.

  • sublist(value, start_index, end_index, separator) – interpret the value as a list of items separated by separator, returning a new list made from the items from start_index to end_index.

  • substr(value, start, end) – returns the start’th through the end’th characters of value

  • swap_around_articles(value, separator) – returns the value with articles moved to the end.

  • swap_around_comma(value) – given a value of the form B, A, return A B.

  • switch(value, [patternN, valueN,]+ else_value) – for each patternN, valueN pair, checks if the value matches the regular expression patternN

  • test(value, text_if_not_empty, text_if_empty) – return text_if_not_empty if the value is not empty, otherwise return text_if_empty.

  • titlecase(value) – returns the value in title case.

  • transliterate(value) – Return a string in a latin alphabet formed by approximating the sound of the words in value.

  • uppercase(value) – returns the value in upper case.

Использование функций и форматирования в одном шаблоне

Предположим, у вас есть целочисленный настраиваемый столбец #myint, который вы хотите отображать с ведущими нулями, как в 003. Один из способов сделать это - использовать формат 03. Однако по умолчанию, если число (целое или с плавающей запятой) равно нулю, тогда значение отображается как пустая строка, поэтому нулевые значения будут давать пустую строку, а не 000. Если вы хотите увидеть значения 000, используйте как строку формата, так и функцию ifempty, чтобы изменить пустое значение обратно в ноль. Шаблон будет:

{#myint:0>3s:ifempty(0)}

Обратите внимание, что вы также можете использовать префикс и суффикс. Если вы хотите, чтобы номер отображался как [003] или [000], то используйте шаблон:

{#myint:0>3s:ifempty(0)|[|]}

Общий программный режим

Общий программный режим (GPM) заменяет шаблонные выражения программой, написанной на языке шаблонов. Синтаксис языка определяется следующей грамматикой:

program         ::= 'program:' expression_list
expression_list ::= top_expression [ ';' top_expression ]*
top_expression  ::= or_expression
or_expression   ::= and_expression [ '||' and_expression ]*
and_expression  ::= not_expression [ '&&' not_expression ]*
not_expression  ::= [ '!' not_expression ]* | concatenate_expr
concatenate_expr::= compare_expr [ '&' compare_expr ]*
compare_expr    ::= add_sub_expr [ compare_op add_sub_expr ]
compare_op      ::= '==' | '!=' | '>=' | '>' | '<=' | '<' |
                    'in' | 'inlist' | 'inlist_field' |
                    '==#' | '!=#' | '>=#' | '>#' | '<=#' | '<#'
add_sub_expr    ::= times_div_expr [ add_sub_op times_div_expr ]*
add_sub_op      ::= '+' | '-'
times_div_expr  ::= unary_op_expr [ times_div_op unary_op_expr ]*
times_div_op    ::= '*' | '/'
unary_op_expr   ::= [ add_sub_op unary_op_expr ]* | expression
expression      ::= identifier | constant | function | assignment | field_reference |
                    if_expr | for_expr | break_expr | continue_expr |
                    '(' expression_list ')' | function_def
field_reference ::= '$' [ '$' ] [ '#' ] identifier
identifier      ::= id_start [ id_rest ]*
id_start        ::= letter | underscore
id_rest         ::= id_start | digit
constant        ::= " string " | ' string ' | number
function        ::= identifier '(' expression_list [ ',' expression_list ]* ')'
function_def    ::= 'def' identifier '(' top_expression [ ',' top_expression ]* ')' ':'
                    expression_list 'fed'
assignment      ::= identifier '=' top_expression
if_expr         ::= 'if' condition 'then' expression_list
                    [ elif_expr ] [ 'else' expression_list ] 'fi'
condition       ::= top_expression
elif_expr       ::= 'elif' condition 'then' expression_list elif_expr | ''
for_expr        ::= for_list | for_range
for_list        ::= 'for' identifier 'in' list_expr
                    [ 'separator' separator_expr ] ':' expression_list 'rof'
for_range       ::= 'for' identifier 'in' range_expr ':' expression_list 'rof'
range_expr      ::= 'range' '(' [ start_expr ',' ] stop_expr
                    [ ',' step_expr [ ',' limit_expr ] ] ')'
list_expr       ::= top_expression
break_expr      ::= 'break'
continue_expr   ::= 'continue'
separator_expr  ::= top_expression
start_expr      ::= top_expression
stop_expr       ::= top_expression
step_expr       ::= top_expression
limit_expr      ::= top_expression

Примечания:

  • top_expression всегда имеет значение. Значение expression_list - это значение последнего top_expression в списке. Например, значение списка выражений 1;2;'foobar';3 равно 3.

  • В логическом контексте любое непустое значение - True

  • В логическом контексте пустым значением является False

  • Строки и числа могут использоваться как взаимозаменяемые. Например, 10 и '10' - это одно и то же.

  • Комментарии - это строки, начинающиеся с символа „#“. Комментарии, начинающиеся позже в строке, не поддерживаются.

Приоритет оператора

Приоритет оператора (порядок оценки) от наивысшего (оценивается первым) до самого низкого (оценивается последним):

  • Вызовы функций, константы, выражения в скобках, выражения операторов, выражения присваивания, ссылки на поля.

  • Унарный плюс (+) и минус (-). Эти операторы вычисляют справа налево.

    Эти и все другие арифметические операторы возвращают целые числа, если результат выражения дает дробную часть, равную нулю. Например, если выражение возвращает 3.0, оно изменяется на 3.

  • Умножение (*) и деление (/). Эти операторы ассоциативны и выполняются слева направо. Используйте круглые скобки, если хотите изменить порядок оценки.

  • Сложение (+) и вычитание (-). Эти операторы ассоциативны и выполняются слева направо.

  • Числовые и строковые сравнения. Эти операторы возвращают 1, если сравнение прошло успешно, в противном случае - пустую строку (''). Сравнения не ассоциативны: a < b < c - синтаксическая ошибка.

  • Конкатенация строк (&). Оператор & возвращает строку сформированную путем объединения левого и правого выражений. Пример: 'aaa' & 'bbb'` возвращает ``'aaabbb'. Оператор является ассоциативным и оценивает слева направо.

  • Унарное логическое НЕ (!). Этот оператор возвращает '1', если выражение ложно (возвращает пустую строку), в противном случае ''.

  • Логическое и (&&). Этот оператор возвращает „1“, если и левое, и правое выражения имеют значение True, или пустую строку '', если любое из них имеет значение False. Он ассоциативен, вычисляется слева направо и выполняет `short-circuiting `_.

  • Логическое ИЛИ (||). Этот оператор возвращает 1, если левое или правое выражение истинно, или '', если оба ложны. Он ассоциативен, вычисляется слева направо и выполняет short-circuiting `_. Это `включающее ИЛИ, возвращающее``“1“``, если и левое, и правое выражения истинны.

Ссылки на поля

A field_reference evaluates to the value of the metadata field named by lookup name that follows the $ or $$. Using $ is equivalent to using the field function. Using $$ is equivalent to using the raw_field function. Examples:

* $authors ==> field('authors')
* $#genre ==> field('#genre')
* $$pubdate ==> raw_field('pubdate')
* $$#my_int ==> raw_field('#my_int')

If выражения

Выражения if сначала оценивают условие. Если condition равно True (непустое значение), тогда expression_list в предложении then оценивается. Если оно равно False, то при его наличии вычисляется список выражений в предложении elif или else. Части elif и else не являются обязательными. Слова if, then, elif, else и fi зарезервированы; вы не можете использовать их в качестве имен идентификаторов. Вы можете помещать символы новой строки и пробелы везде, где они имеют смысл. condition - это top_expression, а не expression_list; точки с запятой не допускаются. expression_list - это разделенные точкой с запятой последовательности «top_expressions». Выражение if возвращает результат последнего выражения top_expression в вычисленном списке выражений или пустую строку, если список выражений не оценивался.

Примеры:

* program: if field('series') then 'yes' else 'no' fi
* program:
      if field('series') then
          a = 'yes';
          b = 'no'
      else
          a = 'no';
          b = 'yes'
      fi;
      strcat(a, '-', b)

Пример вложенного if:

program:
  if field('series') then
    if check_yes_no(field('#mybool'), '', '', '1') then
      'yes'
    else
      'no'
    fi
  else
    'no series'
  fi

Как сказано выше, if выдаёт значение. Это означает, что всё следующее эквивалентно:

* program: if field('series') then 'foo' else 'bar' fi
* program: if field('series') then a = 'foo' else a = 'bar' fi; a
* program: a = if field('series') then 'foo' else 'bar' fi; a

For example, this program returns the value of the series column if the book has a series, otherwise the value of the title column:

program: field(if field('series') then 'series' else 'title' fi)

For выражения

The for expression iterates over a list of values, processing them one at a time. The list_expression must evaluate either to a metadata field lookup name e.g., tags or #genre, or to a list of values. The range generates a list of numbers. If the result is a valid lookup name then the field’s value is fetched and the separator specified for that field type is used. If the result isn’t a valid lookup name then it is assumed to be a list of values. The list is assumed to be separated by commas unless the optional keyword separator is supplied, in which case the list values must be separated by the result of evaluating the separator_expr. A separator cannot be used if the list is generated by range(). Each value in the list is assigned to the specified variable then the expression_list is evaluated. You can use break to jump out of the loop, and continue to jump to the beginning of the loop for the next iteration.

Пример: этот шаблон удаляет первое иерархическое имя для каждого значения в жанре (#genre), создавая список с новыми именами:

program:
  new_tags = '';
  for i in '#genre':
    j = re(i, '^.*?\.(.*)$', '\1');
    new_tags = list_union(new_tags, j, ',')
  rof;
  new_tags

Если исходный жанр - History.Military, Science Fiction.Alternate History, ReadMe, то шаблон возвращает Military, Alternate History, ReadMe. Вы можете использовать этот шаблон в calibre Массовое редактирование метаданных - Поиск и замена с помощью: guilabel:` Search for`, установленного на template, чтобы удалить первый уровень иерархии и присвоить полученное значение Жанру.

Примечание: последняя строка в шаблоне, new_tags, в этом случае не является строго необходимой, потому что for возвращает значение последнего top_expression в списке выражений. Значение присваивания - это значение его выражения, поэтому значение оператора for - это то, что было присвоено new_tags.

Определение функции

If you have repeated code in a template then you can put that code into a local function. The def keyword starts the definition. It is followed by the function name, the argument list, then the code in the function. The function definition ends with the fed keyword.

Аргументы позиционные. При вызове функции предоставленные аргументы сопоставляются слева направо с определенными параметрами, при этом значение аргумента присваивается параметру. Будет ошибкой указывать больше аргументов, чем определено параметров. Параметры могут иметь значения по умолчанию, например a = 25. Если для этого параметра не указан аргумент, используется значение по умолчанию, в противном случае параметру присваивается пустая строка.

Оператор return можно использовать в локальной функции.

Функция должна быть определена до того, как её можно будет использовать.

Пример. Этот шаблон вычисляет приблизительную продолжительность в годах, месяцах и днях из числа дней. Функция to_plural() форматирует вычисляемые значения. Обратите внимание, что в примере также используется оператор &:

program:
      days = 2112;
      years = floor(days/360);
      months = floor(mod(days, 360)/30);
      days = days - ((years*360) + (months * 30));

      def to_plural(v, str):
              if v == 0 then return '' fi;
              return v & ' ' & (if v == 1 then str else str & 's' fi) & ' '
      fed;

      to_plural(years, 'year') & to_plural(months, 'month') & to_plural(days,'day')

Операторы отношения

Relational operators return '1' if the comparison is true, otherwise the empty string ('').

Есть две формы операторов отношения: сравнение строк и сравнение чисел.

String comparisons do case-insensitive string comparison using lexical order. The supported string comparison operators are ==, !=, <, <=, >, >=, in, inlist, and inlist_field. For the in operator, the result of the left hand expression is interpreted as a regular expression pattern. The in operator is True if the value of left-hand regular expression matches the value of the right hand expression.

The inlist operator is true if the left hand regular expression matches any one of the items in the right hand list where the items in the list are separated by commas. The inlist_field operator is true if the left hand regular expression matches any of the items in the field (column) named by the right hand expression, using the separator defined for the field. NB: the inlist_field operator requires the right hand expression to evaluate to a field name, while the inlist operator requires the right hand expression to evaluate to a string containing a comma-separated list. Because of this difference, inlist_field is substantially faster than inlist because no string conversions or list constructions are done. The regular expressions are case-insensitive.

Операторы сравнения чисел: ==#, !=#, <#, <=#, >#, >=#. Левое и правое выражения должны оцениваться как числовые значения с двумя исключениями: как строковое значение «None» (неопределенное поле), так и пустая строка оцениваются как нулевое значение.

Примеры:

  • program: field('series') == 'foo' returns '1' if the book’s series is foo, otherwise ''.

  • program: 'f.o' in field('series') вернёт '1' если серия книги соответствует регулярному выражению f.o (например, foo, Off Onyx и т. д.), иначе ''.

  • program: 'science' inlist $#genre returns '1' if any of the values retrieved from the book’s genres match the regular expression science, e.g., Science, History of Science, Science Fiction etc., otherwise ''.

  • program: '^science$' inlist $#genre returns '1' if any of the book’s genres exactly match the regular expression ^science$, e.g., Science, otherwise ''. The genres History of Science and Science Fiction don’t match.

  • program: 'asimov' inlist $authors returns '1' if any author matches the regular expression asimov, e.g., Asimov, Isaac or Isaac Asimov, otherwise ''.

  • program: 'asimov' inlist_field 'authors' returns '1' if any author matches the regular expression asimov, e.g., Asimov, Isaac or Isaac Asimov, otherwise ''.

  • program: 'asimov$' inlist_field 'authors' returns '1' if any author matches the regular expression asimov$, e.g., Isaac Asimov, otherwise ''. It doesn’t match Asimov, Isaac because of the $ anchor in the regular expression.

  • program: if field('series') != 'foo' then 'bar' else 'mumble' fi returns 'bar' if the book’s series is not foo. Otherwise it returns 'mumble'.

  • program: if field('series') == 'foo' || field('series') == '1632' then 'yes' else 'no' fi returns 'yes' if series is either foo or 1632, otherwise 'no'.

  • program: if '^(foo|1632)$' in field('series') then 'yes' else 'no' fi returns 'yes' if series is either foo or 1632, otherwise 'no'.

  • program: if 11 > 2 then 'yes' else 'no' fi returns 'no' because the > оператор выполняет лексическое сравнение.

  • program: if 11 ># 2 then 'yes' else 'no' fi вернёт 'yes' потому что оператор ># выполняет числовое сравнение.

Functions in General Program Mode

See Template function reference for the list of functions built into the template language.

Примечания:

  • As opposed to Single Function Mode, in General Program Mode you must specify the first parameter value.

  • All parameters are expression_lists (see the grammar above).

Более сложные программы в шаблонных выражениях - Template Program Mode

Template Program Mode (TPM) - смесь General Program Mode и :ref:` Single Function Mode`. TPM отличается от режима одиночной функции тем, что он позволяет писать шаблонные выражения, которые ссылаются на другие поля метаданных, используют вложенные функции, изменяют переменные и выполняют арифметические операции. Он отличается от General Program Mode тем, что шаблон заключен между символами``{`` и``}``и не начинается со слова program:. Программная часть шаблона - это список выражений General Program Mode.

Пример: предположим, что вы хотите, чтобы шаблон отображал серию книги, если она есть, в противном случае показывала бы значение настраиваемого поля #genre. Вы не можете сделать это в Single Function Mode, потому что вы не можете ссылаться на другое поле метаданных в выражении шаблона. В TPM это можно сделать, как демонстрирует следующее выражение:

{series_index:0>7.1f:'ifempty($, -5)'}

Пример показывает несколько вещей:

  • TPM используется, если выражение начинается с :' и заканчивается '}. Предполагается, что все остальное находится в Single Function Mode.

    If the template contains a prefix and suffix, the expression ends with '| where the | is the delimiter for the prefix. Example:

    {series_index:0>7.1f:'ifempty($, -5)'|prefix | suffix}
    
  • Functions must be given all their arguments. For example, the standard built-in functions must be given the initial parameter value.

  • The variable $ is usable as the value argument and stands for the value of the field named in the template, series_index in this case.

  • пробелы игнорируются и могут использоваться в любом месте выражения.

  • константные строки заключаются в соответствующие кавычки, либо ', либо ''.

В TPM использование символов { и } в строковых литералах может привести к ошибкам или неожиданным результатам, поскольку они сбивают с толку обработчик шаблонов. Он пытается рассматривать их как границы выражения шаблона, а не как символы. В некоторых, но не во всех случаях, вы можете заменить { на [[ и } на ]]. Как правило, если ваша программа содержит символы { и ​​``}``, вам следует использовать General Program Mode.

Режим шаблона Python

Python Template Mode (PTM) lets you write templates using native Python and the calibre API. The database API will be of most use; further discussion is beyond the scope of this manual. PTM templates are faster and can do more complicated operations but you must know how to write code in Python using the calibre API.

Шаблон PTM начинается с:

python:
def evaluate(book, context):
    # book is a calibre metadata object
    # context is an instance of calibre.utils.formatter.PythonTemplateContext,
    # which currently contains the following attributes:
    # db: a calibre legacy database object.
    # globals: the template global variable dictionary.
    # arguments: is a list of arguments if the template is called by a GPM template, otherwise None.
    # funcs: used to call Built-in/User functions and Stored GPM/Python templates.
    # Example: context.funcs.list_re_group()

    # your Python code goes here
    return 'a string'

Вы можете добавить приведенный выше текст в свой шаблон с помощью контекстного меню, доступ к которому обычно осуществляется с помощью щелчка правой кнопкой мыши. Комментарии несущественны и могут быть удалены. Вы должны использовать отступы Python.

Объект контекста поддерживает str(context), который возвращает строку содержимого контекста, и context.attributes, который возвращает список имён атрибутов в контексте.

Атрибут context.funcs позволяет вызывать встроенные и пользовательские функции шаблонов, а также Сохранённые шаблоны GPM/Python, чтобы вы могли выполнять их непосредственно в своем коде. Функции извлекаются по их именам. Если имя конфликтует с ключевым словом Python, добавьте в конце имени символ подчеркивания. Примеры:

context.funcs.list_re_group()
context.funcs.assert_()

Вот пример шаблона PTM, который создает список всех авторов серии. Список хранится как Столбец, состоящий из других столбцов, ведущих себя как теги. Он отображается в Описание книги и отмечен как Категории в отдельных строкахНастройки → Оформление → Описание книги). Этот параметр требует, чтобы список был разделён запятыми. Чтобы удовлетворить это требование, шаблон преобразует запятые в именах авторов в точки с запятой, а затем создаёт список авторов, разделённых запятыми. Затем авторы сортируются, поэтому в шаблоне используется author_sort.

python:
def evaluate(book, context):
    if book.series is None:
        return ''
    db = context.db.new_api
    ans = set()
    # Get the list of books in the series
    ids = db.search(f'series:"={book.series}"', '')
    if ids:
        # Get all the author_sort values for the books in the series
        author_sorts = (v for v in db.all_field_for('author_sort', ids).values())
        # Add the names to the result set, removing duplicates
        for aus in author_sorts:
            ans.update(v.strip() for v in aus.split('&'))
    # Make a sorted comma-separated string from the result set
    return ', '.join(v.replace(',', ';') for v in sorted(ans))

Вывод в Описание книги выглядит так:

Диалог конвертации электронной книги

Сохранённые шаблоны

И Общий программный режим, и Режим шаблона Python поддерживают сохранение шаблонов и вызов этих шаблонов из другого шаблона, во многом аналогично вызову хранимых функций. Вы сохраняете шаблоны, используя Настройки → Расширенные → Шаблонные функции. В этом диалоговом окне - ​​дополнительная информация. Вы вызываете шаблон так же, как вызываете функцию, передавая позиционные аргументы, если необходимо. Аргументом может быть любое выражение. Примеры вызова шаблона, предполагая, что сохраненный шаблон называется foo:

  • foo() – вызов шаблона без аргументов.

  • foo(a, b) вызывает шаблон, передавая значения переменных a и b.

  • foo(if field('series') then field('series_index') else 0 fi) – если в книге есть series, то передать series_index, в противном случае - значение 0.

В GPM вы извлекаете аргументы, переданные при вызове сохраненного шаблона, с помощью функции arguments. Она и объявляет, и инициализирует локальные переменные, фактически параметры. Переменные являются позиционными; они получают значение параметра, заданного при вызове, в той же позиции. Если соответствующий параметр не указан в вызове, тогда arguments присваивает этой переменной предоставленное значение по умолчанию. Если значение по умолчанию отсутствует, переменной присваивается пустая строка. Например, следующая функция arguments объявляет 2 переменные, key, alternate:

arguments(key, alternate='series')

Примеры, снова предполагаем, что сохраненный шаблон назван foo:

  • foo('#myseries') – аргументу key присваивается значение 'myseries', а аргументу alternate присваивается значение по умолчанию 'series'.

  • foo('series', '#genre') переменной ``key присваивается значение 'series', а переменной alternate присваивается значение '#genre'.

  • foo() - переменной key присваивается пустая строка, а переменной alternate присваивается значение 'series'.

В PTM аргументы передаются в параметре arguments, который представляет собой список строк. Невозможно указать значения по умолчанию. Вы должны проверить длину списка аргументов, чтобы убедиться, что количество аргументов соответствует ожидаемому.

Простой способ проверить сохраненные шаблоны - использовать диалоговое окно Тестер шаблонов. Для облегчения доступа используйте сочетание клавиш в Preferences-Advanced-Keyboard shortcuts-Template tester. Ярлык для диалогового окна Сохраненные шаблоны“ поможет быстрее переключаться между тестером и редактированием исходного кода сохраненного шаблона.

Передача шаблонам дополнительной информации

Разработчик может выбрать передачу дополнительной информации процессору шаблонов, например метаданные книги для конкретного приложения или информацию о том, что процессору предлагается сделать. Шаблон может получить доступ к этой информации и использовать ее во время оценки.

** Разработчик: как передать дополнительную информацию **

Дополнительная информация - это словарь dict Python, содержащий пары variable_name: variable_value, где значения должны быть строками. Шаблон может получить доступ к dict, создавая локальные переменные шаблона с именем variable_name, содержащие значение variable_value. Пользователь не может изменить имя, поэтому лучше использовать имена, которые не будут конфликтовать с другими локальными переменными шаблона, например, добавив к имени префикс подчеркивания _.

Этот dict передается процессору шаблонов (formatter) с использованием именованного параметра global_vars=your_dict. Полная сигнатура метода:

def safe_format(self, fmt, kwargs, error_value, book,
                column_name=None, template_cache=None,
                strip_results=True, template_functions=None,
                global_vars={})

** Автор шаблона: как получить доступ к дополнительной информации **

Вы получаете доступ к дополнительной информации (словарю globals) в шаблоне с помощью шаблонной функции:

globals(id[=expression] [, id[=expression]]*)

где id - любое допустимое имя переменной. Эта функция проверяет, содержит ли дополнительная информация, предоставленная разработчиком, имя. Если это так, функция присваивает предоставленное значение локальной переменной шаблона с этим именем. Если имя отсутствует в дополнительной информации и если предоставлено expression, то expression оценивается, и результат присваивается локальной переменной. Если ни значение, ни выражение не предоставлены, функция присваивает пустую строку ('') локальной переменной.

Шаблон может установить значение в словаре globals с помощью шаблонной функции:

set_globals(id[=expression] [, id[=expression]]*)

Эта функция устанавливает globals dict key:value пару id:value, где value - значение шаблонной локальной переменной id. Если эта локальная переменная не существует, тогда value устанавливается равным результату вычисления выражения expression.

Замечания о разнице между режимами

Три программных режима Single Function Mode (SFM), Template Program Mode (TPM) и General Program Mode (GPM) работают по-разному. SFM задуман как „простой“, поэтому он скрывает много тонкостей в языке программирования.

Различия:

  • В SFM значение столбца всегда передается как „invisible“ «невидимый» первый аргумент функции, включенной в шаблон.

  • SFM не поддерживает разницу между переменными и строками; все значения являются строками.

  • Следующий шаблон SFM возвращает либо название серии, либо строку «no series»:

    {series:ifempty(no series)}
    

    Эквивалентный шаблон в TPM

    {series:'ifempty($, 'no series')'}
    

    Эквивалентный шаблон в GPM

    program: ifempty(field('series'), 'no series')
    

    Первый аргумент ifempty - это значение поля series. Второй аргумент - это строка no series. В SFM автоматически передается первый аргумент, значение поля (невидимый аргумент).

  • Некоторые функции-шаблоны, например, booksize() и current_library_name(), не принимают аргументов. Из-за „невидимого аргумента“ вы не можете использовать эти функции в SFM.

  • Вложенные функции, когда функция вызывает другую функцию для вычисления аргумента, не могут использоваться в SFM. Например, этот шаблон, предназначенный для возврата первых 5 символов значения серии в верхнем регистре, не будет работать в SFM:

    {series:uppercase(substr(0,5))}
    
  • TPM и GPM поддерживают вложенные функции. Вышеупомянутый шаблон в TPM будет:

    {series:'uppercase(substr($, 0,5))'}
    

    В GPM это было бы:

    program: uppercase(substr(field('series'), 0,5))
    
  • Как отмечалось выше в разделе Template Program Mode, использование символов { и``}`` в строковых литералах TPM может привести к ошибкам или неожиданным результатам, поскольку они сбивают с толку обработчик шаблонов. Он пытается рассматривать их как границы шаблона, а не как символы. В некоторых, но не во всех случаях, вы можете заменить { на [[ и } на ]]. Как правило, если ваша программа содержит символы { и ​​``}``, вам следует использовать General Program Mode.

Пользовательские шаблонные функции Python

You can add your own Python functions to the template processor. Such functions can be used in any of the three template programming modes. The functions are added by going to Preferences  →  Advanced  →  Template functions. Instructions are shown in that dialog. Note that you can use Python Templates for a similar purpose. As calling user-defined functions is faster than calling a Python template, user-defined functions might be more efficient depending on the complexity of what the function or template does.

Особые примечания для шаблонов сохранения/отправки

Специальная обработка применяется, когда шаблон используется в шаблоне save to disk или send to device. Значения полей очищаются, заменяя символы, специальные для файловых систем, подчеркиванием, включая косую черту. Это означает, что текст поля нельзя использовать для создания папок. Однако косые черты не изменяются в строках префиксов или суффиксов, поэтому косые черты в этих строках вызовут создание папок. Благодаря этому вы можете создать структуру папок переменной глубины.

Например, предположим, что нам нужна структура папок series/series_index - title, с оговоркой, что если серия не существует, то заголовок должен находиться в верхней папке. Шаблон для этого:

{series:||/}{series_index:|| - }{title}

Косая черта и дефис появляются только в том случае, если серия не пуста.

Функция поиска позволяет нам выполнять еще более интересную обработку. Например, предположим, что если в книге есть серия, то нам нужна структура папок series/series index - title.fmt. Если в книге нет серии, нам нужна структура папок genre/author_sort/title.fmt. Если у книги нет жанра, мы хотим использовать „Unknown“. Нам нужны два совершенно разных пути, в зависимости от значения серии.

Чтобы этого добиться, мы:

  1. Создать составное поле (дать ему имя для поиска #aa), содержащее {series}/{series_index} - {title}. Если серия не пуста, тогда этот шаблон создаст series/series_index - title.

  2. Создать составное поле (дать ему имя для поиска #bb), содержащее {#genre: ifempty (Unknown)}/{author_sort}/{title}. Этот шаблон создаст genre /author_sort/title, где пустой жанр заменяется на Unknown.

  3. Установить для шаблона сохранения значение {series:lookup(.,#aa,#bb}. Этот шаблон выбирает составное поле #aa, если серия не пуста, и составное поле #bb, если серия пуста, поэтому у нас есть два совершенно разных пути сохранения, в зависимости от того, пуста ли series.

Советы

  • Используйте тестер шаблонов для тестирования шаблонов. Добавьте тестер в контекстное меню для книг в библиотеке и/или назначьте ему сочетание клавиш.

  • Шаблоны могут использовать другие шаблоны, ссылаясь на составные столбцы, построенные с помощью желаемого шаблона. В качестве альтернативы вы можете использовать сохраненные шаблоны.

  • В коммутации полю можно назначить соответствующее его типу пустое значение при помощи специального шаблона {}. Он всегда соответствует пустой строке.

  • Описанный выше метод отображения чисел, даже если они имеют нулевое значение, работает со стандартным полем series_index.

Template function reference