feat(video-from-script): 新增产品宣传片账户配置及 Ken Burns 效果支持

- 添加 product_viral_factory 账户配置,支持产品宣传片自动生成
- 集成 Ken Burns 效果到组装流程
- 优化视频生成阶段的空结果诊断和修复提示
- 改进 manifest 保存逻辑,处理 EPERM 权限错误
- 添加 .claudeignore 忽略生成文件
This commit is contained in:
2026-05-12 01:28:40 +08:00
17 changed files with 2181 additions and 747 deletions

View File

@@ -26,6 +26,24 @@ async function phaseVideos(manifest, manifestPath, options) {
return ['done', 'pending', 'failed'].includes(it.status)
})
if (videoCandidates.length === 0) {
console.log("\n⚠ [videos] 没有符合条件的 item 进入视频生成阶段")
console.log(" manifest 中共有", manifest.items.length, "个 item逐一诊断:")
for (const it of manifest.items) {
const reasons = []
if (it.confirmed === false) reasons.push("confirmed=false")
if (!it.url) reasons.push("缺少 url图片未上传")
if (!it.videoPrompt) reasons.push("缺少 videoPrompt")
if (it.confirmed !== false && it.url && it.videoPrompt && !["done","pending","failed"].includes(it.status)) {
reasons.push("status=" + (it.status || "undefined") + "(不在 done/pending/failed 中)")
}
console.log(" - item", it.id || manifest.items.indexOf(it), ":", reasons.length > 0 ? reasons.join(", ") : "已满足全部条件(不应在此)")
}
console.log("\n 修复命令:")
console.log(" node .claude/skills/video-from-script/scripts/pipeline.js confirm --manifest", manifestPath, "--all")
console.log()
}
// 已有视频(本地或 OSS且状态为 done 的跳过,其余清理后重新生成
const items = []
for (const it of videoCandidates) {

View File

@@ -37,9 +37,16 @@ function loadManifest(manifestPath) {
}
function saveManifest(manifestPath, manifest) {
const tmp = manifestPath + '.tmp'
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), 'utf-8')
fs.renameSync(tmp, manifestPath)
try {
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8')
} catch (err) {
if (err.code === 'EPERM') {
// rename/tmp fallback on EPERM
const tmp = manifestPath + '.tmp'
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), 'utf-8')
try { fs.renameSync(tmp, manifestPath) } catch (_) {}
}
}
}
function loadAccountConfig(accountId) {