Files
digital-me-history/tools/validate_battle_asset_packs.mjs
admin 0593ff7e62
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
数字我 Digital Me:全量入库(大文件走 Git LFS)
2026-10-10 16:24:43 +08:00

82 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fs from 'node:fs'
import path from 'node:path'
import { execFileSync } from 'node:child_process'
const packageDirs = process.argv.slice(2).map((item) => path.resolve(item))
if (!packageDirs.length) {
console.error('Usage: node tools/validate_battle_asset_packs.mjs <package-dir> [...]')
process.exit(2)
}
const failures = []
const assert = (condition, message) => {
if (!condition) failures.push(message)
}
function dimensions(file) {
const output = execFileSync('sips', ['-g', 'pixelWidth', '-g', 'pixelHeight', file], { encoding: 'utf8' })
const width = Number(output.match(/pixelWidth: (\d+)/)?.[1])
const height = Number(output.match(/pixelHeight: (\d+)/)?.[1])
return { width, height }
}
for (const packageDir of packageDirs) {
const label = path.basename(packageDir)
const manifestPath = path.join(packageDir, 'manifest.json')
const readmePath = path.join(packageDir, '素材说明.md')
assert(fs.existsSync(manifestPath), `${label}: missing manifest.json`)
assert(fs.existsSync(readmePath), `${label}: missing 素材说明.md`)
if (!fs.existsSync(manifestPath)) continue
let manifest
try {
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
} catch (error) {
failures.push(`${label}: invalid JSON (${error.message})`)
continue
}
assert(manifest.event?.canonicalName === label, `${label}: canonicalName must match directory name`)
assert(manifest.narration?.language === 'zh-CN', `${label}: narration language must be zh-CN`)
assert(manifest.narration?.estimatedSeconds >= 60 && manifest.narration?.estimatedSeconds <= 90, `${label}: narration must be estimated at 60–90 seconds`)
assert(typeof manifest.narration?.fullText === 'string' && manifest.narration.fullText.length >= 180, `${label}: narration is unexpectedly short`)
assert(Array.isArray(manifest.scenes) && manifest.scenes.length >= 3 && manifest.scenes.length <= 5, `${label}: scene count must be 3–5`)
assert(Array.isArray(manifest.sources) && manifest.sources.length > 0, `${label}: package sources are required`)
assert(Array.isArray(manifest.blacklist) && manifest.blacklist.length > 0, `${label}: blacklist is required`)
assert(manifest.bgm?.catalogId?.length > 0, `${label}: BGM catalogId is required`)
const ids = new Set()
for (const scene of manifest.scenes || []) {
const prefix = `${label}/${scene.id || '?'}`
assert(!ids.has(scene.id), `${prefix}: duplicate scene id`)
ids.add(scene.id)
assert(scene.title && scene.timePlace && scene.purpose && scene.narration, `${prefix}: scene metadata incomplete`)
assert(scene.overlay?.heading && scene.overlay?.line, `${prefix}: overlay copy incomplete`)
assert(Array.isArray(scene.people) && scene.people.length > 0, `${prefix}: people tags required`)
assert(Array.isArray(scene.sources) && scene.sources.length > 0, `${prefix}: scene sources required`)
assert(scene.image?.alt && scene.image?.prompt && scene.image?.visualInference, `${prefix}: image metadata incomplete`)
for (const key of ['original', 'delivery']) {
const relative = scene.image?.[key]
assert(typeof relative === 'string' && relative.startsWith('images/'), `${prefix}: invalid image.${key}`)
if (!relative) continue
const file = path.join(packageDir, relative)
assert(fs.existsSync(file), `${prefix}: missing ${relative}`)
if (!fs.existsSync(file)) continue
const { width, height } = dimensions(file)
assert(width > 0 && height > 0, `${prefix}: could not read dimensions for ${relative}`)
assert(Math.abs(width / height - 16 / 9) < 0.002, `${prefix}: ${relative} is ${width}x${height}, not 16:9`)
}
}
console.log(`checked ${label}: ${manifest.scenes?.length || 0} scenes`)
}
if (failures.length) {
console.error(`\n${failures.length} validation failure(s):`)
for (const failure of failures) console.error(`- ${failure}`)
process.exit(1)
}
console.log(`all ${packageDirs.length} package(s) passed validation`)