import { createWriteStream } from "node:fs"; import { mkdir, unlink } from "node:fs/promises"; import { Readable } from "node:stream"; import { pipeline } from "node:stream/promises"; import { randomUUID } from "node:crypto"; import { NextResponse } from "next/server"; import { requireAdmin } from "@/lib/auth/auth"; export const dynamic = "force-dynamic"; const VIDEO_DIR = process.env.VIDEO_UPLOAD_DIR || "/nfs/erika"; const VIDEO_TYPES = new Set(["video/mp4", "video/quicktime", "video/webm"]); function safeFileName(value: string) { return value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(-180) || "video"; } export async function POST(request: Request) { let filePath: string | null = null; try { const discordId = await requireAdmin(); const encodedName = request.headers.get("x-file-name"); const mimeType = request.headers.get("content-type") ?? ""; const contentLength = Number(request.headers.get("content-length") ?? 0); if (!encodedName || !request.body) { return NextResponse.json( { error: "No video provided." }, { status: 400 }, ); } if (!VIDEO_TYPES.has(mimeType)) { return NextResponse.json( { error: "Use an MP4, MOV, or WebM video." }, { status: 400 }, ); } const originalFilename = decodeURIComponent(encodedName); const stagedVideoId = randomUUID(); const stagingDirectory = `${VIDEO_DIR}/staging/${discordId}`; filePath = `${stagingDirectory}/${stagedVideoId}-${safeFileName(originalFilename)}`; await mkdir(/* turbopackIgnore: true */ stagingDirectory, { recursive: true }); await pipeline( Readable.fromWeb(request.body as never), createWriteStream(/* turbopackIgnore: true */ filePath, { flags: "wx" }), ); return NextResponse.json({ stagedVideoId, originalFilename, mimeType, size: contentLength, }); } catch (error) { if (filePath) await unlink(/* turbopackIgnore: true */ filePath).catch(() => undefined); const message = error instanceof Error ? error.message : "Upload failed."; const status = message === "Unauthorized" || message === "Not authenticated" ? 401 : 400; return NextResponse.json({ error: message }, { status }); } }