Home

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

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

前言

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

文档导出

手撸一个简单的脚本来导出Typecho博客的文章数据。

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, "[$4 ]($2)")
      .replace(/\{abtn\s+icon="([^"]*)"\s+color="([^"]*)"\s+href="([^"]*)"\s+radius="([^"]*)"\s+content="([^"]*)"\s*\/\}/g, "[$5]($3)")
      .replace(/\{cloud\s+title="([^"]+)"\s+type="([^"]+)"\s+url="([^"]+)"\s+password="([^"]*)"\/\}/g, "[$1]($3)")
      .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文件