Fix IMDb backfill timing out by processing in batches with auto-retry in admin UI.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6437e42c30
commit
5749e41148
3 changed files with 73 additions and 18 deletions
|
|
@ -114,27 +114,68 @@ export default function DashboardPage() {
|
||||||
async function backfillImdb() {
|
async function backfillImdb() {
|
||||||
if (
|
if (
|
||||||
!confirm(
|
!confirm(
|
||||||
"IMDb-IDs ophalen via TMDB voor ALLE films én series die die nog missen? Dit kan enkele minuten duren. Series-afleveringenlijst blijft op privé-IDs; IMDb is alleen voor Cinemeta-bronnen."
|
"IMDb-IDs ophalen via TMDB voor films en series die die nog missen? Dit gebeurt in batches (duurt even bij grote bibliotheken)."
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setImdbBusy(true);
|
setImdbBusy(true);
|
||||||
setImdbMsg("Bezig…");
|
setImdbMsg("Batch 1 bezig…");
|
||||||
|
let batch = 0;
|
||||||
|
let totalMoviesUpdated = 0;
|
||||||
|
let totalSeriesUpdated = 0;
|
||||||
|
let prevRemaining = Number.POSITIVE_INFINITY;
|
||||||
try {
|
try {
|
||||||
|
while (batch < 300) {
|
||||||
|
batch += 1;
|
||||||
|
setImdbMsg(`Batch ${batch} bezig…`);
|
||||||
const res = await fetch("/api/v1/admin/library/backfill-imdb", {
|
const res = await fetch("/api/v1/admin/library/backfill-imdb", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ limit: 100 }),
|
||||||
});
|
});
|
||||||
const json = await res.json().catch(() => ({}));
|
const json = await res.json().catch(() => ({}));
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
setImdbMsg(json.error?.message ?? "Mislukt");
|
setImdbMsg(json.error?.message ?? "Mislukt");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const movies = json.movies ?? json;
|
const movies = json.movies ?? {};
|
||||||
const series = json.series ?? {};
|
const series = json.series ?? {};
|
||||||
|
const checked = (movies.checked ?? 0) + (series.checked ?? 0);
|
||||||
|
const updated = (movies.updated ?? 0) + (series.updated ?? 0);
|
||||||
|
totalMoviesUpdated += movies.updated ?? 0;
|
||||||
|
totalSeriesUpdated += series.updated ?? 0;
|
||||||
|
const remaining = (movies.remaining ?? 0) + (series.remaining ?? 0);
|
||||||
|
|
||||||
|
if (remaining === 0) {
|
||||||
setImdbMsg(
|
setImdbMsg(
|
||||||
`Films: gecontroleerd ${movies.checked ?? 0}, bijgewerkt ${movies.updated ?? 0}, open ${movies.remaining ?? 0} · Series: gecontroleerd ${series.checked ?? 0}, bijgewerkt ${series.updated ?? 0}, open ${series.remaining ?? 0}`
|
`Klaar: films +${totalMoviesUpdated}, series +${totalSeriesUpdated} · alles ingevuld`
|
||||||
|
);
|
||||||
|
load();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checked === 0) {
|
||||||
|
setImdbMsg(
|
||||||
|
`Klaar: films +${totalMoviesUpdated}, series +${totalSeriesUpdated} · nog ${remaining} open (geen IMDb op TMDB)`
|
||||||
|
);
|
||||||
|
load();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (remaining >= prevRemaining && updated === 0) {
|
||||||
|
setImdbMsg(
|
||||||
|
`Gestopt na batch ${batch}: films +${totalMoviesUpdated}, series +${totalSeriesUpdated} · nog ${remaining} zonder IMDb (niet beschikbaar op TMDB)`
|
||||||
|
);
|
||||||
|
load();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prevRemaining = remaining;
|
||||||
|
setImdbMsg(
|
||||||
|
`Batch ${batch}: +${movies.updated ?? 0} films, +${series.updated ?? 0} series · nog ${remaining} open…`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setImdbMsg(
|
||||||
|
`Batchlimiet bereikt: films +${totalMoviesUpdated}, series +${totalSeriesUpdated} · druk opnieuw op de knop om verder te gaan`
|
||||||
);
|
);
|
||||||
load();
|
load();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
|
|
@ -514,9 +514,13 @@ export async function registerAdminRoutes(app: FastifyInstance, config: Config)
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/v1/admin/library/backfill-imdb", { preHandler: requireAdmin }, async () => {
|
app.post("/api/v1/admin/library/backfill-imdb", { preHandler: requireAdmin }, async (request) => {
|
||||||
// Process ALL pending movies + series (batched). Meta for series stays mcseries-*.
|
const body = (request.body ?? {}) as { limit?: number };
|
||||||
const result = await metadata.backfillAllImdbIds({ delayMs: 120 });
|
const limit =
|
||||||
|
typeof body.limit === "number" && body.limit > 0
|
||||||
|
? Math.min(Math.floor(body.limit), 500)
|
||||||
|
: 100;
|
||||||
|
const result = await metadata.backfillAllImdbIds({ delayMs: 80, limit });
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1390,7 +1390,12 @@ export class MetadataService {
|
||||||
const movie = await prisma.movie.findUnique({ where: { id: movieId } });
|
const movie = await prisma.movie.findUnique({ where: { id: movieId } });
|
||||||
if (!movie?.tmdbId || movie.imdbId) return false;
|
if (!movie?.tmdbId || movie.imdbId) return false;
|
||||||
const imdbId = await this.fetchTmdbMovieImdbId(movie.tmdbId);
|
const imdbId = await this.fetchTmdbMovieImdbId(movie.tmdbId);
|
||||||
if (!imdbId) return false;
|
if (!imdbId) {
|
||||||
|
await prisma.movie
|
||||||
|
.update({ where: { id: movieId }, data: { updatedAt: new Date() } })
|
||||||
|
.catch(() => undefined);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await prisma.movie.update({ where: { id: movieId }, data: { imdbId } });
|
await prisma.movie.update({ where: { id: movieId }, data: { imdbId } });
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1469,7 +1474,12 @@ export class MetadataService {
|
||||||
const series = await prisma.series.findUnique({ where: { id: seriesId } });
|
const series = await prisma.series.findUnique({ where: { id: seriesId } });
|
||||||
if (!series?.tmdbId || series.imdbId) return false;
|
if (!series?.tmdbId || series.imdbId) return false;
|
||||||
const imdbId = await this.fetchTmdbSeriesImdbId(series.tmdbId);
|
const imdbId = await this.fetchTmdbSeriesImdbId(series.tmdbId);
|
||||||
if (!imdbId) return false;
|
if (!imdbId) {
|
||||||
|
await prisma.series
|
||||||
|
.update({ where: { id: seriesId }, data: { updatedAt: new Date() } })
|
||||||
|
.catch(() => undefined);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await prisma.series.update({ where: { id: seriesId }, data: { imdbId } });
|
await prisma.series.update({ where: { id: seriesId }, data: { imdbId } });
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue