Reduce rendered folder names in title tags to the bare title - #857
Open
krejko wants to merge 2 commits into
Open
Reduce rendered folder names in title tags to the bare title#857krejko wants to merge 2 commits into
krejko wants to merge 2 commits into
Conversation
Folder rendering is configurable through FolderNamingPattern, but folder parsing
is hardcoded to a single convention:
BookFolderPattern = ^(\d{4})\s+-\s+(.+?)(?:\s+\[(.+?)\s+([\d.]+)\])?$
The two disagree out of the box. The default pattern is
"{Author}/{Series}/{Title}", which renders "Brandon Sanderson/Stormlight
Archive/The Way of Kings" - and none of those segments match the parser, which
requires a leading four-digit year. A library organised by Listenarr's own
default settings cannot be read back, and any user whose pattern is not
"{Year} - {Title} [{Series} {Part}]" gets no path-derived series, title or year
at all.
Derive the folder matcher from the configured pattern instead, so parsing is the
inverse of rendering. The derivation mirrors the renderer's elision rules: a
bracket group containing only tokens disappears when all of them are empty, and
renders partially when only some are, so each token inside such a group is
independently optional when reading.
Two safeguards:
- Every token being optional means a bare directory name satisfies the pattern
structurally, so an author folder would be claimed as a book. A match is only
accepted when it carries a non-title marker (series, year, narrator, ...).
- An unparseable pattern returns no matcher rather than throwing, and both that
case and a non-matching folder fall back to the built-in convention, so
existing layouts keep working.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Taggers commonly write the whole rendered folder name into the album/title tag, so a file organised as "[Revelation Space 10] Dilation Sleep (1990)" carries album="[Revelation Space 10] Dilation Sleep". ApplyEmbeddedTags copies that verbatim, and library import then sends it to search as the title. The metadata search is a text search against the Audible storefront, so a decorated query matches nothing: "[Revelation Space 10] Dilation Sleep" returns zero results where "Dilation Sleep" resolves. Users see matching fail on books that are present in the catalogue, and the failure is silent - the search simply returns nothing. When such a tag value parses as the configured folder naming pattern, reduce it to its title. Values that do not parse as the pattern, and values carrying no pattern markers, are returned untouched, so ordinary titles are unaffected. This deliberately does not change tag-versus-path precedence: tags still win for every field. It only un-renders a value that was rendered from the user's own pattern in the first place. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Taggers routinely write the whole rendered folder name into the album tag. A book organised as
[Revelation Space 10] Dilation Sleep (1990)carries:ApplyEmbeddedTagscopies that verbatim, and library import sends it to search as the title.The metadata lookup is a text search against the Audible storefront, so a decorated query matches nothing. Measured on a real instance:
[Revelation Space 10] Dilation SleepDilation SleepThe failure is silent — search returns nothing, and the user sees matching fail on books that are in the catalogue. This is the single most common reason "Start Matching" appears broken on an otherwise well-tagged library.
Why normalising is defensible
The narrow argument: this only un-renders a value that was rendered from the user's own pattern. It runs the tag through the same pattern-derived regex added in #856, and only rewrites when the value parses as that pattern and carries pattern markers. A tag that is already a plain title carries no markers and is returned untouched.
So the rule is not "clean up tags" — it's "if the tag is literally this library's folder name, treat it as one".
Crucially it does not change tag-versus-path precedence. Tags still win for every field, including title. Nothing is reordered.
The counter-argument
Tags are user data, and silently rewriting them is a real cost. If you'd rather the app never second-guess a tag, this should be closed — I'd rather that than argue it into the codebase. Two alternatives if you like the outcome but not the mechanism:
buildLibraryImportSearchParamsso only the query is cleaned and displayed metadata stays verbatim;I'd lean against the frontend option only because the pattern lives server-side and duplicating the derivation in TypeScript invites drift.
Changes
Added
NamingPatternFolderMatcher.ExtractTitle— returns the bare title when a value parses as the configured folder pattern, otherwise the input unchanged.Changed
ApplyEmbeddedTagsroutes the incoming title through it.Testing
30/30 pass.
Verified end-to-end. Titles reaching search, before → after:
[Revelation Space 10] Dilation SleepDilation Sleep[Known Space 00.0] Beclaimed in HellBeclaimed in Hell[Enderverse 07.5][Ender's Saga 1.1] A War Of Gifts {Scott Brick} (2007)A War Of Gifts[Radicalized] RadicalizedRadicalizedUndecorated titles (
Dilation Sleep,The Garden of Rama,Harry Potter and the Sorcerer's Stone) are asserted to pass through unchanged, and with no configured pattern the input is always returned as-is.Three books that previously failed to match resolved immediately afterwards, including one where the catalogue title corrected a typo in the folder name (
Beclaimed→Becalmed in Hell).Notes
No-ops entirely when
FolderNamingPatternis unset. Regex is cached and timeout-guarded;RegexMatchTimeoutExceptionreturns the input unchanged.🤖 Generated with Claude Code