nextav/src/app/api/photos/[id]/route.ts

60 lines
1.9 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import db from "@/db";
import fs from "fs";
import path from "path";
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
try {
const photoId = parseInt(id);
if (isNaN(photoId)) {
return NextResponse.json({ error: "Invalid photo ID" }, { status: 400 });
}
const photo = db.prepare("SELECT * FROM media WHERE id = ? AND type = 'photo'").get(photoId) as { path: string, title: string } | undefined;
if (!photo) {
return NextResponse.json({ error: "Photo not found" }, { status: 404 });
}
const photoPath = photo.path;
if (!fs.existsSync(photoPath)) {
return NextResponse.json({ error: "Photo file not found" }, { status: 404 });
}
const stat = fs.statSync(photoPath);
const fileSize = stat.size;
const ext = path.extname(photoPath).toLowerCase();
// Determine content type based on file extension
let contentType = 'image/jpeg'; // default
if (ext === '.png') contentType = 'image/png';
else if (ext === '.gif') contentType = 'image/gif';
else if (ext === '.webp') contentType = 'image/webp';
else if (ext === '.bmp') contentType = 'image/bmp';
else if (ext === '.tiff' || ext === '.tif') contentType = 'image/tiff';
else if (ext === '.svg') contentType = 'image/svg+xml';
const headers = new Headers({
"Content-Length": fileSize.toString(),
"Content-Type": contentType,
"Cache-Control": "public, max-age=31536000", // Cache for 1 year
});
const file = fs.createReadStream(photoPath);
return new Response(file as any, {
status: 200,
headers,
});
} catch (error) {
console.error("Error serving photo:", error);
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
}
}