Files
video-create/.claude/skills/video-from-script/scripts/lib/capcut-api.js
sion123 73b0860fe5 fix(capcut): 增强API错误响应详情
在API返回错误时,添加完整的响应数据切片到错误信息中,方便调试时定位问题。最多保留300字符的JSON数据。
2026-05-06 23:33:33 +08:00

92 lines
2.5 KiB
JavaScript

/**
* CapCut API 基础设施层
*
* 提供: 配置加载、API 封装、CLI 解析、工具函数
* 无业务逻辑,纯基础设施。
*/
const axios = require('axios')
const path = require('path')
const fs = require('fs')
const mm = require('music-metadata')
const US = 1_000_000
let _config = null
function getConfig() {
if (_config) return _config
const configPath = path.join(__dirname, '..', '..', '..', 'config.json')
if (!fs.existsSync(configPath)) {
console.error('缺少配置文件: skills/config.json')
console.error('请运行 node setup.js 生成配置')
process.exit(1)
}
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
if (!config.jianyingDraftPath || !config.capcutMateDir || !config.capcutMateApiBase) {
console.error('config.json 需要填写 jianyingDraftPath、capcutMateDir 和 capcutMateApiBase')
process.exit(1)
}
_config = config
return _config
}
const BASE_URL = getConfig().capcutMateApiBase
async function api(endpoint, data = {}, timeout = 60000) {
const url = `${BASE_URL}/${endpoint}`
const method = endpoint === 'get_draft' ? 'get' : 'post'
try {
const res = method === 'get'
? await axios.get(url, { params: data, timeout })
: await axios.post(url, data, { timeout })
if (res.data.code !== undefined && res.data.code !== 0) {
throw new Error(`API [${endpoint}] 返回错误: ${res.data.message} | detail: ${JSON.stringify(res.data).slice(0, 300)}`)
}
return res.data
} catch (err) {
if (err.response) {
throw new Error(`API [${endpoint}] HTTP ${err.response.status}: ${JSON.stringify(err.response.data)}`)
}
throw err
}
}
function parseArgs(argv) {
const args = {}
for (let i = 0; i < argv.length; i++) {
if (argv[i].startsWith('--')) {
const key = argv[i].slice(2)
const value = argv[i + 1]
if (value && !value.startsWith('--')) {
args[key] = value
i++
} else {
args[key] = true
}
}
}
return args
}
function getResolution(format) {
const map = {
'9:16': { width: 1080, height: 1920 },
'16:9': { width: 1920, height: 1080 },
'1:1': { width: 1080, height: 1080 },
'4:3': { width: 1440, height: 1080 },
}
return map[format] || map['9:16']
}
async function getAudioDurationSec(filePath) {
try {
const metadata = await mm.parseFile(filePath)
const dur = metadata.format.duration
return dur > 0 ? dur : null
} catch (_) {
return null
}
}
module.exports = { US, getConfig, BASE_URL, api, parseArgs, getResolution, getAudioDurationSec }