delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

07 Feb 2021

把 blog 从 Movable Type 迁移到了 Hugo

花了些时间把 blog 从 Movable Type 迁移到了 Hugo

说起来 Movable Type 已经用了有十七年之久了,不过 Movable Type 商业化以后便基本没有更新了, 由于它是 Perl 写的,因此我也没什么动力去持续维护。

由于 Movable Type 自己就是一个输出模板的引擎,因此考虑使用它来直接输出一套 Markdown 的格式的文本应该就可以了。 不过,我发现没有什么特别好的 Perl HTML -> Markdown 逆向转换的现成的库,那么比较明显的办法便是仍然让它正常输出 HTML, 然后用自己的脚本来把 HTML 转换成 Markdown。

第一步是做一个叫 Markdown 的页面(Entries)模板。

---
title: "<mt:entryTitle encode_php="qq" replace="\$","$">"
date: <$MTEntryDate format_name="iso8601" utc="1" $>
lastmod : <$MTEntryModifiedDate format_name="iso8601" utc="1" $><mt:EntryIfTagged>
tags: [<mt:EntryTags glue=', '>"<$mt:TagName$>"</mt:EntryTags>]</mt:EntryIfTagged>
categories: [<mt:EntryCategories glue=', '>"<$mt:CategoryLabel$>"</mt:EntryCategories>]
aliases:
  - <$mt:EntryPermalink replace="https://blog.delphij.net",""$>
  - /archives/<$mt:EntryID pad="6">.html
---

<mt:MarkdownOptions>
<mt:If tag="EntryBody">
<$mt:EntryBody$>
</mt:If>
<mt:If tag="EntryMore">
<!--more-->
<$mt:EntryMore$>
</mt:If>

<mt:IfCommentsActive>
<hr>
<mt:Comments lastn="1000">
<mt:CommentsHeader><h4>Archived: <$mt:EntryCommentCount singular="1 Comment" plural="# Comments" none="No Comments"$></h4></mt:CommentsHeader>
<$mt:CommentAuthorIdentity$><b><mt:IfCommentParent><$mt:CommentAuthorLink$> replied to comment from <mt:CommentParent><$mt:CommentAuthor$></mt:CommentParent> | <$mt:CommentDate$><mt:Else><$mt:CommentAuthorLink$> | <$mt:CommentDate$></mt:IfCommentParent></b>
<$mt:CommentBody$>
</mt:Comments>
</mt:IfCommentsActive>
<mt:IfPingsActive>
<hr>
<h4>Archived: trackbacks</h4>
<mt:Pings>
<b><a href="<$mt:PingURL$>"><$mt:PingTitle$></a> from <$mt:PingBlogName$> on <a href="#ping-<$mt:PingID$>"><$mt:PingDate$></a></b>
<p><$mt:PingExcerpt$> <a href="<$mt:PingURL$>">Read More</a></p>
</mt:Pings>
</mt:IfPingsActive>
</mt:MarkdownOptions>

这里把目前的回应全部转换成了页面的一部分。这个也不算特别理想,但是因为还没想好把回应弄到什么里面去,加上大部分回应已经是很久以前的了,索性就先这么做吧。

接下来就是把 HTML 转化为 Markdown 了。我使用的是一个叫 html2markdown 的 Python 库,为了满足迁移的需要,我自己做了少量的修改。 脚本本身非常简单:

import html2markdown
import os
import sys
import html

def mdify(input_name):
    if not input_name.endswith('.html.md'):
        raise ValueError("Bad name: %s" % input_name)
    lines = open(input_name).read().split('\n')

    # Find out the second ---
    location = [i for i,x in enumerate(lines) if x == '---'][1]
    # Get the YAML
    yaml = '\n'.join(lines[:location+1])
    # Get the HTML
    html_content = '\n'.join(lines[location+1:])
    # markdownify
    md = html.unescape(html2markdown.convert(html_content))

    output_name = input_name[:-8] + '.md'
    output_file = open(output_name, 'w')
    output_file.write(yaml)
    output_file.write('\n')
    output_file.write(md)
    output_file.close()
    os.remove(input_name)

for file in sys.argv[1:]:
    print("Processing: %s\n" % (file))
    mdify(file)

最后直接用 find . -name '*.html.md' -type f -exec python3 ~/convert.py {} + 转换就可以了。

在迁移过程中,主要遇到了以下一些问题:

  1. 很多曾经存在的网站都已经没有了。这个问题没有太好的解决方法,只能有时间慢慢整理了。目前的想法是如果有 互联网档案馆 的副本,则尽量使用这些副本;如果没有的话,就只能这么算了。
  2. 一些原有的内部链接损坏。在某次 Movable Type 版本升级的过程中,一些旧的链接被破坏掉了, 这次迁移的过程中吸取了这一教训,一部分其他网站链接本blog的链接将会提供一个永久性转向。
  3. 原有的内部图片丢失。我之前使用 Gallery3 做了一个相册并在 blog 中使用了其中的内容,由于 Gallery3 在几年前停止维护,于是我也把 Gallery3 的服务停掉了。这次搬移的过程中发现了这些图片死链, 目前的做法是直接粗暴地改为静态图片,令其看上去大致上还可以看。

一些留待后续解决的问题:

  1. 留言板。目前的打算是使用 isso。之前考虑过使用 Disqus 或是 Gitalk,但前者的免费版本对用户的追踪过于猛烈,而后者则依赖第三方 (GitHub)服务,并不是真正的self-hosting。如果您有更好的建议,欢迎给我发 email(考虑到这个 blog 已经长了多年的草, 我相信能看到这个并给出建议的都是认识的朋友了),或者直接在下面留言。
  2. 一些其他毛边。迁移过程中短暂地丢失了 Atom feed 和 Sitemap,这两个我都重新做了一份,其中 Sitemap 做了一个 XSLT 来呈现一个对人类比较友好的形式。