微语/说说/微博/Mricoblog 嵌入博客网页

本文尝试使用一些程序搭建个人微博,并嵌入到博客网页。

以前使用 hexo butterfly 主题时,注意到有 说说/微语 的进阶配置。近年来看到不少类似的,或者别名,如微语/微言/说说/微言微语/碎碎念/碎语/Artitalk.js/哔哔/唠叨/嘀咕/时光机/Microblog/microblogging。大概,他们可以统称为 微博 或者说 微博客,不过为了与新浪微博分辨开消除歧义,可通过搜索上面的关键词来避开新浪微博相关词条。这类在 github 上有一个话题或者说标签 https://github.com/topics/microblog

我注意到,这个 github 话题下实现 ActivityPub 如 Mastodon ,Misskey 比较流行。实际上,使用相关 API 可以很轻松的嵌入微博到个人博客网站中,互动也是比较方便的,只要一个账号就行了。此外实现了 ActivityPub 还有 Pleroma, PixelFed, PeerTube , GoToSocial, microblog.pub , Firefish(Misskey分支), Akkoma 等等。其中 GoToSocial, microblog.pub 很适合单人实例。分布式开源微博程序有 Farcaster, Mastodon, Nostr 等等,也可以探索使用其中一个,尝试嵌入网页。如果会写代码,写一个类似程序也很简单。

此外,也有仿照微信朋友圈的一些静态博客生成器主题可供选择,当然这类主题很难做到随手一记,不过也算有着简单易用的优点。如 https://github.com/FarseaSH/hugo-theme-moments Moments是适合发布短博文的Hugo主题,作为独立的短文/动态空间。Demo https://farseash.github.io/demo-hugo-theme-moments/moments/

此外可用的工具还有

后端:
Wordpress/Typecho/Mblog 等 php 博客程序插件
借助云函数 部署 Artitalk.js 部署说说/微语
自行部署 memos golang + sqlite 备忘录程序
自行部署 pocketbase golang + sqlite 快速开发后端程序
自行部署或使用 CMS 或 无头 CMS 程序 ,如 Ghost
自行编写后端

前端:
php 程序微语插件附带
mastodon/gotosocial/memos 自带网页 可使用 api 嵌入博客网页
pocketbase/CMS/自行编写后端 需要自行写前端网页

发布:
php 程序一般后台发布/api
mastodon 类使用客户端发布
memos 网页客户端发布
pocketbase 网页管理界面/API 发布
Artitalk.js 网页管理
使用 API 支持 http 请求的工具,或者嵌入到机器人,如微信测试号中,进行发布。

实际上,如果对前后端有一定了解,自习修改或编写自的前后端并不很困难,并且现在可以使用 ChatGPT 进行代码的提示,注释,讲解,生成,优化等等。

如果有 Mastodon ,Misskey 账户,建议直接调用相关 API 。如果部署云函数可以选择 Artitalk.js, 个人实例建议选 gotosocial ,memos 或者 pocketbase 。memos 我没有尝试,本文也不会涉及,不过有热心的网友已经写好了相关教程 https://immmmm.com/bb-by-memos/

gotosocial 部署起来还算简单,但是部署后本身网页没有客户端,必须选择使用一个客户端。程序本身有 rss 和 markdown 支持 ,API 可直接获取到 HTML 。客户端可以选择原生应用,也可以选择 web 端,如基于 JS 客户端 SDK https://github.com/neet/masto.js/

  1. 4.2k https://github.com/elk-zone/elk https://elk.zone/home/ 鹿鸣
  2. 600+ https://neet.github.io/masto.js/
    或者
    100+ https://github.com/NickColley/semaphore https://semaphore.social/

pocketbase 本身和微博客没有什么关系,这是一个快速开发后端程序,也就是一些 CURD 封装,可以搭建个人微博,评论系统之类的。实际上嵌入 js 也很容易实现如后端转 markdown 为 HTML 存储在一个字段之类的功能。自带网页管理面板,增删改查 UI 操作也算方便。

下面给出这两个程序 hugo 静态博客生成器 的 shortcodes ,适用于 pocketbase 和 mastodon 类程序。截至发文,可以在本文下面,或者 https://www.ftls.xyz/whispers/ 找到 demo。

下面这个两个 demo ,我都写个好几个版本,但是大差不差的。自己使用基本都会做一些改变。可以在 https://gitee.com/kkbt/www.ftls.xyz/tree/master/layouts/shortcodes 找到所有版本。

pocketbase shortcode 源码 https://gitee.com/kkbt/www.ftls.xyz/blob/master/layouts/shortcodes/pocketbase2.html
说明: 代码使用了一个依赖 moment.js ,用于将时间转换为 1小时前,3 天前,2000 年 01 月 01 日之类的,moment js 实际上需要引入两个文件,我手动合并成了一个,实际上可以选择更小的,不到 1kb 的 Lately.js ,显示效果差不太多。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<div id="pocketbase">
    <div id="tweetList"></div>
    <a id="moreButton" href="#" onclick="showMore(); return false;">更多</a>
</div>

<script type="text/javascript" src="/js/moment.js"></script>

<script type="text/javascript">
    const tweetList = document.getElementById('tweetList');
    const moreButton = document.getElementById('moreButton');
    const apiUrl = "https://api.ftls.xyz/api/collections/whispers/records";
    let currentPage = 1;

    function escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    function displayTweets(tweets) {
        tweets.forEach(tweet => {
            const blockquote = document.createElement('blockquote');
            const createdAtDiv = document.createElement('div');
            createdAtDiv.textContent = moment(tweet.createdAt).twitter(); // moment.js 或者 相对时间 Lately.js 
            const contentDiv = document.createElement('div');
            contentDiv.innerHTML = escapeHtml(tweet.text).replace(/\!\[.*\]\((.+)\)/g, '<img src="$1" loading="lazy" />');
            blockquote.appendChild(createdAtDiv);
            blockquote.appendChild(contentDiv);
            tweetList.appendChild(blockquote);
        });
        // window.Lately && Lately.init({ target: '.lately' }); // 相对时间 Lately.js 初始化
    }

    function fetchTweets(page) {
        const params = new URLSearchParams({
            sort: '-createdAt',
            perPage: 10,
            page: page
        });
        const url = `${apiUrl}?${params.toString()}`;

        fetch(url)
            .then(response => response.json())
            .then(data => {
                displayTweets(data.items);
                if (data.page < data.totalPages) {
                    moreButton.style.display = 'block';
                    currentPage = data.page + 1;
                } else {
                    moreButton.style.display = 'none';
                }
            });
    }

    function showMore() {
        moreButton.style.display = 'none';
        fetchTweets(currentPage);
    }

    // 页面加载时获取第一页推文
    fetchTweets(currentPage);
</script>
<!-- 简易样式;如果 Hugo 主题有样式可能会被覆盖 -->
<style>
    blockquote {
        margin: 0;
    }

    blockquote p {
        padding: 15px;
        background: #eee;
        border-radius: 5px;
    }
</style>

需要注意的是该 demo 我把 URL 写死了,不需要参数,后端提供 markdown 文本,前端仅使用正则表达式替换 markdown 图片为 HTML 。

gotosocial shortcode 源码 https://gitee.com/kkbt/www.ftls.xyz/blob/master/layouts/shortcodes/mastodon.html
该 shortcode demo 没有任何依赖,并未显示时间,而且会显示回复和转嘟,hugo 页面使用需要2或3个参数,参考上面页面源码。
发布可参考 手机发布微语说说

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<div id="toots"></div>
<button id="toots-moreButton" onclick="tootsShowMore()">更多</button>

<script>
    let maxId = null; // 初始值为 null,表示第一页
    const tootsDiv = document.getElementById('toots');
    const tootsMoreButton = document.getElementById('toots-moreButton');

    // 获取 Mastodon 用户公开Toots
    async function getPublicToots() {
        const queryParams = maxId ? ("?limit={{ .Get 2 | default 5 }}&max_id=" + maxId) : "?limit={{ .Get 2 | default 5 }}";
        const response = await fetch("{{ .Get 0 }}/api/v1/accounts/{{ .Get 1 }}/statuses" + queryParams);
        const toots = await response.json();
        return toots;
    }

    // 将Toots显示在页面上
    async function displayToots() {
        try {
            const toots = await getPublicToots();
            if (toots && toots.length > 0) {
                toots.forEach(toot => {
                    const tootDiv = document.createElement('div');
                    tootDiv.innerHTML = `<p>${toot.content}</p><hr>`;
                    tootsDiv.appendChild(tootDiv);
                    maxId = toot.id; // 更新最大 ID
                });
                tootsMoreButton.style.display = 'block';
            } else {
                tootsMoreButton.style.display = 'none';
            }
        } catch (error) {
            console.error('获取Toots时出错:', error);
            tootsMoreButton.style.display = 'none';
        }
    }

    function tootsShowMore() {
        displayToots();
    }

    displayToots();

    // 页面加载时调用显示Toots函数
    // window.onload = displayToots;
</script>

mastodon 类程序不仅可以用于微博,还可以作为评论系统,如 https://cassidyjames.com/blog/fediverse-blog-comments-mastodon/ ,这位网友同步发布 toots ,然后在博文下面引用该嘟嘟的回复内容,实现了一个很不错的评论系统。

https://github.com/cassidyjames/cassidyjames.github.io/commit/1298d9b39b9e8adeba34f23f3ae83986e0a47260
https://github.com/cassidyjames/cassidyjames.github.io/blob/1298d9b39b9e8adeba34f23f3ae83986e0a47260/_includes/comments.html
https://github.com/cassidyjames/cassidyjames.github.io/blob/main/_includes/comments.html
https://github.com/mastodon/mastodon/issues/25892
这些是 mastodon 做评论系统的相关信息,总的来说,需要一个机器人账户,获取机器人账户 read:statuses 权限的 accesstoken ,访问 /api/v1/statuses/:id/context,显示在前端网页评论区。

这是我自己的探索结果,供参考 https://www.ftls.xyz/posts/2023-08-14-mastodon-comments/

不保证长期有效。

可见这里或下面

Mastodon 实例 API

Mastodon 用户 ID 可使用查看用户头像 URL,如 /accounts/avatars/108/736/608/744/946/761/original/xxx.png,中间的数字合并起来就是。 也可以使用 Mastodon web 客户端,浏览器 F12 查看请求响应信息获取。

或者 gotosocial 实例 API ,和 mastodon 很相似
由于 shortcode 一页放多个会有干扰,所以仅放参数,不保证这些参数长期有效

1
"https://gotosocial-kkbt-tools-xkzlczgovq.cn-hangzhou.fcapp.run" "01CZ5J6DTPXEAHWZYZG73TPNH9" 3 

用户 ID 注册后查看用户头像 URL 获取,或者 web 客户端查看。

本 demo 源码可以在该博客文章左下角,查看本页源码获取源码。

本文介绍了一些工具,搭建微博并嵌入 Hugo 生成的博客网页。我个人尝试了 gotosocial,pocketbase 。

我使用 gotosocial api 开源程序,经过修改适配搭建了一个网页 https://www.ftls.xyz/whispers/ 同时使用 ObcsapiV4 的微信测试号/PWA web 调用 API 发布微语,Mastodon 客户端进行管理。这个方案就博客嵌入来说自由度受限,字段冗余,不过互动比较方便。使用者可根据自身需要选择不同方案。