74 lines
2.2 KiB
TypeScript
74 lines
2.2 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { auth } from "@/auth";
|
|
import { db } from "@/lib/db";
|
|
|
|
const IMAGE_EXTS = new Set(["jpg", "jpeg", "png", "webp", "tiff", "tif", "avif"]);
|
|
|
|
export interface ThumbnailPreviewItem {
|
|
fileName: string;
|
|
stemName: string;
|
|
shotCode: string | null;
|
|
shotId: string | null;
|
|
status: "match" | "no-match";
|
|
currentThumbnailUrl: string | null;
|
|
}
|
|
|
|
function stem(fileName: string): string {
|
|
const dot = fileName.lastIndexOf(".");
|
|
return (dot > 0 ? fileName.slice(0, dot) : fileName).toLowerCase();
|
|
}
|
|
|
|
/**
|
|
* POST /api/batch-upload/thumbnails
|
|
* Body: { projectId: string; fileNames: string[] }
|
|
*/
|
|
export async function POST(req: NextRequest) {
|
|
const session = await auth();
|
|
if (!session?.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
|
|
let body: { projectId?: string; fileNames?: string[] };
|
|
try {
|
|
body = await req.json();
|
|
} catch {
|
|
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
|
|
}
|
|
|
|
const { projectId, fileNames } = body;
|
|
if (!projectId || !Array.isArray(fileNames)) {
|
|
return NextResponse.json({ error: "projectId and fileNames are required" }, { status: 400 });
|
|
}
|
|
|
|
// Only image files
|
|
const imageFiles = fileNames.filter((f) => {
|
|
const ext = f.split(".").pop()?.toLowerCase() ?? "";
|
|
return IMAGE_EXTS.has(ext);
|
|
});
|
|
|
|
const shots = await db.shot.findMany({
|
|
where: { projectId },
|
|
select: { id: true, shotCode: true, thumbnailUrl: true },
|
|
});
|
|
|
|
// Build a lowercase map for case-insensitive matching
|
|
const shotMap = new Map(shots.map((s) => [s.shotCode.toLowerCase(), s]));
|
|
|
|
const items: ThumbnailPreviewItem[] = fileNames.map((fileName) => {
|
|
const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
|
|
if (!IMAGE_EXTS.has(ext)) {
|
|
return { fileName, stemName: stem(fileName), shotCode: null, shotId: null, status: "no-match" as const, currentThumbnailUrl: null };
|
|
}
|
|
const s = stem(fileName);
|
|
const shot = shotMap.get(s) ?? null;
|
|
return {
|
|
fileName,
|
|
stemName: s,
|
|
shotCode: shot?.shotCode ?? null,
|
|
shotId: shot?.id ?? null,
|
|
status: shot ? "match" : "no-match",
|
|
currentThumbnailUrl: shot?.thumbnailUrl ?? null,
|
|
};
|
|
});
|
|
|
|
return NextResponse.json({ items });
|
|
}
|