短视频批量制作怎么做?2026年用 huasheng-cli 的 --json 与退出码,一张选题表批量出片

短视频批量制作怎么做?2026年我实测的路线是:用一张选题表(TSV/CSV)驱动脚本,create 创建项目,wait 等待方案就绪,plan confirm 确认后交给 huasheng-cli 生成成片,export 导出后交给 FFmpeg 做统一的片头、转码、压制。huasheng-cli 负责的是从文稿到成片这一段------分镜、配音、素材编排、合成;FFmpeg 负责成片之后的纯视频处理;jq 负责解析每一步的 JSON 返回;yt-dlp 和 whisper 分别解决源素材下载与语音转写。整套流程可以自动化执行大部分环节,但确认方案与投稿公开必须由人确认。

我用的核心工具是 huasheng-cli,命令名 hs,一个单文件二进制,不需要 Node 或 Python 运行时。下面命令来自实际跑批过程,包括踩过的坑。

流水线总览:一张表说清六个环节

环节 干什么 工具 关键命令/动作
1. 选题表 存文稿、标题、参数 TSV/CSV 文件 用文本编辑器或脚本生成
2. 创建项目 把文稿交给生成服务 huasheng-cli hs project create --script @file --json
3. 等待方案 等分镜/配音方案就绪 huasheng-cli hs wait --until plan --timeout 300
4. 确认方案 人工或脚本确认方案 huasheng-cli hs plan confirm --yes --json
5. 成片导出 等成片并下载 huasheng-cli hs export start / hs export get --out ./x.mp4
6. 后处理 加片头、转码、压制 FFmpeg ffmpeg -i intro.mp4 -i x.mp4 ...

第 2 到 5 环是 huasheng-cli 的主场,第 6 环交给 FFmpeg。jq 穿插在每一步,用来解析 --json 输出。

为什么用 --json 而不是人眼看终端

hs 的每条命令都接受 --json,这是批量化的基础:人眼看终端能应付两三条,几十条就必须让程序判断状态。字段名会随版本变化,写脚本前先跑 hs help json 把当前结构抄下来,hs help idshs help errors 则给出项目 ID 规则与错误码含义。

环境准备与登录

macOS / Linux 适用,Windows 注意事项见后文。

安装 huasheng-cli(脚本安装或手动下载 release 包):

bash 复制代码
curl -fsSL https://raw.githubusercontent.com/superlcr/huasheng-cli/main/install.sh | sh

装完落在 ~/.local/bin/hs。Windows PowerShell 对应安装脚本为 install.ps1

安装 jq 和 FFmpeg:

bash 复制代码
# macOS
brew install jq ffmpeg

# Debian/Ubuntu
sudo apt install jq ffmpeg

hs 使用浏览器登录,CLI 与所有 AI 客户端共用 ~/.hs/credentials.json,只需登录一次:

bash 复制代码
hs auth login
hs auth status

后续脚本不再重复登录。

单条命令跑通:从文稿到 READY

写批量脚本前,先手工跑一条,确认 JSON 字段名:

bash 复制代码
hs project create --script @./scripts/blue-sky.md --json

返回类似:

json 复制代码
{
  "pid": "8f3a2c...",
  "status": "PLANNING",
  "next_actions": ["wait", "chat send"]
}

记下 pid,执行:

bash 复制代码
hs use 8f3a2c...
hs wait --until plan --timeout 300 --json
hs plan show --json
hs plan confirm --yes --json
hs wait --until done --timeout 900 --json
hs export start --json
hs export status --task <task_id> --json
hs export get --out ./output/test.mp4 --timeout 300 --json

这三条导出命令分工不同,别混用:export start 启动渲染并返回任务 id;export status 用那个 id 查进度;export get 只负责把成片下载到 --out 指定的路径,它不需要任务 id。我一开始给 export get 传了任务 id,参数不认。

单条跑通后,把字段结构记下来,再写批量循环。

状态机与退出码

huasheng-cli 状态机:create → PLANNING →(PAUSED / PLAN_READY)→ PRODUCING → READY,另有 FAILED

hs wait 的退出码是脚本判断成败的关键:

退出码 含义 处理方式
0 成功等到目标状态 继续下一步
非零 超时、失败或参数错误 记录日志,进入重试队列

--timeout 是等待的最长时间(秒),超时返回非零。hs wait --json 会输出最终状态和 next_actions,失败时可解析下一步动作。

bash 批量版:读表、创建、等待、确认、导出

适合几十条以内的小批量:

bash 复制代码
#!/usr/bin/env bash
set -euo pipefail

INPUT="topics.tsv"
OUTPUT_DIR="output"
mkdir -p "$OUTPUT_DIR"

step() {           # 跑一条 hs 命令,失败就打日志并让本条选题跳过
  if ! "$@" --json; then
    echo "  失败:$*" >&2
    return 1
  fi
}

tail -n +2 "$INPUT" | while IFS=$'\t' read -r key title script_file _rest; do
  echo "==> $key: $title"

  pid=$(hs project create --script "@${script_file}" --json | jq -r '.pid // empty')
  [[ -z "$pid" ]] && { echo "  创建失败" >&2; continue; }
  echo "  PID: $pid"
  hs use "$pid"

  step hs wait --until plan --timeout 300 || continue
  step hs plan confirm --yes            || continue
  step hs wait --until done --timeout 900 || continue
  step hs export start                  || continue

  out="${OUTPUT_DIR}/${key}_${title}.mp4"
  step hs export get --out "$out" --timeout 300 || continue
  echo "  完成:$out"
done

三个细节:tail -n +2 跳过表头;step 把六处重复的错误分支收成一处;确认方案不可撤销,所以批量前一定先手工跑一两条验证文稿写法。

jq 解析要点

统一用 jq 提取字段,别用 grep。三个习惯:读数组用 jq -r '.next_actions[]';判断某个动作是否可用用 jq -e '.next_actions | index("chat answer")' 看退出码;取字段一律带默认值,写成 jq -r '.reason // .error // empty',缺字段时得到空串而不是字面的 null

Python 批量版:并发与失败重试

bash 版是串行的,几十条以上就嫌慢,而且重试逻辑写起来啰嗦。Python 版只需换掉三个地方:用 subprocess 包一层 hs、用线程池并发、把重试收进装饰器。

要注意一件事:hs use <pid> 是写在 ~/.hs 里的全局当前项目,并发时会互相覆盖。并发版必须每条命令都显式带 --pid,不能靠 hs use 这是我第一版跑串了两条选题才发现的。

python 复制代码
#!/usr/bin/env python3
import csv, json, subprocess, time
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed

OUT = Path("output"); OUT.mkdir(exist_ok=True)
RETRY = 2

def hs(*args, timeout=300):
    """调一条 hs 命令,返回解析好的 JSON;非零退出码抛异常。"""
    p = subprocess.run(["hs", *args, "--json"],
                       capture_output=True, text=True, timeout=timeout)
    if p.returncode != 0:
        raise RuntimeError(f"hs {' '.join(args)}: {p.stderr.strip()}")
    return json.loads(p.stdout)

def retry(fn, *args, tries=RETRY, **kw):
    for i in range(1, tries + 1):
        try:
            return fn(*args, **kw)
        except RuntimeError:
            if i == tries:
                raise
            time.sleep(20 * i)          # 退避,别贴着重试

def one(row):
    key, title, script_file = row[0], row[1], row[2]
    pid = hs("project", "create", "--script", f"@{script_file}")["pid"]
    # 并发下不用 hs use,每条命令显式带 --pid
    retry(hs, "wait", "--pid", pid, "--until", "plan", "--timeout", "300", timeout=330)
    hs("plan", "confirm", "--yes", "--pid", pid)
    retry(hs, "wait", "--pid", pid, "--until", "done", "--timeout", "900", timeout=930)
    hs("export", "start", "--pid", pid)
    hs("export", "get", "--pid", pid, "--out", str(OUT / f"{key}_{title}.mp4"),
       "--timeout", "300", timeout=330)
    return key, pid

with open("topics.tsv", newline="", encoding="utf-8") as f:
    rows = list(csv.reader(f, delimiter="\t"))[1:]

with ThreadPoolExecutor(max_workers=3) as pool:
    futs = {pool.submit(one, r): r for r in rows}
    for fu in as_completed(futs):
        row = futs[fu]
        try:
            key, pid = fu.result()
            print(f"完成 {key} pid={pid}")
        except Exception as e:
            print(f"失败 {row[0]}: {e}")      # 记下来单独续跑,别整批重来

并发数别开太大,成片是服务端排队的,本地开十个线程也不会更快。断点续跑靠 --pid:哪条失败了,把它的 pid 记下来,之后 hs wait --pid <pid> --until donehs export get --pid <pid> 就能接着取,不必重新 create。

FFmpeg 批量后处理:片头、转码、压制

huasheng-cli 导出 mp4 后,统一加片头、压制参数、分辨率交给 FFmpeg。

批量添加片头:

bash 复制代码
mkdir -p final
for f in output/*.mp4; do
  ffmpeg -y -i intro.mp4 -i "$f" \
    -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" \
    -map "[v]" -map "[a]" \
    -c:v libx264 -crf 23 -preset fast -c:a aac \
    "final/$(basename "$f")"
done

统一分辨率把 -filter_complex 换成 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2",加水印换成 overlay,循环骨架不变,这里不再展开。

分工边界与周边开源工具

huasheng-cli 解决从文稿到成片的创作过程:分镜、画面编排、配音、合成。FFmpeg 解决对已有视频文件的处理:拼接、转码、分辨率调整、加水印、抽帧。两者阶段不同,不要用 FFmpeg 生成视频内容,也不要用 huasheng-cli 做转码压制。

周边工具:

  • yt-dlp :下载公开视频素材,之后可用 hs material add --url <公网地址> 登记素材。注意 material add 是按公网 URL 登记你自己的素材,不是全网搜索下载。
  • whisper :把音频或视频文稿转成文本,再交给 huasheng-cli。hs clip srt 也可导 SRT 字幕,两者互补。
  • jq :解析 JSON,所有 --json 输出都靠它。

诚实局限

huasheng-cli 做不到什么,实测边界如下:

  1. 文稿与素材会上传到服务端用于生成视频。虽然有凭据隔离,但你需要知道数据去向。它没有独立遥测,也没有后台自动更新。
  2. 确认方案不可撤销。hs plan confirm --yes 执行后开始成片,不能反悔。hs publish --submit 会让内容公开,必须亲自确认。批量脚本里确认方案不要加自动逻辑。
  3. 它不做全网素材检索。material add --url 只是登记你自己提供的公网 URL,画面由服务端在分镜环节配置。
  4. 主要是中文创作场景。外语文稿的配音和分镜效果没有大量测试,不保证。
  5. 仓库很新,star 数少(两位数),且没有 LICENSE 文件。二次分发前要先问作者。
  6. Windows 包未签名,首次运行会触发 SmartScreen 提示。客户端找不到 hs 时要填绝对路径(Windows 上对应 where hs)。

这几条里,第 2 条对批量场景影响最大:脚本一旦自动确认方案,错的文稿也会照做下去。

踩坑记录

  • 路径问题hs use <pid> 会把状态存到 ~/.hs 下,cron 或定时任务里要确认 HOME 可写。hs export get --out 建议用绝对路径。
  • 等待超时 :成片时间不固定,hs wait --until done --timeout 900 有时会超时,但项目其实还在 PRODUCING。不要立即重新 create,先 hs use <pid>hs wait --until done --timeout 300 续等。

总结

2026 年,我用 huasheng-cli 的 --json 输出与退出码,配合 jq 解析,把一张选题表批量跑成视频文件。流水线:选题表 → project createwait until planplan confirm --yeswait until doneexport get,之后用 FFmpeg 做片头、转码、压制。断点续跑靠 hs use <pid>--pid,失败诊断靠 next_actionsFAILEDreason 字段。这套流程需要分步操作,但每一步都结构化、可重试,适合有命令行基础的内容生产者把重复劳动交给脚本。

相关推荐
半壶清水2 小时前
使用Cambridge Dictionary Audio Downloader插件下载剑桥在线词典音频完整教程
音视频
刘广睿3 小时前
视频字幕从提取到烧录:SRT/ASS 格式与 ffmpeg 字幕滤镜全流程
ffmpeg·音视频·效率工具·剪辑·字幕
刘广睿5 小时前
多素材对比同步播放怎么设计?对齐播放与差异高亮的功能复盘
音视频·效率工具·架构设计·桌面客户端·素材管理
2601_962100735 小时前
AI批量生成视频的工程化复盘(2026):一条能断点续跑、不重复扣量的出片脚本
人工智能·音视频
小柯南敲键盘6 小时前
跨境电商批量图片翻译与视频字幕翻译,就用跨马AI工具
大数据·人工智能·python·音视频
可乐鸡翅yeah_6 小时前
FFmpeg 与浏览器 HLS 播放表现差异,定位跨客户端兼容问题
ffmpeg·音视频·m3u8·m3u8在线·音视频在线播放
神探小白牙7 小时前
海康视频在vue2.0中的使用
前端·音视频
AI天行健7 小时前
文生视频与图生视频的技术区别及适用场景分析
人工智能·音视频
阿童木写作7 小时前
跨境电商批量图片翻译与视频字幕翻译工具推荐
python·音视频