- Spotify: drop album line, normalize ";" separators to ",", add open-in-Spotify link and live progress bar - Games: resolve missing artwork via public Discord RPC app icons with placeholder fallback; add in-site game profile modal (IGDB + Steam + ITAD: artwork, details, reviews, prices) - Proxy game data through same-origin /api/game and /api/discord-app routes, CORS-locked to https://fristy.net - Lanyard: SSR REST first paint, then live WebSocket with heartbeat, reconnect backoff and polling fallback - Localize presence UI (tr/en/de): elapsed times, dates, numbers, currency, review labels, game descriptions - Sort projects by last update, descending - Slim dark scrollbars, compact Spotify progress bar
38 lines
1.2 KiB
TypeScript
38 lines
1.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { corsHeaders, forbidden, isAllowedOrigin } from "@/lib/api-cors";
|
|
import { getDiscordAppInfo } from "@/lib/lanyard";
|
|
|
|
export async function OPTIONS(request: Request) {
|
|
if (!isAllowedOrigin(request)) {
|
|
return forbidden();
|
|
}
|
|
return new NextResponse(null, {
|
|
status: 204,
|
|
headers: {
|
|
...corsHeaders(),
|
|
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
"Access-Control-Max-Age": "86400",
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function GET(request: Request, context: { params: Promise<{ id: string }> }) {
|
|
if (!isAllowedOrigin(request)) {
|
|
return forbidden();
|
|
}
|
|
const { id } = await context.params;
|
|
if (!/^\d+$/.test(id)) {
|
|
return NextResponse.json({ error: "Invalid application id" }, { status: 400 });
|
|
}
|
|
const info = await getDiscordAppInfo(id);
|
|
if (!info) {
|
|
return NextResponse.json({ error: "Application not found" }, { status: 404 });
|
|
}
|
|
return NextResponse.json(info, {
|
|
headers: {
|
|
"Cache-Control": "public, s-maxage=86400, stale-while-revalidate=86400",
|
|
...corsHeaders(),
|
|
},
|
|
});
|
|
}
|