// app/api/transcoder/download/[videoId]/route.ts // Streams the original MP4 directly to the remote transcoder worker. // Never buffers the file in memory. import { NextResponse } from "next/server"; import * as fssync from "fs"; import * as fs from "fs/promises"; import * as path from "path"; import { Readable } from "stream"; import { prisma } from "@/lib/prisma"; import { verifyTranscoderToken } from "@/lib/transcoder-auth"; // Allow up to 45 minutes for large file transfers. export const maxDuration = 2700; const UPLOADS_DIR = process.env.UPLOADS_DIR ?? "/uploads"; const ORIGINALS_DIR = path.join(UPLOADS_DIR, "videos"); // Narrow character set – CUIDs are alphanumeric plus underscore/dash. const SAFE_ID = /^[a-zA-Z0-9_-]{1,64}$/; export async function GET( request: Request, context: { params: Promise<{ videoId: string }> } ) { if (!verifyTranscoderToken(request)) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { videoId } = await context.params; if (!SAFE_ID.test(videoId)) { return NextResponse.json({ error: "Invalid video ID" }, { status: 400 }); } const video = await prisma.video.findUnique({ where: { id: videoId } }); if (!video) { return NextResponse.json({ error: "Not found" }, { status: 404 }); } // Only allow download while the job is actively claimed. if (video.transcodingStatus !== "processing") { return NextResponse.json( { error: "Video is not in processing state" }, { status: 409 } ); } const filePath = path.join(ORIGINALS_DIR, `${videoId}.mp4`); // Security: ensure the resolved path stays within ORIGINALS_DIR. const resolved = path.resolve(filePath); if (!resolved.startsWith(path.resolve(ORIGINALS_DIR))) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } try { const stat = await fs.stat(resolved); const nodeStream = fssync.createReadStream(resolved); const webStream = Readable.toWeb(nodeStream) as ReadableStream; return new Response(webStream, { headers: { "Content-Type": "video/mp4", "Content-Length": stat.size.toString(), "Content-Disposition": `attachment; filename="${videoId}.mp4"`, }, }); } catch { return NextResponse.json({ error: "File not found on disk" }, { status: 404 }); } }