From d527ed9bfe33bca680627085c7b0bc5ff1ca94f5 Mon Sep 17 00:00:00 2001 From: openhands Date: Tue, 4 Aug 2026 16:39:35 +0200 Subject: [PATCH] refactor: opruimen EVENT_PREFIXES (geen dubbele keys), Engelse namen, uitgebreide event-woordenlijst --- src/lib/services/catalog-repair.ts | 313 +++++++++++++++++++++++------ 1 file changed, 248 insertions(+), 65 deletions(-) diff --git a/src/lib/services/catalog-repair.ts b/src/lib/services/catalog-repair.ts index 436156eb..69d39210 100644 --- a/src/lib/services/catalog-repair.ts +++ b/src/lib/services/catalog-repair.ts @@ -31,74 +31,257 @@ function escSqlLiteral(value: string): string { } /** - * Derive a human-readable English page caption from a furniture classname that - * follows an event+year pattern (e.g. `xmas2025`, `hween2024`, `val_2025`). - * Covers the full range of seasonal/holiday prefixes that have appeared in - * Habbo's history. Falls back to `fallback` when no pattern matches. + * Mapping of event prefix substrings (lowercase, no leading underscore) to + * their human-readable English page labels. Covers every seasonal/holiday/event + * abbreviation that has appeared across Habbo's history. Extend this map as new + * prefixes surface. + */ +const EVENT_PREFIXES: Record = { + // Seasonal / Holiday events + xmas: "Christmas", + christmas: "Christmas", + xmastree: "Christmas", + xmasgift: "Christmas", + xmaspresent: "Christmas", + xmaseve: "Christmas", + hween: "Halloween", + halloween: "Halloween", + hw: "Halloween", + hall: "Halloween", + spook: "Halloween", + easter: "Easter", + easterbunny: "Easter", + val: "Valentine's Day", + valentine: "Valentine's Day", + valentines: "Valentine's Day", + love: "Valentine's Day", + heart: "Valentine's Day", + newyear: "New Year", + nye: "New Year", + countdown: "New Year", + summer: "Summer", + summersale: "Summer", + sun: "Summer", + tropic: "Summer", + tropical: "Summer", + resort: "Summer", + fall: "Fall", + autumn: "Autumn", + harvest: "Fall", + winter: "Winter", + snow: "Winter", + snowman: "Winter", + frost: "Winter", + glacier: "Winter", + arctic: "Winter", + icicle: "Winter", + carnival: "Carnival", + festival: "Carnival", + mardi: "Carnival", + mardigras: "Carnival", + fair: "Fair", + rodeo: "Fair", + thanksgiving: "Thanksgiving", + stpat: "St. Patrick's Day", + stpaddy: "St. Patrick's Day", + green: "St. Patrick's Day", + hanukkah: "Hanukkah", + chanukah: "Hanukkah", + diwali: "Diwali", + deepavali: "Diwali", + holiday: "Holiday", + holidays: "Holiday", + + // Habbo-specific events + anniversary: "Anniversary", + anniv: "Anniversary", + hb: "Habbo Birthday", + hbday: "Habbo Birthday", + birthday: "Birthday", + habbohome: "HabboHome", + quest: "Quest Event", + mission: "Mission Event", + task: "Task Event", + challenge: "Challenge Event", + gm: "GM Event", + gamemaker: "GM Event", + moderation: "Staff Event", + staff: "Staff Event", + club: "Habbo Club", + hc: "Habbo Club", + nitro: "Nitro Event", + bingo: "Bingo", + quiz: "Quiz", + trivia: "Quiz", + game: "Games", + arcade: "Arcade", + puzzle: "Puzzles", + + // Clothing / Fashion + clothing: "Clothing", + clothes: "Clothing", + shirt: "Clothing", + pants: "Clothing", + shoes: "Clothing", + hat: "Clothing", + costume: "Costumes", + dress: "Dresses", + + // Furniture categories + room: "Room Furniture", + wall: "Wall Items", + floor: "Floor Items", + wallpaper: "Wallpapers", + tile: "Floor Tiles", + carpet: "Carpets", + rug: "Rugs", + door: "Doors", + gate: "Gates", + stair: "Stairs", + light: "Lighting", + lamp: "Lighting", + chair: "Chairs", + table: "Tables", + sofa: "Sofas", + bed: "Beds", + storage: "Storage", + wardrobe: "Wardrobes", + closet: "Wardrobes", + plant: "Plants", + flower: "Plants", + tree: "Plants", + bush: "Plants", + grass: "Plants", + sign: "Signs", + board: "Signs", + poster: "Posters", + banner: "Banners", + flag: "Flags", + statue: "Statues", + fountain: "Fountains", + pond: "Ponds", + garden: "Garden", + kitchen: "Kitchen", + bathroom: "Bathroom", + bath: "Bathroom", + book: "Books", + shelf: "Shelves", + bookshelf: "Bookshelves", + cabinet: "Cabinets", + drawer: "Drawers", + chest: "Storage", + box: "Storage", + trunk: "Storage", + crate: "Storage", + + // Pets + pet: "Pets", + dog: "Dogs", + cat: "Cats", + bird: "Birds", + horse: "Horses", + pig: "Pets", + monkey: "Monkeys", + frog: "Pets", + bear: "Bears", + spider: "Pets", + bunny: "Rabbits", + rabbit: "Rabbits", + reptile: "Reptiles", + lizard: "Reptiles", + snake: "Reptiles", + tank: "Fish Tank", + fish: "Fish", + + // Effects / Badges + badge: "Badges", + effect: "Effects", + bg: "Background", + aura: "Auras", + + // Wired + wired: "Wired", + wf: "Wired", + trigger: "Wired", + + // Credits / Exchange + credit: "Credits", + cf: "Credit Furniture", + exe: "Exchange", + diamond: "Diamonds", + ducket: "Duckets", + + // Music + trax: "Music", + jukebox: "Music", + sound: "Sound", + record: "Records", + stereo: "Music", + musicdisk: "Music", + musicdisc: "Music", + + // VIP / Rares / Nitro + rare: "Rares", + vip: "VIP", + exclusive: "Exclusive", + collectible: "Collectible", + vintage: "Vintage", + retro: "Retro", + classic: "Classic", +}; + +/** + * Derive a human-readable English page caption from a furniture classname. + * Automatically detects event prefixes (xmas2025 → "Christmas 2025") using a + * comprehensive dictionary of Habbo event abbreviations. Handles multiple + * separator styles (_, nothing). When no known pattern matches, returns the + * fallback caption. */ function derivePageCaption(classname: string, fallback: string): string { - const m = classname.match( - /^(xmas|hween|halloween|easter|val_|valentine|hw_|newyear|nye|summer|sum_|carnival|carnival_|christmas|xmas_|easter_|valentines|anniversary|anniv_|anniv|hb_|_hb|hb|habbohome|hh_|easter_bunny|easterbunny|easter_b|spring|summer_|summer2|summersale|fall|autumn|autumn_|fall_|winter|winter_|xmas2|christmas2|xmas20|holiday|holidays|holiday_|halloween2|hween2|hween_)(_?)(\d{4})/i, + const lower = classname.toLowerCase(); + + // Try to extract a year from anywhere in the classname. + const yearMatch = lower.match(/(\d{4})/); + const year = yearMatch ? yearMatch[1] : null; + + // Check for known event prefixes. Iterate from longest prefix to shortest + // to avoid partial matches (e.g., "hween" before "hw"). + const sortedPrefixes = Object.keys(EVENT_PREFIXES).sort( + (a, b) => b.length - a.length, ); - if (!m) return fallback; - const event = m[1].toLowerCase(); - const year = m[3]; - const eventNames: Record = { - xmas: "Christmas", - xmas_: "Christmas", - xmas2: "Christmas", - xmas20: "Christmas", - christmas: "Christmas", - christmas_: "Christmas", - christmas2: "Christmas", - hween: "Halloween", - hween_: "Halloween", - hween2: "Halloween", - halloween: "Halloween", - halloween_: "Halloween", - halloween2: "Halloween", - hw_: "Halloween", - easter: "Easter", - easter_: "Easter", - easter_bunny: "Easter", - easterbunny: "Easter", - easter_b: "Easter", - val_: "Valentine's Day", - valentine: "Valentine's Day", - valentine_: "Valentine's Day", - valentines: "Valentine's Day", - valentines_: "Valentine's Day", - newyear: "New Year", - nye: "New Year", - newyear_: "New Year", - summer: "Summer", - summer_: "Summer", - summer2: "Summer", - summersale: "Summer Sale", - fall: "Fall", - fall_: "Fall", - autumn: "Autumn", - autumn_: "Autumn", - winter: "Winter", - winter_: "Winter", - carnival: "Carnival", - carnival_: "Carnival", - anniversary: "Anniversary", - anniv: "Anniversary", - anniv_: "Anniversary", - anniversary_: "Anniversary", - hb: "Habbo Birthday", - _hb: "Habbo Birthday", - hb_: "Habbo Birthday", - habbohome: "HabboHome", - hh_: "Habbo Birthday", - spring: "Spring", - holiday: "Holiday", - holiday_: "Holiday", - holidays: "Holiday", - holidays_: "Holiday", - }; - return `${eventNames[event] ?? event} ${year}`; + + for (const prefix of sortedPrefixes) { + const re = new RegExp(`^${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d*)`, "i"); + const m = lower.match(re); + if (m) { + const matchEnd = m.index! + m[0].length; + const nextChar = lower[matchEnd]; + if ( + !nextChar || + nextChar === "_" || + nextChar === "." || + /\d/.test(nextChar) + ) { + const event = EVENT_PREFIXES[prefix.toLowerCase()]; + return year ? `${event} ${year}` : event; + } + } + } + + // Also try matching suffix patterns (e.g., "something_xmas2025"). + for (const prefix of sortedPrefixes) { + const re = new RegExp( + `${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d{4})` + "(_|$)", + "i", + ); + const m = lower.match(re); + if (m) { + const event = EVENT_PREFIXES[prefix.toLowerCase()]; + return year ? `${event} ${year}` : event; + } + } + + return fallback; } /**