mirror of
https://github.com/myronblair/kino-app
synced 2026-07-28 05:23:45 -05:00
Add live progress status to bulk TMDB movie enrichment
Was a single synchronous request with no visibility into progress — large libraries gave no indication whether it was working or just slow. Now runs as a background job (matching the existing music-enrich pattern) with GET /api/tmdb/enrich-all/status polled every 2s; Settings shows "Enriching... N/total" while running and a summary once done.
This commit is contained in:
@@ -57,6 +57,7 @@ export default function Settings() {
|
||||
const [pw, setPw] = useState({ current_password: "", new_password: "", confirm: "" });
|
||||
const [pwShow, setPwShow] = useState(false);
|
||||
const [pwSaving, setPwSaving] = useState(false);
|
||||
const [enrich, setEnrich] = useState(null);
|
||||
|
||||
const load = async () => {
|
||||
if (!isAdmin) return;
|
||||
@@ -119,10 +120,32 @@ export default function Settings() {
|
||||
|
||||
const enrichAll = async () => {
|
||||
if (!window.confirm("Sweep all movies with missing metadata and fill from TMDB? This may take a while.")) return;
|
||||
try { const { data } = await api.post("/tmdb/enrich-all"); toast.success(`Enriched ${data.enriched}, skipped ${data.skipped}, failed ${data.failed}`); }
|
||||
catch (err) { toast.error(err.response?.data?.detail || "Enrichment failed"); }
|
||||
try {
|
||||
await api.post("/tmdb/enrich-all");
|
||||
const { data } = await api.get("/tmdb/enrich-all/status");
|
||||
setEnrich(data);
|
||||
toast.success("Enrichment started");
|
||||
} catch (err) { toast.error(err.response?.data?.detail || "Enrichment failed"); }
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAdmin) return;
|
||||
api.get("/tmdb/enrich-all/status").then(({ data }) => setEnrich(data)).catch(() => {});
|
||||
}, [isAdmin]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enrich?.running) return;
|
||||
const t = setInterval(async () => {
|
||||
const { data } = await api.get("/tmdb/enrich-all/status");
|
||||
setEnrich(data);
|
||||
if (!data.running) {
|
||||
clearInterval(t);
|
||||
toast.success(`Enrichment done — ${data.enriched} enriched, ${data.skipped} already complete, ${data.failed} not found`);
|
||||
}
|
||||
}, 2000);
|
||||
return () => clearInterval(t);
|
||||
}, [enrich?.running]);
|
||||
|
||||
return (
|
||||
<FieldCtx.Provider value={{ s, setS, show, setShow }}>
|
||||
<div className="min-h-screen bg-[#050505] pt-32 pb-24" data-testid="settings-page">
|
||||
@@ -183,9 +206,16 @@ export default function Settings() {
|
||||
<p className="text-sm text-[#8A8A8A] mb-4">Free key at <a className="text-[#D9381E]" href="https://www.themoviedb.org/settings/api" target="_blank" rel="noreferrer">themoviedb.org</a></p>
|
||||
<Field label="API key (v3)" k="tmdb_api_key" mask />
|
||||
{info.tmdb_configured && (
|
||||
<button type="button" onClick={enrichAll} className="mt-4 text-xs uppercase tracking-[0.2em] border border-[#222] hover:border-[#D9381E] hover:text-[#D9381E] text-[#8A8A8A] px-4 py-2 transition-colors" data-testid="enrich-all-button">
|
||||
Bulk enrich all movies →
|
||||
</button>
|
||||
<div className="mt-4 flex items-center gap-4 flex-wrap">
|
||||
<button type="button" onClick={enrichAll} disabled={enrich?.running} className="text-xs uppercase tracking-[0.2em] border border-[#222] hover:border-[#D9381E] hover:text-[#D9381E] text-[#8A8A8A] px-4 py-2 transition-colors disabled:opacity-50" data-testid="enrich-all-button">
|
||||
{enrich?.running ? `Enriching… ${enrich.done}/${enrich.total}` : "Bulk enrich all movies →"}
|
||||
</button>
|
||||
{enrich && !enrich.running && enrich.total > 0 && (
|
||||
<span className="text-xs text-[#8A8A8A]" data-testid="enrich-all-summary">
|
||||
Last run: {enrich.enriched} enriched · {enrich.skipped} already complete · {enrich.failed} not found on TMDB
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user