Process all pending movies in IMDb backfill instead of capping at 200.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a9df10ed7c
commit
fc842aa145
5 changed files with 45 additions and 36 deletions
|
|
@ -70,7 +70,7 @@ export default function DashboardPage() {
|
|||
async function backfillImdb() {
|
||||
if (
|
||||
!confirm(
|
||||
"IMDb-IDs ophalen via TMDB voor films die die nog missen? Nodig zodat Cinemeta jouw lokale bronnen toont."
|
||||
"IMDb-IDs ophalen via TMDB voor ALLE films die die nog missen? Dit kan enkele minuten duren bij een grote bibliotheek. Nodig zodat Cinemeta jouw lokale bronnen toont."
|
||||
)
|
||||
) {
|
||||
return;
|
||||
|
|
@ -86,7 +86,7 @@ export default function DashboardPage() {
|
|||
return;
|
||||
}
|
||||
setImdbMsg(
|
||||
`Gecontroleerd: ${json.checked ?? 0}, bijgewerkt: ${json.updated ?? 0}, nog open: ${json.skipped ?? 0}`
|
||||
`Gecontroleerd: ${json.checked ?? 0}, bijgewerkt: ${json.updated ?? 0}, nog open: ${json.remaining ?? json.skipped ?? 0}, mislukt: ${json.failed ?? 0}`
|
||||
);
|
||||
load();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,7 +445,8 @@ export async function registerAdminRoutes(app: FastifyInstance, config: Config)
|
|||
});
|
||||
|
||||
app.post("/api/v1/admin/library/backfill-imdb", { preHandler: requireAdmin }, async () => {
|
||||
const result = await metadata.backfillMovieImdbIds({ delayMs: 150, limit: 500 });
|
||||
// Process ALL pending movies (batched). Can take a few minutes for large libraries.
|
||||
const result = await metadata.backfillMovieImdbIds({ delayMs: 120 });
|
||||
return result;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -126,16 +126,16 @@ async function main() {
|
|||
await app.listen({ port: config.PORT, host: config.HOST });
|
||||
console.log(`Master API listening on ${config.HOST}:${config.PORT}`);
|
||||
|
||||
// Background: fill missing movie imdbIds so Cinemeta detail pages can resolve local streams.
|
||||
// Background: fill ALL missing movie imdbIds (batched) so Cinemeta can resolve local streams.
|
||||
if (config.TMDB_API_KEY) {
|
||||
const metadata = new MetadataService(config.TMDB_API_KEY);
|
||||
setTimeout(() => {
|
||||
void metadata
|
||||
.backfillMovieImdbIds({ delayMs: 200, limit: 200 })
|
||||
.backfillMovieImdbIds({ delayMs: 120 })
|
||||
.then((r) => {
|
||||
if (r.checked > 0) {
|
||||
console.log(
|
||||
`IMDb backfill: checked=${r.checked} updated=${r.updated} remaining=${r.skipped}`
|
||||
`IMDb backfill: checked=${r.checked} updated=${r.updated} remaining=${r.remaining} failed=${r.failed}`
|
||||
);
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -666,28 +666,37 @@ export class MetadataService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Fill missing imdbId for all movies that have a TMDB id.
|
||||
* Fill missing imdbId for movies that have a TMDB id.
|
||||
* Processes in batches until none remain (or `limit` is hit).
|
||||
* Rate-limited to avoid TMDB bans. Safe for series (movies only).
|
||||
*/
|
||||
async backfillMovieImdbIds(options?: {
|
||||
delayMs?: number;
|
||||
/** Max movies to process this run. Omit / 0 = all pending. */
|
||||
limit?: number;
|
||||
}): Promise<{ checked: number; updated: number; skipped: number; failed: number }> {
|
||||
const delayMs = options?.delayMs ?? 200;
|
||||
const limit = options?.limit ?? 500;
|
||||
batchSize?: number;
|
||||
}): Promise<{ checked: number; updated: number; remaining: number; failed: number }> {
|
||||
const delayMs = options?.delayMs ?? 150;
|
||||
const batchSize = Math.min(Math.max(options?.batchSize ?? 100, 1), 500);
|
||||
const maxTotal = options?.limit && options.limit > 0 ? options.limit : Number.POSITIVE_INFINITY;
|
||||
if (!this.tmdbApiKey) {
|
||||
return { checked: 0, updated: 0, skipped: 0, failed: 0 };
|
||||
return { checked: 0, updated: 0, remaining: 0, failed: 0 };
|
||||
}
|
||||
|
||||
const pending = await prisma.movie.findMany({
|
||||
where: { tmdbId: { not: null }, imdbId: null },
|
||||
select: { id: true, title: true, tmdbId: true },
|
||||
take: limit,
|
||||
orderBy: { updatedAt: "asc" },
|
||||
});
|
||||
|
||||
let checked = 0;
|
||||
let updated = 0;
|
||||
let failed = 0;
|
||||
|
||||
while (checked < maxTotal) {
|
||||
const take = Math.min(batchSize, maxTotal - checked);
|
||||
const pending = await prisma.movie.findMany({
|
||||
where: { tmdbId: { not: null }, imdbId: null },
|
||||
select: { id: true },
|
||||
take,
|
||||
orderBy: { updatedAt: "asc" },
|
||||
});
|
||||
if (pending.length === 0) break;
|
||||
|
||||
for (const row of pending) {
|
||||
try {
|
||||
const ok = await this.ensureMovieImdbId(row.id);
|
||||
|
|
@ -696,20 +705,19 @@ export class MetadataService {
|
|||
} catch {
|
||||
failed += 1;
|
||||
}
|
||||
checked += 1;
|
||||
if (delayMs > 0) {
|
||||
await new Promise((r) => setTimeout(r, delayMs));
|
||||
}
|
||||
}
|
||||
|
||||
const stillMissing = await prisma.movie.count({
|
||||
if (pending.length < take) break;
|
||||
}
|
||||
|
||||
const remaining = await prisma.movie.count({
|
||||
where: { tmdbId: { not: null }, imdbId: null },
|
||||
});
|
||||
return {
|
||||
checked: pending.length,
|
||||
updated,
|
||||
skipped: stillMissing,
|
||||
failed,
|
||||
};
|
||||
return { checked, updated, remaining, failed };
|
||||
}
|
||||
|
||||
private async absorbOrphanMovies(
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ async function getStreams(
|
|||
);
|
||||
// Do not block this request — fill IMDb ids in background for next try.
|
||||
if (isImdb && missingImdb > 0) {
|
||||
void metadata.backfillMovieImdbIds({ delayMs: 150, limit: 80 }).catch(() => undefined);
|
||||
void metadata.backfillMovieImdbIds({ delayMs: 120, limit: 30 }).catch(() => undefined);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue