/** * Why is a shot not showing a render-derived thumbnail? * * Walks the chain in order and reports the first broken link: * * ffmpeg on the worker → Export.thumbnailKey → project flag → * Shot.generatedThumbnailUrl → what the UI resolves * * Usage: node scripts/diagnose-thumbnails.mjs [PROJECT_CODE] */ import { PrismaClient } from "@prisma/client"; const db = new PrismaClient(); const projectCode = process.argv[2]?.toUpperCase(); const projects = await db.project.findMany({ where: projectCode ? { code: projectCode } : {}, select: { id: true, code: true, name: true, pipelineConfig: true }, orderBy: { code: "asc" }, }); if (projects.length === 0) { console.log(projectCode ? `No project with code ${projectCode}.` : "No projects."); process.exit(0); } for (const p of projects) { const cfg = (p.pipelineConfig ?? {}); const flag = cfg.autoShotThumbnail; const on = flag === true; console.log(`\n━━ ${p.code} — ${p.name}`); console.log(` auto-promote flag : ${JSON.stringify(flag)} ${on ? "✔ on" : "✘ OFF"}`); if (flag === undefined) { console.log(` ⚠ key absent from pipelineConfig. Either the setting was never saved,`); console.log(` or the server that saved it predates the boolean fix in actions/projects.ts.`); console.log(` Stored keys: ${JSON.stringify(Object.keys(cfg))}`); } const exports = await db.export.findMany({ where: { shot: { projectId: p.id } }, orderBy: { createdAt: "desc" }, take: 10, select: { versionString: true, status: true, createdAt: true, thumbnailKey: true, skipPreview: true, shot: { select: { shotCode: true, thumbnailUrl: true, generatedThumbnailUrl: true, generatedThumbnailFrom: true, }, }, }, }); if (exports.length === 0) { console.log(" (no exports yet)"); continue; } console.log(` last ${exports.length} exports:`); for (const e of exports) { const s = e.shot; const displayed = s.thumbnailUrl || s.generatedThumbnailUrl || null; const source = s.thumbnailUrl ? "reference" : s.generatedThumbnailUrl ? "render" : "NOTHING"; console.log( `\n ${s.shotCode} ${e.versionString} [${e.status}]${e.skipPreview ? " skipPreview" : ""}` ); console.log(` export.thumbnailKey : ${e.thumbnailKey ?? "✘ NULL — worker produced no thumbnail (ffmpeg?)"}`); console.log(` shot.thumbnailUrl : ${s.thumbnailUrl ?? "(none)"}`); console.log(` shot.generatedThumbnail : ${s.generatedThumbnailUrl ?? "(none)"}${s.generatedThumbnailFrom ? ` [from ${s.generatedThumbnailFrom}]` : ""}`); console.log(` → UI shows : ${displayed ?? "nothing"} (${source})`); if (!e.thumbnailKey) { console.log(` ⇒ Broken at the WORKER. Check ffmpegPath in config.json on the`); console.log(` machine that ran it, and its log for "no thumbnail".`); } else if (!on) { console.log(` ⇒ Thumbnail exists but the project flag is off, so it was not promoted.`); console.log(` Turn on "Use render frames as shot thumbnails", or use the`); console.log(` per-export "Use frame" button on the shot's Exports tab.`); } else if (!s.generatedThumbnailUrl) { console.log(` ⇒ Thumbnail exists and the flag is on, but nothing was promoted.`); console.log(` This export probably finalized BEFORE the flag was turned on —`); console.log(` promotion happens at finalize, it is not retroactive. Re-render,`); console.log(` or press "Use frame" on the Exports tab.`); } } } await db.$disconnect();