某はてなブログからHexoに移行

  • はてなブログの残念ポイント
    • バージョン管理ができない
    • 数式にエスケープや中括弧が必要(x_1, x^{2}など)
    • 複数回同じ脚注を使うことができない
    • 編集途中に回線が落ちると編集内容が消える
  • 面倒だったので、静的サイトジェネレータに移行することにしました。
  • 新しいものを使いたくなり(Cloudflare Pages+GitHub+)Hexoに移行することにしました。ただ、ユーザーのほとんどが中国語話者のようで、READMEが中国語で書かれているテーマだらけでした。とりあえず無難にIcarusを使うことにしました。結局テーマなんて萌え絵が貼ってあればどうでもいい説(適当
    • コメントは適当にDisqusを選び, 広告と寄付欄を消し, 共有欄はMastodonがあったAddToAnyに変更(NostrやらBlueskyやらがねえ!!!), ライセンスを削除しました。レンダラーはなんとなくPandocにしました。
1
2
3
4
npm install hexo-theme-icarus --save
npm install hexo-renderer-pandoc --save
npm install hexo-generator-sitemap --save
npm install hexo-generator-robotstxt --save

なぜかtrailing_indextrailing_htmlfalseにしないと、サイトマップに.html付きのurlが記載されリダイレクトが行われてSearch Consoleでエラーが出ました。

_config.yml
1
2
3
pretty_urls:
trailing_index: false # Set to false to remove trailing 'index.html' from permalinks
trailing_html: false # Set to false to remove trailing '.html' from permalinks
  • はてなブログは最近ではMarkdownで記事を書いていたので、変換は幾分楽でした。
  • 画像以外の独自機能をあまり使い込んでいなかったので、pre-commitの悪用で適当にうまくいきました。

pre-commitの設定

.pre-commit-config.yaml
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
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: "{{package_name}}|.all-contributorsrc"
default_stages: [commit]

repos:
- repo: local
hooks:
- id: replace-hatena
name: Replace Hatena
entry: python replace_hatena.py
language: python
additional_dependencies:
- requests
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: debug-statements
- id: check-builtin-literals
- id: check-case-conflict
- id: check-docstring-first
- id: check-json
- id: check-toml
- id: check-xml
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/python-poetry/poetry
rev: 1.8.1
hooks:
- id: poetry-check
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
args: ["--tab-width", "2"]
exclude: "scaffolds/"
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/psf/black
rev: 24.2.0
hooks:
- id: black
replace_hatena.py
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
import re
from pathlib import Path

import requests

DOWNLOAD = True
SOURCE_DIR = Path("source")
DEST_DIR = Path("source/images")

for path in Path.cwd().rglob("*.md"):
content = path.read_text(encoding="utf-8")

# replace escaped characters
content_new = content.replace(r"_", "_").replace(r"\\", r"\\")

# replace image links
# ![](/images/20240217192923.png) -> ![](/images/20240217192923.png)
content_new = re.sub(
r"\[f:id:(\w+?):(\d{8})(\d{6})p:(?:.+?)\]",
r"![](https://cdn-ak.f.st-hatena.com/images/fotolife/m/\1/\2/\2\3.png)",
content_new,
)

# download images
if DOWNLOAD:
for url in re.findall(
r"https://cdn-ak.f.st-hatena.com/images/fotolife/m/\w+/\d{8}/\d{14}.(?:png|jpg)",
content_new,
):
dest = DEST_DIR / url.split("/")[-1]

# download only if not exists
if not dest.exists():
# create directory if not exists
dest.parent.mkdir(parents=True, exist_ok=True)

# download image
r = requests.get(url, timeout=10)
if r.status_code == 200:
dest.write_bytes(r.content)
else:
# do not replace url if download failed
continue

# replace url
# need "/" at the beginning to make it relative path
content_new = content_new.replace(
url, "/" + dest.relative_to(SOURCE_DIR).as_posix()
)

# replace only if content is changed
if content != content_new:
path.write_text(content_new, encoding="utf-8")

  • コードにタイトルをつけられるのすごい
  • 記事編集はVSCodeで行い、Markdown Pasteを使った。Ctrl+Shift+Vで画像を貼り付けると、source/imagesに勝手に保存される。
.vscode/settings.json
1
2
3
{
"MarkdownPaste.path": "../images"
}
  • Copilotが勝手に続き書いてくれるのこy

コメント