惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
量子位
G
Google Developers Blog
J
Java Code Geeks
N
Netflix TechBlog - Medium
博客园 - 聂微东
宝玉的分享
宝玉的分享
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
月光博客
月光博客
The Cloudflare Blog
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
雷峰网
雷峰网
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 三生石上(FineUI控件)
Microsoft Azure Blog
Microsoft Azure Blog
aimingoo的专栏
aimingoo的专栏
Martin Fowler
Martin Fowler
有赞技术团队
有赞技术团队
T
The Blog of Author Tim Ferriss

小球飞鱼

白露 | 明天世界就要毁灭了,但沉迷结缘小网站 处暑 | 就为这点事把大家叫出来! 博客 | 在AI时代来搭博客吧! 博客 | 一份来自花边小报的发刊词 博客 | 从Neodb到Blog的全面自动化 立秋 | 新式人体舍利子炼成手记 手账 | 关于一些爱用品的随便讲讲 手账 | 如何选择一本手账 夏至 | 朕和最终幻想14何曾有过嫌隙 芒种 | 像魔法少女一样 立夏 | 来不及解释了,立刻突入二次元 玩具箱 | 个人大生活家三件套之2026篇
博客 | 在博客文章中显示Fedi互动数据
2026-08-28 · via 小球飞鱼

23年的时候看过一篇文章,讲的是怎么在博客中显示联邦宇宙(Fediverse,以下简称 Fedi)中对应嘟文的评论。把动态 SNS 和静态博客互相连接起来的想法非常有趣,但我不是很能接受这个方案,在我看来这涉及到一个知情同意的问题,不是每个在博客发布的嘟文下评论的朋友都知道自己的评论会被同步到博客站点,在另外一个平台展示。另外,我也不是那么愿意把 SNS 和博客进行强关联:我希望它是单向的,可以通过 Fedi 看我的博客,但博客最好不要直接暴露我的 Fedi 账号。

但我还是觉得这个功能非常时髦,很想拥有,25年1月我给博客加装了一个点赞按钮,昨天我突然在想,我每次写完博客会在 Fedi 发一条嘟嘟,那么是不是也可以把它的互动数量显示到博客里?

于是立刻开工。

最终实现效果

博客文章页尾的 Fedi 互动数据显示效果

Fedi 数据显示在每篇博客的页尾部分,其中♥️部分是博客文章的站内点赞,可以点击增加,🔁是对应博客发布嘟文的转嘟数量,⭐是喜欢数量,后两者均仅展示,数据由 Mastodon API 返回并更新在对应位置。其中人工参与的部分是在博客文章的 Markdown 文件中加入一行 YAML,填写发布嘟文的链接。

具体实现步骤

:每个人的 Hugo 博客结构不同,想要实现的效果不同,加上相关代码可以通过 AI 输出,因此以下只介绍思路、工具和方案优缺点,不涉及到具体实现。

另外,由于我只使用 Fedi 宇宙中的 Mastodon,不太清楚如 Misskey 等的 API 情况,所以以下也只涉及到 Mastodon API。

数据获取方案

根据隐私性和实时性的不同,获取 Fedi 互动数据有两种方案。

  • 方案1:文章打开时,浏览器根据嘟文链接,直接请求 Mastodon API,通过 API 返回最新互动数据,在博客界面显示
    • 优点:实现非常简单,数据接近实时,不需要重新构建和部署博客。
    • 缺点:博客对应的嘟文链接在浏览器控制台中明文展示,如 HTML 结构 中包含完整链接,NetWork 面板能看到对应请求,API 返回的 JSON 包含账号 username、url 等信息。另外,如果实例离线,数据就不能正常返回。
  • 方案2:定时请求 Mastodon API 获取数据,把统计数据保存为 Hugo 中的数据文件,之后重新构建博客,形成静态 HTML
    • 优点:隐私性很好,网页需要加载的仅仅是两个数字,而不是整个嘟文链接。同时,只需要在脚本中设计好请求失败时保留上一次的数据,那么它就不依赖于实例是否在线,某日如果实例消失,仍然能正常显示历史数据。
    • 缺点:数据的实时性依赖于定时请求频率,同步后需要重新构建和部署博客,整体实现比方案1要复杂一些。

需要注意的是:由于联邦宇宙的分布式特性,API 返回的始终是实例当前已知的互动数量,它会受到实例之间的延迟、互通性等因素影响,不一定是一个绝对准确的数字。此外,由于相关实例信息仍然被保存在文章的 front-matter、同步脚本等位置,如果 GitHub repo 是公开的,那么仍然能被看到相关链接,隐私性始终是一个相对问题而不是绝对问题。

这两个方案还涉及到一个负载量的问题,方案1每次打开文章产生一次公开的 API 请求,方案2则是根据定时频率来请求 API,请求量根据文章数量逐渐增加,但对于个人博客有限的访问量来说,二者都不构成实际的性能负担。

方案1 :

两个方案中,我们都需要一条嘟文链接,把它填进博客文章的 front-matter 位置。 比如:mastodon: "https://example.social/@name/123456789"

注意,这个嘟文链接必须指向具体的嘟文,不可以是个人主页,我们可以通过点击嘟文右下角的三个点展开菜单,再点击 复制嘟文链接 来得到它。有些做法是建立一张博客文章和嘟文链接的对应表,但是我觉得直接把信息放在博客文章中更容易维护。

接下来我们创建一个 Hugo partial,Hugo Partial 是 Hugo 支持的一种可复用的代码模板片段,通过把想要的内容写成一个独立的 Hugo Partial 文件,就可以在不同的页面模板中重复调用。在这个例子里,Hugo Partial 用于判断文章是否有 mastodon 字段,并输出与互动数据有关的 HTML 结构。

想要获取互动数据,我们需要一个 JavaScript,从 Mastodon 公开 API 返回的 JSON 中我们得知,Mastodon API 中关于嘟文转嘟数量和喜欢数量的对应字段分别是 reblogs_countfavourites_count。JavaScript 负责解析嘟文链接,请求公开 API,以及把这两个字段返回的数据写入页面。

最后,在文章的 single 模板中调用之前创建的 Hugo partial,使用 CSS 修饰样式。

方案2:

方案2就要复杂一点,除了文章 front-matter 中的嘟文链接和用于展示数据的 Hugo Partial 之外,还需要一个负责获取数据的同步脚本、一份保存互动数量的 Hugo Data 文件,以及一个定时运行脚本并重新部署博客的工具。

首先,我们仍然需要在文章的 front-matter 中填写对应的嘟文链接。不同的是,这次读取链接的不是访客浏览器中的 JavaScript,而是提前运行的同步脚本。我用 Python 编写这个脚本,放在博客的 scripts 目录中,它负责扫描整个博客的 Markdown 文件,找到包含 mastodon 字段的文章,请求 API,然后解析字段中的链接,把读到的内容写进本地 JSON 文件中,比如 data/mastodon.json

在这之后,Hugo Partial 在每次博客构建时读取这份 JSON 文件(这个文件不需要保存完整的请求响应内容,只要记录文章和互动数据的对应关系就可以了),根据文件内容,把对应的互动数写进 HTML,并显示在页面上。

Python 可以本地手动运行,但每次更新博客都手动运行太折磨了,我们还需要一个定时任务脚本,比如 GitHub Actions,在 .github/workflows/ 中创建一个 workflow,要求它每隔一段时间(我是24h,以及手动推送的时候)执行一次同步脚本,更新 data/mastodon.json,把数据变化写回仓库,仓库更新后触发 Hugo 自动部署。

这里需要注意的是:

  1. 要写入失败情况的处理,同步某篇文章失败的时候,不应该删除原来的同步数据。
  2. 要求 WorkFlow 只在数据发生变化的时候更新仓库内容,防止出现大量无意义的提交和部署,同时还要注意防止脚本出现反复提交和触发部署的死循环。
  3. 和方案1不同的是,方案1是每次读者打开文章请求一次 API,方案2的请求数量是关联嘟文的文章数量 x 每日同步次数。如果请求频繁,文章数量大,那么负载也会随之增加。
  4. 由于涉及到了 GitHub Actions 自动更新仓库,在之后的本地推送中,需要先拉取线上仓库内容,同步到本地再推送,防止出现冲突。

最后:

其实在博客上加 Fedi 互动数据没什么意义,但挺好玩的,夏天就适合做没什么意义但是好玩的事情,这篇博客也写的很开心,感觉在“AI 已经能写完所有代码了那么记录还有什么意义”和“可是我还挺想写下来并分享的”之间稍微找到了一个平衡。顺便还把博客首页头版头条的逻辑调整了一下,不固定是最新一篇文章:那么,下次再见!