gongxiangp2/lib/material-access-scope-storage.ts

65 lines
3.0 KiB
TypeScript

import { randomUUID } from 'crypto'
import { mkdir } from 'fs/promises'
import path from 'path'
import { downloadS3ObjectToFile } from '@/lib/s3'
import { resolveStoredUploadPath } from '@/lib/upload-paths'
import { buildPublicDisplayUrl, buildWhiteBackgroundPublicDisplayPathFromAssetPath } from '@/lib/public-display'
import { existsSync } from 'fs'
const MATERIAL_FILE_FIELDS = [
'previewUrl', 'zipFilePath', 'zipFileName', 'videoSourceUrl',
'videoPreview540Url', 'videoPreviewClipUrl', 'videoCoverUrl',
] as const
/** 将已公开的存储对象改为受素材访问权限保护的独立文件。 */
export async function prepareOperationsGMaterialFiles(
material: Record<string, any>,
assets: Array<{ id: string; fileUrl: string }>,
skus: Array<{ id: string; filePath: string; previewUrl: string | null }> = [],
) {
const replacements = new Map<string, string>()
const copyUrl = async (url: string) => {
if (!/^https?:\/\//i.test(url)) return url
const existing = replacements.get(url)
if (existing) return existing
const fileName = `${randomUUID()}${path.posix.extname(new URL(url).pathname)}`
const storedPath = path.posix.join('uploads', 'materials', material.id, 'protected-display', fileName)
const destination = resolveStoredUploadPath(storedPath)
await mkdir(path.dirname(destination), { recursive: true })
await downloadS3ObjectToFile(url, destination)
replacements.set(url, storedPath)
return storedPath
}
const materialFiles: Record<string, string | string[]> = {}
for (const field of MATERIAL_FILE_FIELDS) {
if (material[field]) materialFiles[field] = await copyUrl(material[field])
}
if (Array.isArray(material.displayImages)) {
materialFiles.displayImages = []
for (const url of material.displayImages) materialFiles.displayImages.push(await copyUrl(url))
}
const assetFiles = []
for (const asset of assets) {
const fileUrl = await copyUrl(asset.fileUrl)
if (fileUrl !== asset.fileUrl) assetFiles.push({ id: asset.id, fileUrl })
const previewPath = buildWhiteBackgroundPublicDisplayPathFromAssetPath(asset.fileUrl)
const publicPreview = previewPath && /\.webp$/i.test(previewPath) ? buildPublicDisplayUrl(previewPath) : null
if (previewPath && publicPreview) {
const storedPath = path.posix.join('uploads', 'materials', material.id, 'protected-display', previewPath)
const destination = resolveStoredUploadPath(storedPath)
if (!existsSync(destination)) {
await mkdir(path.dirname(destination), { recursive: true })
await downloadS3ObjectToFile(publicPreview, destination)
}
replacements.set(publicPreview, storedPath)
}
}
const skuFiles = []
for (const sku of skus) {
const filePath = await copyUrl(sku.filePath)
const previewUrl = sku.previewUrl ? await copyUrl(sku.previewUrl) : sku.previewUrl
if (filePath !== sku.filePath || previewUrl !== sku.previewUrl) skuFiles.push({ id: sku.id, filePath, previewUrl })
}
return { materialFiles, assetFiles, skuFiles, publicUrls: Array.from(replacements.keys()) }
}