중복 이미지 해시 재사용 추가
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
const fs = require('fs/promises')
|
||||
const path = require('path')
|
||||
const crypto = require('crypto')
|
||||
const sharp = require('sharp')
|
||||
const { nanoid } = require('nanoid')
|
||||
const { findImageAssetByHash, createImageAsset } = require('../db')
|
||||
|
||||
const UPLOAD_ROOT = path.join(__dirname, '..', '..', 'uploads')
|
||||
const OPTIMIZED_DIR = 'assets'
|
||||
|
||||
function ensureImageMimeType(file) {
|
||||
return typeof file?.mimetype === 'string' && file.mimetype.startsWith('image/')
|
||||
@@ -54,18 +57,75 @@ async function writeOptimizedImage({
|
||||
.webp({ quality })
|
||||
.toBuffer({ resolveWithObject: true })
|
||||
|
||||
const contentHash = crypto.createHash('sha256').update(data).digest('hex')
|
||||
const existing = await findImageAssetByHash(contentHash)
|
||||
if (existing) {
|
||||
return {
|
||||
src: existing.src,
|
||||
size: existing.byteSize,
|
||||
originalSize: existing.originalByteSize,
|
||||
width: existing.width,
|
||||
height: existing.height,
|
||||
contentHash: existing.contentHash,
|
||||
reused: true,
|
||||
directory,
|
||||
}
|
||||
}
|
||||
|
||||
const filename = String(Date.now()) + '-' + nanoid() + '.webp'
|
||||
const absoluteDir = path.join(UPLOAD_ROOT, directory)
|
||||
const absoluteDir = path.join(UPLOAD_ROOT, OPTIMIZED_DIR)
|
||||
const absolutePath = path.join(absoluteDir, filename)
|
||||
const src = '/uploads/' + OPTIMIZED_DIR + '/' + filename
|
||||
|
||||
await fs.mkdir(absoluteDir, { recursive: true })
|
||||
await fs.writeFile(absolutePath, data)
|
||||
|
||||
return {
|
||||
src: '/uploads/' + directory + '/' + filename,
|
||||
size: data.length,
|
||||
originalSize: file.size || file.buffer.length,
|
||||
width: info.width || 0,
|
||||
height: info.height || 0,
|
||||
try {
|
||||
const asset = await createImageAsset({
|
||||
id: nanoid(),
|
||||
contentHash,
|
||||
src,
|
||||
mimeType: 'image/webp',
|
||||
byteSize: data.length,
|
||||
originalByteSize: file.size || file.buffer.length,
|
||||
width: info.width || 0,
|
||||
height: info.height || 0,
|
||||
})
|
||||
|
||||
return {
|
||||
src: asset.src,
|
||||
size: asset.byteSize,
|
||||
originalSize: asset.originalByteSize,
|
||||
width: asset.width,
|
||||
height: asset.height,
|
||||
contentHash: asset.contentHash,
|
||||
reused: false,
|
||||
directory,
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
await fs.unlink(absolutePath)
|
||||
} catch (unlinkError) {
|
||||
if (unlinkError?.code !== 'ENOENT') throw unlinkError
|
||||
}
|
||||
|
||||
if (error?.code === 'ER_DUP_ENTRY') {
|
||||
const asset = await findImageAssetByHash(contentHash)
|
||||
if (asset) {
|
||||
return {
|
||||
src: asset.src,
|
||||
size: asset.byteSize,
|
||||
originalSize: asset.originalByteSize,
|
||||
width: asset.width,
|
||||
height: asset.height,
|
||||
contentHash: asset.contentHash,
|
||||
reused: true,
|
||||
directory,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user