import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/db"; import { readFile, stat } from "fs/promises"; import path from "path"; import { getApiLang, pickText } from "@/lib/api-locale"; import { getDownloadWowVersion } from "@/lib/wow-versions"; const LAUNCHER_SLUG = "nanami-launcher"; export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url); const infoOnly = searchParams.get("info") === "1"; const lang = getApiLang(request); // Download endpoint: only the URL determines what gets downloaded. // Cookies (wow / locale) do not influence the binary. const wowVersion = getDownloadWowVersion(request); const software = await prisma.software.findUnique({ where: { slug: LAUNCHER_SLUG }, include: { versions: { where: { isLatest: true, wowVersion }, take: 1, }, }, }); if (!software || software.versions.length === 0) { if (infoOnly) { return NextResponse.json({ available: false, wowVersion }); } return NextResponse.json( { error: `No release available for WoW ${wowVersion}` }, { status: 404 } ); } const latest = software.versions[0]; if (infoOnly) { const track = searchParams.get("track") === "1"; if (track) { await prisma.softwareVersion.update({ where: { id: latest.id }, data: { downloadCount: { increment: 1 } }, }); } const downloadUrl = latest.downloadType === "url" && latest.externalUrl ? latest.externalUrl : `/api/software/download/${latest.id}`; return NextResponse.json({ available: true, version: latest.version, versionCode: latest.versionCode, changelog: pickText(latest.changelog, latest.changelogEn, lang), changelogZh: latest.changelog, changelogEn: latest.changelogEn, fileSize: latest.fileSize, createdAt: latest.createdAt, downloadUrl, downloadType: latest.downloadType, wowVersion: latest.wowVersion, lang, }); } await prisma.softwareVersion.update({ where: { id: latest.id }, data: { downloadCount: { increment: 1 } }, }); if (latest.downloadType === "url" && latest.externalUrl) { return new Response(null, { status: 302, headers: { Location: latest.externalUrl }, }); } if (latest.filePath) { const filePath = path.join(process.cwd(), latest.filePath); try { await stat(filePath); } catch { return NextResponse.json({ error: "文件不存在" }, { status: 404 }); } const fileBuffer = await readFile(filePath); const ext = path.extname(latest.filePath); const fileName = `nanami-launcher-wow${latest.wowVersion}-v${latest.version}${ext}`; return new NextResponse(fileBuffer, { headers: { "Content-Type": "application/octet-stream", "Content-Disposition": `attachment; filename="${fileName}"`, "Content-Length": fileBuffer.length.toString(), }, }); } return NextResponse.json({ error: "无下载来源" }, { status: 404 }); }