博客 Telegram 频道自动化推送实战记录
为了方便读者及时获取更新,近期我为博客增加了 Telegram 频道自动推送功能。目标很明确:每当有新文章发布时,GitHub Actions 自动触发脚本,将文章标题、摘要和链接发送到订阅频道,并且支持 Instant View(即时预览)以提供丝滑的阅读体验。
本文整合了整个开发过程中的实战经验,特别是解决“时序竞争”和“Instant View 适配”等棘手问题的方案。
1. 基础架构设计
整个自动化链路的基础逻辑如下:
- Git 检测:在 CI/CD 流程中检测本次 Commit 新增的 Markdown 文件。
- 内容解析:读取文件 Frontmatter,提取标题、日期、标签和摘要。
- API 推送:调用 Telegram Bot API 将消息发送到指定频道。
1.1 申请机器人与频道配置
这是最基础的一步:
- 在 Telegram 找 @BotFather 申请 Bot,获取
API Token。 - 建立频道(Channel),将 Bot 拉入并设为管理员。
- 通过转发消息给 @getidsbot 获取频道的
Chat ID(通常以-100开头)。
1.2 自动化脚本逻辑
使用 Node.js 编写脚本 (scripts/telegram-notify.js)。核心难点在于准确识别“新文章”。最初我只检测 Added (A) 状态的文件,后来发现重命名文件(如修正文件名拼写)会导致漏推。
解决方案:将 git diff 的过滤器升级为 ACR,覆盖 Add、Copy、Rename 三种情况。
// 示例:获取变更文件列表
let command = 'git diff --name-only --diff-filter=ACR HEAD~1 HEAD';
2. 核心挑战与踩坑记录
虽然原理简单,但在实际落地过程中遇到了不少意想不到的坑。
2.1 时序陷阱:通知发了,预览却挂了
现象: 消息成功发送到了频道,但无论是在 App 端还是 Web 端,都没有显示文章的预览卡片(Preview Card)。
原因分析:
这是一个典型的**竞争条件(Race Condition)**问题。
最初的工作流顺序是:构建 -> 发布 -> 通知。
看似合理,但 GitHub Pages 的部署(Deploy)步骤完成后,CDN 的缓存刷新和全球分发需要时间。当脚本立即触发 Telegram Bot 发送消息时,Telegram 的爬虫服务器(Crawler)立刻去抓取该链接,此时新文章在 CDN 节点上可能还未生效(返回 404)。一旦爬虫抓取失败,它就会缓存这个失败结果,导致预览卡片无法生成。
解决方案: 调整 GitHub Actions 的执行顺序,并强制增加等待时间。
- 顺序调整:确保
通知步骤严格在部署步骤成功之后执行。 - 增加延迟:在两者之间插入
sleep 60,给 GitHub Pages 的 CDN 留出足够的传播时间。
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
# ... 配置省略 ...
- name: Wait for deployment propagation
run: sleep 60 # 关键:等待 CDN 生效
- name: Check for new content and notify
if: success()
run: node scripts/telegram-notify.js
2.2 Instant View 的“严苛”规范
为了提升阅读体验,我配置了 Telegram Instant View。但在测试规则时报错:Element <img> is not supported in <p>。
原因:
Hugo 或其他 Markdown 渲染器通常会将图片包裹在 <p> 标签中(例如 <p><img ...></p>)。然而,Telegram Instant View 的规范非常严格,不允许块级的 <img> 元素出现在 <p> 内部。
解决方案:
在 IV 模板规则中使用 @split_parent 指令,强制将图片从段落中“剥离”出来。
# Fix: <img> inside <p> is not allowed in Instant View
@split_parent: //p/img
此外,对于博客中嵌入的复杂 HTML 组件(如交互式图表、Hugo Shortcodes),Instant View 无法渲染,直接展示会显得凌乱。因此需要专门制定规则将其移除:
# Remove embedded HTML content and Hugo cards
@remove: //div[contains(@class, "embedded-html-card")]
@remove: //iframe
2.3 Web 端与 App 端的体验割裂
现象:
生成的 Instant View 链接 (t.me/iv?url=...) 在 Telegram App 上点击顺滑,但在 Telegram Web 端点击时往往无反应或报错,体验极差。
解决方案:
利用 Telegram Bot API 的 link_preview_options 功能。
我们在调用 API 发送消息时,显式指定用于生成预览卡片的 URL(即 IV 链接),而在消息正文的 [阅读原文] 按钮中保留博客的原始 URL。
这样实现了完美兼容:
- App 用户:看到带有 Instant View 按钮的精美卡片,点击即读。
- Web 用户:预览卡片可能退化为普通链接,但点击正文链接依然能直接跳转博客原站。
3. 最终工作流总结
经过多次迭代,目前的发布流程已经非常稳健:
- 写作:本地撰写 Markdown 文章。
- 推送:
git push触发 GitHub Actions。 - 构建部署:Hugo 构建站点并推送到
gh-pages分支。 - 等待生效:CI 流程自动暂停 60 秒。
- 智能通知:脚本检测到新文件 -> 生成标题/摘要/标签 -> 通过 Bot API 发送消息(携带 Instant View 配置)。
- 触达:频道订阅者收到推送,秒开阅读。
舒服了,继续搬砖。