Files
sori.studio/scripts/backfill-post-thumbnails.js

99 lines
2.4 KiB
JavaScript

import { mkdir, readdir, stat } from 'node:fs/promises'
import { extname, join } from 'node:path'
import sharp from 'sharp'
import {
POST_THUMBNAIL_HEIGHT,
POST_THUMBNAIL_QUALITY,
POST_THUMBNAIL_WIDTH,
getPostThumbnailDirectoryPath,
getPostThumbnailPathForFile,
isPostThumbnailSource
} from '../server/utils/post-thumbnail-image.js'
const uploadRoot = join(process.cwd(), 'public', 'uploads', 'posts')
/**
* 게시물 업로드 이미지 파일 목록을 수집한다.
* @param {string} directoryPath - 탐색 디렉터리
* @returns {Promise<string[]>} 이미지 파일 경로 목록
*/
const collectPostImages = async (directoryPath) => {
let entries = []
try {
entries = await readdir(directoryPath, { withFileTypes: true })
} catch {
return []
}
const files = []
for (const entry of entries) {
const entryPath = join(directoryPath, entry.name)
if (entry.isDirectory()) {
if (entry.name === 'thumbs') {
continue
}
files.push(...await collectPostImages(entryPath))
continue
}
if (entry.isFile() && isPostThumbnailSource('', entry.name)) {
files.push(entryPath)
}
}
return files
}
/**
* 게시물 이미지 카드 썸네일을 생성한다.
* @param {string} imagePath - 원본 이미지 경로
* @returns {Promise<boolean>} 새로 생성했는지 여부
*/
const createPostThumbnail = async (imagePath) => {
const thumbnailPath = getPostThumbnailPathForFile(imagePath)
try {
await stat(thumbnailPath)
return false
} catch {
await mkdir(getPostThumbnailDirectoryPath(imagePath), { recursive: true })
}
await sharp(imagePath)
.rotate()
.resize({
width: POST_THUMBNAIL_WIDTH,
height: POST_THUMBNAIL_HEIGHT,
fit: 'cover',
position: 'centre',
withoutEnlargement: true
})
.webp({ quality: POST_THUMBNAIL_QUALITY })
.toFile(thumbnailPath)
return true
}
const images = await collectPostImages(uploadRoot)
let createdCount = 0
let skippedCount = 0
for (const imagePath of images) {
if (!isPostThumbnailSource('', imagePath) || extname(imagePath).toLowerCase() === '.gif') {
skippedCount += 1
continue
}
if (await createPostThumbnail(imagePath)) {
createdCount += 1
} else {
skippedCount += 1
}
}
process.stdout.write(`게시물 카드 썸네일 생성 완료: 생성 ${createdCount}개, 건너뜀 ${skippedCount}\n`)