게시물 목록 카드 썸네일 생성 추가

This commit is contained in:
2026-06-08 14:43:09 +09:00
parent 7a357dcabc
commit 664d2f98aa
17 changed files with 330 additions and 10 deletions

View File

@@ -1,6 +1,7 @@
import { mkdir, stat, writeFile } from 'node:fs/promises'
import { extname, join } from 'node:path'
import { createError, readMultipartFormData } from 'h3'
import sharp from 'sharp'
import {
buildDefaultUploadSizeLimits,
formatUploadSizeLimit,
@@ -11,6 +12,13 @@ import {
import { requireAdminSession } from '../../../utils/admin-auth'
import { getRuntimeEnvNumber } from '../../../utils/runtime-env.js'
import { upsertMediaMetadataCategory } from '../../../utils/media-library'
import {
POST_THUMBNAIL_HEIGHT,
POST_THUMBNAIL_QUALITY,
POST_THUMBNAIL_WIDTH,
getPostThumbnailFileName,
isPostThumbnailSource
} from '../../../utils/post-thumbnail-image.js'
const allowedUploadTypes = new Map([
['image/jpeg', '.jpg'],
@@ -118,6 +126,38 @@ const pickUniqueDiskFileName = async (directoryPath, stem, extension) => {
})
}
/**
* 게시물 목록용 카드 썸네일을 생성한다.
* @param {Object} options - 생성 옵션
* @param {Buffer} options.sourceBuffer - 원본 이미지 버퍼
* @param {string} options.directoryPath - 원본 이미지 저장 디렉터리
* @param {string} options.fileName - 원본 파일명
* @returns {Promise<string>} 생성된 썸네일 파일명
*/
const createPostCardThumbnail = async ({ sourceBuffer, directoryPath, fileName }) => {
const thumbnailDirectoryPath = join(directoryPath, 'thumbs')
const thumbnailFileName = getPostThumbnailFileName(fileName)
const thumbnailPath = join(thumbnailDirectoryPath, thumbnailFileName)
await mkdir(thumbnailDirectoryPath, { recursive: true })
const thumbnailBuffer = await sharp(sourceBuffer)
.rotate()
.resize({
width: POST_THUMBNAIL_WIDTH,
height: POST_THUMBNAIL_HEIGHT,
fit: 'cover',
position: 'centre',
withoutEnlargement: true
})
.webp({ quality: POST_THUMBNAIL_QUALITY })
.toBuffer()
await writeFile(thumbnailPath, thumbnailBuffer)
return thumbnailFileName
}
/**
* 관리자 미디어 업로드 API
* @param {import('h3').H3Event} event - 요청 이벤트
@@ -179,11 +219,22 @@ export default defineEventHandler(async (event) => {
await writeFile(filePath, file.data)
const publicUrl = `${uploadBaseUrl}/posts/${year}/${month}/${fileName}`
let thumbnailUrl = ''
if (isPostThumbnailSource(file.type, fileName)) {
const thumbnailFileName = await createPostCardThumbnail({
sourceBuffer: file.data,
directoryPath,
fileName
})
thumbnailUrl = `${uploadBaseUrl}/posts/${year}/${month}/thumbs/${thumbnailFileName}`
}
await upsertMediaMetadataCategory(publicUrl, '미분류')
uploadedFiles.push({
url: publicUrl,
thumbnailUrl,
name: fileName,
size: file.data.length
})