import { NextRequest, NextResponse } from "next/server"; import { spawn } from "node:child_process"; import { findVideosForCode } from "@/lib/video"; import { assertLocalRequest } from "@/lib/api/localOnly"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; /** * Open the OS file manager pre-selected on the cover's video file. * Local-only — explicitly gated by assertLocalRequest. */ export async function POST(req: NextRequest, ctx: { params: Promise<{ code: string }> }) { const blocked = assertLocalRequest(req); if (blocked) return blocked; const { code } = await ctx.params; const decoded = decodeURIComponent(code); const url = new URL(req.url); const partRaw = url.searchParams.get("part"); const part = partRaw == null ? 0 : Math.max(0, parseInt(partRaw, 10) || 0); const files = findVideosForCode(decoded); if (files.length === 0) return NextResponse.json({ error: "not found" }, { status: 404 }); const file = files[Math.min(part, files.length - 1)]; try { if (process.platform === "win32") { // explorer doesn't return zero-exit even on success; detach and don't await. spawn("explorer", ["/select,", file.abs], { detached: true, stdio: "ignore" }).unref(); } else if (process.platform === "darwin") { spawn("open", ["-R", file.abs], { detached: true, stdio: "ignore" }).unref(); } else { // Linux: open the parent dir; most file managers don't have a select API. const parent = file.abs.replace(/[/\\][^/\\]*$/, ""); spawn("xdg-open", [parent], { detached: true, stdio: "ignore" }).unref(); } return NextResponse.json({ ok: true, path: file.abs }); } catch (e) { return NextResponse.json({ error: (e as Error).message }, { status: 500 }); } }