feat(video-pipeline): 支持滤镜和转场从账号配置继承
- 新增 Q18 滤镜和 Q19 转场字段到账号创建参考文档 - 重构账号配置加载函数为通用 `loadAccountConfig`,支持读取滤镜和转场 - `capcut_assemble.js` 支持 CLI 参数优先、账号配置兜底的滤镜/特效继承逻辑 - 模板 `account.json` 将闭幕转场从 "黑场" 修正为 "闪黑
This commit is contained in:
@@ -233,6 +233,20 @@ async function assemble(args) {
|
||||
}
|
||||
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf-8'))
|
||||
|
||||
// 从 account.json 自动继承 effects / filter(CLI 参数优先)
|
||||
let finalEffects = effectsStr
|
||||
let finalFilter = filterStr
|
||||
if (!finalEffects || !finalFilter) {
|
||||
const accountData = loadAccountConfig(manifest)
|
||||
if (!finalEffects && accountData.capcut?.effects?.length) {
|
||||
finalEffects = accountData.capcut.effects.join(',')
|
||||
}
|
||||
if (!finalFilter && accountData.capcut?.filter) {
|
||||
finalFilter = accountData.capcut.filter
|
||||
}
|
||||
}
|
||||
|
||||
const { width, height } = getResolution(format)
|
||||
const defaultDurationUs = parseFloat(duration) * US
|
||||
|
||||
@@ -284,6 +298,8 @@ async function assemble(args) {
|
||||
console.log(` 模式: ${mode} 画幅: ${format} (${width}x${height})`)
|
||||
console.log(` 时间线: ${hasTTS ? 'TTS音频驱动' : `固定${duration}s/段`} 总时长: ${(totalDurationUs / US).toFixed(1)}s`)
|
||||
console.log(` 字幕: ${subtitles} 配音: ${voiceover} 动画: ${animation}`)
|
||||
if (finalEffects) console.log(` 特效: ${finalEffects}`)
|
||||
if (finalFilter) console.log(` 滤镜: ${finalFilter}`)
|
||||
console.log(` 素材: ${items.length} 个可用\n`)
|
||||
|
||||
const steps = []
|
||||
@@ -397,7 +413,7 @@ async function assemble(args) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) saveManifest(manifestFile, manifest)
|
||||
if (changed) fs.writeFileSync(manifestFile, JSON.stringify(manifest, null, 2))
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(` OSS 上传失败,将尝试本地路径: ${err.message}\n`)
|
||||
@@ -445,26 +461,26 @@ async function assemble(args) {
|
||||
|
||||
// -- 添加特效 --
|
||||
step++; console.log(`[${step}/${totalSteps}] 添加特效...`)
|
||||
if (effectsStr) {
|
||||
if (finalEffects) {
|
||||
try {
|
||||
await addEffects(draftUrl, effectsStr, totalDurationUs)
|
||||
await addEffects(draftUrl, finalEffects, totalDurationUs)
|
||||
} catch (e) {
|
||||
console.log(` 特效跳过: ${e.message}`)
|
||||
}
|
||||
} else {
|
||||
console.log(' 跳过(未指定 --effects)')
|
||||
console.log(' 跳过(未配置特效)')
|
||||
}
|
||||
|
||||
// -- 添加滤镜 --
|
||||
step++; console.log(`[${step}/${totalSteps}] 添加滤镜...`)
|
||||
if (filterStr) {
|
||||
if (finalFilter) {
|
||||
try {
|
||||
await addFilter(draftUrl, filterStr, totalDurationUs)
|
||||
await addFilter(draftUrl, finalFilter, totalDurationUs)
|
||||
} catch (e) {
|
||||
console.log(` 滤镜跳过: ${e.message}`)
|
||||
}
|
||||
} else {
|
||||
console.log(' 跳过(未指定 --filter)')
|
||||
console.log(' 跳过(未配置滤镜)')
|
||||
}
|
||||
|
||||
// -- 保存草稿 --
|
||||
@@ -809,31 +825,23 @@ async function addBGM(draftUrl, bgmUrl, totalDurationUs) {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 读取账号字幕风格配置
|
||||
// 读取账号配置
|
||||
// ============================================================================
|
||||
|
||||
function loadSubtitleStyle(manifest) {
|
||||
function loadAccountConfig(manifest) {
|
||||
const account = manifest.account
|
||||
if (!account) return {}
|
||||
const scriptDir = __dirname
|
||||
const accountFile = path.join(scriptDir, '..', '..', '..', 'accounts', account, 'account.json')
|
||||
const accountFile = path.join(__dirname, '..', '..', '..', '..', 'accounts', account, 'account.json')
|
||||
if (!fs.existsSync(accountFile)) return {}
|
||||
try {
|
||||
const accountData = JSON.parse(fs.readFileSync(accountFile, 'utf-8'))
|
||||
return accountData.capcut?.subtitleStyle || {}
|
||||
} catch { return {} }
|
||||
try { return JSON.parse(fs.readFileSync(accountFile, 'utf-8')) } catch { return {} }
|
||||
}
|
||||
|
||||
function loadSubtitleStyle(manifest) {
|
||||
return loadAccountConfig(manifest).capcut?.subtitleStyle || {}
|
||||
}
|
||||
|
||||
function loadKeywordStyle(manifest) {
|
||||
const account = manifest.account
|
||||
if (!account) return {}
|
||||
const scriptDir = __dirname
|
||||
const accountFile = path.join(scriptDir, '..', '..', '..', 'accounts', account, 'account.json')
|
||||
if (!fs.existsSync(accountFile)) return {}
|
||||
try {
|
||||
const accountData = JSON.parse(fs.readFileSync(accountFile, 'utf-8'))
|
||||
return accountData.capcut?.keywordStyle || {}
|
||||
} catch { return {} }
|
||||
return loadAccountConfig(manifest).capcut?.keywordStyle || {}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -894,15 +902,7 @@ async function addKeywordOverlays(draftUrl, items, timeline, style = {}) {
|
||||
}
|
||||
|
||||
function loadTransitions(manifest) {
|
||||
const account = manifest.account
|
||||
if (!account) return null
|
||||
const scriptDir = __dirname
|
||||
const accountFile = path.join(scriptDir, '..', '..', '..', 'accounts', account, 'account.json')
|
||||
if (!fs.existsSync(accountFile)) return null
|
||||
try {
|
||||
const accountData = JSON.parse(fs.readFileSync(accountFile, 'utf-8'))
|
||||
return accountData.capcut?.transitions || null
|
||||
} catch { return null }
|
||||
return loadAccountConfig(manifest).capcut?.transitions || null
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user