Files
video-create/.claude/skills/video-from-script/scripts/lib/phase-assemble.js
sion123 ac6f110f28 feat(video-from-script): 自动解析草稿地址并修复导出空值问题
在 `cmdMark` 命令中,当标记为已完成状态且未提供草稿地址时,自动从子任务的 `manifestPath` 中读取 `draftUrl`;在 `cmdExport` 导出 CSV 时,使用 `resolveDraftUrl` 函数统一解析草稿地址,确保导出结果包含完整的公网可下载链接。

同时修改 `phaseAssemble` 阶段,使用 `BASE_URL` 和 `draftId` 构造公网可访问的绝对路径保存到 manifest 中,替代之前仅保存相对路径的方式。
2026-05-17 23:43:30 +08:00

66 lines
2.5 KiB
JavaScript
Raw 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.
/**
* Phase: assemble — CapCut 成片组装
*
* 图片/视频 + TTS → 剪映草稿
*/
const fs = require('fs')
const { log, getManifestDir } = require('./pipeline-utils')
async function phaseAssemble(manifest, manifestPath, options) {
const dir = getManifestDir(manifestPath)
const accountConfig = options.accountConfig || {}
const capcutConfig = accountConfig.capcut || {}
const videoItems = manifest.items.filter(it => it.video && it.status === 'done')
const hasVideos = videoItems.length > 0
const mode = hasVideos ? 'videos' : 'images'
// 前置校验:图片模式下检查 file 字段
if (mode === 'images') {
const missingFile = manifest.items.filter(it => !it.file)
if (missingFile.length > 0) {
throw new Error(`${missingFile.length} 个 item 缺少 file 字段id: ${missingFile.map(it => it.id).join(', ')}),请先运行 images 阶段生成图片`)
}
}
// 检测是否有配音和字幕
const hasAudio = manifest.items.some(it => it.audio)
const hasSubtitles = manifest.items.some(it => it.script && it.script.trim() && it.script !== '[无配音]')
const assembleArgs = {
input: dir,
manifest: manifestPath,
mode,
format: manifest.format || accountConfig.defaultFormat || '9:16',
subtitles: hasSubtitles ? 'true' : 'false',
voiceover: hasAudio ? 'true' : 'false',
animation: capcutConfig.animation || '渐显+放大',
}
if (capcutConfig.defaultBGM) assembleArgs.bgm = capcutConfig.defaultBGM
if (capcutConfig.effects) assembleArgs.effects = capcutConfig.effects.join(',')
if (capcutConfig.filter) assembleArgs.filter = capcutConfig.filter
log('assemble', `模式: ${mode}, 字幕: ${assembleArgs.subtitles}, 配音: ${assembleArgs.voiceover}, 动画: ${assembleArgs.animation}`)
try {
const { assemble } = require('../capcut_assemble')
const { BASE_URL } = require('./capcut-api')
const result = await assemble(assembleArgs)
// 保存草稿地址到 manifest供批量导出使用
// 用 BASE_URL + draft_id 构造公网可下载的绝对路径
if (result && result.draftId) {
manifest.draftUrl = `${BASE_URL}/get_draft?draft_id=${result.draftId}`
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8')
log('assemble', `草稿地址已保存: ${manifest.draftUrl}`)
}
log('assemble', '成片完成')
} catch (err) {
log('assemble', `成片失败: ${err.message}`)
throw err
}
}
module.exports = { phaseAssemble }