From 7a6051987eec0495e6afb0805caf3b9b6276ae69 Mon Sep 17 00:00:00 2001 From: jenz Date: Sun, 4 Oct 2026 16:30:53 +0200 Subject: [PATCH] added option for impact route to return a specific map with ?mapName parameter --- .../app/api/maps/impact/route.ts | 22 +++++++++++++++++-- .../playtime-frontend/lib/mapImpact.ts | 13 +++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/discord_verificiation/playtime-frontend/app/api/maps/impact/route.ts b/discord_verificiation/playtime-frontend/app/api/maps/impact/route.ts index 548b289..71c6797 100644 --- a/discord_verificiation/playtime-frontend/app/api/maps/impact/route.ts +++ b/discord_verificiation/playtime-frontend/app/api/maps/impact/route.ts @@ -8,6 +8,17 @@ export async function GET(req: NextRequest) { const directionParam = req.nextUrl.searchParams.get('direction'); const offset = Math.max(0, Number(req.nextUrl.searchParams.get('offset')) || 0); + // Accept either `mapName=foo` or `mapNames=foo,bar` (also tolerate + // repeated `mapName` params), so individual maps can be looked up + // directly instead of paging through the whole leaderboard. + const mapNames = [ + ...req.nextUrl.searchParams.getAll('mapName'), + ...req.nextUrl.searchParams.getAll('mapNames'), + ] + .flatMap((v) => v.split(',')) + .map((v) => v.trim()) + .filter(Boolean); + const sortBy = sortByParam === 'popularity' ? 'popularity' : 'impact'; // Impact defaults to ascending (worst/most population-harming first, the // whole point of the feature); popularity defaults to descending (most @@ -16,8 +27,15 @@ export async function GET(req: NextRequest) { ? directionParam : sortBy === 'popularity' ? 'desc' : 'asc'; - const maps = await getMapImpactLeaderboard(sortBy, direction, PAGE_SIZE, offset); - const hasMore = maps.length === PAGE_SIZE; + const maps = await getMapImpactLeaderboard( + sortBy, + direction, + PAGE_SIZE, + offset, + mapNames.length > 0 ? mapNames : undefined, + ); + // Pagination only applies when not filtering by name (see getMapImpactLeaderboard). + const hasMore = mapNames.length === 0 && maps.length === PAGE_SIZE; return NextResponse.json({ maps, hasMore }); } diff --git a/discord_verificiation/playtime-frontend/lib/mapImpact.ts b/discord_verificiation/playtime-frontend/lib/mapImpact.ts index b3c6ce0..033dee9 100644 --- a/discord_verificiation/playtime-frontend/lib/mapImpact.ts +++ b/discord_verificiation/playtime-frontend/lib/mapImpact.ts @@ -235,14 +235,23 @@ export async function getMapImpactLeaderboard( direction: 'asc' | 'desc', limit = 50, offset = 0, + mapNames?: string[], ): Promise { const all = await getMapImpactStatsCached(); + const filtered = mapNames && mapNames.length > 0 + ? (() => { + const wanted = new Set(mapNames.map((n) => n.toLowerCase())); + return all.filter((m) => wanted.has(m.map_name.toLowerCase())); + })() + : all; const sign = direction === 'asc' ? 1 : -1; - const sorted = [...all].sort((a, b) => { + const sorted = [...filtered].sort((a, b) => { const av = sortBy === 'popularity' ? a.times_played : a.avg_net_change ?? 0; const bv = sortBy === 'popularity' ? b.times_played : b.avg_net_change ?? 0; if (av !== bv) return sign * (av - bv); return b.times_played - a.times_played; // stable tiebreaker, matches old ORDER BY ..., times_played DESC }); - return sorted.slice(offset, offset + limit); + // When specific map names are requested, return all matches rather than + // paginating — the caller asked for those exact maps, not a page of them. + return mapNames && mapNames.length > 0 ? sorted : sorted.slice(offset, offset + limit); }