/install mp3-list-to-video
Skill: mp3-list-to-video
将文件夹下的所有 MP3 文件按自然顺序拼接成一个 MP4 视频文件。支持两种输出:
- 黑色背景视频:仅拼接音频,画面为黑色
- 菜单高亮视频:画面显示全部歌曲清单,并根据播放时间高亮当前歌曲,右侧默认叠加持续旋转的黑胶唱片
运行时会自动做依赖检查、输入顺序确认和输出媒体流校验。
前提条件
- ffmpeg: 必须已安装并可在 PATH 中访问
- ffprobe: 必须已安装并可在 PATH 中访问,用于合成后校验输出文件
- Python 3: 用于运行合并脚本
- ffmpeg filters: 生成菜单和黑胶动效时需要 FFmpeg 支持
ass、rotate、overlay滤镜
检查依赖:
which ffmpeg
which ffprobe
python3 --version
ffmpeg -hide_banner -filters | rg ' ass '
ffmpeg -hide_banner -filters | rg ' rotate | overlay '
输入文件
默认从工作区根目录的 playlist/ 目录读取所有 .mp3 文件,按自然文件名排序后拼接。自然排序会让 10.xxx.mp3 排在 9.xxx.mp3 后面,而不是排在 2.xxx.mp3 前面。
playlist/
├── 1.朵.mp3
├── 2.感官先生.mp3
├── 3.I Want It That Way.mp3
└── ...
输出文件
默认输出到工作区根目录:playlist_output.mp4
- 视频格式:MP4 (H.264)
- 分辨率:1920x1080
- 帧率:30fps
- 音频:AAC 44.1kHz stereo
- 视频流:黑色画面(无实际视频内容)
生成菜单高亮视频时,默认输出:
- 最终视频:
playlist_menu_output.mp4 - 菜单背景视频:
output/playlist_menu_background.mp4 - 菜单字幕层:
output/playlist_menu.ass - 歌曲时间轴:
output/playlist_menu_timeline.json - 预览抽帧:
output/playlist_menu_preview_*.png - 智能渲染帧:
output/playlist_menu_frames/frame_*.png - 智能渲染计划:
output/playlist_menu_frame_plan.json - 黑胶唱片 PNG:
output/playlist_vinyl.png - 菜单加动效视频:
output/playlist_menu_visual.mp4
使用方法
快速开始
生成黑色背景的合并视频:
脚本已包含在 skill 的 scripts/ 目录下,直接运行:
python3 scripts/merge_playlist.py
在当前工作区直接调用本 skill 中的脚本时:
python3 .opencode/skill/mp3-list-to-video/scripts/merge_playlist.py
基于已生成的 playlist_output.mp4 生成带歌曲清单和当前歌曲高亮的版本:
python3 .opencode/skill/mp3-list-to-video/scripts/add_playlist_menu.py
上面的命令默认使用优化后的 smart 模式。除非用户明确要求逐帧完整渲染,否则不要使用 --render-mode full。
自定义配置
脚本支持命令行参数,优先使用参数而不是手改脚本:
python3 scripts/merge_playlist.py \
--playlist-dir playlist \
--output playlist_output.mp4 \
--temp-dir output
可选参数:
--playlist-dir: MP3 输入目录--output: MP4 输出文件--temp-dir: 临时文件目录,会写入concat_list.txt--skip-verify: 跳过合成后的ffprobe校验,仅在排查问题时使用
菜单高亮脚本支持:
python3 scripts/add_playlist_menu.py \
--playlist-dir playlist \
--source-video playlist_output.mp4 \
--output playlist_menu_output.mp4 \
--temp-dir output \
--render-mode smart \
--jobs 4 \
--active-seconds 3 \
--active-frames 60
可选参数:
--playlist-dir: MP3 输入目录,用来计算每首歌时长和歌曲顺序--source-video: 已合并 MP4,用来复用最终音频--output: 带菜单高亮的最终 MP4--temp-dir: 中间文件目录,会写入 ASS 菜单层、背景视频和时间轴 JSON--menu-video: 单独指定菜单背景视频输出路径--render-mode: 菜单背景渲染模式,默认smart;可选full--jobs:smart模式下并行生成菜单帧的任务数--active-seconds: 每首歌开头按高帧密度生成的秒数,默认3--active-frames: 每首歌开头高帧密度段生成的帧数,默认60--disable-vinyl: 禁用右侧旋转黑胶唱片动效--vinyl-size: 黑胶唱片尺寸,默认360--vinyl-x: 黑胶唱片左上角 X 坐标,默认1480--vinyl-y: 黑胶唱片左上角 Y 坐标,默认370--vinyl-rotation-seconds: 黑胶唱片转一圈所需秒数,默认4--preview-times: 逗号分隔的抽帧检查时间,例如00:00:10,00:05:00,00:34:10--skip-previews: 跳过合成后的预览帧抽取--preview-only: 不重新生成视频,只对已有输出抽取预览帧
只复查已有菜单视频的画面时:
python3 scripts/add_playlist_menu.py \
--output playlist_menu_output.mp4 \
--preview-only \
--preview-times 00:00:10,00:05:00,00:34:10
自动检查机制
运行脚本时会自动执行以下检查:
- 依赖检查: 确认
ffmpeg、ffprobe和 Python 可用,并打印实际路径/版本 - 输入检查: 确认 playlist 目录存在,且至少包含一个
.mp3文件 - 顺序检查: 打印最终合并顺序,便于确认
1, 2, ..., 10是否正确 - 输出文件检查: 确认 MP4 文件存在且大小大于 0
- 媒体流检查: 使用
ffprobe确认输出包含 H.264 视频流和 AAC 音频流 - 规格检查: 确认视频为
1920x1080,音频为44100Hz双声道 - 时长检查: 确认输出时长大于 0,并打印可读时长
菜单高亮脚本还会额外检查:
source-video是否存在- FFmpeg 是否支持
ass、rotate、overlay滤镜 - 每首 MP3 的真实时长
- 每首歌的开始/结束时间,最后一首会对齐
source-video的总时长,避免封装误差导致结尾空白 - 合成后自动抽取预览帧,默认覆盖首歌、第二首相邻两秒和最后一首;相邻帧用于验证黑胶持续旋转
- 计算预览帧 MD5,确认不同时间点的画面不是完全相同,避免高亮没有随时间变化
smart模式会写出帧计划 JSON,记录 active/static 帧数量和每帧持续时间- 默认生成
playlist_vinyl.png并叠加旋转动效;最终视频即使当前歌曲不切换,右侧黑胶也会持续运动
合成完成后应看到类似输出:
输出校验通过:
- 文件大小: 39.2MB
- 时长: 37:35 (2254.633s)
- 视频流: h264 1920x1080
- 音频流: aac 44100Hz 2ch
实现原理
黑色背景合并
- 扫描 MP3 文件: 使用
pathlib扫描playlist/目录,按自然文件名排序 - 生成 concat 列表: 创建 FFmpeg concat 格式的文件列表
- 实时生成黑色视频: 使用 FFmpeg lavfi 的 color 滤镜实时生成黑色视频流(避免预生成大文件)
- 拼接音频: 使用 FFmpeg concat 协议拼接所有 MP3 文件
- 合并音视频: 将黑色视频流与拼接后的音频合并为最终 MP4
- 校验输出: 使用
ffprobe校验文件大小、时长、视频流和音频流
核心 FFmpeg 命令:
ffmpeg -y \
-f concat -safe 0 -i concat_list.txt \
-f lavfi -i color=black:size=1920x1080:rate=30 \
-c:v libx264 -preset ultrafast -pix_fmt yuv420p \
-c:a aac -shortest \
output.mp4
菜单高亮背景
- 读取歌曲时长: 使用
ffprobe获取每个 MP3 的真实时长 - 生成时间轴: 计算每首歌的开始时间和结束时间,例如
00:00 - 04:45 - 生成 ASS 菜单层: 写入所有歌曲清单,并为每首歌创建只在对应时间段显示的高亮行
- 生成菜单背景视频:
smart模式:只渲染必要 PNG 帧。每首歌开头active-seconds内生成active-frames帧,其余静态段只生成 1 帧并用 concatduration拉长;帧生成会按--jobs并行执行full模式:回退到整段 30fps 渲染,速度较慢但实现直接
- 生成黑胶动效层: 脚本用内置 PNG 写入逻辑生成透明背景黑胶唱片,不依赖 Pillow 或外部素材
- 叠加旋转黑胶: 使用 FFmpeg
rotate + overlay将黑胶放到菜单右侧,并按--vinyl-rotation-seconds持续转动 - 融合原音频: 将最终视觉视频与
playlist_output.mp4的音频流合并 - 校验输出: 确认最终视频包含视频流、音频流、时长和分辨率
- 抽帧复查: 从关键时间点抽取 PNG 帧,确认菜单可见且高亮随时间变化
full 模式核心 FFmpeg 命令:
ffmpeg -y \
-f lavfi -i color=c=0x111214:size=1920x1080:rate=30:duration=2255.2 \
-vf "ass=filename='output/playlist_menu.ass'" \
-an -c:v libx264 -preset ultrafast -pix_fmt yuv420p \
output/playlist_menu_background.mp4
ffmpeg -y \
-i output/playlist_menu_background.mp4 \
-i playlist_output.mp4 \
-map 0:v:0 -map 1:a:0 \
-c:v copy -c:a copy -shortest \
playlist_menu_output.mp4
smart 模式的核心思路:
# 对每个需要的时间点生成一张菜单帧;通过 setpts 让 ASS 按全局时间渲染对应高亮
ffmpeg -y -loglevel error \
-f lavfi -i color=c=0x111214:size=1920x1080:rate=1:duration=1 \
-vf "setpts=PTS+300/TB,ass=filename='output/playlist_menu.ass',setpts=PTS-STARTPTS" \
-frames:v 1 -update 1 output/playlist_menu_frames/frame_00100.png
# 使用 concat duration 拉长静态帧,再统一输出 30fps 标准 MP4
ffmpeg -y \
-f concat -safe 0 -i output/playlist_menu_frames.txt \
-vf "fps=30,format=yuv420p" \
-an -c:v libx264 -preset ultrafast -pix_fmt yuv420p \
output/playlist_menu_background.mp4
# 黑胶动效层叠加
ffmpeg -y \
-i output/playlist_menu_background.mp4 \
-loop 1 -framerate 30 -i output/playlist_vinyl.png \
-filter_complex "[1:v]format=rgba,rotate='2*PI*t/4':ow=iw:oh=ih:c=none[vinyl];[0:v][vinyl]overlay=1480:370,fps=30,format=yuv420p[v]" \
-map "[v]" -an -c:v libx264 -preset ultrafast \
output/playlist_menu_visual.mp4
抽帧复查命令:
ffmpeg -y -loglevel error \
-ss 00:05:00 \
-i playlist_menu_output.mp4 \
-frames:v 1 -update 1 \
output/playlist_menu_preview_0500.png
注意事项
1. 文件排序
默认按自然排序(如 1.mp3, 2.mp3, 10.mp3),适合带数字前缀的播放列表。脚本中的排序逻辑:
import re
files.sort(key=natural_key)
2. FFmpeg concat 协议
使用 -f concat -safe 0 格式拼接音频文件,要求:
- 所有 MP3 文件编码参数一致(采样率、声道数)
- 文件列表使用绝对路径避免路径问题
3. 性能优化
- 使用
-preset ultrafast加速视频编码(牺牲少量压缩率) - 黑色视频通过 lavfi 实时生成,无需预生成临时文件
- 音频统一转为 AAC,提升 MP4 兼容性
- 菜单高亮视频默认使用
smart模式,避免整段 30fps 重渲染 smart模式下,长静态区间只生成 1 帧,通过 concatduration保持时长- 黑胶唱片动效在菜单背景完成后单独叠加,因此不会被 smart 模式的静态帧优化冻结
--jobs控制并行生成帧的 ffmpeg 进程数;机器负载过高时调低,CPU 空闲时可调高- 如果用户明确需要所有时间点逐帧渲染,使用
--render-mode full
推荐默认策略:
- 不需要动画时,保留默认
--active-seconds 3 --active-frames 60 - 如果只想极速生成静态菜单,可使用
--active-seconds 0 --active-frames 1 - 如果高亮切换需要更细腻,可提高
--active-frames - 如果机器发热或并行进程太多,可降低
--jobs
4. 手动复查命令
如果需要在脚本外手动复查黑色背景合并输出,使用:
ls -lh playlist_output.mp4 output/concat_list.txt
ffprobe -v error \
-show_entries format=duration,size \
-show_entries stream=index,codec_type,codec_name,width,height,sample_rate,channels \
-of default=noprint_wrappers=1 \
playlist_output.mp4
sed -n '1,20p' output/concat_list.txt
菜单高亮视频复查重点:
ls -lh playlist_menu_output.mp4 output/playlist_menu_background.mp4 output/playlist_menu.ass output/playlist_menu_timeline.json
ls -lh output/playlist_menu_frame_plan.json output/playlist_menu_frames.txt output/playlist_vinyl.png output/playlist_menu_visual.mp4
ffprobe -v error \
-show_entries format=duration,size \
-show_entries stream=index,codec_type,codec_name,width,height,sample_rate,channels \
-of default=noprint_wrappers=1 \
playlist_menu_output.mp4
python3 scripts/add_playlist_menu.py --preview-only --preview-times 00:00:10,00:05:00,00:34:10
验收标准:
playlist_menu_output.mp4同时包含视频流和音频流- 视频分辨率为
1920x1080 - 时间轴 JSON 中每首歌有
start_text和end_text smart模式下,帧计划 JSON 中应包含 active/static 帧数量- 帧计划中的
duration_sum应接近total_duration - 预览帧文件存在,且多个时间点的 MD5 不完全相同
- 打开一个中间时间点预览帧,当前歌曲行应高亮,时间列和歌名列之间应有清楚间距
- 默认预览会抽取第二首歌内相邻 1 秒的两帧,MD5 应不同,以确认黑胶唱片持续旋转
5. 扩展方向
此 skill 为第一阶段实现(仅拼接音频)。后续可扩展:
- 添加专辑封面作为背景画面
- 添加歌曲名、时间轴等文字叠加
- 生成歌词卡拉OK动画视频(参考 song-movie-generater skill)
- 支持更多音频格式(m4a, flac 等)
菜单高亮视频当前使用静态列表和当前歌曲高亮。可继续扩展:
- 根据专辑封面生成背景图
- 添加播放进度条
- 当前行添加淡入淡出或指示图标
- 歌曲较多时分页显示
- 将黑胶中心标签替换为专辑封面
故障排查
ffmpeg: command not found
安装 ffmpeg:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
输出视频时长为 0
脚本会自动用 ffprobe 检查时长。如果失败:
- 检查
output/concat_list.txt是否包含所有 MP3 - 检查 FFmpeg 命令是否包含
-shortest参数 - 单独用
ffprobe playlist_output.mp4查看输出媒体信息
文件顺序不正确
检查脚本打印的“合并顺序”。脚本使用自然排序,推荐输入文件使用数字前缀,例如 1.xxx.mp3、2.xxx.mp3、10.xxx.mp3。
输出校验失败
脚本会直接列出失败项,例如缺少视频流、缺少音频流、时长为 0、分辨率不符或采样率不符。先查看脚本打印的错误,再用“手动复查命令”确认具体媒体流信息。
菜单文字无法显示中文或日文
菜单脚本默认使用 macOS 上常见的 Hiragino Sans GB。如果目标机器没有该字体,修改 scripts/add_playlist_menu.py 中的 FONT_NAME,或安装支持中日文的字体。修改字体后运行 --preview-only 抽帧确认中文、日文和英文都正常显示。
菜单文字太挤或重叠
菜单脚本中的布局常量控制文字位置:
NUMBER_X: 序号列TIME_X: 时间列TITLE_X: 歌名列ROW_START_Y: 第一行纵向位置ROW_HEIGHT: 行高
如果时间和歌名贴得太近,优先调大 TITLE_X。调整后先运行:
python3 scripts/add_playlist_menu.py --preview-only --preview-times 00:05:00
如果已改动 ASS 生成逻辑且需要完整重渲染,再运行完整菜单生成命令。
智能渲染速度或质量不合适
默认参数针对“每首歌开头 3 秒生成 60 帧,其余静态段 1 帧”的场景:
python3 scripts/add_playlist_menu.py \
--render-mode smart \
--jobs 4 \
--active-seconds 3 \
--active-frames 60
调整建议:
- 生成太慢:降低
--active-frames或--jobs - 开头动画/高亮过渡不够细:提高
--active-frames - 机器 CPU 足够:提高
--jobs - 怀疑 concat 或时间轴问题:临时使用
--render-mode full回退整段渲染
黑胶唱片位置或速度不合适
默认黑胶参数:
python3 scripts/add_playlist_menu.py \
--vinyl-size 360 \
--vinyl-x 1480 \
--vinyl-y 370 \
--vinyl-rotation-seconds 4
调整建议:
- 唱片挡住菜单文字:调大
--vinyl-x或调小--vinyl-size - 唱片太靠右或超出画面:调小
--vinyl-x - 转得太快:调大
--vinyl-rotation-seconds - 转得太慢:调小
--vinyl-rotation-seconds - 不需要动效:使用
--disable-vinyl
ffmpeg 不支持 ass 滤镜
菜单高亮视频依赖 ass 滤镜。检查:
ffmpeg -hide_banner -filters | rg ' ass '
如果没有输出,需要安装带 libass 的 FFmpeg。
相关 Skills
- song-movie-generater: 生成带歌词卡拉OK动画的视频,功能更丰富
- gequbao-downloader: 从歌曲宝下载 MP3,配合此 skill 可实现"下载+拼接"完整流程
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install mp3-list-to-video - After installation, invoke the skill by name or use
/mp3-list-to-video - Provide required inputs per the skill's parameter spec and get structured output
What is mp3-list-to-video?
将指定文件夹下的所有 MP3 文件拼接成一个 MP4 视频文件,可生成黑色背景视频,也可基于已合并 MP4 生成带歌曲清单、当前歌曲高亮和右侧旋转黑胶唱片动效的菜单背景视频。菜单高亮默认使用智能分段渲染:并行生成关键帧、每首歌开头高帧密度、其余静态区间单帧拉长,避免整段 30fps 慢速重渲染;黑胶唱片作为独立动... It is an AI Agent Skill for Claude Code / OpenClaw, with 52 downloads so far.
How do I install mp3-list-to-video?
Run "/install mp3-list-to-video" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is mp3-list-to-video free?
Yes, mp3-list-to-video is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does mp3-list-to-video support?
mp3-list-to-video is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created mp3-list-to-video?
It is built and maintained by 桔子桑 (@ecojust); the current version is v1.0.0.