前言

在前不久,LeanCloud 发布公告,宣布其停止新用户注册和新应用创建,且将于 2027 年 1 月 12 日停止服务。

此时我刚捣鼓好 Valine 的邮件通知系统没有多久,但可惜的是我不得不面对现实。由于 Valine 官方基本沉寂,我大概率等不来一个好的替代方案(Valine 仅支持 LeanCloud 作为数据库)。在这段时间忙完自己的论文后,终于有了时间来处理博客事务,研究了一天成功将博客的评论系统进行了迁移,故有此文。

评论系统迁移

一些可能需要提前注意的事项

迁移到 Waline 可能需要你有一个自己的域名(因为要绑定一个子域名作为评论管理系统页面),如果你没有自己的域名,可以考虑购买一个或使用其他评论系统作为替代(即本文内容对你可能无用)。此外,本博客基于 hexo+butterfly 搭建,一些后续的调整可能在其他主题中不适用

Waline 部署

这一部分内容主要来自:Waline 官方教程 —— 快速上手,并针对部分内容进行细节补充。

部署服务端及创建数据库

这两个部分基本与上述官方教程无异,虽然当前 Vercel 页面布局可能存在些许不同,但总体流程没有变化,所以请根据官方教程进行操作:

绑定域名

在完成以上两步后,点击项目页面左侧的 Domains,在弹出页面里点击 Add Existing 将弹出以下窗口:

此时,请根据你的域名,填入以下地址模板:[你个人想要的前缀].[你的域名],以我的博客 biojuse.com 为例,我想要前缀代表评论,因此我最终的选择为:

  • comment.biojuse.comcomment 为前缀,biojuse.com 为域名)
  • 这里使用的域名即后续的 serverURL

由于还没创建有关的子域名,此时其会显示错误(Invalid Configuration),点击 Learn More 我们可以看到以下信息:

复制保存此处的 Value,请先根据自己的域名服务商创造子域名。以腾讯云为例:

  1. 打开腾讯云域名控制台:链接
  2. 选择自己的域名,点击解析

  1. 在 DNS 记录中,如果你在 GitHub 上托管博客,那么你应该已有几条与 GitHub 有关的记录,例如:

  1. 新建记录,主机填写之前添加的 domain 前缀,记录类型选择 A,记录值填写之前复制的 Value

填写完毕后,点击确认添加该记录,过段时间刷新 Vercel project 中 Domains(点击 Refresh),若其通过则上述工作完成:

类似地,如果你的域名 DNS 是在 CloudFlare 中管理的,可以在左侧 DNS-记录 里进行类似操作:

至此,Waline 服务端/数据库/管理端均已完成。访问 <serverURL>/ui/register 进行注册,首个注册的人会被设定成管理员。管理员登陆后,可以看到管理界面,并对评论进行相关操作。

Hexo+Butterfly 切换至 Waline

此处我使用的 Hexo+Butterfly 版本为 V4.4.0,该版本中要正常使用 Waline 评论系统,需要经过以下几点操作:

  1. _config.butterfly.yml 中修改 comments 并添加 waline 配置:
1
2
3
4
5
6
7
8
9
10
11
comments:
use: Waline
text: true # Display the comment name next to the button
lazyload: true
count: true # Display comment count in top_img

waline:
serverURL: <填写你的 serverURL,结尾无需斜杠>
bg: # waline background
pageview: false
option:

可选:结合 waline.pug 以及官网文档,如果想修改评论框中的文字(默认为 '欢迎评论'),可以在 option 中添加 locale,再在 locale 中添加 placeholder,在 placeholder 中指定你想替换的字符。更多 option 可见文档说明。

  1. 由于最新的 Waline (v3) 在 butterfly v4.4.0 中存在问题,这里需手动修改配置文件使其替换为 Waline v2。具体而言,搜索并打开 butterfly theme 中的 plugins.yml 文件,将其中的 waline_jswaline_css 替换为以下内容:
1
2
3
4
5
6
7
8
9
10
waline_js:
name: '@waline/client@2'
file: dist/waline.min.js
other_name: waline
version: 2.6.3
waline_css:
name: '@waline/client@2'
file: dist/waline.css
other_name: waline
version: 2.6.3

进行以上修改后,你应该能发现博客的评论系统正确地变为了 Waline。

评论数据迁移

先前的评论并不在 Waline 中保存,为了保持评论数据一致,需要从其他系统迁移过来。

本文展示的为 Valine+LeanCloud 转移至 Waline 的操作方式,如果你的评论数据原先存储在其他平台,也可以参考本文的方式进行对应调整。

从 LeanCloud 下载评论数据

打开 LeanCloud 控制台,选中自己博客的评论管理项目,点击左侧的 数据存储-导入导出,选择 数据导出,勾选 限定 Class,勾选 Comment 并点击导出。

后续你会在邮箱里收到相关的文件,解压后会得到一个 .jsonl 文件,里面存储了博客中所有的评论数据,假设其名为 a.jsonl,留作后用。

从 Waline 管理界面中导出数据

打开 Waline 管理界面,点击左上角 管理-导入导出,点击导出按钮获得文件 waline.json,这里导出数据的目的仅为获取管理员信息,并与 LeanCloud 数据合并。

运行 Python 获得整合后的 Waline 评论数据

新建 python 脚本文件,输入以下内容(根据注释部分将一些文件路径换为自己对应的文件路径)并运行:

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
import json

objs = []
# 将此处的 xxx.jsonl 换为你在 LeanCloud 导出并解压得到的文件
with open("xxx.jsonl", "r", encoding="utf-8") as f:
f.readline()
for line in f:
obj = json.loads(line)
objs.append(obj)

# 将原先评论的结构映射到 Waline 系统中的结构
target_attributes = [
"user_id",
"comment",
"ip",
"link",
"mail",
"nick",
"pid",
"rid",
"sticky",
"status",
"like",
"ua",
"url",
"objectId",
"insertedAt",
"createdAt",
"updatedAt",
]
new_objs = []

for obj in objs:
new_obj = {}
for key in target_attributes:
if key in obj:
if key != "insertedAt":
new_obj[key] = obj[key]
else:
new_obj[key] = obj[key]["iso"]
else:
new_obj[key] = None

new_objs.append(new_obj)

# 将此处的 waline.json 换为你在 Waline 管理界面中导出的数据文件路径
waline_json = json.load(open('waline.json', 'r'))
waline_json["data"]["Comment"] = new_objs

# 此处的 waline.integrate.json 即整合后的评论数据
with open("waline.integrate.json", "w", encoding="utf-8") as f:
json.dump(waline_json, f, ensure_ascii=False, indent=4)

以上脚本运行完成后,打开 Waline 管理界面,点击左上角 管理-导入导出,点击导入按钮,将输出的文件(此处即 waline.integrate.json)导入,即可将 LeanCloud 中的评论数据全部迁移至 Waline 中。

开通邮件提示功能

Waline 开通邮件通知的方式与 Valine 极其相近,涉及到的环境变量详细可见:Waline-功能-评论通知

具体而言,先打开 Vercel 中的对应项目,点击左侧栏中 Settings,再点击 Environmental Variables。在环境变量列表中,点击 Add Environment Variable,输入以下环境变量(加粗的 key 为必填,其他为选填):

Key Value
SMTP_SERVICE SMTP 邮件发送服务提供商(QQ 邮箱则填写 'QQ',163 邮箱则填写 '163')
SMTP_USER SMTP 邮件发送服务的用户名,一般为登录邮箱
SMTP_PASS SMTP 邮件发送服务的密码,开通 SMTP 及设置授权码的教程可见此处,注意不要和登录密码混为一谈
SMTP_SECURE 填写 'true' 即可
SITE_NAME 网站名称(例如 Juse's blog)
SITE_URL 网站网址(例如 https://biojuse.com)
AUTHOR_EMAIL 博主邮箱,用来接收新评论通知(可选择填写与 SMTP_USER 相同的值)
SENDER_NAME 自定义发送邮件的发件人(例如 Juse)
SENDER_EMAIL 自定义发送邮件的发件地址(可选择填写与 SMTP_USER 相同的值)
MAIL_SUBJECT 自定义评论回复邮件标题
MAIL_TEMPLATE 自定义评论回复邮件内容
MAIL_SUBJECT_ADMIN 自定义新评论通知邮件标题
MAIL_TEMPLATE_ADMIN 自定义新评论通知邮件内容

后四个 Key 可以填写一些相关变量作为补充(具体可见此处),例如:

  • MAIL_SUBJECT:{{site.name|safe}} 上的评论收到了回复,此处 {{site.name|safe}} 会变为 SITE_NAME 填写的值。
  • MAIL_SUBJECT_ADMIN:{{site.name|safe}} 上有新评论了,同上。
  • MAIL_TEMPLATE:以下给出一个博主本人基于 ChatGPT 润色生成的简易模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div
style="max-width:600px;margin:40px auto;padding:0 20px;font-family:Arial,Helvetica,sans-serif;color:#333;line-height:1.6;font-size:14px;background:#ffffff;border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,0.05);">
<div style="padding:20px 25px;border-bottom:1px solid #f0f0f0;background:#f9fbfc;border-radius:8px 8px 0 0;">
<h2 style="font-size:16px;margin:0;color:#0c99c8;font-weight:600;">您在 <a href="{{site.url}}" target="_blank"
style="color:#0c99c8;text-decoration:none;">{{site.name|safe}}</a> 上的评论有新回复</h2>
</div>
<div style="padding:25px 25px 10px 25px;">
<p style="margin:0 0 10px 0;font-size:14px;">{{parent.nick}},您曾发表评论:</p>
<div
style="background:#f5f7f8;border-left:3px solid #0c99c8;padding:12px 15px;margin:12px 0;border-radius:4px;word-wrap:break-word;">
{{parent.comment|safe}}</div>
<p style="margin:15px 0 10px 0;font-size:14px;"><strong>{{self.nick}}</strong> 回复说:</p>
<div
style="background:#f5f7f8;border-left:3px solid #5cb85c;padding:12px 15px;margin:12px 0;border-radius:4px;word-wrap:break-word;">
{{self.comment|safe}}</div>
<p style="margin-top:20px;font-size:14px;">您可以点击 <a href="{{site.postUrl}}" target="_blank"
style="color:#0c99c8;text-decoration:none;">查看完整回复</a>。欢迎再次访问 <a href="{{site.url}}" target="_blank"
style="color:#0c99c8;text-decoration:none;">{{site.name|safe}}</a></p>
</div>
<div
style="padding:15px 25px;font-size:12px;color:#888;background:#fafafa;border-top:1px solid #f0f0f0;border-radius:0 0 8px 8px;text-align:center;">
本邮件为系统自动发送,请勿直接回复。</div>
</div>
  • MAIL_TEMPLATE_ADMIN:同上,给出博主本人模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div
style="max-width:600px;margin:40px auto;padding:0 20px;font-family:Arial,Helvetica,sans-serif;color:#333;line-height:1.6;font-size:14px;background:#ffffff;border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,0.05);">
<div style="padding:20px 25px;border-bottom:1px solid #f0f0f0;background:#f9fbfc;border-radius:8px 8px 0 0;">
<h2 style="font-size:16px;margin:0;color:#0c99c8;font-weight:600;">您在 <a href='{{site.url}}' target='_blank'
style='color:#0c99c8;text-decoration:none;'>{{site.name|safe}}</a> 上的文章有了新的评论</h2>
</div>
<div style="padding:25px 25px 10px 25px;">
<p style="margin:0 0 10px 0;font-size:14px;"><strong>{{self.nick}}</strong> 评论说:</p>
<div
style="background:#f5f7f8;border-left:3px solid #5cb85c;padding:12px 15px;margin:12px 0;border-radius:4px;word-wrap:break-word;">
{{self.comment|safe}}</div>
<p style="margin-top:20px;font-size:14px;">您可以点击 <a href='{{site.postUrl}}' target='_blank'
style='color:#0c99c8;text-decoration:none;'>查看评论的完整內容</a></p>
</div>
<div
style="padding:15px 25px;font-size:12px;color:#888;background:#fafafa;border-top:1px solid #f0f0f0;border-radius:0 0 8px 8px;text-align:center;">
本邮件为系统自动发送,请勿直接回复。</div>
</div>

在所有环境变量填写成功后,对 Vercel 项目进行重新部署,邮件提示功能即可生效。

后记

至此,所有的评论数据/功能已从 Valine+LeanCloud 移植到 Waline+Neon,在此特作记录,以帮助其他可能有需要的朋友。