furniture-3d-system-Wu/scripts/sync-material-textures.ts

85 lines
2.4 KiB
TypeScript

import { mkdir, readFile, stat, writeFile } from 'node:fs/promises'
import path from 'node:path'
const PRESETS_FILE = path.join(process.cwd(), 'src/lib/3d/material-pbr-presets.ts')
const OUTPUT_ROOT = path.join(process.cwd(), 'public/materials/pbr/polyhaven')
const URL_PATTERN = /https:\/\/(?:dl\.polyhaven\.org|polyhaven\.com|cdn\.polyhaven\.com)\/[^\s'"]+/g
function toLocalFilePath(remoteUrl: string): string | null {
try {
const parsed = new URL(remoteUrl)
const segments = parsed.pathname.split('/').filter(Boolean)
const fileName = segments.at(-1)
if (!fileName) return null
const assetName = segments.at(-2) || 'misc'
return path.join(OUTPUT_ROOT, assetName, fileName)
} catch {
return null
}
}
async function exists(filePath: string): Promise<boolean> {
try {
await stat(filePath)
return true
} catch {
return false
}
}
async function downloadTexture(remoteUrl: string, localFilePath: string): Promise<void> {
const response = await fetch(remoteUrl)
if (!response.ok) {
throw new Error(`下载失败 ${response.status}: ${remoteUrl}`)
}
const buffer = Buffer.from(await response.arrayBuffer())
await mkdir(path.dirname(localFilePath), { recursive: true })
await writeFile(localFilePath, buffer)
}
async function main() {
const source = await readFile(PRESETS_FILE, 'utf8')
const matches = source.match(URL_PATTERN) || []
const remoteUrls = Array.from(new Set(matches))
if (remoteUrls.length === 0) {
console.log('未发现需要同步的远程贴图 URL。')
return
}
let downloaded = 0
let skipped = 0
let failed = 0
for (const remoteUrl of remoteUrls) {
const localFilePath = toLocalFilePath(remoteUrl)
if (!localFilePath) {
failed += 1
console.warn(`无法解析路径: ${remoteUrl}`)
continue
}
if (await exists(localFilePath)) {
skipped += 1
continue
}
try {
await downloadTexture(remoteUrl, localFilePath)
downloaded += 1
console.log(`已下载: ${path.relative(process.cwd(), localFilePath)}`)
} catch (error) {
failed += 1
console.warn(`下载失败: ${remoteUrl}`)
console.warn(error)
}
}
console.log(`同步完成:下载 ${downloaded},跳过 ${skipped},失败 ${failed}`)
}
main().catch((error) => {
console.error('贴图同步脚本执行失败', error)
process.exit(1)
})