mikutterコードリーディングの手引き
この度、久々にOSC京都に行けることになりました!わっほーい!
しかしながらこの2年ほど、まったくOSSな活動をせずにダジャレを量産するおっさんと化していたワタクシ。
このままだとアトリウムに着いた瞬間にておくれ達に拉致られて、京都湾(?)に沈められる!
と言う強迫観念に苛まれて夜しか寝れない体になってしまったので、
これまでのノウハウを生かしてmikutterのコードを読むときに知っといた方がいいことを纏めることにしました。
一人でもmikutterに興味を持ってソースをいじり始める人が増えますように。
前提
ソースコードの入手
公式サイトからgitコマンドで取得できます。
GitHubにあるmikutterリポジトリは有志がメンテしているもので、バージョンが古い可能性があります。
git clone git://mikutter.hachune.net/mikutter.git
mikutterのディレクトリ構成
|-- core | |-- boot | |-- lib | |-- miku | |-- mui | |-- plugin | |-- skin | |-- system |-- deployment |-- tasks |-- test
core/boot
mikutterの起動直後に動き出す処理がまとまっています。
コマンドラインオプション解析や(GTKプラグインが無い時の)イベントループ、プラグイン読み込みなどのコードがあります。
core/mui
mikutterのGUI(GTK2)のコードが格納されています。GUIを改造したいときは大体ここ。
後述のcore/plugin/gtkにはGTKを呼び出すコードはほとんどないので注意しましょう。
core/system
システムメッセージをTLに表示するためのユーザー(所謂みくったーちゃん)のモデルが定義されています。
core/plugin
標準プラグインが格納されています。後述します。
development
大体のLinuxディストリビューションで使えるパッケージ「AppImage」生成用のファイルが格納されています。
tasks
国際化のための翻訳関連のファイルが置いてあります。
test
ライブラリのテスト用のコードが格納されています。
標準プラグイン
mikutterはプラグイン機構が非常に柔軟で、主要な機能もプラグインとして実装されています。
その数なんと72個!この企画を選んだことを後悔しつつ、簡単に説明していきます。
core/plugin/achievement
mikutterを使っていると突如付与される「実績」を管理するプラグイン。
管理するのが仕事なので、実績の発動条件や実績メッセージは実績を授与する各プラグインに分散しています。
core/plugin/bitly
メッセージ含まれるURL短縮サービスBitlyで短縮したURLを展開するプラグイン。
core/plugin/bugreport
たまによくmikutterが落ちた時に、作者にバグレポートを送信するプラグイン。
core/plugin/account_change
「Twitterやその他のサービス」(World)のユーザーアカウントを管理するGUIと、アカウントを切り替えるGUIやコマンドを提供するプラグイン。
core/plugin/command
「本文をコピー」「返信」などのmikutterの標準的なコマンドが定義されています。
また「複数のメッセージが選択されている」などのコマンドが実行できる条件も定義されています。
自作コマンドを作るときにお世話になります。
core/plugin/console
Alt + Xで呼び出せるmikutterコンソールを司るプラグインです。
core/plugin/core
なんだこれ?
起動完了後にイベントフィルタのマルチスレッド動作を許可する感じ?
core/plugin/current_world
「現在選択されているアカウント」っていう概念を表現するプラグイン。
core/plugin/extract
mikutterの強力なメッセージフィルタ機能「抽出タブ」を司るプラグイン。
core/plugin/followingcontrol
プロフィール画面にフォロワー・フォロイー関係を表示するプラグイン。
core/plugin/gtk
GTK2によるGUIを司るプラグイン。
メインウインドウやダイアログと言った、大物のGUI部品のコードがあります。
TLなどの中身は、前述のcore/muiを参照すること。
後はイベントループがあったりします。
core/plugin/gui
通常、GUIを持つアプリはツールキット(mikutterの場合GTK2)と密接な関係があるので、
別のツールキット(Qtとか)を適用しようとするとめっちゃ改造が必要です。
しかし、mikutterはGTK以外のツールキットを使ったGUIプラグインが出てくることを想定して、
画面の操作はこのGUIプラグイン経由で行うことになっています。
core/plugin/guide
mikutterをはじめて起動したときに始まる茶番チュートリアルを司るプラグイン。
ここで使われてるTLメッセージにボタンが表示できる機能は有用なので、ぜひとも汎用化したいですね。
core/plugin/image_file_cache
画像ファイルをキャッシュする仕組みを提供するプラグイン。
core/plugin/intent
TLのメッセージのURLを開くときの処理を行うプラグイン。
マストドンのURLはブラウザじゃなくてマストドンプラグインのタブで表示したいとか。そんなことが出来る仕組みです。
core/plugin/libnotify
notify-sendコマンド経由でOSの通知ポップアップを表示するプラグイン。
core/plugin/mastodon
mikutterがメインターゲットとするSNS「Mastodon」と通信するためのプラグイン。
金具さんが作ってたWorldonっていうプラグインを取り込んだ形になります。
core/plugin/message_detail_view
mikutter 3.4で搭載された「詳細タブ」を司るプラグイン。
core/plugin/message_favorite
同じく「詳細タブ」機能のふぁぼられたユーザー一覧部分をつかさどるプラグイン。
core/plugin/modelviewer
mikutter 3.9から導入された汎用モデルビューワのプラグイン。
core/plugin/notification
ウインドウ下部のステータスバーにmikutterのおもしろ最新情報を表示するプラグイン。
core/plugin/openimg
画像のURLから実際の画像を得るためのプラグイン。
core/plugin/photo
画像のURLから画像モデルを得るためのプラグイン。
core/plugin/photo_support
画像を保持するサービスから具体的にどうやって画像を取得するかを定義するプラグイン。
core/plugin/profile
「プロフィール」タブの言語ファイルのみが格納されている。
enと言いながら中身がもろ日本語なのウケる。
core/plugin/proxy
設定画面の「プロキシ」の設定項目と、Net:HTTPクラスに対するモンキーパッチ。
core/plugin/quickstep
mikutter 3.9の新機能「Quick Step」。
core/plugin/skin_setting_gtk
設定画面の「スキン」の設定項目を提供するプラグイン。
ちなみにこれは拙作だったりします。
あー、ヤバいなぁ。本体の進化に取り残されてるなぁ。やっぱりとしぁさんに京都湾(?)に沈められるのでは。
core/plugin/smartthread
「会話スレッド」タブを司るプラグイン。
core/plugin/spell
mikutter 3.6から導入された、1つ以上のModelが連携する処理を定義する仕組み「Spell」を提供します。
core/plugin/user_detail_view
「プロフィール」タブを司るプラグイン。
core/plugin/web
クリックしたURLを外部ブラウザで開くためのプラグイン。
mikutterに特化したRuby Gemたち
mikutterを読み解くには、mikutterに特化したいくつかのgemも読み解かないといけないかも知れません。
これらは元々はmikutterに内蔵されていた処理ですが、その汎用性の高さからgemとして切り出した方が世のため人のためになると言う判断なんだと思います。
他のgemと違ってWebに使用例が転がっている状況ではないので、mikutterでの使用箇所をExampleだと思って頑張ってください。
diva
様々なメンバを保持する「モデル」を定義するためのライブラリ。
delayer
処理を登録しておいて、暇になったら実行してくれる。
pluggaloid
mikutterのプラグイン機構を実現するライブラリ。
delayer-deferred
delayerにnext()とかtrap()みたいなdeferred由来のメソッドを追加したもの。
WSLを使ってWindowsでmikutterを動かす。
愛機MacBook Air(Mid 2012)の調子が悪くなったので、メインマシンを買い置きしていたThinkpad X1 Carbon(2016)に変更しました。*1
画面が広い!重量も軽い!Windows10も結構使いやすくなってきてる!と概ね満足だったのですが、唯一の懸念事項がmikutter。
mikutterはバージョンアップを重ねるごとにWindowsで動かすのが難しくなってきてるんで、これからWindowsで暮らしていく上で、伴侶であるみくったーちゃんと添い遂げることは出来るのかしらと。
そういえば、最近流行りのWSLでmikutterの動作報告があったなぁ。試してみるかと設定してみました。
結論としてはすごくいい感じ。macOS(X11版)と同等の使い勝手が得られました。
WSLのインストール
ここはいろんなサイトで手順が公開されているので端折ります。
(1)コルタナたんに「更新」と伝え「更新プログラムのチェック」を起動する。
「開発者向け」にある「開発者モード」を有効にする
(2)コルタナたんに「コントロール」と伝え「コントロールパネル」を起動する。
「プログラムと機能」の「Windowsの機能の有効化または無効化」から
「Windows Subsystem for Linux(Beta)」をインストールする。
(3)コルタナたんに「bash」と伝え「Bash on Windows on Windows」を起動する。
(Ubuntuのインストールが始まる。)
コルタナたんは仕事のできる子。
(4)bashが起動したら、環境を最新化しておく。
sudo apt-get update sudo apt-get dist-upgrade
mikutterのインストール
今回は手抜きでUbuntuのリポジトリにいるmikutterを使います。腕に覚えがある人はgitで最新版を取ってきてインストールしてください。なんだかんだでUbuntuなので、ハマり要素はかなり少ないと思います。
sudo apt-get install mikutter
日本語フォントのインストール
こちらを参考にしてGoogle謹製のnotoフォントをインストールします。
ぽぬぽぬ: Bash on Ubuntu on Windows + XサーバでLXDEを起動
ついでに絵文字(ttf-ancient-fonts)も入れておきましょう。
sudo apt-get install noto-fonts-hinted noto-fonts-cjk ttf-ancient-fonts
日本語入力システムのインストール
ここではちょっと懐かしいuimとanthyをインストールします。*2
あれやこれやZakki: bash on ubuntu on windows(WSL)でGUIを立ち上げて日本語入力までやる
sudo apt-get install uim uim-xim uim-anthy
ブラウザ起動シェルスクリプトの作成
mikutterには、アカウントの認証時やURLをクリックしたときに起動するWebブラウザが必要です。
WSL側にfirefoxとかをインストールしてもいいのですが、せっかくのWindowsなのでEdgeとかIEを使いたいなと。
WSLでは、Windows用のプログラムを拡張子.exeまで含めて指定すると、そのプログラムが起動できるので、それでサクッと解決・・・と思ったのですが、EdgeもIEも実は.exeファイルは存在せずシェルエクステンションみたいな概念に昇華されてしまっているので、この方法はとれません。
なので、コマンドプロンプト(cmd.exe)を経由して、Windowsの既定のブラウザを起動するようにします。
/opt/mikutter-wsl/bin/start
#!/bin/sh ESCAPED_URI=`echo "$1" | sed s/\&/^\&/g` cmd.exe /C start "$ESCAPED_URI"
実行権限を付けておきましょう。
chmod 755 /opt/mikutter-wsl/bin/start
Xサーバのインストール
Windows用のXサーバはけっこう豊富に存在しますが、ここではVcXsrvを選択しました。理由はたまたま目についたからです。
この子どうやら高速なことで有名みたいです。実際サクサク動きます。
VcXsrvの起動スクリプトの作成
VcXsrvには起動時に任意のコマンドを実行する機能があるので、mikutterをダイレクトに起動するようにします。
下記のXMLファイルを作成します。LocalProgramがキモの部分です。
mikutter.xlaunch
<?xml version="1.0" encoding="UTF-8"?> <XLaunch WindowMode="MultiWindow" ClientMode="StartProgram" LocalClient="True" Display="0" LocalProgram="bash -c "DISPLAY=:0 GTK_IM_MODULE=uim mikutter" > /dev/null 2>&1" RemoteProgram="xterm" RemotePassword="" PrivateKey="" RemoteHost="" RemoteUser="" XDMCPHost="" XDMCPBroadcast="False" XDMCPIndirect="False" Clipboard="True" ClipboardPrimary="True" ExtraParams="" Wgl="True" DisableAC="False" XDMCPTerminate="False"/>
実体参照が入ってて分かりにくいですが、デコードするとこんな感じになります。
bash -c "DISPLAY=:0 GTK_IM_MODULE_uim mikutter" > /dev/null 2>&1
標準出力、標準エラー出力を/dev/nullに捨てるのがポイントです。
そうしないとmikutterがコンソールにwarningとか出力するたびに、VcXsrvが「大丈夫?コマンド打つ?」ってダイアログを出してくるので。
mikutter3.5のUserMixinでユーザーアイコンにスキンの画像を使いたいとき
UserMixinを混ぜ込んだ自作のユーザーモデルのアイコンを、みくったーちゃん(スキンのicon.png)にしたい場合です。
- UserMixinは自身のprofile_image_urlフィールドをキーにして、Photo::PhotoからPixbufを得ている。なので、ユーザーモデルのprofile_image_urlにアイコン画像のURLを入れておけば良い。
※Photo::Photoは"file://hoge/fuga.png"みたいなfile://スキームのURLが解釈できない(バグ?)ので、URI::path()を使って/から始まるUNIXパス形式で渡してやる必要がありました。ってこれまたWindowsでハマるパターンじゃん。。。
コード的にはこんな感じになります。
user = DashButtonUser.new_ifnecessary({ :uri => URI.parse("dashbutton://singleton"), :name => "Amazon Dash Button", :idname => "Dashボタン", :profile_image_url => Skin["icon.png"].uri.path })