目录

Boostnote 内容导入到 hugo

我为什么使用 boostnote

第一,开源,自己的内容就是自己的,可以各种导出;

第二,对 Vim 支持良好(Vim 已中毒)。

缺点也是有的,Vim 模拟的并不全。

后面我会往 org-mode 迁移。

本博客所记内容大部分是使用 Boostnote 记录的。

内容管理软件大致是这个样子:

思路

  1. 首先需要导入的文章,我会给其一个 publicBlog 的标签(tag)。

  2. hugo 的文章需要一个 url,因此,我在每篇文章开头会加入几个元数据(格式与 org-mode 保持一致,我定的规矩)。因多次更换过内容管理软件,导致文章的写作时间已经无法准确区分了,因此这些缺失的时间会统一暂定为 2019-10-01

1
2
3
4
#+AUTHOR: Liu Tao
#+EMAIL: i@liutao.me
#+DATE: 2019-10-01
#+EXPORT_FILE_NAME: this_is_title
  1. 推送文章到 github

实践

  1. 找出 tag 为 publicBlog 的文章
  2. 获取元数据
  3. 处理数据,生成 markdown 文件
  4. git 管理,然后推送至 github

完整代码

代码使用 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
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import os
import shutil
import cson

boostnote_path = r"/Users/tao/Google Drive/sync/Boostnote/notes"
blog_path = r"/Users/tao/Work/mine/blog"
posts_path = blog_path + "/content/posts"
local_public_path = blog_path + '/public'
line_break = "\n"


def generate_posts_from_boostnote():
    os.chdir(boostnote_path)

    for file in os.listdir(boostnote_path):

        # 忽略后缀名不是 .cson  的文件
        if file[-5:] != '.cson':
            continue

        #  文章信息,默认作者、email
        #  没有记录时间的,统一按 2019-10-01 处理
        post_info = {
            'title': "",
            'author': "Liu Tao",
            'email': "i@liutao.me",
            'date': "2019-10-01",
            'export_file_name': "",
            'content': ""
        }
        with open(file, 'r') as fin:
            obj = cson.load(fin)
            if "publicBlog" in obj['tags']:
                post_info['title'] = obj['title']
                # 判断 info 信息是否已获取完成
                is_info_completed = False

                for line in obj["content"].split(sep=line_break):
                    if line.startswith('#+') and not is_info_completed:
                        print(line)
                        meta = line[2:].split(':')
                        post_info[meta[0].lower()] = meta[1].strip()
                        continue

                    #  此处不要标题,因为已经取到标题了
                    if line.startswith('# '):
                        # info 信息已取完整,那么后面碰到 #+ 的内容就不会再去解析
                        # 因为代码块中有 #+
                        is_info_completed = True
                        continue

                    post_info["content"] += line + line_break

        # 没有短链接的,不处理
        if post_info['export_file_name'] == "":
            continue

        # 新的博客地址
        blog_file = os.path.join(posts_path, post_info['export_file_name'] + '.md')
        print('prepare to generate new post')
        print(post_info['title'])
        print(file)
        print(blog_file)
        with open(blog_file, 'w') as file_object:
            file_object.write("---" + line_break)
            file_object.write('title: "' + post_info['title'] + '"' + line_break)
            file_object.write("date: " + post_info['date'] + line_break)
            file_object.write('draft: false' + line_break)

            # ananke 主题模板中的分享变量
            file_object.write('disable_share: true' + line_break)

            file_object.write("---" + line_break)
            file_object.write(post_info['content'])


def exec_github_commands():
    os.chdir(blog_path)

    for cmd in ['rm -rf public', 'gsed -i \'1c base = "https://liutao.me"\' config.toml ', 'hugo', ]:
        exec_cmd(cmd)

    os.chdir(local_public_path)

    cmds = [
        'echo "liutao.me" > CNAME',
        'git init',
        'git remote add origin liutao-me.github.com:liutao-me/liutao-me.github.io.git',
        'git add .',
        'git commit -m "publish posts"',
        'git push -f origin master',
    ]

    for cmd in cmds:
        exec_cmd(cmd)


def exec_gitee_commands():
    os.chdir(blog_path)

    for cmd in ['rm -rf public', 'gsed -i \'1c base = "https://liutao-me.gitee.io"\' config.toml ', 'hugo', ]:
        exec_cmd(cmd)

    os.chdir(local_public_path)

    cmds = [
        'git init',
        'git remote add gitee git@gitee.com:liutao-me/liutao-me.git',
        'git add .',
        'git commit -m "publish posts"',
        'git push -f gitee master',
    ]

    for cmd in cmds:
        exec_cmd(cmd)


def use_git_and_push():
    os.chdir(blog_path)

    cmds = [
        'git checkout develop',
        'git add .',
        'git commit -m "auto import posts from boostnote"',
    ]
    for cmd in cmds:
        exec_cmd(cmd)

    exec_gitee_commands()
    exec_github_commands()


def exec_cmd(cmd):
    print('current command: ' + cmd)
    print(os.system(cmd))


def empty_dir(path):
    for f in os.listdir(path):
        filepath = os.path.join(path, f)
        if os.path.isfile(filepath):
            os.remove(filepath)
            print(str(filepath) + " removed!")
        elif os.path.isdir(filepath):
            shutil.rmtree(filepath, True)
            print("dir " + str(filepath) + " removed!")


if __name__ == '__main__':
    # 清空 content/posts 目录
    empty_dir(posts_path)

    # boostnote 迁移到 hugo
    generate_posts_from_boostnote()

    # git 管理,并上传
    use_git_and_push()

    print('Congratulations, everything is OK!')

完整代码及后续更新:GitHub - liutao-me/boostnote2hugo