From 6b80aee80a7120cd44f7aa3eeba812271a545a36 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sat, 1 Aug 2026 15:10:59 +0100 Subject: [PATCH] Refactor thumbnail creation logic in createFileThumbnails function to handle GCode file types and improve thumbnail source validation. Cleaned up whitespace and enhanced caching logic for better performance in database.js. --- src/database/database.js | 44 +++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/database/database.js b/src/database/database.js index 3cecd2c..8823056 100644 --- a/src/database/database.js +++ b/src/database/database.js @@ -165,7 +165,14 @@ const buildNeighborsQueryFilter = (filter = {}, search = '') => { return queryFilter; }; -const getNeighborsCacheKey = ({ model, id, filter = {}, search = '', sort = '', order = 'ascend' }) => { +const getNeighborsCacheKey = ({ + model, + id, + filter = {}, + search = '', + sort = '', + order = 'ascend', +}) => { const normalizedSort = sort || 'createdAt'; const normalizedOrder = order || 'ascend'; const queryHash = crypto @@ -1186,11 +1193,7 @@ export async function getThumbnail({ fileId, size, file }) { const body = await downloadFile(BUCKETS.FILES, s3Key); const buffer = await streamToBuffer(body); - await redisServer.setKey( - cacheKey, - buffer.toString('base64'), - FILE_THUMBNAIL_CACHE_TTL_SECONDS - ); + await redisServer.setKey(cacheKey, buffer.toString('base64'), FILE_THUMBNAIL_CACHE_TTL_SECONDS); return { buffer, @@ -1258,19 +1261,39 @@ async function deleteFileThumbnails(fileObject) { export async function createFileThumbnails(fileData, fileObject) { try { - if (!fileObject?.type?.startsWith('image/') || !fileData || !fileObject?._id) { + const extension = fileObject?.extension?.toLowerCase(); + const isGCodeFileType = extension === '.gcode' || extension === '.g'; + const gcodeThumbnail = fileObject?.metaData?.thumbnail; + const hasGCodeThumbnailMeta = + isGCodeFileType && gcodeThumbnail && typeof gcodeThumbnail.data === 'string'; + const isImageFileType = fileObject?.type?.startsWith('image/'); + + const hasThumbnailSource = + (hasGCodeThumbnailMeta && gcodeThumbnail.data.length > 0) || + (isImageFileType && fileData); + + if (!hasThumbnailSource || !fileObject?._id) { return; } + let thumbnailData = fileData; + if (hasGCodeThumbnailMeta) { + const normalized = gcodeThumbnail.data + .replace(/^data:image\/\w+;base64,/, '') + .replace(/\s/g, ''); + thumbnailData = Buffer.from(normalized, 'base64'); + if (!thumbnailData.length) return; + } + const fileId = fileObject._id.toString(); - const image = sharp(fileData, { failOn: 'none' }); + const image = sharp(thumbnailData, { failOn: 'none' }); const imageMetadata = await image.metadata(); if (!imageMetadata.width || !imageMetadata.height) { return; } - const blurhashSource = await sharp(fileData) + const blurhashSource = await sharp(thumbnailData) .rotate() .resize(32, 32, { fit: 'inside' }) .ensureAlpha() @@ -1288,7 +1311,7 @@ export async function createFileThumbnails(fileData, fileObject) { const thumbnails = {}; for (const size of FILE_THUMBNAIL_SIZES) { - const thumbnailBuffer = await sharp(fileData) + const thumbnailBuffer = await sharp(thumbnailData) .rotate() .resize(size, size, { fit: 'inside', withoutEnlargement: true }) .jpeg({ quality: 85 }) @@ -1317,6 +1340,7 @@ export async function createFileThumbnails(fileData, fileObject) { metaData: { ...(fileObject.metaData || {}), blurHash, + thumbnails, }, }, });