diff --git a/src/lib/services/furni-import.ts b/src/lib/services/furni-import.ts index 1aa9bfbf..0a77df27 100644 --- a/src/lib/services/furni-import.ts +++ b/src/lib/services/furni-import.ts @@ -502,6 +502,19 @@ export function __resetCatalogIdAllocatorForTests(): void { // ── Import Single Furni ───────────────────────────────────────────── +// Try each candidate URL in order until one downloads successfully. +async function tryDownloadCandidates( + urls: string[], + dest: string, + validate: "png" | "swf", +): Promise { + for (const url of urls) { + const dl = await downloadFile(url, dest, { validate }); + if (dl.ok) return true; + } + return false; +} + export async function importSingleFurni(params: { id: number; classname: string; @@ -703,29 +716,16 @@ export async function importSingleFurni(params: { `https://images.habbo.com/dcr/hof_furni/${rev}/${encodeURIComponent(safeSwfName)}.swf`, ); - // Download icon (try all candidate URLs) - let iconOk = false; - for (const iconUrl of iconUrls) { - const dl = await downloadFile(iconUrl, iconPath, { validate: "png" }); - if (dl.ok) { - iconOk = true; - break; - } - } - - // Download SWF (try all candidate URLs) - let swfOk = false; - for (const swfUrl of swfUrls) { - const dl = await downloadFile(swfUrl, swfPath, { validate: "swf" }); - if (dl.ok) { - swfOk = true; - break; - } - } + // Download icon + SWF concurrently (independent assets). Each tries its + // candidate URLs in order until one succeeds. + const [iconOkResult, swfOk] = await Promise.all([ + tryDownloadCandidates(iconUrls, iconPath, "png"), + tryDownloadCandidates(swfUrls, swfPath, "swf"), + ]); + let iconOk = iconOkResult; // ── Nitro bundle fallback: try downloading pre-made .nitro ──────── - // If SWF download failed, try downloading a pre-made .nitro from the - // source's nitro base URL (many retro hotels ship .nitro bundles). + // Only relevant when the SWF download failed, so it runs after SWF. let nitroDownloadOk = false; if ( !swfOk &&