podcast-kit — 播客工具包 是做什么的?
用途
发布一集播客包含一组从一套事实数据中复制的小任务:节目笔记、YouTube 章节描述、Podcasting 2.0 章节文件,以及寻找值得剪辑的时刻。本工具接受一个单集 JSON 文件,产出所有这些内容,让事实只存在一处。基于纯 Python 标准库;仅本地运行;唯一读取的文件是单集 JSON 文件。
本工具的诚实核心: 章节列表仅在有效时才会导出——播放器会静默忽略损坏的列表,因此输出一个损坏的导出比不输出更糟糕;音频剪辑评分是根据转录文本计算出的一个排名,指示优先查看的位置。它绝不是对时刻效果的预测,一个计划也永远不是渲染好的音频视频。
何时使用 / 何时不使用
在以下情况使用:
- 一集播客已存在(或可以写成)一个单集 JSON 文件:完成发布意味着产生节目笔记、YouTube 和播客应用的章节,以及决定剪辑什么。
- 一个流水线需要一个通过/不通过的章节门控:
chapters退出码 0 = 列表有效且导出在输出中;退出码 1 = 不要按现有方式发布章节。 - 编辑希望获得五个值得在浏览整个录音之前先听的时刻。
不要使用的情况:
- 需要转录——转录是这里的输入。请先用转录工具生成片段。
- 需要音频或视频渲染——
audiogram-plan是一个计划(时间戳 + 文字 + 原因)。把它交给编辑器或渲染工具。 - 需要 RSS、托管或批量处理——本工具有意每次只处理一集文件。
命令
每个命令将单集文件作为位置参数,并支持 --json 标志。
# 节目笔记 —— Markdown(默认)或纯文本
python3 src/podcast_kit.py show-notes EPISODE.json \
[--format md|text]
# 验证 + 导出章节(无效时退出码 1 且不导出)
python3 src/podcast_kit.py chapters EPISODE.json \
[--format youtube|json|both]
# 对值得剪辑的时刻排名(无合格片段时退出码 1)
python3 src/podcast_kit.py audiogram-plan EPISODE.json \
[--top 5]
单集字段:show(可选)、episode(可选整数)、title(show-notes 必需)、published(可选,按原样输出)、duration_seconds(chapters 必需;秒数或时间戳字符串)、summary(show-notes 必需)、guests —— {"name", "role"?} 的列表、links —— {"label", "url"} 的列表、chapters —— {"start", "title"} 的列表、transcript —— {"start", "end", "speaker"?, "text"} 的列表。时间戳在所有地方均接受秒数(754)、"M:SS" 或 "H:MM:SS" 格式。每次读取时都会对文件进行验证;结构性问题(缺少字段、错误的时间戳、片段结束早于开始、片段超出时长)属于退出码 2 的错误,并会指出有问题的章节或片段。
章节验证(精确)
问题(退出码 1,不导出):第一个章节不从 0 开始;某个起始时间不严格大于前一个起始时间;某个起始时间等于或超过了 duration_seconds(起始时间为 duration − 1 有效);标题为空。
警告(报告,但仍会导出):章节少于 3 个;章节短于 10 秒。这两条是 YouTube 的规则,而非 Podcasting 2.0 的——无论如何导出都是有效的,但 YouTube 可能会忽略它们。
导出格式:YouTube 行是 MM:SS 标题(若单集时长达到或超过 1 小时,则使用 H:MM:SS)。Podcasting 2.0 是 {"version": "1.2.0", "chapters": [{"startTime", "title", "endTime"}]}——每个章节的 endTime 是下一个章节的 startTime,最后一个章节的 endTime 是总时长。
音频剪辑评分(精确)
对于每个转录片段,仅基于其文本:
- 问号:每个 +2,上限 +4
- 数字(数字序列,例如
18、1,900):每个 +2,上限 +4 - 感叹号:每个 +1,上限 +2
- 强词——固定的列表
"the truth is"、"biggest mistake"、"nobody tells you"、"everyone gets wrong"、"never"、"always"、"secret"、"myth"(整词匹配,忽略大小写):每个 +3,上限 +6 - 片段长度在 15–60 秒(含)之间:+2
最低门槛:一个片段需要总分 5 才能被列出。排序规则:分数降序,平局时按开始时间最早的优先。--top N 限制列出数量(0 或负数表示列出所有合格片段)。每个列出的时刻都会打印其评分原因,包含实际找到的信号——在本工具中,有评分但没有原因的情况是不存在的。
输出 JSON 模式(--json)
通用字段:tool("podcast-kit")、version、command、episode_file(文件名)。
show-notes:title、format("markdown" 或 "text")、notes——渲染后的笔记字符串,与文本视图打印的完全一致。
chapters:title、duration_seconds、valid(布尔值)、problems(字符串列表)、warnings(字符串列表)、chapters——每个 {start_seconds, start, title, end_seconds, end, length_seconds}——youtube(导出的文本,无效时为 null)、podcasting20(导出的对象,无效时为 null)。
audiogram-plan:title、segments_scanned、floor(5)、moments——每个 {rank, start_seconds, start, end_seconds, end, duration_seconds, speaker, text, score, reasons}。当没有合格片段时,moments 为 [],并增加一个 note 字段说明未达到最低门槛(退出码 1)。
发生错误时,stdout 输出一个对象:{"error": "<message>"},退出码为 2——包括 --json 模式下 argparse 的使用错误。绝不输出纯文本或堆栈跟踪。
退出码
0——命令成功;对于audiogram-plan,至少有一个片段达到最低门槛。1——发现:chapters发现验证问题(未产生导出),或audiogram-plan未找到值得剪辑的片段。这两者都不是崩溃——请基于发现进行后续处理。2——错误:单集文件不存在或不是有效 JSON,缺少必需字段,错误的时间戳,格式错误的章节或片段,无效的标记。不得将失败运行的输出事实引用为有效结果。
代理必须遵守的限制与诚实规则
- **无效的章节导出为空。**当
chapters退出码为 1 时,不要从 JSON 输出中的chapters数组重建导出并发布——列出的问题正是播放器会忽略它的原因。请修正单集文件后重新运行。 - **警告不是问题。**带有警告的有效列表可以发布;请明确说明 YouTube 可能不会显示章节(数量太少或某个太短),但播客应用会正常显示。
- **评分不是预测。**将某个时刻报告为“根据文本信号排名第一”,永远不要说是“最佳时刻”或“会表现好的剪辑”。该工具无法听到录音;实际的演绎方式可能使低分片段成为正确的剪辑,而计划已经说明了这一点。
- **
audiogram-plan的退出码 1 不代表单集空洞。**它表示没有片段携带足够的排名信号。报告时务必附加限定说明:该工具仅读取文本。 - 计划不是文件。
audiogram-plan产生时间戳和文本。在渲染工具实际根据计划生成音频剪辑之前,绝不要告诉用户存在一个音频剪辑。 - **仅本地运行:**该工具只读取命令行指定的单集文件,不向任何地方发送任何数据。