小宇宙播客语音转文本的实践路:我最后为什么选了半自动

1. 背景

我只是想把小宇宙播客转文字稿,但是路径很长,每次打开网页、找标题、找音频、复制链接、再整理笔记。

看起来这是一个很适合自动化的小任务。

给 Agent 一个小宇宙链接,它帮我把音频下载下来,再把页面里的节目介绍和时间轴整理成 showNotes.md。如果能更进一步,直接上传到飞书妙记,等它转写完成,再把逐字稿拉回来,那就更完整了。

但真正做下来,我发现这里面有两类问题。

第一类是确定的,可以自动化。

比如解析小宇宙页面、找到音频地址、下载音频、生成 Markdown、保存元数据。这些动作都很清楚,输入和输出也很稳定。只要脚本写好,Agent 每次都能按同样的方式执行。

第二类是不太稳定的,硬要全自动会变复杂。

比如飞书妙记的上传、转写状态、权限、用户身份、CLI 登录状态、转写完成时间。这些都不是一个脚本内部能完全控制的。尤其是妙记相关操作,有些接口需要用户身份,有些需要权限,有些还要等服务端处理完。为了把这一步完全自动化,我需要处理一堆授权、等待、重试、异常判断。

所以我最后决定:不要追求一步到位,先把最稳定、最高频、最烦人的部分自动化。

也就是:下载播客音频和 show notes,并在完成后打开本地文件夹。

2. 第一个版本:先把音频拿下来

最早的目标很直接。

我给 Agent 一个小宇宙单集链接:

text
https://www.xiaoyuzhoufm.com/episode/69f1fa4e0694c843e781e8da

Agent 要做三件事:

  1. 打开页面,解析出播客标题、节目名、音频地址。
  2. 下载音频文件。
  3. 把 show notes 转成适合阅读的 Markdown。

这一步很快就跑通了。脚本可以从页面里的 JSON-LD 里读到 PodcastEpisode 信息,音频地址优先用 associatedMedia.contentUrl,不行再用 og:audio 兜底。标题、发布时间、时长、节目介绍也都能拿到。

下载完成后,本地会有三个文件:

text
任鑫 AI 转型没戏,得重新投胎.m4a
showNotes.md
episode.json

这里我没有只保存音频。因为如果只是一个 .m4a,过几天再看就不知道它从哪里来、标题是什么、show notes 是什么、后续有没有转写过。

所以我把同一期节目的所有东西放在同一个目录里:

text
/Users/liguwe/skills/podcast/<播客标题>/

音频、show notes、元数据都在这里。这个目录就是这一期播客的本地归档单元。

3. 路径这件小事,折腾了很久

在 Codex 里是好的,在 Cursor 里就不对,这是因为安装技能不是还是使用 link 的方式更好,已经同步更新 我的 AI Agent Skills 管理工作流

4. 为什么下载完要打开文件夹

后来我又加了一个看似很小的功能:下载完成后自动打开这一期播客所在的文件夹。

这个功能很小,但体验差别很大。

之前流程是:Agent 告诉我文件路径,我再去 Finder 里一级一级找,或者复制路径打开。其实下一步我只是要把音频拿去上传到转写工具。文件已经下载好了,但还要手动找它,这一步很烦。

所以我把脚本改成:下载和写入完成后,默认打开本地节目目录。

也就是跑完以后,Finder 直接打开:

text
/Users/liguwe/skills/podcast/任鑫 AI 转型没戏,得重新投胎/

我马上就能看到音频、show notes 和 episode.json。要复制音频、拖到飞书妙记、或者后面做别的处理,都很顺。

如果是自动化测试,不想弹出文件夹,也可以加:

bash
--no-open-folder

这个设计本质上不是炫技,而是减少断点。

一个半自动流程里,最重要的不是把每一步都自动化,而是让人工介入的那一步尽量顺手。既然我下一步要手动上传,那脚本就应该把我带到那个文件面前。

5. 最终命令

现在这个技能的核心命令就是:

bash
python3 /Users/liguwe/.agents/skills/xiaoyuzhou-audio-download/scripts/download_xiaoyuzhou_episode.py "<小宇宙单集链接>"

它做的事情包括:

  • 解析小宇宙单集页面。
  • 下载音频。
  • 保存 show notes。
  • 写入 episode.json
  • 打开本地节目目录。

如果音频已经存在,它不会重复下载,但会刷新 show notes 和元数据。返回结果里也会告诉我:

json
"downloaded": false,
"folder_opened": true

downloaded: false 不是失败,而是说明文件已经在本地了。folder_opened: true 才是我现在最关心的,它说明下一步可以直接去复制音频。

6. 为什么不是全自动

我一开始确实想过全自动

理想状态是:

  1. 给一个小宇宙链接。
  2. 自动下载音频。
  3. 自动上传到飞书妙记。
  4. 自动等待转写完成。
  5. 自动下载逐字稿。
  6. 自动整理成 Markdown。

但这个链路太长了。每一步都可能失败,尤其是飞书妙记部分:权限、登录态、用户身份、转写等待时间、标题匹配,都可能变成不稳定因素。

如果为了追求全自动,把一堆不稳定因素都塞进一个脚本里,最后很可能变成“看起来高级,但经常卡住”。

我现在更愿意接受一个朴素的半自动方案:

text
Agent 负责稳定重复的部分
人负责权限敏感和不稳定的部分

下载、整理、归档,这些交给 Agent。

上传转写、确认状态,这些先由我手动做。

等后续飞书妙记这条链路足够稳定,再把“检查转写是否完成”和“下载逐字稿”拆成第二个 skill,而不是一开始就把所有东西塞进第一个 skill。

7. 最后的工作流

现在我的播客转文本路径是这样的:

  • 第一步,我给 Agent 一个小宇宙链接。
  • 第二步,Agent 下载音频,保存 show notes 和元数据。
  • 第三步,本地节目目录自动打开。
  • 第四步,我把音频复制或拖到转写飞书妙记中。
  • 第五步,等转写完成后,再让 Agent 帮我把转写文本整理成 Markdown。

8. 一些想法💡

对于个人来说,完全的自动化,ROI并不高,本来这个自动化对于个人来说就不是一个高频动作