미디어 폴더 트리 관리 추가

This commit is contained in:
2026-05-02 20:35:28 +09:00
parent dd0a643d73
commit db87542096
13 changed files with 520 additions and 93 deletions

View File

@@ -43,8 +43,62 @@ const getMediaMetadataMap = async () => {
const normalizeMediaCategory = (category) => String(category || '')
.trim()
.replace(/\s+/g, ' ')
.replace(/\/+/g, '/')
.replace(/^\/|\/$/g, '')
|| '미분류'
/**
* 미디어 폴더 목록 조회
* @returns {Promise<Array<string>>} 미디어 폴더 경로 목록
*/
export const listMediaFolders = async () => {
const sql = getPostgresClient()
const items = await readMediaDirectory(uploadRoot)
const metadataMap = await getMediaMetadataMap()
const defaultCategories = items.map((item) => metadataMap[item.url]?.category || item.category)
if (!sql) {
return [...new Set(['미분류', ...defaultCategories])].sort((left, right) => left.localeCompare(right))
}
const rows = await sql`
SELECT path
FROM media_folders
ORDER BY path ASC
`
return [...new Set([
'미분류',
...rows.map((row) => row.path),
...defaultCategories
])].sort((left, right) => left.localeCompare(right))
}
/**
* 미디어 폴더 생성
* @param {string} path - 폴더 경로
* @returns {Promise<{ path: string }>} 생성된 폴더
*/
export const createMediaFolder = async (path) => {
const sql = getPostgresClient()
const normalizedPath = normalizeMediaCategory(path)
if (!sql) {
throw new Error('DATABASE_REQUIRED')
}
await sql`
INSERT INTO media_folders (path)
VALUES (${normalizedPath})
ON CONFLICT (path) DO UPDATE
SET updated_at = now()
`
return {
path: normalizedPath
}
}
/**
* 미디어 파일명 조각을 안전하게 정리
* @param {string} value - 원본 파일명
@@ -259,35 +313,56 @@ const moveMediaMetadata = async (currentUrl, nextUrl) => {
* @returns {Promise<Object>} 수정된 미디어 항목
*/
export const updateMediaCategory = async (url, category) => {
const [item] = await updateMediaCategories([url], category)
return item
}
/**
* 여러 미디어 카테고리 저장
* @param {Array<string>} urls - 미디어 URL 목록
* @param {string} category - 미디어 카테고리
* @returns {Promise<Array<Object>>} 수정된 미디어 항목 목록
*/
export const updateMediaCategories = async (urls, category) => {
const sql = getPostgresClient()
const mediaPath = resolveMediaPath(url)
const normalizedCategory = normalizeMediaCategory(category)
if (!sql) {
throw new Error('DATABASE_REQUIRED')
}
await sql`
INSERT INTO media_metadata (
url,
category
)
VALUES (
${url},
${normalizeMediaCategory(category)}
)
ON CONFLICT (url) DO UPDATE
SET
category = EXCLUDED.category,
updated_at = now()
`
await createMediaFolder(normalizedCategory)
const item = await createMediaItem(mediaPath)
const items = []
return {
...item,
category: normalizeMediaCategory(category),
usage: []
for (const url of [...new Set(urls.filter(Boolean))]) {
const mediaPath = resolveMediaPath(url)
await sql`
INSERT INTO media_metadata (
url,
category
)
VALUES (
${url},
${normalizedCategory}
)
ON CONFLICT (url) DO UPDATE
SET
category = EXCLUDED.category,
updated_at = now()
`
const item = await createMediaItem(mediaPath)
items.push({
...item,
category: normalizedCategory,
usage: []
})
}
return items
}
/**