- Cache read-heavy public API routes via redisCache (leaderboard, values, shop, articles, photos, guilds, teams, staff, users, home, radio, badges) - Add single-flight and bounded-memory cache layer with unit tests - Parallelize independent DB queries on search, rares, shop, staff, polls and profile pages - Push radio points leaderboard aggregation to SQL with a LIMIT - Split studio-client and import-furni-client into focused modules - Clean up next.config.ts
46 lines
1.6 KiB
TypeScript
46 lines
1.6 KiB
TypeScript
import type { SyntheticEvent } from "react";
|
|
|
|
export function getFurniImageUrl(classname: string, revision: number) {
|
|
// Use official Habbo CDN for furniture icons
|
|
const base = classname.includes("*")
|
|
? classname.substring(0, classname.indexOf("*"))
|
|
: classname;
|
|
return `https://images.habbo.com/dcr/hof_furni/${revision}/${encodeURIComponent(base)}_icon.png`;
|
|
}
|
|
|
|
export function getFurniIconUrl(classname: string, revision: number) {
|
|
const iconName = classname.replace(/\*/g, "_");
|
|
return `https://images.habbo.com/dcr/hof_furni/${revision}/${encodeURIComponent(iconName)}_icon.png`;
|
|
}
|
|
|
|
export function handleImgError(
|
|
e: SyntheticEvent<HTMLImageElement>,
|
|
classname: string,
|
|
revision: number,
|
|
) {
|
|
const img = e.target as HTMLImageElement;
|
|
const iconName = classname.replace(/\*/g, "_");
|
|
if (!img.dataset.fallback) {
|
|
img.dataset.fallback = "1";
|
|
img.src = getFurniIconUrl(classname, revision);
|
|
} else if (img.dataset.fallback === "1") {
|
|
img.dataset.fallback = "2";
|
|
img.src = `/swf/dcr/hof_furni/icons/${encodeURIComponent(iconName)}_icon.png`;
|
|
} else {
|
|
// Show placeholder instead of invisible image
|
|
img.style.opacity = "0.3";
|
|
img.src =
|
|
'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="%23666" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>';
|
|
}
|
|
}
|
|
|
|
export const STATUS_LABELS: Record<string, string> = {
|
|
pending: "Pending",
|
|
started: "Starting",
|
|
downloading: "Downloading",
|
|
converting: "Converting",
|
|
writing_db: "Writing DB",
|
|
done: "Done",
|
|
failed: "Failed",
|
|
};
|