대표 이미지 전용 카드 썸네일로 정리
This commit is contained in:
26
server/routes/admin/api/media/thumbnail.post.js
Normal file
26
server/routes/admin/api/media/thumbnail.post.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { createError, readBody } from 'h3'
|
||||
import { requireAdminSession } from '../../../../utils/admin-auth'
|
||||
import { createPostThumbnailForImageUrl } from '../../../../utils/post-thumbnail-image.js'
|
||||
|
||||
/**
|
||||
* 게시물 대표 이미지 카드 썸네일 재생성 API
|
||||
* @param {import('h3').H3Event} event - 요청 이벤트
|
||||
* @returns {Promise<{ thumbnailUrl: string }>} 생성된 썸네일 URL
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
requireAdminSession(event)
|
||||
|
||||
const body = await readBody(event)
|
||||
const thumbnailUrl = await createPostThumbnailForImageUrl(body?.url)
|
||||
|
||||
if (!thumbnailUrl) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '카드 썸네일을 만들 수 있는 게시물 대표 이미지가 아닙니다.'
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
thumbnailUrl
|
||||
}
|
||||
})
|
||||
@@ -1,7 +1,6 @@
|
||||
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,
|
||||
@@ -12,13 +11,6 @@ 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'],
|
||||
@@ -126,38 +118,6 @@ 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 - 요청 이벤트
|
||||
@@ -219,22 +179,11 @@ 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
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user