Files
pinkudex/app/api/video-reveal/[code]/route.ts
T
2026-05-26 22:46:00 +02:00

43 lines
1.7 KiB
TypeScript

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 });
}
}