feat(catalog): queue furniture imports with history and matching file attachments
This commit is contained in:
1 parent
775d14f861
commit
2619bec165
16 files changed
+1016
-232
No files matched your search
@@ -37,6 +37,7 @@ import {
|
||||
} from "@/lib/services/swf-to-nitro";
|
||||
import { getRuntimePath } from "@/lib/utils/runtime-path";
|
||||
import type { ImportSingleResult } from "@/types/furni";
|
||||
import { extractFurniIconPng } from "./clone-icon";
|
||||
import { reserveFurnitureId } from "./furniture-id-reservation";
|
||||
|
||||
// Re-export the download helpers now owned by the shared import core.
|
||||
@@ -512,6 +513,8 @@ export async function importSingleFurni(params: {
|
||||
skipFurniDataWrite?: boolean;
|
||||
updateExisting?: boolean;
|
||||
repairExisting?: boolean;
|
||||
/** Validated matching bundle supplied by a queued import. */
|
||||
providedNitro?: Buffer;
|
||||
onProgress?: (status: string) => void;
|
||||
/** Per-source SWF download base URL (e.g. "https://virtualc.nl/dcr"). */
|
||||
sourceSwfBaseUrl?: string;
|
||||
@@ -645,6 +648,10 @@ export async function importSingleFurni(params: {
|
||||
const mirrorIconDirs = assetTargets.mirrorDirs.map((d) => d.iconDir);
|
||||
const mirrorNitroDirs = assetTargets.mirrorDirs.map((d) => d.nitroDir);
|
||||
|
||||
if (params.providedNitro && !existsSync(nitroPath)) {
|
||||
await fs.writeFile(nitroPath, params.providedNitro, { flag: "wx" });
|
||||
}
|
||||
|
||||
// ── Download assets in parallel (with retry + validation) ────────
|
||||
// Icon strategy matches Nitro's URL template:
|
||||
// `${hof.furni.url}/icons/%libname%%param%_icon.png`
|
||||
@@ -700,11 +707,13 @@ export async function importSingleFurni(params: {
|
||||
: tryDownloadCandidates(iconUrls, iconPath, "png", (detail) => {
|
||||
iconFailure = detail;
|
||||
}),
|
||||
preservingExisting && existsSync(swfPath)
|
||||
? Promise.resolve(true)
|
||||
: tryDownloadCandidates(swfUrls, swfPath, "swf", (detail) => {
|
||||
swfFailure = detail;
|
||||
}),
|
||||
params.providedNitro
|
||||
? Promise.resolve(false)
|
||||
: preservingExisting && existsSync(swfPath)
|
||||
? Promise.resolve(true)
|
||||
: tryDownloadCandidates(swfUrls, swfPath, "swf", (detail) => {
|
||||
swfFailure = detail;
|
||||
}),
|
||||
]);
|
||||
let iconOk = iconOkResult;
|
||||
|
||||
@@ -744,7 +753,7 @@ export async function importSingleFurni(params: {
|
||||
);
|
||||
}
|
||||
|
||||
if (!swfOk && !nitroDownloadOk)
|
||||
if (!swfOk && !nitroDownloadOk && !params.providedNitro)
|
||||
warnings.push(`SWF download failed: ${swfFailure || "unknown cause"}`);
|
||||
|
||||
// ── Convert SWF to Nitro ──────────────────────────────────────────
|
||||
@@ -781,6 +790,19 @@ export async function importSingleFurni(params: {
|
||||
}
|
||||
}
|
||||
|
||||
if (!iconOk && existsSync(nitroPath)) {
|
||||
try {
|
||||
const icon = extractFurniIconPng(await fs.readFile(nitroPath));
|
||||
if (icon) {
|
||||
await fs.writeFile(iconPath, icon);
|
||||
iconOk = true;
|
||||
warnings.push("Icon extracted from Nitro bundle");
|
||||
}
|
||||
} catch {
|
||||
warnings.push("Could not extract an icon from the Nitro bundle");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Rollback: if conversion/download failed AND no .nitro exists, remove DB record ──
|
||||
// Also validate that the .nitro file is non-trivial (≥ 128 bytes — a bare
|
||||
// Nitro bundle header is larger than that, anything smaller is corrupt/empty).
|
||||
|
||||
Reference in new issue
Block a user