Design & media

B站横屏视频转视频号竖屏切片

Try it

把B站横屏中长视频(读书解读/知识类)自动改造为微信视频号9:16竖屏短视频切片。当用户说"B站视频转视频号""横屏转竖屏切片""读书视频切片""视频号短视频制作""横屏改竖屏"时使用。覆盖下载→转写→选段→横转竖→烧字幕→封面全流程, 含本机环境坑与画质/字幕优化。

What it does

把 B 站 16:9 中长视频(20-40分钟读书解读/知识类)改造成 1-5 条 1-3 分钟 9:16 竖屏短视频。 已在本机 4 核 CPU + 16GB 内存上跑通两个样例: BV1TFe56uEnJ《马斯克: 重回太空》31 分钟(动态画面) → 5 条切片 BV1g8aa6REa1《学会提问》21 分钟(静态幻灯片+内嵌字幕) → 1 条切片, 全流程约 8 分钟

The skill document

B站横屏视频 → 微信视频号竖屏切片

把 B 站 16:9 中长视频(20-40分钟读书解读/知识类)改造成 1-5 条 1-3 分钟 9:16 竖屏短视频。 已在本机 4 核 CPU + 16GB 内存上跑通两个样例:

  • BV1TFe56uEnJ《马斯克: 重回太空》31 分钟(动态画面) → 5 条切片
  • BV1g8aa6REa1《学会提问》21 分钟(静态幻灯片+内嵌字幕) → 1 条切片, 全流程约 8 分钟

何时使用

  • 用户要把 B 站/其他横屏长视频搬运或改造到微信视频号、抖音、快手
  • 需要"横转竖 + 切片 + 烧字幕 + 封面"这套组合拳
  • 用户问"横屏视频能不能直接发视频号"(不能, 必须改造)

环境准备(一次性)

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, 稳定可复现。 排查顺序: 遇到上面两个错误先加离线模式, 不要先去查内存或换模型。

五步流程

1. 下载(B站 DASH 分离流, 需 ffmpeg 合并)

python -m yt_dlp -F ""          # 先看格式 ID
python -m yt_dlp -f "bv*[height<=720]+ba/b" --ffmpeg-location bin \
  -o "download/src.mp4" --merge-output-format mp4 ""
  • 通用选择器 bv*[height<=720]+ba/b 比写死 30064+30280 更稳(不同稿件格式 ID 会变)
  • 1080P 通常需大会员; 720P(约 29MB / 26s 下完)对本流程足够
  • 合并后会删中间流, 受控环境会被 safe-delete hook 拦 → 子进程 env 设 CODEBUDDY_SAFE_DELETE_ENABLED=0
  • B站字幕拿不到: yt-dlp 报需登录; 直接调 player/wbi/v2(带 wbi 签名)也返回 subtitles=[]。 DownKyi 能拿到是因为它带登录态。没有登录态就走 whisper 转写。
  • 频道批量选题: yt_dlp --flat-playlist --print "%(id)s|%(duration)s|%(title)s" "https://space.bilibili.com//video" 只给 ID 不给标题/时长; 逐个 --skip-download --print "%(id)s|%(duration)s|%(title)s" 补元数据。 直接打 api.bilibili.com/x/space/arc/search 容易吃 -799 请求过于频繁。

1.5 抽帧探形态(30 秒, 决定后面字幕怎么处理)

bin/ffmpeg.exe -y -ss 300 -i download/src.mp4 -frames:v 1 -q:v 2 download/probe.png

看清两类源片:

  • 动态画面(口播/实拍/动画) → 走默认: 源画面居中 + 外烧字幕
  • 静态幻灯片/图文轮播 + 画面内嵌字幕 → 必须处理重复问题, 见下节 再跑 scripts/probe_subs_band.py 量出"内嵌字幕带"的像素行范围。

2. 提音频

bin/ffmpeg.exe -i download/src.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 download/src.wav

3. 两段式转写(关键性能策略)

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="以下是普通话的句子,请使用简体中文输出。" 这句能显著减少繁体
  • 实测: 97 秒音频 → 44 秒转完, 33 段, 简体, 质量明显优于 tiny
  • small 还会自动纠正 tiny 的错(如 tiny 的"904的人/你而" → small 的"94%的人/尼尔")
  • 异常时脚本按 small beam1 → small beam5 → tiny 逐级降级

4. LLM 选段(这步由主 agent 做, 是流水线最值钱的环节)

读 30 秒分块预览, 选 1-3 分钟片段, 优先这几类:

  • 决策转折: 有戏剧性的临场改变(如"凌晨电话把5台发动机改9台")
  • 可落地干货: 反常识数字对比(如"300万设备8.6万从废品站淘, 波音花3.75亿")
  • 情绪爆点: 全书高潮(如"火箭落地那刻全员以为炸了")
  • 反常识钩子: 一句能立住的颠覆性判断(如"统计数据看起来最科学, 但它经常撒谎")
  • 金句升华: 适合收尾(如"多考察这些论据的来龙去脉") 避免选需要上下文铺垫的段落——切片是独立观看的。 时间戳要卡在句子边界(用第 3 步的区间打印确认), 不要在句子中间切。

5. 切片 + 横转竖 + 烧字幕 + 封面

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% 安全区(视频号会裁上下)。

静态幻灯片/图文轮播源: 解决字幕重复

这类源片(读书号很常见)是一张静态书封 + 画面底部一行内嵌字幕。若照默认烧外字幕, 一屏会出现两套字幕。处理顺序:

  1. 量内嵌字幕带位置(不要目测):
    python scripts/probe_subs_band.py download/src.mp4 24
    # 输出: 内容带 y ∈ [396, 531] 最多 24/24 帧命中
    #       内容带 y ∈ [605, 639] 最多 20/24 帧命中   <- 这条就是内嵌字幕带
    
    原理: 采 24 帧, 跳过左上角频道水印, 统计底部各行与背景色的差异像素数。
  2. 设 slice_vertical.py 的 DROP_BOTTOM(1280×720 基准, 单位像素): DROP_BOTTOM = 120 → 裁掉 y≥600, 内嵌字幕带(605-639)整体消失, 而画面内容止于 531 不受影响。 裁剪后源变 1280×600, 居中占 y∈[707,1213], 下方模糊区更宽, 字幕更好放。
  3. 不要用"干脆不烧字幕"(旧方案): 内嵌字幕是 720P 里的 ~30px 小字, 缩到 1080 宽后仅约 25px, 手机上看不清。裁源 + 烧自己的大字幕才是正解。
  4. 裁多少由第 1 步实测值决定, 换视频要重量。

关键坑(血泪清单)

坑症状解法
系统代理劫持 HFProxyError: 502 Bad Gateway 或 mkl_malloc: failed to allocate memoryHF_HUB_OFFLINE=1(只读本地缓存)。先试这个, 再谈内存
HF xet 后端cas-server.xethub.hf.co 401HF_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 shimCould 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 管道(会缓冲到进程结束)

复用入口(换一个视频怎么做)

  1. 下载 → -o download/src.mp4(文件名统一, 后面脚本都按这个路径写死)
  2. 提音频 → download/src.wav; 抽帧 + probe_subs_band.py 定 DROP_BOTTOM
  3. scripts/transcribe_full.py download/src.wav ... 出预览 → 主 agent 读预览选段
  4. scripts/transcribe_clips.py 的 CLIPS 填 (序号, 起, 止, 标题)
  5. scripts/fix_terms.py 的 TERMS 按新主题新增一组(社科/财经/人物…, 长词排前)
  6. scripts/slice_vertical.py 的 CLIPS 填 (起, 止, 标题, 封面金句) + DROP_BOTTOM
  7. scripts/make_cover.py 的 __main__ 改书名/金句/序号总数
  8. 重跑: fix_terms.py → slice_vertical.py → make_cover.py
  9. 抽帧验收: bin/ffmpeg.exe -ss <秒> -i output/clip1_*.mp4 -frames:v 1 verify.png

诊断工具: scripts/bench_transcribe.py [threads] —— 单模型计时+首段文本, 用来快速定位转写异常。

视频号发布提醒(人工环节, 无法自动化)

  • 真人片头必须自己录(哪怕只 5 秒)——纯图文/无真人会被判低质限流, 200-500 播放封顶
  • 视频号没有对个人开放的发布 API, 上传只能手动
  • 竖屏 9:16 完播率比横屏高约 27%; 前 3 秒必须有钩子
  • 千万别留微信号/外链; 口播引导"完整版看主页"是安全的

Related skills

Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.

by nssa.io1.0k installs47 stars

Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.

by johnpatternai22 installs8 stars

Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.

by Iván559 installs18 stars

Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.

by fly0pants4.3k installs296 stars

Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.

by Iván855 installs69 stars

More from oracis

Browse all skills

把本地 Skill 打包并发布到 SkillHub(腾讯 skillhub.cn)与 ClawHub,覆盖预检、发布、状态回读与竞品对标全链路,并在上传被拒时用二分/ddmin 脚本把「服务端 WAF 拦内容(566)」与「包结构/字段问题」精确区分开。当用户说「发布技能到市场」「上架 skill」「SkillHub 提交失败」「Failed to fetch」「566」「上传 zip 报错」「技能审核状态」「版本号被拒」时使用。也讲清「入库成功 ≠ 已公开」——用 `mine` 的 `reviewStatus`、重发探测 `409 VERSION_EXISTS`、`/versions/<v>/signature` 三个探针判断版本到底走到哪一步。

by oracis1 installs1 stars

平台只有网页后台、没有上传 API 时,用本机已装的 Chrome/Edge + CDP 自动化走完上传/发布/填表流程——复用真实登录态、零安装(不下载 500MB Chromium)、能给文件选择框塞文件;并实测富文本编辑器(公众号 / CMS / 邮件模板)里到底哪些 CSS 能活下来,以及在决定是否接入平台自带的「一键排版 / AI 美化」前先抓它输出做结构化 diff。当用户说「只能网页上传」「后台发布」「网页填表自动提交」「发布到技能市场/各平台控制台」「复用已登录的浏览器」「公众号排版样式不生效/保存后样式没了」「一键排版要不要用」「点了按钮没反应/提交没成功也没报错」时使用。

by oracis2 installs

一键安装并实测验证已验证可用的免费 LLM 到 WorkBuddy/Claude Code,无需注册、无需 API Key。当用户说「装免费模型」「加免费模型」「免费 LLM」「免费模型一键装」「验证免费模型可用吗」「免费模型怎么接入」「帮我配几个免费模型」「监控免费模型」「免费模型挂了吗」「kilo 网关」「kilo-auto」「nemotron 免费」「space-bunny」「智谱 glm 免费」「zhipu 免费」「glm-4-flash」「glm-4.7-flash」「glm-z1-flash」「glm-4v-flash」「探测国外免费模型」「国外平台免费 llm」「优先用免费模型」「读图桥接」「vision bridge」「给 glm-4-flash 加读图」「不读图的模型怎么看图」「阶跃星辰」「stepfun」「step 5」「step-5-preview」「限时免费模型」「ccproxy 读图转发」「给 claude code 加读图」时使用。也用于验证已有免费模型配置是否真的可用(tool calling 是否支持、是否限流、是否支持读图),以及定期 watch 监控免费模型是否下线/限流/失去工具调用能力。

by oracis1 installs

在中国大陆网络环境下用 yt-dlp 下载视频(含 Windows GUI 封装)。当用户要下载 YouTube、Bilibili、SoundCloud 等 yt-dlp 支持的站点内容,或遇到「yt-dlp 装不上 / 下载报 502 / Tunnel connection failed / ffmpeg not found / 缺 JS runtime / TLS fingerprint / watch?v=&list= 把整个列表都下了 / Sign in to confirm you're not a bot / The page needs to be reloaded / 下到一半突然下不动 / 下回来的视频糊、有拖影残影 / 下载速度特别慢」等问题时使用。

by oracis2 installs

聚合搜索百度网盘/夸克网盘/阿里云盘等网盘分享链接。当用户想按作者名、课程名、剧名、书名、软件名找网盘下载路径,或提到「网盘搜索」「PanSou」「盘搜」「找到下载链接」「夸克/百度/阿里网盘资源」时使用。包含已验证的 PanSou 协议端点、绕过系统代理的必要写法、以及可直接运行的本地 Web 应用 panradar.py。

by oracis2 installs

在 WorkBuddy(Windows)环境里交付零依赖本地 Web 应用,并绕开官方测试技能完全不覆盖的本机专属坑。当用户要在本机跑起来一个本地 Web 应用 / 单文件工具 / 案例库 / 看板 / 小工具,或要验证刚写完的 HTML/JS/Python 交付物真的能工作时使用。独家覆盖:Bash 缺 coreutils、bash 是 WSL 启动桩、rm 是坏 shim、PowerShell 不回显 stdout、cwd 漂移、预览面板靠 HEAD 探活——这些在干净 Linux 环境里遇不到。

by oracis1 installs