From 7daa0d61a4a8bc13fc0aed8fe1fb20045862c98c Mon Sep 17 00:00:00 2001 From: Steppenstreuner Date: Sat, 29 Aug 2026 07:25:49 +0200 Subject: [PATCH] add(schema): {Narrators} placeholder, {Narrator} now names the first speaker --- README.md | 11 ++++++++++- static/index.html | 5 +++-- tests/test_naming.py | 23 +++++++++++++++++++++++ wordarr/naming.py | 7 ++++++- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ed807f3..9c4a022 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,16 @@ Jede Library kann eine **Sprache** tragen (`Deutsch`/`Englisch`, Default: egal). ## Namensschemata -Pro Library konfigurierbar (Tab *Libraries*), Platzhalter: `{Author}` `{Authors}` `{Title}` `{Year}` `{Series}` `{Volume}`. +Pro Library konfigurierbar (Tab *Libraries*), Platzhalter: `{Author}` `{Authors}` `{Narrator}` `{Narrators}` `{Title}` `{Year}` `{Series}` `{Volume}`. + +`{Author}` und `{Narrator}` nennen jeweils nur den **ersten** Namen, `{Authors}` und `{Narrators}` die vollständige Liste — bei einer Full-Cast-Produktion mit 20 Sprechern willst du Letzteres nicht im Ordnernamen. Fehlt ein Wert, verschwindet er samt Klammern und Trennzeichen: `{Series}/{Volume} - {Title} ({Narrator})` wird für einen Einzeltitel ohne Sprecherangabe schlicht zu `Titel`. + +Liegt dieselbe Ausgabe in mehreren Fassungen vor (Harry Potter mit Stephen Fry *und* als Full-Cast), gehört `{Narrator}` in den Ordnernamen — sonst kollidieren beide im selben Verzeichnis: + +``` +Harry Potter/01 - Philosopher's Stone (Stephen Fry)/ +Harry Potter/01 - Philosopher's Stone (Hugh Laurie)/ +``` Defaults: - Ebook: `{Author}/{Title} ({Year})` / `{Author} - {Title}` diff --git a/static/index.html b/static/index.html index 01d66d9..5efe13b 100644 --- a/static/index.html +++ b/static/index.html @@ -288,8 +288,9 @@

- Platzhalter: {Author} {Authors} {Narrator} {Title} {Year} {Series} - {Volume} + Platzhalter: {Author} {Authors} {Narrator} {Narrators} {Title} {Year} + {Series} {Volume} — {Author}/{Narrator} nennen den ersten Namen, + {Authors}/{Narrators} alle. Leere Werte fallen samt Trenner weg.

diff --git a/tests/test_naming.py b/tests/test_naming.py index 1ede37a..2ad696e 100644 --- a/tests/test_naming.py +++ b/tests/test_naming.py @@ -59,3 +59,26 @@ def test_missing_values_do_not_leave_dangling_separators(): series="Tony Ballard", volume=1, year=2020, narrator="") assert render_template("{Series}/{Volume} - {Title}", numbered) == \ "Tony Ballard/01 - Die Höllenbrut" + + +def test_narrator_uses_the_first_name_only(): + """Two editions of one book differ by narrator; a full cast must not blow up + the folder name.""" + fry = SimpleNamespace(title="Philosopher's Stone", authors="J.K. Rowling", + series="Harry Potter", volume=1, year=None, + narrator="Stephen Fry") + cast = SimpleNamespace(title="Philosopher's Stone", authors="J.K. Rowling", + series="Harry Potter", volume=1, year=None, + narrator="Hugh Laurie, Matthew Macfadyen, Riz Ahmed, Michelle Gomez") + template = "{Series}/{Volume} - {Title} ({Narrator})" + assert render_template(template, fry) == "Harry Potter/01 - Philosopher's Stone (Stephen Fry)" + assert render_template(template, cast) == "Harry Potter/01 - Philosopher's Stone (Hugh Laurie)" + # the full list stays available + assert render_template("{Narrators}", cast) == \ + "Hugh Laurie, Matthew Macfadyen, Riz Ahmed, Michelle Gomez" + + +def test_narrator_missing_leaves_no_empty_brackets(): + req = SimpleNamespace(title="Ein Buch", authors="Jemand", series="", volume=None, + year=None, narrator="") + assert render_template("{Series}/{Volume} - {Title} ({Narrator})", req) == "Ein Buch" diff --git a/wordarr/naming.py b/wordarr/naming.py index 50bc3b0..0f512d9 100644 --- a/wordarr/naming.py +++ b/wordarr/naming.py @@ -14,12 +14,17 @@ def sanitize(part: str, max_len: int = 120) -> str: def render_template(template: str, request) -> str: """Render a naming template against a BookRequest. Each path segment is sanitized.""" author = (request.authors or "").split(",")[0].strip() or "Unknown Author" + narrators = getattr(request, "narrator", "") or "" + # like {Author}: the first name only, so a full-cast production does not turn + # into a 200 character folder name + narrator = narrators.split(",")[0].strip() values = { "Author": author, "Authors": request.authors or author, "Title": request.title or "Unknown Title", "Year": str(request.year) if request.year else "", - "Narrator": getattr(request, "narrator", "") or "", + "Narrator": narrator, + "Narrators": narrators, "Series": request.series or "", "Volume": f"{request.volume:02d}" if request.volume is not None else "", }