Typecho转到Hexo(主题由Joe主题转Butterfly主题)

前言

使用了好久好久好久的动态博客,身为一个前端的我,总是想着把动态博客转为静态博客,但是一直没有动手,最近博客被持续的攻击,无法正常访问等因素,终于决定把博客迁移到Hexo上,下面就来分享一下迁移过程。

文档导出

因为之前使用的是TypechoTypecho-Joe-Theme主题,主题中包含了很多自定义标签,所以我们在导出的过程中要处理一下数据,把Typecho-Joe-Theme的标签转换成HexoButterfly主题的标签,身为前端的我无脑选择使用NodeJs手撸一个简单的脚本来导出Typecho博客的文章数据。

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
const mysql = require("mysql");
const fs = require("fs");
const moment = require("moment");
var con = mysql.createConnection({
host: "数据库地址",
database: "数据库名",
user: "数据库用户名",
password: "数据库密码"
});

// 数据库前缀
const prefix = "typecho_";

con.connect(function (err) {
if (err) {
return console.log(err);
}
});

// 数据库查询语句
const sql = `select title,slug,text,created,modified,category,tags from ${prefix}contents c,(select cid,group_concat(m.name) tags from ${prefix}metas m,${prefix}relationships r where m.mid=r.mid and m.type='tag' group by cid ) t1,(select cid,m.name category from ${prefix}metas m,${prefix}relationships r where m.mid=r.mid and m.type='category') t2 where t1.cid=t2.cid and c.cid=t1.cid`;

con.query(sql, function (err, posts) {
if (err) {
console.log(err.message);
return;
}

posts.forEach(function (post) {
const { title, slug, tags, created: oldCreated, modified: oldModified, text: oldText, category: cat } = post;
let text = oldText.replace("<!--markdown-->", "");
const created = moment.unix(oldCreated).format("YYYY-MM-DD HH:mm:ss");
const updated = moment.unix(oldModified).format("YYYY-MM-DD HH:mm:ss");
// 封面图
const regex = /https:\/\/jsd\.onmicrosoft\.cn\/gh\/uxiaohan\/uxiaohan\.github\.io@master\/v2\/(\d{4}\/\d{2}\/\d+)\.(png|jpg|jpeg|gif|mp4)/;
const match = text.match(regex);
const cover = match ? match[0] : "";

// Typecho Joe主题标签 转 Hexo 的 Butterfly 主题标签
text = text
.replace(/\{message type="([^"]+)" content="([^"]+)"\/\}/g, (match, type, content) => `{% note purple 'fas fa-info-circle' flat %}\n${content}\n{% endnote %}`)
.replace(/\{anote\s+icon="([^"]+)"\s+href="([^"]+)"\s+type="([^"]+)"\s+content="([^"]+)"\s*\/\}/g, "{% btn '$2', $4 , far fa-hand-point-right,outline purple larger %}")
.replace(/\{abtn\s+icon="([^"]*)"\s+color="([^"]*)"\s+href="([^"]*)"\s+radius="([^"]*)"\s+content="([^"]*)"\s*\/\}/g, "{% btn '$3', $5,far fa-hand-point-right,outline purple larger %}")
.replace(/\{cloud\s+title="([^"]+)"\s+type="([^"]+)"\s+url="([^"]+)"\s+password="([^"]*)"\/\}/g, "{% btn '$3', $1, far fa-hand-point-right,purple larger %}")
.replace(/\{callout color="([^"]+)"\}/g, "{% note default no-icon %}")
.replace(/\{gird\s+column="([^"]+)"\s+gap="([^"]+)"\}/g, "{% note default no-icon %}")
.replace(/\{dplayer\s+src="([^"]+)"\/\}/g, '{% dplayer "url=$1" %}')
.replace(/{\/callout}/g, "{% endnote %}", "{% gallery %}")
.replace(/\{\/gird\}/g, "{% endnote %}", "{% endgallery %}")
.replace(/\{alert type="([^"]+)"\}/g, "{% note default modern %}")
.replace(/{\/alert}/g, "{% endnote %}")
.replace(/\{gird-item\}/g, "")
.replace(/\{\/gird-item\}/g, "")
.replace(/#([\u4e00-\u9fa5]+)/g, "# $1");

const fileName_ = title.replace(/\//g, " ").replace(/-/g, " ").replace(/\?/g, " ").replace(/\[/g, "(").replace(/\]/g, ")");
const filename = "./post/" + fileName_ + ".md";
fs.appendFileSync(filename, "---\n");
fs.appendFileSync(filename, "title: " + title.replace(/\[/g, "(").replace(/\]/g, ")").replace(/#/g, " ") + "\n");
fs.appendFileSync(filename, "date: " + created + "\n");
fs.appendFileSync(filename, "updated: " + updated + "\n");
fs.appendFileSync(filename, "categories: " + cat + "\n");
fs.appendFileSync(filename, "tags:\n- " + tags.replace(/,/g, "\n- ") + "\n");
fs.appendFileSync(filename, "id: " + slug + "\n");
fs.appendFileSync(filename, "cover: " + cover + "\n");
fs.appendFileSync(filename, "---\n");
fs.appendFileSync(filename, text);
});
});

con.end();

// 导出完毕后,在脚本目录的`post`目录下,可以看到所有文章的markdown文件。

博客评论导出移步

Typecho评论导出为Hexo的Valine、Twikoo等评论所支持的JSON文件