feat(skills): 完善视频生产 pipeline 及新增健身跟练账号
- SKILL.md: 新增工作流阶段定义、质量卡点、分镜规则 - manifest-schema.md: 补充完整字段规范及类型定义 - phase-tts.js: 优化 TTS 合成长逻辑,添加进度追踪 - capcut-tracks.js: 扩展轨道构建能力,支持更多元素类型 - capcut-timeline.js: 改进时间线生成,支持淡入淡出 - capcut_assemble.js: 新增 assemble 阶段完整实现 - cmd-init.js: 完善 init 命令逻辑 - qwen-tts.js: 调整超时配置 - accounts/禁忌帝王学: 更新拆分/图像/台词提示词 - accounts/健身跟练: 新增账号含 account.json 及全套提示词模板 - 新增 workflow-issues-20260501.md 参考文档 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,7 @@ const { buildTimeline, adjustVideoSpeed } = require('./lib/capcut-timeline')
|
||||
const {
|
||||
loadAccountConfig, loadSubtitleStyle,
|
||||
loadKenBurns, loadTransitions,
|
||||
addImages, addVideos, addKenBurns,
|
||||
addImages, addVideos, addSlotsLocally,
|
||||
addVoiceover, addBGM,
|
||||
addSubtitles,
|
||||
addEffects, addFilter,
|
||||
@@ -65,23 +65,43 @@ async function batchUploadToOSS(inputDir, files, concurrency = 3) {
|
||||
async function batchUploadAudio(inputDir, items) {
|
||||
const urls = {}
|
||||
for (const item of items) {
|
||||
if (!item.audio || item.audio.startsWith('http')) {
|
||||
if (item.audio) urls[item.audio] = item.audio
|
||||
continue
|
||||
// 处理主音频
|
||||
if (item.audio && !item.audio.startsWith('http')) {
|
||||
if (!urls[item.audio]) {
|
||||
const filePath = path.isAbsolute(item.audio)
|
||||
? item.audio
|
||||
: path.resolve(inputDir, item.audio)
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
urls[item.audio] = await uploadToOSS(filePath)
|
||||
console.log(` 上传: ${path.basename(filePath)} -> OK`)
|
||||
} catch (err) {
|
||||
console.error(` 上传失败: ${path.basename(filePath)} - ${err.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (item.audio) {
|
||||
urls[item.audio] = item.audio
|
||||
}
|
||||
if (urls[item.audio]) continue
|
||||
const filePath = path.isAbsolute(item.audio)
|
||||
? item.audio
|
||||
: path.resolve(inputDir, item.audio)
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error(` 音频文件不存在: ${filePath}`)
|
||||
continue
|
||||
}
|
||||
try {
|
||||
urls[item.audio] = await uploadToOSS(filePath)
|
||||
console.log(` 上传: ${path.basename(filePath)} -> OK`)
|
||||
} catch (err) {
|
||||
console.error(` 上传失败: ${path.basename(filePath)} - ${err.message}`)
|
||||
// 处理分段音频
|
||||
if (item.segments && item.segments.length > 0) {
|
||||
for (const seg of item.segments) {
|
||||
if (!seg.audio || seg.error) continue
|
||||
if (urls[seg.audio]) continue
|
||||
const filePath = path.isAbsolute(seg.audio)
|
||||
? seg.audio
|
||||
: path.resolve(inputDir, seg.audio)
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error(` 音频文件不存在: ${filePath}`)
|
||||
continue
|
||||
}
|
||||
try {
|
||||
urls[seg.audio] = await uploadToOSS(filePath)
|
||||
console.log(` 上传: ${path.basename(filePath)} -> OK`)
|
||||
} catch (err) {
|
||||
console.error(` 上传失败: ${path.basename(filePath)} - ${err.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return urls
|
||||
@@ -288,7 +308,11 @@ async function assemble(args) {
|
||||
}
|
||||
}
|
||||
}
|
||||
await addVideos(draftUrl, inputDir, items, timeline, width, height, transitionConfig)
|
||||
const segmentIds = await addVideos(draftUrl, inputDir, items, timeline, width, height, transitionConfig)
|
||||
// 将 segment_ids 附加到 items,供后续 addSlotsLocally 使用
|
||||
if (segmentIds && segmentIds.length > 0) {
|
||||
items.forEach((item, i) => { item._segmentId = segmentIds[i] || null })
|
||||
}
|
||||
}
|
||||
|
||||
// -- Ken Burns --
|
||||
@@ -383,6 +407,13 @@ async function assemble(args) {
|
||||
await syncToLocalJianying(draftUrl, draftId, totalDurationUs)
|
||||
console.log(' 同步完成\n')
|
||||
|
||||
// -- 视频轨道 slot 写入(在 syncToLocalJianying 之后执行,此时本地草稿文件已存在)--
|
||||
if (mode !== 'images') {
|
||||
step++; console.log(`[${step}/${totalSteps}] 写入视频轨道时间线...`)
|
||||
await addSlotsLocally(draftUrl, items, timeline, null, { draftId })
|
||||
console.log(' 视频轨道写入完成\n')
|
||||
}
|
||||
|
||||
// -- 云渲染(可选)--
|
||||
if (apiKey) {
|
||||
console.log('提交云渲染...')
|
||||
|
||||
Reference in New Issue
Block a user