mycofi-earth-website/app/api/zine/[id]/route.ts

106 lines
3.2 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { getZine, readFileAsBuffer, getPageImagePath, getPrintLayoutPath } from "@/lib/storage";
interface RouteContext {
params: Promise<{ id: string }>;
}
// GET /api/zine/[id] - Get zine metadata
// GET /api/zine/[id]?image=p1 - Get page image
// GET /api/zine/[id]?print=true - Get print layout
export async function GET(request: NextRequest, context: RouteContext) {
try {
const { id } = await context.params;
const url = new URL(request.url);
const imageParam = url.searchParams.get("image");
const printParam = url.searchParams.get("print");
// Serve page image
if (imageParam) {
const pageMatch = imageParam.match(/^p(\d)$/);
if (!pageMatch) {
return NextResponse.json(
{ error: "Invalid image parameter. Use p1-p8." },
{ status: 400 }
);
}
const pageNumber = parseInt(pageMatch[1], 10);
if (pageNumber < 1 || pageNumber > 8) {
return NextResponse.json(
{ error: "Page number must be between 1 and 8" },
{ status: 400 }
);
}
const imagePath = await getPageImagePath(id, pageNumber);
if (!imagePath) {
return NextResponse.json(
{ error: "Page image not found" },
{ status: 404 }
);
}
const imageBuffer = await readFileAsBuffer(imagePath);
return new NextResponse(new Uint8Array(imageBuffer), {
headers: {
"Content-Type": "image/png",
"Cache-Control": "public, max-age=31536000, immutable",
},
});
}
// Serve print layout
if (printParam === "true") {
const printPath = await getPrintLayoutPath(id);
if (!printPath) {
return NextResponse.json(
{ error: "Print layout not found. Generate it first." },
{ status: 404 }
);
}
const printBuffer = await readFileAsBuffer(printPath);
const downloadParam = url.searchParams.get("download");
const headers: Record<string, string> = {
"Content-Type": "image/png",
"Cache-Control": "public, max-age=31536000, immutable",
};
// Only add Content-Disposition for explicit downloads
if (downloadParam === "true") {
headers["Content-Disposition"] = `attachment; filename="${id}_print.png"`;
}
return new NextResponse(new Uint8Array(printBuffer), { headers });
}
// Return zine metadata
const zine = await getZine(id);
if (!zine) {
return NextResponse.json(
{ error: "Zine not found" },
{ status: 404 }
);
}
// Build response with image URLs
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || "";
const response = {
...zine,
pageUrls: Array.from({ length: 8 }, (_, i) => `${baseUrl}/api/zine/${id}?image=p${i + 1}`),
printLayoutUrl: zine.printLayout ? `${baseUrl}/api/zine/${id}?print=true` : null,
shareUrl: `${baseUrl}/zine/z/${id}`,
};
return NextResponse.json(response);
} catch (error) {
console.error("Get zine error:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Failed to get zine" },
{ status: 500 }
);
}
}