From c03bd4a2e208a792eadda993a52ce854fc4e6a62 Mon Sep 17 00:00:00 2001 From: Steppenstreuner Date: Fri, 28 Aug 2026 14:08:02 +0200 Subject: [PATCH] add(metadata): chose and request entity while scanning download/ --- static/app.js | 99 ++++++++++++++++++++++++++++++++++++++++++++++- static/index.html | 18 +++++++++ static/style.css | 2 + 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/static/app.js b/static/app.js index fef8863..154b23c 100644 --- a/static/app.js +++ b/static/app.js @@ -292,13 +292,110 @@ function renderImportTable() { ${esc(item.name)}${item.is_dir ? " 📁" : ""} ${esc(item.media_type)} - + + + + ${item.suggested_request_id ? item.score : "—"} `; }) .join(""); table.hidden = false; $("#import-btn").hidden = false; + tbody.querySelectorAll("[data-quick]").forEach((b) => + b.addEventListener("click", () => openQuickDialog(parseInt(b.dataset.quick))) + ); +} + +// ---- quick request from a scanned file ---- +let quickItemIndex = null; + +function cleanFileName(name) { + return name + .replace(/[._\-\[\]()]+/g, " ") + .replace(/\b(mp3|m4b|flac|epub|pdf|cbz|cbr|retail|unabridged|kompl.*)\b/gi, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function openQuickDialog(i) { + quickItemIndex = i; + const item = scanItems[i]; + $("#quick-file").textContent = item.name; + $("#quick-q").value = cleanFileName(item.name); + $("#quick-library").innerHTML = + libOptions(item.media_type) || ""; + $("#quick-results").innerHTML = ""; + $("#quick-dialog").showModal(); + runQuickSearch(); +} + +async function runQuickSearch() { + const item = scanItems[quickItemIndex]; + const box = $("#quick-results"); + box.innerHTML = "

Suche läuft…

"; + try { + const results = await api( + `/api/search?media_type=${item.media_type}&q=${encodeURIComponent($("#quick-q").value)}` + ); + if (!results.length) { box.innerHTML = "

Keine Treffer — Suchbegriff anpassen.

"; return; } + box.innerHTML = results + .map( + (r, j) => `
+ ${r.cover_url ? `` : '
?
'} +
+ ${esc(r.title)} + ${esc(r.authors)} + ${r.year ?? ""} +
+
+
` + ) + .join(""); + box.querySelectorAll("[data-pick]").forEach((btn) => + btn.addEventListener("click", () => pickQuickResult(results[btn.dataset.pick])) + ); + } catch (err) { + box.innerHTML = ""; + toast(err.message, true); + } +} + +$("#quick-search-form").addEventListener("submit", (e) => { + e.preventDefault(); + runQuickSearch(); +}); +$("#quick-close").addEventListener("click", () => $("#quick-dialog").close()); + +async function pickQuickResult(r) { + 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 api("/api/requests", { + method: "POST", + body: JSON.stringify({ + library_id: parseInt(libId), + title: r.title, authors: r.authors, external_id: r.external_id, + year: r.year, series: r.series, cover_url: r.cover_url, + }), + }); + missingReqs.push(req); + // add the new request to every dropdown of the same media type, then link this row + const item = scanItems[i]; + scanItems.forEach((it, j) => { + if (it.media_type !== item.media_type) return; + const sel = document.querySelector(`[data-select="${j}"]`); + const opt = document.createElement("option"); + opt.value = req.id; + opt.textContent = `${req.title} — ${req.authors} (${req.library_name})`; + sel.appendChild(opt); + }); + document.querySelector(`[data-select="${i}"]`).value = req.id; + document.querySelector(`[data-check="${i}"]`).checked = true; + $("#quick-dialog").close(); + toast(`„${req.title}" angefragt und verbunden`); + } catch (err) { toast(err.message, true); } } $("#import-btn").addEventListener("click", async () => { diff --git a/static/index.html b/static/index.html index 57190c3..216288a 100644 --- a/static/index.html +++ b/static/index.html @@ -113,6 +113,24 @@
+ + +

Suchen & Anfragen

+

+
+ + +
+ +
+
+ +
+