损坏的 Typecho 备份处理为 JSON

友站 Typecho 备份数据损坏了(从头开始 – 林林杂语),搜了下似乎并不是个例。

本来要了份存档想帮忙试下修复下,不过拖延症了几天,站长自己修复了。留份 Typecho dat 文件转 json 的代码以备后用吧

(转完再处理成对应的博客系统的备份格式就行了)

吐槽下 Typecho 的备份格式挺怪的,感觉不是一个人写出来的……
我一个 Go 开发,写一半 Go 突然顿悟切 JS 写,效率反而暴增。论处理 JSON 时 JS 的优越性

const fs = require('fs');

const path = 'typecho.dat';

function splitBuffer(b, splitWith) {
  const ret = [];
  let s = 0;
  let i = b.indexOf(splitWith, s);
  while (i >= 0) {
    if (i >= 0) {
      ret.push(b.slice(s, i));
    }
    s = i + 1;
    i = b.indexOf(splitWith, s);
  }
  ret.push(b.slice(s));
  return ret;
}

function parsePost(buf) {
  // 忽略头部的字符
  buf = buf.slice(5);

  // 解析 header
  var jsonLeft = 0;
  var jsonRight = buf.indexOf('}');
  if (jsonLeft == -1 || jsonRight == -1) {
    return undefined;
  }

  var jsonPart = buf.slice(jsonLeft, jsonRight + 1).toString();
  const header = JSON.parse(jsonPart);

  // 处理内容
  buf = buf.slice(jsonRight + 1);
  const readBytes = (n) => {
    if (!!n) {
      const result = buf.slice(0, n).toString();
      buf = buf.slice(n);
      const num = parseInt(result);
      return isNaN(num) ? result : num;
    } else {
      return '';
    }
  };
  const post = Object.keys(header)
    .map((key) => ({ key, value: readBytes(header[key]) }))
    .reduce((pre, cur) => ({ ...pre, [cur.key]: cur.value }), {});

  return post;
}

function main() {
  var buf = fs.readFileSync(path);

  // 删除前面的 Waring 数据
  buf = buf.slice(buf.indexOf('%TYPECHO_BACKUP_FILE%'));

  // 文章分割
  var posts = splitBuffer(buf, '\x01\x00');
  console.log('post length', posts.length);
  posts = posts.map(parsePost);

  const failed = posts.filter((item) => !item).length;
  if (failed > 1) {
    console.log('read filed', failed - 1);
  }

  fs.writeFileSync(
    'data.json',
    JSON.stringify(
      posts.filter((item) => !!item),
      undefined,
      4
    )
  );
}

main();