tcardgenとGitHub ActionsでHugoのブログのOGPを動的に作る
概要
markdownファイルからOGP画像を生成するLadicle/tcardgenを使い、Hugoで作っているブログで記事のmarkdownファイルをGitHubにpushすると、記事のOGP画像を動的に作るGitHub Actionsを作りました。動的というのは、markdownファイルのFront Matterからtitleなどを取り出してOGP画像を作るということです。
こんな感じです。
OGP画像にはうずらフォントを使いました。わたしの好きなかわいいフォントを選べてうれしいです。こういうのがモチベーションを上げるのです。
GitHub Actionsではなくローカルでtcardgenを実行してもいいですが、HugoのビルドもGitHub Actionsで行っている場合、markdownファイルを書いてpushするだけでビルドもOGP画像生成も自動でできちゃうのでとっても快適です。
このブログはHugo(テーマはanubis)のページバンドルとして、Leaf Bundleを採用しています。tcardgenをLeaf Bundleで動かすところとHugoのテーマにOGPを入れるのにちょっと苦戦したので、HugoのLeaf Bundleを採用しているサイトでtcardgenによってOGP画像をGitHub Actionsで作る方法をご紹介します。
大手ブログや技術ブログサイトなら何もしなくてもOGPを作ってくれるのでこういう手間はありませんが、自分だけのお城をHugoで好きなように建てていくのも悪くないです。使い慣れたエディタ(VSCode)とGitとGitHubで全てが完結できるのもいいですね。
技術構成
技術構成はこのようになっています。
もともと、Hugoのソースのリポジトリ(suzuna/blog-source)にpushすると、GitHub ActionsによってHugoのビルドを行い、生成物をHugoの公開用のリポジトリ(suzuna/blog)にpushするようにしていたのですが、このGitHub ActionsにtcardgenでのOGP画像生成を加えました。
Hugoのディレクトリ構成
content/
以下はこのような構成になっています。content/posts
以下に、記事を書いた日付をyyyymmdd
で先頭に付与したフォルダを作り、その中に記事をindex.md
で作成します。
content
├── about.md
└── posts
├── yyyymmdd-hoge-fuga-piyo
│ └── index.md
└── yyyymmdd-foo-bar-baz
├── images
│ └── image01.jpg
└── index.md
やったこと
tcardgenの出力OGP画像のファイル名の調整
tcardgenで、特定のディレクトリ以下にある全てのmarkdownファイルについてそれぞれOGP画像を作るなら、まずこちらを行います。
- Goをインストールする
path/to/fontDir
以下に、<font-name>-Bold.ttf
,<font-name>-Medium.ttf
,<font-name>-Regular.ttf
のファイル名で3個のフォントを置く1path/to/templateFile
というファイル名でOGP画像のテンプレートファイルを置く
そして、tcardgenのREADMEのとおり以下を実行すれば、path/to/static/ogp
直下に、path/to/content/posts/*.md
に該当する個々のmarkdownファイルから作成したOGP画像が出力されます。
go install github.com/Ladicle/tcardgen@latest
# 出力先の画像のディレクトリは事前に作る必要がある
mkdir -p path/to/static/ogp
tcardgen \
--fontDir path/to/fontDir \
--output path/to/static/ogp \
--template path/to/templateFile \
path/to/content/posts/*.md
ここで、出力される画像のファイル名は、Markdownファイルのファイル名と同じものになります。index.mdならindex.pngです。Leaf Bundleでは、記事のmarkdownファイルのファイル名は全てindex.mdのため、全ての記事のOGP画像はindex.pngとなり、ファイルが上書きされて1個しか生成されません。当たり前と言えば当たり前なのですが、ここでハマりました。
これを解消するために、content/posts/yyyymmdd-hoge-fuga-piyo/index.md
のOGP画像はhoge-fuga-piyo.png
とするように、1ファイルずつtcardgenを走らせます。
go install github.com/Ladicle/tcardgen@latest
mkdir -p static/ogp
files=`find ./content/posts/*/index.md -type f`
for f in $files; do
slugname=`dirname ${f} | xargs -I@ basename @ | cut -c 10-`
tcardgen --fontDir ogp/font --output "static/ogp/${slugname}.png" \
--template ogp/tcard/template.png ${f}
done
このシェルスクリプトでcontent/posts/yyyymmdd-<適当な名前>/index.md
に合致する全てのmarkdownファイルのOGP画像がstatic/ogp/<適当な名前>.png
に出力されます。
ローカルで実行すればローカルで画像が生成されますが、今回はGitHub Actions上で行います。あとで説明します。
HugoのテンプレートにOGPを入れる
Step1でOGP画像は出力されますが、Hugoのテーマで対応していなければURLが貼られたときにOGP画像が表示されません。
OGP画像とOGPのdescriptionが表示されるよう、HugoのAnubisというThemeのfooter.html
に以下を追加しました2。テーマ側でOGPに対応していなければどのテーマでも自分で書くことになります。
<meta property="og:url" content="{{ .Permalink }}" />
<meta property="og:type" content="{{ if .IsHome }}website{{ else }}article{{ end }}" />
<meta property="og:site_name" content="{{ .Site.Title }}" />
<meta property="og:title" content="{{ .Title }}" />
<meta property="og:description" content="{{ with .Description -}}{{ . }}{{ else -}}{{ if .IsPage }}{{ substr .Summary 0 300 }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end }}" />
<meta property="og:image" content="{{ if .Params.thumbnail -}}{{ .Params.thumbnail|absURL }}{{ else if and .IsPage (eq .Section "posts")}}{{ path.Join "ogp" (print .Slug ".png") | absURL }}{{ else -}}{{ "img/default.png" | absURL }}{{ end -}}" />
posts/yyyymmdd-hoge-fuga-piyo/index.md
のOGP画像として、ogp/{slug}.png
が読み込まれます。
このため、各記事のindex.mdのslugをhoge-fuga-piyo
にする必要があります。ディレクトリ名のyyyymmdd-hoge-fuga-piyo
のhoge-fuga-piyo
とslugを一致させる必要があるということです。実装的に微妙な気はしますがこれで困らないのでいいかなと…。
なお、OGP画像の下に展開されるdescriptionは、各index.mdのFront Matterにdescription
を書いていればそれが、書いていなければFront Matterの直下から最初の300文字になります。
GitHub Actionsのyamlファイルの作成
以上をGitHub Actionsにするとこうなります。.github/workflows
直下に拡張子.yml
で任意のファイル名で保存します。
OGP生成に必要なのはSetup Go
とInstall tcardgen
とGenerate ogp images
です。他は通常のHugoのビルド部分とGitHub Pagesへのpush部分なので必要に応じて変更してください。
name: github-pages
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v2
with:
submodules: true # Fetch Hugo themes (true OR recursive)
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.21.1'
- name: Install tcardgen
run: go install github.com/Ladicle/tcardgen
- name: Generate ogp images
run: |
mkdir -p static/ogp
files=`find ./content/posts/*/index.md -type f`
for f in $files; do
slugname=`dirname ${f} | xargs -I@ basename @ | cut -c 10-`
tcardgen --fontDir ogp/font --output "static/ogp/${slugname}.png" \
--template ogp/tcard/template.png ${f}
done
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
# extended: true
- name: Build
run: hugo
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
external_repository: suzuna/blog
publish_dir: ./docs
publish_branch: main
tcardgenを改造する版
わたしはtcardgenを改造しましたので、上と少し違ったGitHub Actionsを動かしています。
tcardgenは、HugoのyamlのFront MatterのTitleだけでなく、CategoryとTag, Author, DateをOGP画像に含めます。
しかし個人的にCategory, Tag, Author, DateはOGP画像に含めなくていいと思ったのと、Authorの代わりにブログのタイトルを表示したかったので、tcardgenをforkしてソースをいじって実現しました。Goは全く分からないのでソースは汚いです。
本家のインストールのこちらの代わりに、
go install github.com/Ladicle/tcardgen@latest
自作のfork版をインストールします。
go install github.com/suzuna/tcardgen@latest
forkしてGoを書いていじれる人はこんな記事を見なくてもできると思いますが…
自作のfork版を使っているため、GitHub ActionsのInstall tcardgen
とGenerate ogp images
はさきほど紹介したものの代わりにこちらを使っています。Generate ogp images
のtcardgenの実行部分に--topTitle
や--bottomAuthor
というオプションが付いているのは独自仕様です。
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.21.1'
- name: Install tcardgen
run: go install github.com/suzuna/tcardgen
- name: Generate ogp images
run: |
mkdir -p static/ogp
files=`find ./content/posts/*/index.md -type f`
for f in $files; do
slugname=`dirname ${f} | xargs -I@ basename @ | cut -c 10-`
tcardgen --fontDir ogp/font --output "static/ogp/${slugname}.png" \
--template ogp/tcard/template.png --topTitle "" --bottomAuthor "suzuna's memo" ${f}
done
参考
うずらフォントもですが、BoldやMediumがないフォントの場合は、-Bold, -Mediumをファイル名につけた全く同じフォントを置く必要があります。tcardgenの内部でファイル名をパースしているからです。もちろん、そのようにしてBoldやMediumがないフォントを使うと、OGP画像のフォントの太さは当然すべて同じになります。 ↩︎
footer.htmlは
themes/hugo-theme-anubis/layouts/partials/footer.html
にあるので、実際には、これをプロジェクトルートディレクトリ直下のlayouts/partials/footer.html
にコピーし、そのコピーしたファイルに追加しました。theme/<テーマ名>/layouts/
以下のファイルをlayouts
以下のファイルで上書きできるので、テーマを編集する場合は後者を変更します。そうしないとテーマ本体のアップデートによって編集内容が上書きされてしまいます。 ↩︎