Communitygithub.com

RolynTrotter/vibe-podcast

从 YouTube 讲座、演讲或以往播客剧集中挖掘可引用的素材,提取带时间戳的片段,并为播客生成引用来源与底部三分之一文字提示。

vibe-podcast 是什么?

该技能是一个专为播客制作设计的 AI 辅助工具链,它能将原始视频源(YouTube 讲座、演讲、自制的播客剧集)转化为结构化的引用、时间戳片段和视频剪辑提示。核心工作流程分为四步:下载(通过 yt-dlp 获取音频及信息)、转录(调用 mlx-whisper 生成带词级时间戳的转录稿,并支持手动修正误听)、挖掘引用(基于正则搜索定位关键语句,并手动整理到 `quotes.json`)、以及生成最终输出(包括引用提示表、剪辑用 JSON、FCPX 兼容的底部三分之一字幕等)。它主要支持 macOS 平台,依赖标准库 Python、`mlx_whisper` 和 ffmpeg,强调非破坏性操作,所有输出都带有时间锚点,方便后期在 Final Cut Pro 等编辑软件中精确放置。该工具链能高效处理长视频(如 15 分钟的音频约 35 秒完成转录),并自动修复常见的人名拼写错误,让播客制作人能够快速、准确地从大量素材中提取高质量引用。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RolynTrotter/vibe-podcast/tree/HEAD/.claude/skills/citations

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

引用:源 → 转录稿 → 引文 → 提示与片段

工具:agent-citations/citekit.py(标准库 Python 加上 mlx_whisper 和 ffmpeg)。它永远不会覆盖输入文件,并且在没有 --force 参数的情况下拒绝替换自己的输出。

批次目录结构

每个主题一个文件夹,位于 active_edits/<主题>/ 下:

sources/video_sources.txt         用户的 URL 列表
sources/audio/<id>.m4a .info.json  来自 yt-dlp(步骤 1)
sources/transcripts/<id>.json .md   步骤 2
podcast/<ep>.json .md                 我们自己的剧集字幕,已导入(步骤 2b)
sources/quotes.json                  步骤 3,由你编写
sources/citations/                   步骤 4 的输出

1. 下载(由用户运行)

YouTube 在此处阻止了匿名 yt-dlp。请将以下命令提供给用户,而不是直接运行它。 它需要 Firefox cookies 和 tv/safari 客户端,并保持音频较小(Whisper 只需要 16 kHz 单声道):

cd active_edits/<主题>/sources && for id in ID1 ID2; do yt-dlp --cookies-from-browser firefox --extractor-args "youtube:player_client=tv,web_safari,mweb" -f "wa/w" -x --audio-format m4a --postprocessor-args "ExtractAudio:-ac 1 -ar 16000" --write-info-json --write-auto-subs --sub-langs en --sub-format json3 --no-overwrites -o "audio/%(id)s.%(ext)s" "https://youtu.be/$id"; done

对于频道的过往视频,先列出列表,然后挑选:yt-dlp --flat-playlist --print "%(id)s %(duration_string)s %(title)s" https://www.youtube.com/@频道名/videos。 如果列表很长,可以使用 Jev(vibe-classification)对标题进行分类。

2. 转录

  • citekit.py transcribe sources/audio/<id>.m4a:使用 mlx-whisper large-v3-turbo 模型,带词级时间戳。初始提示为视频的标题和描述,这能修正大多数名字的拼写。在此 Mac 上运行速度约为 85 倍实时(一段 15 分钟的音频大约需要 35 秒;模型会下载一次)。
  • citekit.py captions sources/audio/<id>.en.json3:YouTube 的自动字幕。即时生成,但没有标点符号。tv 客户端通常不会保存它们。
  • 2b. 我们自己的剧集:citekit.py itt EP.itt --id podcastN --media EP.mp4 --out active_edits/<主题>/podcast --fix 'REGEX=>Right'。 FCP 的字幕会弄乱名字。对于第 1 集:--fix '\bver ?m+[iu]l+e?\b=>Vermeule' --fix '\bvermil\b=>Vermeule' --fix '\bAsian Vermeule=>Adrian Vermeule'。 第 1 集还有词级修正记录在 podcast/podcast1.fixes.json 中(例如 Schmidt→Schmitt 等),重新导入时会回放。

随时修正误听(不要先问)

当你发现 确定的 误听(例如名字、混乱的引文、Whisper 因口吃而重复的词语)时,请修正它: citekit.py fix TRANSCRIPT '旧词=>新词' [...] [--near SECONDS]。它会就地编辑 <id>.json/.md 文件(新词共享旧时间段的计时,匹配可以跨段进行,末尾的标点符号会保留下来),将未修改的引擎输出保存为 <id>.raw.json,并将每次修正记录在 <id>.fixes.json 中。transcribe 和 itt 命令会回放该日志,因此修正能在重新运行时保留。不确定?请重新听取该片段,而不是猜测: ffmpeg -ss T -to T2 -i audio.m4a x.wav && mlx_whisper x.wav --output-format txt。先修正,再引用修正后的词语:locate 命令会根据修正后的转录稿进行匹配。

3. 挖掘引文(需要你的判断)

  1. 如果有我们的剧集转录稿,请阅读它,并列出主持人关于该主题提出的观点,每个观点附上其在剧集中的时间。这些时刻就是片段可以支持或反驳的论点。
  2. 对于每个观点,使用 citekit.py search '正则表达式' sources/transcripts/ 来寻找候选内容,然后阅读命中结果周围的 .md 文件。也要通读整个讲座:最好的台词并不总是主持人提到的那些。
  3. 一个好的引文应该简短(说话时长 5–25 秒)、自包含、明确是发言者本人的立场(而不是他总结对手的观点),并且可以放在底部三分之一处。请保留转录稿中的原词。不要清理它们,否则 locate 命令将无法找到它们。
  4. 编写 sources/quotes.json:
{"project": "Ep1 Vermeule 引用", "fps": 29.97, "episode": "../podcast/podcast1.json",
 "quotes": [{"id": "publius-weak-exec", "source": "Bw9M01S8MFI", "approx": 1234,
   "text": "转录稿中的原话",
   "episode_at": 2575, "episode_context": "主持人谈论汉密尔顿和罗马独裁官",
   "why": "他本人对论点的陈述", "tags": ["executive", "Federalist"],
   "citation": {"author": "~Adrian Vermeule", "title": "The Publius Paradox", "date": "2018年6月5日",
                "publication": "Chorley Lecture, LSE"}}]}

episode(相对于 quotes.json 的路径)是我们剧集的转录稿。使用它,每个引文的 episode_at(大致是主持人提出观点的时间)就成为一个插入点:即该时间点正在运行的主持人句子的结尾。 引用完整的思路。如果下一句完善了画面或论点,请将其包含在内(目标是一个 5–25 秒的片段,不是硬性限制)。

citation 默认为视频标题、上传日期和频道。请在顶层 "sources": {"<id>": {"citation": {...}}} 中为每个讲座设置一次真实的演讲地点和日期(来自视频描述)。引文自己的 citation 会覆盖该默认值。作者名字前面加上节目的 ~ 前缀,而 \n 会将长标题分行显示。

检查他 引用的 任何内容(汉密尔顿、卡夫卡、《学说汇纂》)是否与原文一致。Whisper 会听到似是而非的错误词语:在 Publius 讲座中,它将卡夫卡的“牺牲的祭品”(原文为"sacrificial pitchers")听成了“图片”("pictures")。

4. 提示与片段

citekit.py cues sources/quotes.json 会将每个引文对齐到词级时间戳(模糊匹配;如果匹配分数低于 0.8 则会发出警告),并写入 sources/citations/:

文件用途
citations.md按剧集顺序整理的审阅表:插入时间(记录时间和更早插入后时间)、就在切换前主持人的话、引文、来源/片段时间、YouTube ?t= 链接
clips.json供 AI 剪辑使用:来源入/出点、填充后入/出点(默认每边 5 秒,通过 --pad-before/--pad-after 可配置,每个引文可设置 pad_before/pad_after)、insert_at、insert_at_after_earlier_inserts、insert_after
citation_cues.json供 agent-motion/titles_fcpxml.py 使用:针对已插入片段后的剧集定时生成的引用 v2 底部三分之一字幕,在他开始说话时出现。未放置的引文会首尾相连排列
download_clips.sh用户运行它:仅下载这些填充范围的全质量视频(使用 --download-sections)

然后执行 citekit.py audio-clips sources/citations/clips.json 从本地音频中剪切出带填充的音频预览,以便通过耳朵检查。若要在 FCP 中放置底部三分之一字幕,请遵循 motion-graphics 技能的说明: python3 agent-motion/titles_fcpxml.py sources/citations/citation_cues.json -o citations.fcpxml。

备注

  • transcribe 会自行解码为 16 kHz WAV,并拒绝解码后长度远短于视频的音频。使用不同 -f 参数恢复的 yt-dlp 下载会将两种编解码器拼接到一个 .m4a 文件中(2026-10-18 日观察到:先是 AAC-LC 然后是 HE-AAC),而 ffmpeg 会无声地丢弃切换后的所有内容。请使用 --no-continue 重新下载。切勿在不同格式之间恢复下载。

  • 请通过耳朵验证片段,或者低成本验证:mlx_whisper citations/audio_clips/<id>.m4a --output-format txt 应该能显示引文以及几秒的前导和尾随空白。

  • Whisper 的时间戳在词级上精确到约 ±0.3 秒。这就是片段填充存在的意义。FCP 的 iTT 字幕仅为整行计时,因此 itt 会将词语均匀分布在每行中。

  • Wispr Flow 连接器仅能读取会议记录器转录稿。它不能转录文件。

相关技能