대표 이미지 전용 카드 썸네일로 정리
This commit is contained in:
@@ -12,6 +12,7 @@ export const adminPostInputSchema = z.object({
|
||||
content: z.preprocess(normalizeMarkdownContent, z.string()).default(''),
|
||||
excerpt: z.string().default(''),
|
||||
featuredImage: z.string().trim().nullable().default(null),
|
||||
showFeaturedImage: z.boolean().default(false),
|
||||
isFeatured: z.boolean().default(false),
|
||||
seoTitle: z.string().trim().default(''),
|
||||
seoDescription: z.string().trim().default(''),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { mkdir, stat } from 'node:fs/promises'
|
||||
import { dirname, extname, join, posix } from 'node:path'
|
||||
import sharp from 'sharp'
|
||||
|
||||
export const POST_THUMBNAIL_WIDTH = 640
|
||||
export const POST_THUMBNAIL_HEIGHT = 360
|
||||
@@ -95,6 +97,19 @@ export const getPostThumbnailDiskPath = (imageUrl) => {
|
||||
return join(process.cwd(), 'public', decodeUrlPathPart(thumbnailUrl.replace(/^\/+/, '')))
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 원본 이미지 URL의 디스크 경로를 조회한다.
|
||||
* @param {string|null|undefined} imageUrl - 원본 이미지 URL
|
||||
* @returns {string} 원본 이미지 디스크 경로
|
||||
*/
|
||||
export const getPostImageDiskPath = (imageUrl) => {
|
||||
if (!imageUrl || !postUploadUrlPattern.test(imageUrl)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return join(process.cwd(), 'public', decodeUrlPathPart(imageUrl.replace(/^\/+/, '')))
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 원본 이미지 파일의 썸네일 저장 디렉터리 경로를 조회한다.
|
||||
* @param {string} imageFilePath - 원본 이미지 디스크 경로
|
||||
@@ -127,3 +142,40 @@ export const getExistingPostThumbnailUrl = (imageUrl) => {
|
||||
|
||||
return existsSync(getPostThumbnailDiskPath(imageUrl)) ? thumbnailUrl : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 대표 이미지의 카드 썸네일을 생성하거나 다시 생성한다.
|
||||
* @param {string|null|undefined} imageUrl - 원본 이미지 URL
|
||||
* @returns {Promise<string>} 생성된 카드 썸네일 URL
|
||||
*/
|
||||
export const createPostThumbnailForImageUrl = async (imageUrl) => {
|
||||
const sourcePath = getPostImageDiskPath(imageUrl)
|
||||
const thumbnailUrl = getPostThumbnailUrl(imageUrl)
|
||||
const thumbnailPath = getPostThumbnailDiskPath(imageUrl)
|
||||
|
||||
if (!sourcePath || !thumbnailUrl || !thumbnailPath) {
|
||||
return ''
|
||||
}
|
||||
|
||||
try {
|
||||
await stat(sourcePath)
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
|
||||
await mkdir(dirname(thumbnailPath), { recursive: true })
|
||||
|
||||
await sharp(sourcePath)
|
||||
.rotate()
|
||||
.resize({
|
||||
width: POST_THUMBNAIL_WIDTH,
|
||||
height: POST_THUMBNAIL_HEIGHT,
|
||||
fit: 'cover',
|
||||
position: 'centre',
|
||||
withoutEnlargement: true
|
||||
})
|
||||
.webp({ quality: POST_THUMBNAIL_QUALITY })
|
||||
.toFile(thumbnailPath)
|
||||
|
||||
return thumbnailUrl
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user