Coelacanth's Dream

ActivityPub サーバー、honk をカスタマイズしてみる

最近の Twitter の情勢を受けて、他の SNS、特に Mastodon サーバーに移行または独自のサーバーを構築する人が増えている。
加えて自分の観測範囲では、以前に紹介した Ted Unangst 氏による Go言語製の ActivityPub サーバーの最小実装、honk を構築する人が増えている。1
honk は省メモリであるため、メモリ 512MB の VPS でも快適に動作する。
メインでも予備でも、個人で運用可能な ActivityPub サーバーが欲しい人にとって honk は有力な選択肢になると思う。
また、最小実装ということが手伝い、カスタマイズ、それによる再ビルドと再起動に必要とするコストは小さく、バイナリサイズも自分が運用しているもので 13M と小さい。
そこで、個人的に honk を運用しながらカスタマイズしていって得た知見を共有することで、誰かの honk を構築し、カスタマイズする切っ掛けになればと思い、この記事を書いている。

カスタマイズにあたって先にオープンソースライセンス周りの話に触れると、有名な ActivityPub サーバー、Mastodon, Pleroma, Misskey, Pixelfed, PeerTube では AGPLv3 が採用されているが、honk では ISCライセンスが採用されている。
ライセンスについて詳しい訳ではないため雑な解説となるが、AGPLv3 ではソフトウェアの利用にあたってコピーレフトが適用されるが、ISCライセンスにコピーレフト条項はない。
こうした点でも honk はカスタマイズが容易だと言えるかもしれない。

Index

Customization

CSS

まず一番簡単な honk のカスタマイズは CSS による配色の変更だろう。
honk では {datadir}/views/ 下に local.css がある場合に追加で読み込むため、ソースファイルを編集しなくとも、local.css を追加するだけで CSS は変更できる。
honk では主に使う色を views/style.css で CSS 変数を使って指定しており、CSS 変数には --bg-page, --bg-dark, --fg, --hl, --fg-subtle, --fg-limitied が宣言されている。
--bg-page は背景色、--bg-dark は一部の要素に使われる背景色、--fg はテキストやボーダー、アウトラインの色、--hl はボタン要素等を強調するのに使われる色、--fg-subtle はリプライ等に使われる色、--fg-limited はパブリックではない投稿に使われる色となっている。
合わせて、honk では上記 CSS 変数を上書きするための local.css を追加するだけで独自の配色、テーマを適用することができる。

自分の honk サーバーでは以下の内容だけの local.css を追加して、このブログと近い配色にしている。

    html {
      --bg-page: #145;
      --fg: #ffe;
      --hl: #fa3;
      --bg-dark: #023;
    }

他には views/style.css を編集してマージン、フォントサイズ、ボーダーのスタイルを変更しているが、これも local.css にルールを上書きする形で記述すれば適用される。

HTMLテンプレート

honk では html/template 2 パッケージを採用しており、{viewdir} にある HTMLテンプレートを起動時に読み込む。
少し注意が必要なのが、HTMLテンプレートは {viewdir} 下にあるものを読み込むが、local.css, local.js{datadir}/views/ 下にあるものを読み込む点となる。
また、HTMLテンプレートの変更には golang の text/template, html/template に関する知識が必要になる。と言っても、変数や分岐の概念が追加されるだけで、後はほとんど HTML/CSS/JS がそのまま使われている。
それと、あまり悪く言うつもりはないのだが、honk の HTMLテンプレートでは <p> 要素をスペース目的で使っていたり、<p> 要素の閉じる前に他のブロックレベル要素が見つかった場合は自動で閉じる仕様を活用した部分が多く、</p> が HTMLテンプレート内になかったり、そしてインデントがほとんどされていないため、正直読みにくかった。
HTMLテンプレートを変更する際は、まず好みのコードフォーマットを適用することをオススメする。

HTMLテンプレートの変更は、それを前提とした CSS セレクタや JavaScript コードの動作に影響を与える可能性があるため、ブラウザの開発者ツールで確認しながら試し、それから HTMLテンプレートに変更を適用することを推奨。

JavaScript

honk の WebUI では JavaScript が使われており、例えば投稿に対する Boost (bonk)、リプライ (honk back)、削除 (bonk)、編集 (edit)、ブックマーク (save) をサーバーにリクエストする部分に JavaScript が使われている。
主な JavaScript コードは views/honkpage.js にまとめられているが、グローバル変数は HTMLテンプレート views/honkpage.html に記述されている。

Admin

./honk admin コマンドから、一部のページに表示されるメッセージやアバターカラー、用語を変更することができる。
メッセージはタイムライン上部、/about ページ、ログインページに表示するものを設定でき、HTML を直接記述する形式となっている。
アバターカラーは #RRGGBB または #RRGGBBAA を 4個設定でき、設定した色が生成するアバター画像に用いられる。

lingo for ... からは honk 独自の用語である honked, bonked, honked back, qonked, evented を置き換えることができる。
自分が見たことのある例では、honkedpostedbonkedrepostedhonked backreplied に設定している人がいた。

Go Code

見た目だけでなく処理部分もカスタマイズしようとすると Go で書かれたソースコードの変更が必要となる。
honk の各ソースコードファイルの短い説明は docs/vim.3 にまとめられている。
自分は honk のソースコードを読み込んでいる訳ではないが、カスタマイズし、自分の fork を作っていく中で触れた部分について簡単な解説を書いていく。

activity.go には ActivityPub 形式との変換、他 ActivityPub 実装との相互運用のための処理がまとめられている。
ActivityPub における Inbox/Outbox や RSS の出力は web.go にまとめられている。

honk ではアバター画像を保存せず、WebUI では設定された色のパターンとユーザー名のハッシュから生成した画像を表示する。その部分の実装が avatar.go にまとめられている。
一応、{datadir}/memes に画像を置き、アカウントのプロフィールで avatar: <file> の形式で記述することで外部に対してアバター画像を設定することはできる。

fun.goAll sorts of fun stuff. とあるように、投稿に対する色々な処理がまとめられてある。
具体的には投稿の種類の判定、ユーザー名の正規化、HTML 要素からの不要な属性の削除、フィルターの適用、画像リンクの処理、データベースへの添付ファイルの保存といった処理がある。
honk では投稿内のインライン <img> 要素も処理し、画像を保存するが、これを無効化するには fun.go 内の func inlineimgsfor を常に return "" となるように変更すればいい。3
画像リンクの処理は func replaceimgsand で行われる。自分の fork では WebUI 上ですべての <img> 要素に loading="lazy" を追加するため、その関数内のフォーマット文字列を変更した。4

データベースからの取得は database.go に実装されている。何日以内の公開投稿を表示するか等も database.go 内で定義されているため、その部分を適切に変更することで、通常は一週間以内の表示期間を変更することができる。

sensors.go には /about ページで表示される honk のメモリ使用量 (syscall Maxrss)、起動時間 (Uptime)、CPU 使用量を取得する処理が実装されている。

honk のユーザーごとに設定可能なフィルター機能、Honk Filtering and Censorship System (hfcs) は hfcs.go に実装されている。
hfcs では正規表現を使うことができるが、ユーザーが設定した文字列の前後に \\b が追加したものをフィルタリングに用いるため、日本語等をフィルター対象に指定する場合は \\b を追加しないようコードを変更する必要があった。5
投稿の表示を折り畳むかどうかの判定も hfcs.go 内の func unsee で行われる。
honk ではフィルター対象は折り畳むが、sensitive フラグが有効な投稿はそのまま表示する。自分の fork では簡単な変更を適用して sensitive: true な投稿も折り畳むようにしている。6
ちなみに sensitive: true でも折り畳まないのは意図的なものらしく、その理由を Ted Unangst 氏に聞いた所、Python のインストールに関するスレッドを読むためだけに 20回もクリックして展開することにうんざりしているから、とのことだった。7

honk では投稿時に Markdown 記法が使えるが、Markdown パーサーは Ted Unangst 氏が別に公開している webs パッケージに実装されている。
そのため、Markdown パーサー部を変更するには go.mod を編集し、ローカルにある webs パッケージを参照するようにする等の方法が必要になる。

fork of honk

レポジトリが公開されている honk の fork には以下のようなものがある。

Ben Cartwright-Cox (benjojo) 氏の fork では、外部ユーザーのアバター画像のサポートと WebUI 上での表示、MP4 と GIF のサポートが追加されており、また外部からの Like をログに出力するよう (記録はしない) 変更されている。
honk のクセが強い (と思う) 部分が緩和され、使いやすくなっているように思う。

好みの fork をそのまま運用してもいいが、それぞれの変更内容を一部取り込んでいって独自の honk を構築する手もある。
上で挙げた fork の中にもそのようなレポジトリがいくつかある。

自分の fork は Umio-Yasuno/honk-fisherman で公開している。いくつかの変更を各ブランチで分けているが、それらをまとめ、実際に運用しているのが dream ブランチとなっている。
変更は HTMLテンプレートが主で、処理部は先に挙げた細かい修正くらいしかしていない。
投稿に表示される時刻フォーマットを 2006-01-02 15:04:05 に変更したり、honkpage.js を書き直したり、メニュー部を自分なりに分かりやすくしたりしている。

参考リンク