短视频批量制作怎么做?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 ids 和 hs 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 done 再 hs 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 create → wait until plan → plan confirm --yes → wait until done → export get,之后用 FFmpeg 做片头、转码、压制。断点续跑靠 hs use <pid> 和 --pid,失败诊断靠 next_actions 与 FAILED 的 reason 字段。这套流程需要分步操作,但每一步都结构化、可重试,适合有命令行基础的内容生产者把重复劳动交给脚本。

相关推荐
EasyGBS8 小时前
摄像头还在线,画面已经不能用了?国标GB28181视频平台EasyGBS视频质量诊断怎么用
服务器·安全·音视频
2601_955662468 小时前
情感解说视频如何提升感染力?配音细节很关键
人工智能·音视频·语音识别·视频
摸鱼 特供版9 小时前
一款边录边标注的轻量截图录屏工具
windows·学习·电脑·音视频·软件需求
技灵AI11 小时前
AI 带货视频会被限流吗?AIGC 标识、功效演示、同质化量产与画质四项判定对照
人工智能·aigc·音视频·ai电商·seedance
Black蜡笔小新12 小时前
老旧小区改造难题:新旧摄像头如何统一接入?EasyCVR一招融合
网络·音视频·easycvr
揽秀亭长13 小时前
视频转脚本怎么处理更高效?四种工具的工作流程与适用场景分析
人工智能·音视频·语音识别
昨日之日200614 小时前
Winxvideo:AI全能工具,智能修复老视频照片、清理噪音、录屏剪辑超方便
人工智能·音视频
_大峰_15 小时前
索尼 A7M4 误删视频恢复实战:基于原始卡镜像重建 MP4 数据
ffmpeg·数据恢复·音视频·mp4·exfat
AOI小白新手上路16 小时前
视频去雨·论文蒸馏笔记:从物理先验到状态空间模型
数据库·笔记·音视频
鱼宵16 小时前
LangChain4j 结构化输出:让模型吐出 Java 对象,JSON 不再手写解析
java·开发语言·json·langchain4j