From f24b3f14098a6fc7b1e5e70212b1724183991627 Mon Sep 17 00:00:00 2001 From: Jos Vooges | STH Date: Tue, 25 Aug 2026 03:55:27 +0200 Subject: [PATCH] Fix Stremio catalog pagination and reduce duplicate movie/series rows. Catalogs now support skip so Stremio can load more than 100 titles; matching prefers TMDB and can merge orphans; admin can dedupe and see available vs scanned counts. Co-authored-by: Cursor --- apps/admin-ui/src/app/dashboard/page.tsx | 138 ++++++--- apps/master-api/src/admin/routes.ts | 33 ++- .../src/metadata/filename-parser.ts | 7 +- apps/master-api/src/metadata/service.ts | 271 ++++++++++++++++-- apps/master-api/src/stremio/routes.ts | 101 ++++--- node/media-node/internal/scanner/parser.go | 2 + 6 files changed, 453 insertions(+), 99 deletions(-) diff --git a/apps/admin-ui/src/app/dashboard/page.tsx b/apps/admin-ui/src/app/dashboard/page.tsx index b8a1afc..dff00bb 100644 --- a/apps/admin-ui/src/app/dashboard/page.tsx +++ b/apps/admin-ui/src/app/dashboard/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { Nav, useAuth } from "@/components/Nav"; interface Dashboard { @@ -11,6 +11,11 @@ interface Dashboard { movies: number; series: number; episodes: number; + availableMovies?: number; + availableSeries?: number; + mediaFiles?: number; + availableFiles?: number; + scannedFiles?: number; activeStreams: number; currentBandwidth: string; } @@ -38,8 +43,9 @@ export default function DashboardPage() { useAuth(); const [data, setData] = useState(null); const [error, setError] = useState(""); + const [dedupeMsg, setDedupeMsg] = useState(""); - useEffect(() => { + const load = useCallback(() => { fetch("/api/v1/admin/dashboard", { credentials: "include" }) .then(async (r) => { const json = await r.json(); @@ -54,6 +60,34 @@ export default function DashboardPage() { }); }, []); + useEffect(() => { + load(); + }, [load]); + + async function dedupe() { + if ( + !confirm( + "Duplicaten samenvoegen? Titels met dezelfde naam worden samengevoegd (TMDB-versie wint)." + ) + ) { + return; + } + setDedupeMsg("Bezig…"); + const res = await fetch("/api/v1/admin/library/dedupe", { + method: "POST", + credentials: "include", + }); + const json = await res.json(); + if (!res.ok) { + setDedupeMsg(json.error?.message ?? "Mislukt"); + return; + } + setDedupeMsg( + `Klaar: ${json.moviesMerged} film-duplicaten, ${json.seriesMerged} serie-duplicaten, ${json.emptied} lege records opgeruimd.` + ); + load(); + } + return ( <>