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 自动更新, 这个应该更没法解决了。