diff --git a/README.md b/README.md index 32f189f..58aef3f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Sonarr/Radarr-Style Request- & Import-Manager für **Ebooks**, **Comics/Mangas** 1. **Anfragen**: Im Web-UI per Titel/Autor/ISBN suchen (Ebooks: Open Library · Audiobooks: Audible · Manga: AniList) oder manuell anlegen. Beim Request wählst du die **Ziel-Library** (z.B. deine 8 Bookorbit-Libraries oder die 3 Audiobookshelf-Libraries english/adult/kids). Der Titel erscheint als **Missing**. Gehört ein Audiobook-Treffer zu einer Serie, legt **„Ganze Serie…"** alle Folgen auf einmal an (Folgennummer + echter Titel von Audible, optional auf einen Folgenbereich eingegrenzt). Audible hat keine Serien-Abfrage — wordarr sammelt die Folgen über mehrere Suchläufe ein; sollte eine fehlen, zeigt der Dialog die Lücke an. 2. **Download-Ordner**: wordarr überwacht keinen Downloader aktiv — du legst Dateien selbst in den Download-Ordner (`/mnt/downloads`). -3. **Import missing**: Im Tab *Import* den Ordner scannen. wordarr schlägt per Fuzzy-Matching Datei→Request-Zuordnungen vor (bei Serien zählt die Folgennummer im Ordnernamen plus der Serienname im Pfad, `???` und `Fragezeichen` gelten als dasselbe); du bestätigst oder korrigierst. Über 🔍 lässt sich zu einem Ordner direkt eine Anfrage suchen — eine führende Folgennummer (`017 - Titel`) wird dabei aus der Suchanfrage genommen, weil Audible sonst schlechter trifft, und stattdessen als Band/Folge übernommen. Beim Import wird die Datei nach dem Namensschema der Library **umbenannt und verschoben**. Ordner mit mehreren Audio-Dateien werden als ein Audiobook behandelt (`Titel - Part 01.mp3`, …). Auch Ordner, die in Disc-Unterordner (`CD`, `CD1`, `CD 2`, `Disc 3`, `Teil 1`) aufgeteilt sind, gelten als **ein** Audiobook — der Ordnername darüber liefert den Titel, die Parts werden über alle Discs hinweg durchnummeriert. Unterordner ohne Audio (`Cover`, Scans, Booklets) werden dabei ignoriert. Mehrteiler in Unterordnern (`Teil A`/`Teil B`, `A - Titel`/`B - Titel`) zählen ebenfalls als ein Hörbuch. Liegen die Teile dagegen **nebeneinander** (`100 - Toteninsel Teil 1`, `… Teil 2`, …), markierst du sie und klickst *Ausgewählte zusammenfassen* — sie werden als ein Hörbuch mit durchlaufenden Parts importiert (✂️ löst das wieder auf). Sind mehrere Einträge derselben Anfrage zugeordnet, fragt wordarr vor dem Import nach und fasst sie zusammen — sonst importiert nur der erste und der Rest scheitert. Fehlt einem bereits importierten Hörbuch später ein Teil, wählst du es im Zuordnungs-Dropdown unter *Bereits importiert — Teile anhängen* (↩︎); die neuen Dateien werden hinten angehängt und alle Tracks neu getaggt. +3. **Import missing**: Im Tab *Import* den Ordner scannen. wordarr schlägt per Fuzzy-Matching Datei→Request-Zuordnungen vor (bei Serien zählt die Folgennummer im Ordnernamen plus der Serienname im Pfad, `???` und `Fragezeichen` gelten als dasselbe); du bestätigst oder korrigierst. Über 🔍 lässt sich zu einem Ordner direkt eine Anfrage suchen — eine führende Folgennummer (`017 - Titel`) wird dabei aus der Suchanfrage genommen, weil Audible sonst schlechter trifft, und stattdessen als Band/Folge übernommen. Was Audible gar nicht führt (Live-Hörspiele, Fan-Editionen), legst du im selben Dialog unter *Nicht bei Audible? Manuell anlegen* an — Titel und Folge sind aus dem Ordnernamen vorbelegt, die Serie bleibt für den nächsten Eintrag stehen. Beim Import wird die Datei nach dem Namensschema der Library **umbenannt und verschoben**. Ordner mit mehreren Audio-Dateien werden als ein Audiobook behandelt (`Titel - Part 01.mp3`, …). Auch Ordner, die in Disc-Unterordner (`CD`, `CD1`, `CD 2`, `Disc 3`, `Teil 1`) aufgeteilt sind, gelten als **ein** Audiobook — der Ordnername darüber liefert den Titel, die Parts werden über alle Discs hinweg durchnummeriert. Unterordner ohne Audio (`Cover`, Scans, Booklets) werden dabei ignoriert. Mehrteiler in Unterordnern (`Teil A`/`Teil B`, `A - Titel`/`B - Titel`) zählen ebenfalls als ein Hörbuch. Liegen die Teile dagegen **nebeneinander** (`100 - Toteninsel Teil 1`, `… Teil 2`, …), markierst du sie und klickst *Ausgewählte zusammenfassen* — sie werden als ein Hörbuch mit durchlaufenden Parts importiert (✂️ löst das wieder auf). Sind mehrere Einträge derselben Anfrage zugeordnet, fragt wordarr vor dem Import nach und fasst sie zusammen — sonst importiert nur der erste und der Rest scheitert. Fehlt einem bereits importierten Hörbuch später ein Teil, wählst du es im Zuordnungs-Dropdown unter *Bereits importiert — Teile anhängen* (↩︎); die neuen Dateien werden hinten angehängt und alle Tracks neu getaggt. ## Setup (Docker) diff --git a/static/app.js b/static/app.js index fcfdf6e..b1adb40 100644 --- a/static/app.js +++ b/static/app.js @@ -861,6 +861,7 @@ function splitMergedItem(i) { // ---- quick request from a scanned file ---- let quickItemIndex = null; let quickEpisode = null; +let lastSeries = ""; // "017 - Titel", "Folge 17: Titel", "[003] Titel" -> episode number + rest. // A bare number without a separator ("100 Stunden") or without a leading zero is @@ -901,6 +902,10 @@ function openQuickDialog(i) { $("#quick-file").textContent = (item.rel_dir ? item.rel_dir + "/" : "") + item.name; $("#quick-episode").textContent = number != null ? `Folge ${number} — nicht mitgesucht` : ""; $("#quick-q").value = cleanFileName(rest); + $("#quick-m-title").value = cleanFileName(rest); + $("#quick-m-volume").value = number ?? ""; + $("#quick-m-series").value = lastSeries; + $("#quick-manual").open = false; $("#quick-library").innerHTML = libOptions(item.media_type) || ""; $("#quick-results").innerHTML = ""; @@ -987,17 +992,13 @@ $("#quick-search-form").addEventListener("submit", (e) => { }); $("#quick-close").addEventListener("click", () => $("#quick-dialog").close()); -async function pickQuickResult(r) { +// create the request and wire it to the scanned entry the dialog was opened for +async function requestAndConnect(body) { const libId = $("#quick-library").value; if (!libId) { toast("Erst eine Library für diesen Typ anlegen", true); return; } const i = quickItemIndex; try { - const req = await createRequest({ - library_id: parseInt(libId), - title: r.title, authors: r.authors, narrator: r.narrator || "", - external_id: r.external_id, volume: r.volume ?? quickEpisode, - year: r.year, series: r.series, cover_url: r.cover_url, - }); + const req = await createRequest({ library_id: parseInt(libId), ...body }); setLastLib(scanItems[i].media_type, libId); missingReqs.push(req); scanItems[i].request_id = req.id; @@ -1009,6 +1010,26 @@ async function pickQuickResult(r) { } catch (err) { toast(err.message, true); } } +function pickQuickResult(r) { + return requestAndConnect({ + title: r.title, authors: r.authors, narrator: r.narrator || "", + external_id: r.external_id, volume: r.volume ?? quickEpisode, + year: r.year, series: r.series, cover_url: r.cover_url, + }); +} + +// live shows, box sets and fan releases are not in the Audible catalogue at all +$("#quick-m-submit").addEventListener("click", () => { + const title = $("#quick-m-title").value.trim(); + if (!title) { toast("Titel angeben", true); return; } + const volume = $("#quick-m-volume").value; + return requestAndConnect({ + title, + series: (lastSeries = $("#quick-m-series").value.trim()), + volume: volume ? parseInt(volume) : null, + }); +}); + // ---- import execution (batched, with progress) ---- const IMPORT_BATCH_SIZE = 20; diff --git a/static/index.html b/static/index.html index bbf9f01..5a85463 100644 --- a/static/index.html +++ b/static/index.html @@ -204,6 +204,15 @@ >
+
+ Nicht bei Audible? Manuell anlegen +
+ + + +
+ +