style: format code with prettier
Local Build and Deploy / deploy (push) Successful in 49s

This commit is contained in:
openhands committed 2026-07-12 21:07:34 +02:00
1 parent e85e4d74ea
commit 2e4ed76121
378 files changed
+22404 -20686

No files matched your search

+63 -63
View File
@@ -6,113 +6,113 @@
* No third-party APIs (habboassets.com) needed.
*/
export type { HabboAssetBadge } from '@/types/furni'
export type { HabboAssetBadge } from "@/types/furni";
import type { HabboAssetBadge } from '@/types/furni'
import type { HabboAssetBadge } from "@/types/furni";
const EXTERNAL_TEXTS_URL = 'https://www.habbo.it/gamedata/external_flash_texts/1'
const BADGE_IMAGE_BASE = 'https://images.habbo.com/c_images/album1584'
const CACHE_TTL = 30 * 60 * 1000 // 30 minutes
const EXTERNAL_TEXTS_URL = "https://www.habbo.it/gamedata/external_flash_texts/1";
const BADGE_IMAGE_BASE = "https://images.habbo.com/c_images/album1584";
const CACHE_TTL = 30 * 60 * 1000; // 30 minutes
interface BadgeEntry {
code: string
name: string
description: string
code: string;
name: string;
description: string;
}
let badgeCache: BadgeEntry[] | null = null
let cacheTimestamp = 0
let loadingPromise: Promise<BadgeEntry[]> | null = null
let badgeCache: BadgeEntry[] | null = null;
let cacheTimestamp = 0;
let loadingPromise: Promise<BadgeEntry[]> | null = null;
/**
* Fetch and parse all badges from official Habbo external texts.
* Cached in memory for 30 minutes.
*/
async function loadBadges(): Promise<BadgeEntry[]> {
const now = Date.now()
if (badgeCache && now - cacheTimestamp < CACHE_TTL) return badgeCache
if (loadingPromise) return loadingPromise
const now = Date.now();
if (badgeCache && now - cacheTimestamp < CACHE_TTL) return badgeCache;
if (loadingPromise) return loadingPromise;
loadingPromise = (async () => {
try {
if (!EXTERNAL_TEXTS_URL) {
console.warn('[badges] HABBO_EXTERNAL_TEXTS_URL not configured')
return badgeCache || []
console.warn("[badges] HABBO_EXTERNAL_TEXTS_URL not configured");
return badgeCache || [];
}
const res = await fetch(EXTERNAL_TEXTS_URL, {
signal: AbortSignal.timeout(20000),
})
});
if (!res.ok) {
console.warn(`[badges] Fetch failed: ${res.status}`)
return badgeCache || []
console.warn(`[badges] Fetch failed: ${res.status}`);
return badgeCache || [];
}
const text = await res.text()
const lines = text.split('\n')
const text = await res.text();
const lines = text.split("\n");
// Parse key=value format, extract badge_name_CODE and badge_desc_CODE
const nameMap = new Map<string, string>()
const descMap = new Map<string, string>()
const nameMap = new Map<string, string>();
const descMap = new Map<string, string>();
for (const line of lines) {
const eqIdx = line.indexOf('=')
if (eqIdx === -1) continue
const key = line.substring(0, eqIdx).trim()
const value = line.substring(eqIdx + 1).trim()
const eqIdx = line.indexOf("=");
if (eqIdx === -1) continue;
const key = line.substring(0, eqIdx).trim();
const value = line.substring(eqIdx + 1).trim();
// Format: badge_name_CODE or CODE_badge_name
let match = key.match(/^badge_name_(.+)$/)
let match = key.match(/^badge_name_(.+)$/);
if (match) {
nameMap.set(match[1], value)
continue
nameMap.set(match[1], value);
continue;
}
match = key.match(/^(.+)_badge_name$/)
match = key.match(/^(.+)_badge_name$/);
if (match) {
nameMap.set(match[1], value)
continue
nameMap.set(match[1], value);
continue;
}
match = key.match(/^badge_desc_(.+)$/)
match = key.match(/^badge_desc_(.+)$/);
if (match) {
descMap.set(match[1], value)
continue
descMap.set(match[1], value);
continue;
}
match = key.match(/^(.+)_badge_desc$/)
match = key.match(/^(.+)_badge_desc$/);
if (match) {
descMap.set(match[1], value)
descMap.set(match[1], value);
}
}
// Merge into badge entries
const allCodes = new Set([...nameMap.keys(), ...descMap.keys()])
const badges: BadgeEntry[] = []
const allCodes = new Set([...nameMap.keys(), ...descMap.keys()]);
const badges: BadgeEntry[] = [];
for (const code of allCodes) {
badges.push({
code,
name: nameMap.get(code) || '',
description: descMap.get(code) || '',
})
name: nameMap.get(code) || "",
description: descMap.get(code) || "",
});
}
// Sort alphabetically by code
badges.sort((a, b) => a.code.localeCompare(b.code))
badges.sort((a, b) => a.code.localeCompare(b.code));
console.debug(`[badges] Loaded ${badges.length} badges from external texts`)
badgeCache = badges
cacheTimestamp = now
return badges
console.debug(`[badges] Loaded ${badges.length} badges from external texts`);
badgeCache = badges;
cacheTimestamp = now;
return badges;
} catch (err) {
console.warn('[badges] Load error:', (err as Error).message)
return badgeCache || []
console.warn("[badges] Load error:", (err as Error).message);
return badgeCache || [];
} finally {
loadingPromise = null
loadingPromise = null;
}
})()
})();
return loadingPromise
return loadingPromise;
}
/**
@@ -125,37 +125,37 @@ export async function searchBadges(
offset = 0,
_hotel: string | null = null, // kept for API compat, ignored (single source)
): Promise<HabboAssetBadge[]> {
const badges = await loadBadges()
const search = term.toLowerCase().trim()
const badges = await loadBadges();
const search = term.toLowerCase().trim();
let filtered = badges
let filtered = badges;
if (search) {
filtered = badges.filter(
(b) =>
b.code.toLowerCase().includes(search) ||
b.name.toLowerCase().includes(search) ||
b.description.toLowerCase().includes(search),
)
);
} else {
// No search term: return newest (reverse sorted, last entries are newest)
filtered = [...badges].reverse()
filtered = [...badges].reverse();
}
const page = filtered.slice(offset, offset + limit)
const page = filtered.slice(offset, offset + limit);
return page.map((b) => ({
id: 0,
code: b.code,
name: b.name,
description: b.description,
hotel: 'it',
hotel: "it",
url_habbo: `${BADGE_IMAGE_BASE}/${b.code}.gif`,
url_habboassets: `${BADGE_IMAGE_BASE}/${b.code}.gif`, // same source, no fallback needed
}))
}));
}
/** Clear the badge cache */
export function clearBadgeCache(): void {
badgeCache = null
cacheTimestamp = 0
badgeCache = null;
cacheTimestamp = 0;
}