Skip to content

feat(naming): {Narrator} placeholder and MyAnonamouse series fallback - #1407

Merged
calibrain merged 1 commit into
calibrain:mainfrom
adman234:feature/narrator-path-token
Oct 3, 2026
Merged

calibrain merged 1 commit into
calibrain:mainfrom
adman234:feature/narrator-path-token

Conversation

@adman234

@adman234 adman234 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Human-Written explanation:

Following up on previous PR to use MAM ID to get nararrator and series to show up in search, this PR will allow the series and nararrator fields to be added to the path when saving an audiobook.

I have tested my ghcr.io image on my instance and it seemed to work properly.

All the text below is written by Claude.

feat(naming): {Narrator} placeholder and MyAnonamouse series fallback

Follow-up to #1390 and #1399. Related to #605 and #934 (narrator support).

Problem

Several narrations of the same audiobook currently land in the same folder, because nothing in the path template tells them apart. Keeping more than one version means renaming folders by hand after every download.

Since #1390, MyAnonamouse results carry the release's narrator and series in extra, but the naming templates can't use them: there is no {Narrator} placeholder, and {Series} / {SeriesPosition} only come from the metadata provider.

Changes

  • {Narrator} placeholder (core/naming.py, download/postprocess/transfer.py, core/models.py): DownloadTask gains narrator, read from narrator or extra.narrator when a release is queued, and kept in the restart-safe retry payload. It's available in audiobook templates like any other placeholder, including prefix/suffix blocks such as { - Narrator}.
  • Audiobookshelf folder style: Audiobookshelf reads the narrator from folder names like Title {Narrator}. The template {Title} {{Narrator}} already matches as { + {Narrator}; the parser now also drops the closing brace when the narrator is empty, so the folder is Title rather than Title }.
  • No stray spaces around /: an empty placeholder at the start or end of a folder name no longer leaves a space there (e.g. Title /Title). This applies to all templates.
  • Series fallback (release_sources/prowlarr/mam.py, source.py, download/orchestrator.py): MAM enrichment also stores the first series' name and number as extra.series_name / extra.series_position, which queueing already falls back to when the metadata provider has no series. The provider's series still wins. A release-level series number is only used when it names the same series as the provider, so a provider series is never paired with the number of a different MAM series (an omnibus, for example).
  • Settings and preview (config/settings.py, namingTemplatePreview.ts): the audiobook template descriptions list {Narrator} and explain {{Narrator}}. The settings page preview mirrors the parser changes and offers {Narrator} under "Insert variable" for audiobook templates only.
  • Docs: regenerated environment-variables.md. This also picked up the Library Check settings, which weren't in the generated docs yet; happy to drop that part to keep the diff focused.

Example

Audiobook Path Template {Author}/{Title} {{Narrator}}/{Title}:

Narrator Result
Samuel Roukin Christopher Ruocchio/Empire of Silence {Samuel Roukin}/Empire of Silence.m4b
none Christopher Ruocchio/Empire of Silence/Empire of Silence.m4b

Testing

  • tests/core/test_narrator_template_variable.py (new, 16 tests): {{Narrator}} with and without a value, the { {Narrator}} prefix form, prefix/suffix blocks, sanitizing, build_library_path, task metadata, retry payload round trip, MAM series name/number parsing (including a 1-3 range having no number), and queueing (narrator from extra, series fallback, no cross-series number, blank narrator).
  • namingTemplatePreview.test.ts: the same {{Narrator}} cases for the preview.
  • Updated test_generate_env_docs.py for the new template description.
  • Full pytest -m "not integration and not e2e" compared with an upstream main worktree on the same machine: no new failures (the remaining ones are Windows-only on both).
  • ruff check, ruff format --check, basedpyright (0 errors) and vulture on touched files; frontend tsc --noEmit, oxlint, oxfmt --check, vitest (218 passed).
  • Checked the settings page locally: the audiobook preview renders ... {Simon Vance}.mp3 and {Narrator} is listed for audiobook templates only.

No behavior change for existing templates, apart from spaces next to / being trimmed.

🤖 Generated with Claude Code

Audiobook templates can use {Narrator}, filled from the release's narrator
(MyAnonamouse enrichment), so several narrations of one book land in
separate folders. "{Title} {{Narrator}}" renders Audiobookshelf's
"Title {Name}" folder style and, with no narrator, drops both braces and
the trailing space instead of leaving "Title }".

MAM enrichment now also stores the first series' name and number in
extra.series_name/series_position, which queueing already uses when the
metadata provider has no series. A release-level series number is only
borrowed when it names the same series the provider did.

Folder names no longer keep spaces left next to "/" by an empty token.
The narrator survives the restart-safe retry payload, and the settings
preview offers {Narrator} for audiobook templates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adman234
adman234 marked this pull request as ready for review September 30, 2026 14:46
@calibrain
calibrain merged commit 32abaff into calibrain:main Oct 3, 2026
17 checks passed
@calibrain

Copy link
Copy Markdown
Owner

Thank you ! Awesome work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants