Rongbin Fan

用 Webmention 接收 Mastodon 互动

长毛象作为 Hugo 评论系统、 加入联邦宇宙, 还讨论了使用 Github Actions 自动化

Note

更新于 2024-07-09:

已删去此功能。 原因:

  • 维护麻烦 (大改了一下 Stream 页面后, 没法正常同步 fediverse 上回应, 跟这个 issue 差不多)
  • 用的人少 (well, that’s what we called indie)
  • 确实有一些 ethical problem

什么是 webmention

Webmention 是由 IndieWeb 发起的 W3C 标准, 用来实现网页间相互提及, 不必借助平台或引入评论系统。 它的工作流程如下:

  1. 我上传了一篇文章
  2. 文章被你引用
  3. 你向我的网站发送带有引用处 url 的 webmention
  4. 我通过 webmention.io 等服务或自行挂载, 接收到你的 webmention

现在你就可以试试, 在自己的页面提及此页 url, 例如:

<p><a href="https://fanrongbin.com/hugo-webmention-bridgy-mastodon">I'm trying webmention!</a></p>

然后把你的页面 url 在文末输入框提交, 大约一分钟后刷新此页, 就会看到你的 webmention。

接收 webmention

这里给出使用 webmention.io 的步骤, 你也可以自行挂载:

1. 用 IndieAuth 标识你的身份

Webmention.io 使用 IndieAuth 登录, 所以需要先设置 IndieAuth。 在 index.html 中, 对自己的帐号说明为 rel="me", 例如:

<a rel="me" href="mailto:your_email@email.com">Send me an email</a>

或者以隐藏的方式在<head>说明:

<link rel="me" href="mailto:your_email@email.com">

这样一来, 采用 IndieAuth 登录的地方, 会通过这些方式验证你的身份, 例如向邮箱发送邮件, 或跳转 Github 登录。

2. 使用 webmention.io 挂载

在 webmention.io 登录后, 你会看到一个 Settings-Setup 页面, 给出了需要你在<head>加入的 tag:

<link rel="webmention" href="https://webmention.io/your_domain/webmention" />

这条 tag 说明你的页面能够接受别人的提及, 你可以通过 webmention.rocks 测试能否接收到。

到此, 你已经实现了 webmention 的接收。

你可以在 webmention.io 的 Dashboard, 或它提供的 Mentions Feed, 查看他人提及。

3. 借助 webmention.js 在博文页面显示 webmention

Webmention.io 提供 API 返回你接受到的具体内容, 这里我们借助前人造好的轮子 webmention.js, 根据 readme, 在你的网站存放 webmention.min.js 文件并用<script src=""></script>引入, 在需要展示 webmention 列表的地方插入:

<div id="webmentions"></div>

你可以新建一个测试页面, 用来提及目标页, 以测试是否能正常发出和显示。 也可以在连接 Mastodon 后, 通过发 toot 和回复的方式测试。 webmention 列表的样式可通过 css 自定义。

发送 webmention

很多支持 webmention 的站点, 都会给出一个 form 方便你手动提交自己的链接。

你也可以用 curl 发出 webmention, 发送前需检查对方收不收得到 webmention, 下面这条指令会进行检查。 $your_url 替换为你自己的引用页, $target_url 替换为目标页。

curl -i -d "source=$your_url&target=$target_url" `curl -i -s $target_url | grep 'rel="http://webmention.org/"' | sed 's/rel="webmention"//' | grep -o -E 'https?://[^ ">]+' | sort | uniq`

也可以用 telegraph.p3k.io (需要 IndieAuth 登录), 或 mention.tech (不需要登录) 的在线服务。

使用 webmention.app 自动发送

你可能一次在博文中引用多个网页, 但是不想再进行繁琐的手动发送 webmention。 Webmention.app 可以读取页面 class="h-entry" 中的链接, 帮你一键发送。

可以使用 Test 页面 检查 (只会检查前 10 个 h-entry), 也可以通过 API。 登录服务获得 token 后没有 request 限制。 具体请参见官网。

将你的博文发送到社交平台

连接到 Bridgy

Bridgy 可将网站和社交平台相联, 使得没有个人页面的用户, 也能通过支持的平台进行回复, Bridgy 会帮助进行 webmention。

进入主页选择 Mastodon, 使用 cross-post 或直接连接联邦宇宙的方式均可。 如果 cross-post, 你需要用验证过的帐号 publish 带有博文链接的 toot, 在这条 toot 下的回复、 转发、 喜爱才会作为 webmention 传过来。

如果直接连接 (也就是我目前的做法), 你会以@your-domain.com@your-domain.com 加入联邦宇宙, 向 Bridgy 的每次 update 都会对应更新这个账号下的 toot。

使用 Github Actions 自动化

我使用 Hugo 作为博客系统, 希望实现根据我是否上传或更新.md, 自动发出 webmention。 tj-actions/changed-files 能够找到 repo 下文件的修改情况, 故可以先寻找是否有文件被修改, 之后发出 curl 命令即可。

在之前的博文里, 我设置了 deploy.yml 用来自动部署 Hugo、 生成静态文件。 故对应在此设置为在 deploy 后才运行。

name: send webmentions to bridgy according to md changes

on:
  workflow_run:
    workflows: ["deploy"]
    types: 
      - completed
    branches:
      - main

jobs:
  changed_files_send_webmention:
    runs-on: ubuntu-latest
    name: send webmentions according to md changes
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: get changed files
        id: changed-files
        uses: tj-actions/changed-files@v41
        with:
          files: content/posts/*.md # 注意这里根据实际需要修改目录位置

      - name: list all changed files
        run: |
          ALL_CHANGED_FILES="${{ steps.changed-files.outputs.all_changed_files }}"
          for file in $ALL_CHANGED_FILES; do
            echo "$file was changed"
          done

      - name: send webmentions
        if: steps.changed-files.outputs.all_changed_files != '' # 判断不为空才运行
        run: |
          CHANGED_FILES=$(echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ',' '\n')
          for FILE in $CHANGED_FILES; do
            if [[ $FILE == content/posts/*.md ]]; then
              POST_NAME=$(basename "$FILE" .md)
              POST_URL="https://your-domain.com/${POST_NAME}"
              echo "Sending Webmention for $POST_URL"
              curl -i -d source=${POST_URL} -d target=https://fed.brid.gy https://fed.brid.gy/webmention
            fi
          done

你还可以接着使用${POST_URL}trigger webmention.app 的 webhook。


最初是看到 IndieWeb 上关于 webmention 的介绍, 于是想着要不要自己也折腾一下, 搜索到 Aaron Parecki 的博文, 以及 Jayeless.net 的博文 后, 觉得配置起来也不是很难嘛, 然后就开始了……用第三方服务接收很简单, 主要是一直卡在 Bridgy 这边。 我新建了一个 Stream 页面, 相当于有了自己的一条时间轴, 为了传上联邦宇宙, 需要把每条小 note 以锚点#id 的方式传到 Bridgy。 但, 用 webmention.app 或者是 telegraph.p3k.io 始终没法发现到 https://fed.brid.gy/这条链接, 导致我没法 API 传出去, 后来:

  1. 尝试以<a href="https://fed.brid.gy" hidden="from-humans"></a>的方式, 加到带 class="e-content"的元素里面。 但如果 note 不包含其他 url, 具有 Link Preview 功能的地方, 还是会显示出 fed.brid.gy 的链接卡片。
  2. 在对 Stream 页面部署自动化时, 分成了三个部分:
    • 固定以 url#id 作为 source 并以 Bridgy 作为 target、
    • 检查这条 note 的类型并以相关 url 作为 target (例如 reply、 like)
    • 检查这条 note 的内容并以相关 url 作为 target (里面所有的<a href="...")

一些遗留的问题

  1. 如果 fediverse 上对博文的回应 (回复、 转发、 喜爱) 被修改或删除, 无法触发 Bridgy 自动更新, 即以回应为 source, 以博文为 target 重新发一次 webmention
  2. 如果发出回应的用户更改了自己的个人信息, 也无法触发 Bridgy 自动更新, 这个应该更没法解决了。