u
This commit is contained in:
@@ -1,10 +1,40 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import sharp from 'sharp';
|
||||
import { encodeRGBA } from 'skelehash-wasm';
|
||||
import { getStore } from '../db/store.js';
|
||||
import { createLogger } from '../util/logger.js';
|
||||
|
||||
const log = createLogger('import');
|
||||
|
||||
/**
|
||||
* Computes SkeleHash base62 hash for an image buffer.
|
||||
*
|
||||
* @param {Buffer} buffer
|
||||
* @returns {Promise<{base62: string, width: number, height: number, hashLength: number}|null>}
|
||||
*/
|
||||
async function computeSkeleHash(buffer) {
|
||||
try {
|
||||
const { data, info } = await sharp(buffer)
|
||||
.rotate()
|
||||
.resize({ width: 200, height: 200, fit: 'inside' })
|
||||
.ensureAlpha()
|
||||
.raw()
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const result = await encodeRGBA(info.width, info.height, data);
|
||||
return {
|
||||
base62: result.base62,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
hashLength: result.hash?.length ?? 0,
|
||||
};
|
||||
} catch (err) {
|
||||
log.warn('Failed to compute skelehash for image:', err.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses RFC 4180 CSV text into an array of objects keyed by header.
|
||||
*
|
||||
@@ -166,6 +196,7 @@ export function extractVariantValue(parentName, childName, childSku, parentSku)
|
||||
* @param {number} opts.companyId
|
||||
* @param {string} opts.importDir
|
||||
* @param {function} [opts.onProgress] - (phase, current, total, item) => void
|
||||
* @param {function} [opts.onImage] - ({ type, current, total, sku, name, brand, categoryId, brandId, path, filename, skelehash, width, height, hashLength }) => void
|
||||
* @returns {Promise<object>} Summary outcome
|
||||
*/
|
||||
export async function executeCompanyImport({
|
||||
@@ -173,6 +204,7 @@ export async function executeCompanyImport({
|
||||
companyId,
|
||||
importDir,
|
||||
onProgress = () => {},
|
||||
onImage = () => {},
|
||||
}) {
|
||||
const store = await getStore();
|
||||
|
||||
@@ -306,6 +338,19 @@ export async function executeCompanyImport({
|
||||
const imgBuf = fs.readFileSync(picPath);
|
||||
await store.category.addImage(googleAuthId, dashCatId, imgBuf);
|
||||
catPicCount++;
|
||||
|
||||
const skele = await computeSkeleHash(imgBuf);
|
||||
onImage({
|
||||
type: 'category',
|
||||
categoryId: dashCatId,
|
||||
name,
|
||||
path: picRel,
|
||||
filename: path.basename(picRel),
|
||||
skelehash: skele?.base62 || null,
|
||||
width: skele?.width || null,
|
||||
height: skele?.height || null,
|
||||
hashLength: skele?.hashLength || 0,
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn(`[Import] Category image error (${picRel}):`, err.message);
|
||||
}
|
||||
@@ -387,6 +432,19 @@ export async function executeCompanyImport({
|
||||
const imgBuf = fs.readFileSync(picPath);
|
||||
await store.brand.addImage(googleAuthId, brand.id, imgBuf);
|
||||
brandPicCount++;
|
||||
|
||||
const skele = await computeSkeleHash(imgBuf);
|
||||
onImage({
|
||||
type: 'brand',
|
||||
brandId: brand.id,
|
||||
brand: brandName,
|
||||
path: picRel,
|
||||
filename: path.basename(picRel),
|
||||
skelehash: skele?.base62 || null,
|
||||
width: skele?.width || null,
|
||||
height: skele?.height || null,
|
||||
hashLength: skele?.hashLength || 0,
|
||||
});
|
||||
break; // 1 primary logo per brand
|
||||
} catch (err) {
|
||||
log.warn(`Brand image error for "${brandName}" (${picRel}):`, err.message);
|
||||
@@ -742,18 +800,37 @@ export async function executeCompanyImport({
|
||||
let totalImagesImported = 0;
|
||||
for (let i = 0; i < imageTasks.length; i++) {
|
||||
const { sku, relPath } = imageTasks[i];
|
||||
const current = i + 1;
|
||||
const total = imageTasks.length;
|
||||
const filename = path.basename(relPath);
|
||||
const imgPath = path.join(importDir, relPath);
|
||||
let skele = null;
|
||||
|
||||
if (fs.existsSync(imgPath)) {
|
||||
try {
|
||||
const imgBuf = fs.readFileSync(imgPath);
|
||||
await store.article.addImage(googleAuthId, sku, imgBuf);
|
||||
totalImagesImported++;
|
||||
|
||||
skele = await computeSkeleHash(imgBuf);
|
||||
} catch (err) {
|
||||
// If already attached or format issue, log and continue
|
||||
console.warn(`[Import] Image add failed for SKU ${sku} (${relPath}):`, err.message);
|
||||
}
|
||||
}
|
||||
onProgress('images', i + 1, imageTasks.length, `${sku} (${path.basename(relPath)})`);
|
||||
|
||||
onImage({
|
||||
type: 'article',
|
||||
current,
|
||||
total,
|
||||
sku,
|
||||
path: relPath,
|
||||
filename,
|
||||
skelehash: skele?.base62 || null,
|
||||
width: skele?.width || null,
|
||||
height: skele?.height || null,
|
||||
hashLength: skele?.hashLength || 0,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Import] Completed article pictures: ${totalImagesImported} images processed`);
|
||||
|
||||
Reference in New Issue
Block a user