Install
openclaw skills install @oracis/bilibili-to-shipinhao把B站横屏中长视频(读书解读/知识类)自动改造为微信视频号9:16竖屏短视频切片。当用户说"B站视频转视频号""横屏转竖屏切片""读书视频切片""视频号短视频制作""横屏改竖屏"时使用。覆盖下载→转写→选段→横转竖→烧字幕→封面全流程, 含本机环境坑与画质/字幕优化。
openclaw skills install @oracis/bilibili-to-shipinhao把 B 站 16:9 中长视频(20-40分钟读书解读/知识类)改造成 1-5 条 1-3 分钟 9:16 竖屏短视频。 已在本机 4 核 CPU + 16GB 内存上跑通两个样例:
Python(managed): C:/Users/DELL/.workbuddy/binaries/python/versions/3.13.12/python.exe
该环境已有 yt-dlp 2026.08.19、faster-whisper、Pillow、imageio-ffmpeg。
ffmpeg: scoop 装的常是空壳 shim(报 Could not create process)。用 imageio-ffmpeg 自带的二进制:
python -c "import imageio_ffmpeg; print(imageio_ffmpeg.get_ffmpeg_exe())"
# 复制为 ./bin/ffmpeg.exe —— 文件名必须叫 ffmpeg.exe, 否则 yt-dlp 的 --ffmpeg-location 认不出
mkdir -p bin && cp "<上面输出的路径>" bin/ffmpeg.exe
./bin/ffmpeg.exe -version # 必须真跑一次验证
本机有系统代理(http://127.0.0.1:12902), HF 相关脚本一律设 HF_HUB_OFFLINE=1
不设离线时 huggingface_hub 会走代理去校验/拉模型, 表现为两种随机故障:
ProxyError: 502 Bad Gateway(加载直接失败) 或
RuntimeError: mkl_malloc: failed to allocate memory(加载到一半分配失败, 极易误判成内存不足)。
设了 HF_HUB_OFFLINE=1 后只读本地缓存: small 加载 5s、97s 音频转写 44s, 稳定可复现。
排查顺序: 遇到上面两个错误先加离线模式, 不要先去查内存或换模型。
python -m yt_dlp -F "<URL>" # 先看格式 ID
python -m yt_dlp -f "bv*[height<=720]+ba/b" --ffmpeg-location bin \
-o "download/src.mp4" --merge-output-format mp4 "<URL>"
bv*[height<=720]+ba/b 比写死 30064+30280 更稳(不同稿件格式 ID 会变)CODEBUDDY_SAFE_DELETE_ENABLED=0player/wbi/v2(带 wbi 签名)也返回 subtitles=[]。
DownKyi 能拿到是因为它带登录态。没有登录态就走 whisper 转写。yt_dlp --flat-playlist --print "%(id)s|%(duration)s|%(title)s" "https://space.bilibili.com/<mid>/video"
只给 ID 不给标题/时长; 逐个 --skip-download --print "%(id)s|%(duration)s|%(title)s" 补元数据。
直接打 api.bilibili.com/x/space/arc/search 容易吃 -799 请求过于频繁。bin/ffmpeg.exe -y -ss 300 -i download/src.mp4 -frames:v 1 -q:v 2 download/probe.png
看清两类源片:
scripts/probe_subs_band.py 量出"内嵌字幕带"的像素行范围。bin/ffmpeg.exe -i download/src.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 download/src.wav
4 核 CPU 上 small 模型转写全片 20-30 分钟音频要半小时以上, 所以分两步:
① 全片用 tiny 快速转写 + 生成 30 秒分块预览(只为选段):
python scripts/transcribe_full.py download/src.wav download/src_transcript.json download/preview_30s.txt
# 21分钟音频 -> 5分34秒(3.84x 实时), 651 段 / 43 块, 预览约 1 万字, 供主 agent 通读
tiny 有错字和繁体, 但足够判断内容结构。想看精确边界时再从 JSON 里打区间:
for s in js:
if 1040 <= s['start'] <= 1200: print(s['start'], s['text'])
② 只精转选中的片段(用 small, 简体引导 + 内存降级):
python scripts/transcribe_clips.py # 改脚本里的 CLIPS 时间戳
initial_prompt="以下是普通话的句子,请使用简体中文输出。" 这句能显著减少繁体small beam1 → small beam5 → tiny 逐级降级读 30 秒分块预览, 选 1-3 分钟片段, 优先这几类:
python scripts/fix_terms.py # 先修专名+半角标点
python scripts/slice_vertical.py # 默认: 裁源内嵌字幕带 + 模糊背景 + 烧字幕
python scripts/slice_vertical.py --no-crop --tag _原样 # 技能原样, 用于对比
python scripts/make_cover.py # 竖屏封面(改 __main__ 里的书名/金句)
横转竖用模糊背景填充(不是加黑边——黑边会被算法判为低质搬运):
crop=iw:ih-{DROP_BOTTOM}:0:0, # 可选: 先裁掉源内嵌字幕带
split=2[bg][fg];
[bg]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,gblur=sigma=28,eq=brightness=-0.06[bgout];
[fg]scale=1080:-2[fgout];
[bgout][fgout]overlay=(W-w)/2:(H-h)/2,subtitles='{srt}':force_style='FontSize=12,FontName=Microsoft YaHei,Outline=2,Alignment=2,MarginV=38,...'
字幕样式依据: libass 默认按 PlayResY=288 缩放 force_style, 实际像素 = 值×1920/288≈6.7 倍—— FontSize=12→约80px, MarginV=38→距底约253px, 正好落在下方模糊区, 不挡内容。 封面用 PIL 生成 1080×1920, 关键信息放中间 60% 安全区(视频号会裁上下)。
这类源片(读书号很常见)是一张静态书封 + 画面底部一行内嵌字幕。若照默认烧外字幕, 一屏会出现两套字幕。处理顺序:
python scripts/probe_subs_band.py download/src.mp4 24
# 输出: 内容带 y ∈ [396, 531] 最多 24/24 帧命中
# 内容带 y ∈ [605, 639] 最多 20/24 帧命中 <- 这条就是内嵌字幕带
slice_vertical.py 的 DROP_BOTTOM(1280×720 基准, 单位像素):
DROP_BOTTOM = 120 → 裁掉 y≥600, 内嵌字幕带(605-639)整体消失, 而画面内容止于 531 不受影响。
裁剪后源变 1280×600, 居中占 y∈[707,1213], 下方模糊区更宽, 字幕更好放。| 坑 | 症状 | 解法 |
|---|---|---|
| 系统代理劫持 HF | ProxyError: 502 Bad Gateway 或 mkl_malloc: failed to allocate memory | HF_HUB_OFFLINE=1(只读本地缓存)。先试这个, 再谈内存 |
| HF xet 后端 | cas-server.xethub.hf.co 401 | HF_HUB_DISABLE_XET=1 |
| Windows symlink | 模型下完了但 model.bin is incomplete / snapshot 0 字节 | HF_HUB_DISABLE_SYMLINKS=1 + 删掉 0 字节文件重建(blob 保留, 不用重下) |
| 模型下载卡死 | .incomplete 文件停在整 40MB 不动 | 弃用该模型, 换本地已完整的(如 small 928MB 完整可用) |
| 模型下载慢 | — | HF_ENDPOINT=https://hf-mirror.com |
| ffmpeg shim | Could not create process | 用 imageio-ffmpeg 二进制, 改名 ffmpeg.exe |
| ffmpeg 路径 | subtitles 滤镜报找不到文件 | Windows 路径要转义 : → \: |
| 4核CPU太慢 | small 全片 30 分钟跑不完 | 两段式: tiny 选段 + small 只精转选中段 |
| whisper 出繁体 | 字幕是繁体 | initial_prompt 引导简体(无登录态拿不到源字幕) |
| 专名音译错 | 猎鹰→列英, 梅林→美林, 尼尔→您而, 论据→论句 | fix_terms.py 术语表(长词优先, 按主题分组) |
| 半角标点 | 字幕里出现 , ? | fix_terms.py 的 PUNCT 归一化为 ,? |
| 源视频自带字幕 | 外烧字幕与画面内文字重复 | 抽帧 + probe_subs_band.py 定量, 再 DROP_BOTTOM 裁掉源字幕带 |
| 字幕巨大+挡画面 | force_style FontSize=20 渲染成 130px+ 大字压在源画面上 | libass 按 PlayResY=288 缩放(×6.7); 用 FontSize=12 + MarginV=38 把字幕放进下方模糊区 |
| 后台任务无输出 | 跑十几分钟没结果, 无法判断是慢还是卡 | 用 python -u 且不接 grep/tail 管道(会缓冲到进程结束) |
-o download/src.mp4(文件名统一, 后面脚本都按这个路径写死)download/src.wav; 抽帧 + probe_subs_band.py 定 DROP_BOTTOMscripts/transcribe_full.py download/src.wav ... 出预览 → 主 agent 读预览选段scripts/transcribe_clips.py 的 CLIPS 填 (序号, 起, 止, 标题)scripts/fix_terms.py 的 TERMS 按新主题新增一组(社科/财经/人物…, 长词排前)scripts/slice_vertical.py 的 CLIPS 填 (起, 止, 标题, 封面金句) + DROP_BOTTOMscripts/make_cover.py 的 __main__ 改书名/金句/序号总数fix_terms.py → slice_vertical.py → make_cover.pybin/ffmpeg.exe -ss <秒> -i output/clip1_*.mp4 -frames:v 1 verify.png诊断工具: scripts/bench_transcribe.py <model> <beam> <wav> [threads] —— 单模型计时+首段文本, 用来快速定位转写异常。