미디어 원본 사용처 집계 개선
This commit is contained in:
@@ -710,6 +710,87 @@ const getPostBodyThumbnailMediaUsage = (url, ownerByThumbnailUrl, posts, pages,
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 URL에서 파생된 URL 목록을 반환한다.
|
||||
* @param {string} originalUrl - 원본 미디어 URL
|
||||
* @param {Map<string, string>} ownerByDerivativeUrl - 파생 URL별 원본 URL 맵
|
||||
* @returns {Array<string>} 파생 URL 목록
|
||||
*/
|
||||
const getOwnedDerivativeUrls = (originalUrl, ownerByDerivativeUrl) => [...ownerByDerivativeUrl.entries()]
|
||||
.filter(([, ownerUrl]) => ownerUrl === originalUrl)
|
||||
.map(([derivativeUrl]) => derivativeUrl)
|
||||
|
||||
/**
|
||||
* 원본 이미지에 연결된 파생 이미지 사용처를 조회한다.
|
||||
* @param {string} originalUrl - 원본 미디어 URL
|
||||
* @param {Map<string, string>} ownerByDerivativeUrl - 파생 URL별 원본 URL 맵
|
||||
* @param {Array<Object>} posts - 게시물 목록
|
||||
* @param {Array<Object>} pages - 페이지 목록
|
||||
* @param {Object} siteSettings - 사이트 설정
|
||||
* @param {Array<Object>} tags - 태그 목록
|
||||
* @param {{ location: string, label: string, onlyLocation?: string }} options - 사용처 표시 옵션
|
||||
* @returns {Array<Object>} 원본에 연결할 파생 이미지 사용처 목록
|
||||
*/
|
||||
const getOriginalDerivativeMediaUsage = (
|
||||
originalUrl,
|
||||
ownerByDerivativeUrl,
|
||||
posts,
|
||||
pages,
|
||||
siteSettings,
|
||||
tags,
|
||||
options
|
||||
) => getOwnedDerivativeUrls(originalUrl, ownerByDerivativeUrl)
|
||||
.flatMap((derivativeUrl) => getDirectMediaUsage(derivativeUrl, posts, pages, siteSettings, tags)
|
||||
.filter((usage) => !options.onlyLocation || usage.location === options.onlyLocation)
|
||||
.map((usage) => ({
|
||||
...usage,
|
||||
location: options.location,
|
||||
label: options.label,
|
||||
sourceUrl: originalUrl,
|
||||
derivativeUrl
|
||||
})))
|
||||
|
||||
/**
|
||||
* 원본 미디어 URL의 직접·파생 사용처를 함께 조회한다.
|
||||
* @param {string} url - 미디어 URL
|
||||
* @param {Array<Object>} posts - 게시물 목록
|
||||
* @param {Array<Object>} pages - 페이지 목록
|
||||
* @param {Object} siteSettings - 사이트 설정
|
||||
* @param {Array<Object>} tags - 태그 목록
|
||||
* @param {{ thumbnailOwnerByUrl: Map<string, string>, pageCoverThumbnailOwnerByUrl: Map<string, string>, bodyThumbnailOwnerByUrl: Map<string, string> }} ownerMaps - 파생 URL별 원본 URL 맵 묶음
|
||||
* @returns {Array<Object>} 사용처 목록
|
||||
*/
|
||||
const getOriginalMediaUsage = (url, posts, pages, siteSettings, tags, ownerMaps) => [
|
||||
...getDirectMediaUsage(url, posts, pages, siteSettings, tags),
|
||||
...getOriginalDerivativeMediaUsage(url, ownerMaps.thumbnailOwnerByUrl, posts, pages, siteSettings, tags, {
|
||||
location: 'featuredImageThumbnail',
|
||||
label: '목록 카드 썸네일',
|
||||
onlyLocation: 'featuredImage'
|
||||
}),
|
||||
...getOriginalDerivativeMediaUsage(url, ownerMaps.pageCoverThumbnailOwnerByUrl, posts, pages, siteSettings, tags, {
|
||||
location: 'pageCoverThumbnail',
|
||||
label: '페이지 커버 썸네일',
|
||||
onlyLocation: 'featuredImage'
|
||||
}),
|
||||
...getOriginalDerivativeMediaUsage(url, ownerMaps.bodyThumbnailOwnerByUrl, posts, pages, siteSettings, tags, {
|
||||
location: 'contentBodyImage',
|
||||
label: '본문 표시 이미지',
|
||||
onlyLocation: 'content'
|
||||
})
|
||||
]
|
||||
|
||||
/**
|
||||
* 원본 삭제 시 함께 제거할 자동 생성 파생 URL 목록을 반환한다.
|
||||
* @param {string} originalUrl - 원본 미디어 URL
|
||||
* @param {{ thumbnailOwnerByUrl: Map<string, string>, pageCoverThumbnailOwnerByUrl: Map<string, string>, bodyThumbnailOwnerByUrl: Map<string, string> }} ownerMaps - 파생 URL별 원본 URL 맵 묶음
|
||||
* @returns {Array<string>} 함께 제거할 파생 URL 목록
|
||||
*/
|
||||
const getOwnedGeneratedMediaUrls = (originalUrl, ownerMaps) => [...new Set([
|
||||
...getOwnedDerivativeUrls(originalUrl, ownerMaps.thumbnailOwnerByUrl),
|
||||
...getOwnedDerivativeUrls(originalUrl, ownerMaps.pageCoverThumbnailOwnerByUrl),
|
||||
...getOwnedDerivativeUrls(originalUrl, ownerMaps.bodyThumbnailOwnerByUrl)
|
||||
])]
|
||||
|
||||
/**
|
||||
* 게시물 업로드 이미지의 카드 썸네일 상태를 조회한다.
|
||||
* @param {Object} item - 미디어 항목
|
||||
@@ -885,11 +966,16 @@ export const listMediaItems = async () => {
|
||||
const thumbnailOwnerByUrl = buildPostThumbnailOwnerMap(items)
|
||||
const pageCoverThumbnailOwnerByUrl = buildPageCoverThumbnailOwnerMap(items)
|
||||
const bodyThumbnailOwnerByUrl = buildPostBodyThumbnailOwnerMap(items)
|
||||
const ownerMaps = {
|
||||
thumbnailOwnerByUrl,
|
||||
pageCoverThumbnailOwnerByUrl,
|
||||
bodyThumbnailOwnerByUrl
|
||||
}
|
||||
const itemsWithUsage = items.map((item) => {
|
||||
const rawCategory = metadataMap[item.url]?.category ?? item.category
|
||||
const category = normalizeStoredDisplayCategory(item.url, rawCategory)
|
||||
const avatarOwner = avatarOwnerByUrl.get(item.url) || null
|
||||
const directUsage = getDirectMediaUsage(item.url, posts, pages, siteSettings, tags)
|
||||
const directUsage = getOriginalMediaUsage(item.url, posts, pages, siteSettings, tags, ownerMaps)
|
||||
const thumbnailUsage = getPostThumbnailMediaUsage(item.url, thumbnailOwnerByUrl, posts, pages, siteSettings)
|
||||
const pageCoverThumbnailUsage = getPageCoverThumbnailMediaUsage(item.url, pageCoverThumbnailOwnerByUrl, posts, pages, siteSettings)
|
||||
const bodyThumbnailUsage = getPostBodyThumbnailMediaUsage(item.url, bodyThumbnailOwnerByUrl, posts, pages, siteSettings)
|
||||
@@ -1046,11 +1132,19 @@ export const deleteMediaItem = async (url) => {
|
||||
listAdminTags()
|
||||
])
|
||||
const items = await readMediaDirectory(uploadRoot)
|
||||
const thumbnailOwnerByUrl = buildPostThumbnailOwnerMap(items)
|
||||
const pageCoverThumbnailOwnerByUrl = buildPageCoverThumbnailOwnerMap(items)
|
||||
const bodyThumbnailOwnerByUrl = buildPostBodyThumbnailOwnerMap(items)
|
||||
const ownerMaps = {
|
||||
thumbnailOwnerByUrl,
|
||||
pageCoverThumbnailOwnerByUrl,
|
||||
bodyThumbnailOwnerByUrl
|
||||
}
|
||||
const usage = [
|
||||
...getDirectMediaUsage(url, posts, pages, siteSettings, tags),
|
||||
...getPostThumbnailMediaUsage(url, buildPostThumbnailOwnerMap(items), posts, pages, siteSettings),
|
||||
...getPageCoverThumbnailMediaUsage(url, buildPageCoverThumbnailOwnerMap(items), posts, pages, siteSettings),
|
||||
...getPostBodyThumbnailMediaUsage(url, buildPostBodyThumbnailOwnerMap(items), posts, pages, siteSettings)
|
||||
...getOriginalMediaUsage(url, posts, pages, siteSettings, tags, ownerMaps),
|
||||
...getPostThumbnailMediaUsage(url, thumbnailOwnerByUrl, posts, pages, siteSettings),
|
||||
...getPageCoverThumbnailMediaUsage(url, pageCoverThumbnailOwnerByUrl, posts, pages, siteSettings),
|
||||
...getPostBodyThumbnailMediaUsage(url, bodyThumbnailOwnerByUrl, posts, pages, siteSettings)
|
||||
]
|
||||
|
||||
if (usage.length) {
|
||||
@@ -1067,8 +1161,15 @@ export const deleteMediaItem = async (url) => {
|
||||
})
|
||||
}
|
||||
|
||||
const ownedGeneratedUrls = getOwnedGeneratedMediaUrls(url, ownerMaps)
|
||||
|
||||
await rm(resolveMediaPath(url))
|
||||
await deleteMediaMetadata(url)
|
||||
|
||||
for (const generatedUrl of ownedGeneratedUrls) {
|
||||
await rm(resolveMediaPath(generatedUrl), { force: true })
|
||||
await deleteMediaMetadata(generatedUrl)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1092,11 +1193,19 @@ export const renameMediaItem = async (url, name) => {
|
||||
listAdminTags()
|
||||
])
|
||||
const items = await readMediaDirectory(uploadRoot)
|
||||
const thumbnailOwnerByUrl = buildPostThumbnailOwnerMap(items)
|
||||
const pageCoverThumbnailOwnerByUrl = buildPageCoverThumbnailOwnerMap(items)
|
||||
const bodyThumbnailOwnerByUrl = buildPostBodyThumbnailOwnerMap(items)
|
||||
const ownerMaps = {
|
||||
thumbnailOwnerByUrl,
|
||||
pageCoverThumbnailOwnerByUrl,
|
||||
bodyThumbnailOwnerByUrl
|
||||
}
|
||||
const usage = [
|
||||
...getDirectMediaUsage(url, posts, pages, siteSettings, tags),
|
||||
...getPostThumbnailMediaUsage(url, buildPostThumbnailOwnerMap(items), posts, pages, siteSettings),
|
||||
...getPageCoverThumbnailMediaUsage(url, buildPageCoverThumbnailOwnerMap(items), posts, pages, siteSettings),
|
||||
...getPostBodyThumbnailMediaUsage(url, buildPostBodyThumbnailOwnerMap(items), posts, pages, siteSettings)
|
||||
...getOriginalMediaUsage(url, posts, pages, siteSettings, tags, ownerMaps),
|
||||
...getPostThumbnailMediaUsage(url, thumbnailOwnerByUrl, posts, pages, siteSettings),
|
||||
...getPageCoverThumbnailMediaUsage(url, pageCoverThumbnailOwnerByUrl, posts, pages, siteSettings),
|
||||
...getPostBodyThumbnailMediaUsage(url, bodyThumbnailOwnerByUrl, posts, pages, siteSettings)
|
||||
]
|
||||
|
||||
if (usage.length) {
|
||||
|
||||
Reference in New Issue
Block a user