数字我 Digital Me:全量入库(大文件走 Git LFS)
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
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`)
|
||||
Reference in New Issue
Block a user