もぐてっく

人は1つ歳をとるたび、1ビットづつ大きくなれると信じてた。

mikutterプラグインのTIPSをコツコツ纏めて行きたい。

TIPS

メッセージをageる

msg.is_a?(Message)
  msg[:modified] = Time.now
  Plugin::call(:message_modified, msg)
end

Delayer実行時は、プラグインが全てロードされている事が保証されている。

Delayerは必ずメインスレッドで動作する。(GTKがidleの時に実行される。)

Reserverはメインスレッド以外で動作する。

イベント

on_appear(messages)

Messageオブジェクトを生成した時に発生。

on_update(service, messages)

TwitterからRESTまたはUserStreamでメッセージを受信した時に発生。

on_gui_timeline_add_message(i_timeline, messages)

メッセージがあるタイムラインに突っ込まれた時に発生。
messagesはMessageまたはMessagesのインスタンス
Array(messages).eachで統一的に扱えるぞ。

on_message_modified(messages)

Messageの内容が更新された時に発生。
(ふぁぼられ、リツイートなど)

ポケットミクたんといちゃいちゃKit for Windows

Gakkenのポケットミク(NSX-39)の機能をお手軽に体験できるWindowsアプリです。
出先でポケミクのデモをするのにWindows8.1タブレットを使いたかったので作りました。

f:id:moguno:20140430124603j:plain

見た目

f:id:moguno:20140506124330p:plain

インストール

1. 下記サイトからzipファイルをダウンロードして下さい。

https://www.dropbox.com/s/si8pgc2w6ns2chl/NSX39Mog.zip

2. ダウンロードしたzipファイルを適当なフォルダに解凍します。

3. setup.exeを実行します。

あなたも超モテ!ポケミクたんといちゃいちゃテクニック!

アプリをきっかけに楽しくお話ししよう

さっそくアプリを起動してポケミクたんを接続してみましょう。
すると、画面下部のステータスが「ポケミクがいないよ」から「ポケミクにんしきちゅう!」に変わります。
Windows7だと少々時間がかかることがあります。)


この状態で画面の鍵盤の1段目に触れると、ポケミクたんが歌ってくれます。

鍵盤左側の「MOD」ボタンを押すとポケミクたんの声にビブラートが掛かります。
(マルチタッチ対応:押している間はON。マルチタッチ非対応:押すたびにON/OFF切り替え。)

ポケミクたんの隠れた魅力に触れてみよう

実はポケミクたんは楽器の演奏も得意です。
鍵盤部分の2段目に触れるとGM音源に準拠した128種類の楽器と1セットのドラムを演奏する事が出来ます。


マルチタッチ対応であれば鍵盤の同時押しが出来るので、頑張れば伴奏付きでポケミクたんに歌ってもらう事も出来ますね。

オリジナルソングを歌ってもらおう

画面中央のテキストボックスにひらがなで歌詞を入力してみましょう。
「セット」ボタンを押して鍵盤(画面、本体どちらでもOK)に触れると、ポケミクが歌詞の通りに歌ってくれます。

「セット」ボタンを押した時に赤くなった文字はポケミクが歌えない文字になります。
(歌えない文字を「ん」に変換して送信します。)

エフェクトでロマンチックな雰囲気を演出

画面上部の「リバーブ」、「コーラス」、「バリエーション」コンボボックスの項目を選択してみましょう。
すると、ポケミクの声に色々なエフェクトが掛かります。
(なんと230種類以上のエフェクトがあります!)

コンボボックス下のスライダーは各エフェクトの掛かり具合が調整出来ます。

ポケミクたんのいつもと違う一面を楽しみましょう。

ソースコード

このソフトウェアはオープンソースです。GitHubソースコードを公開しています。
機能追加などは各自で行った方が色々良いと思います。

https://github.com/moguno/nsx39Mog

mikutter Advent Calendar 2013 17日目 肉食系プラグイン作成術

はじめに

この記事はmikutter Advent Calendar 2013(http://www.adventar.org/calendars/120)17日目です。

まだまだカレンダーには空きがございます。チャンスです。
mikutterを使ってみての感想とか、短めのエントリも全然OKと思います。
ぜひともmikutterへの思いを繋いで行きましょう。


さてさて、皆さんご存知の通り、mikutterのプラグイン機構はとってもエレガント。
ほんの少しのコーディングで様々な機能をmikutterに追加することが出来ます。

例えば、クリスマスムード漂うあなたのTLを真っ赤に染める位なら、ほんの数行でちょちょいのちょいです。

# -*- coding: utf-8 -*-

Plugin.create :red_background do
  filter_message_background_color do |message, color|
    color = [65535, 0, 0]
    [message, color]
  end
end


でも「mikutterちゃんにこんなこともして欲しい(>_<)」がエスカレートしてくると、用意されたAPIでは実現できないことも出てきますよね。

そこで今回は「肉食系mikutterプラグイン作成術」と題して、少々強引な方法を使って、あなた好みのステキなmikutterをgetする方法を書いてみようと思います。

復習:1分で何となく分かるmikutterプラグイン

mikutterは処理の要所要所で「フィルタ」や「イベント」を通じて、プラグインと会話しようとします。
プラグインは興味のある「フィルタ」、「イベント」をハンドリングする事でmikutterの挙動を変更しする事が出来ます。

上記の真っ赤なTLの例ではfilter_message_background_colorと言うハンドラを定義して、つぶやきが描画される際に呼ばれる:message_backgroundと言うフィルタを捕捉しています。
そしてfilter_message_background_colorの中で色コードを設定することで、つぶやきの背景色を変更しています。

さて、本題

この様に強力なイベント機構によってダントツの拡張性を誇っているmikutterさんですが、残念ながらこのモデルは万能ではありません。


例えば、タブに表示されるアイコンのサイズを変更したいとします。

この場合、タブのアイコンが書き換わるタイミングに発行されるフィルタをハンドリングして、少し小さめのアイコンを返してやれば良いと言う発想になります。

しかしながら、mikutterには残念ながらそのフィルタは用意されていません。
フィルタが発行されない事にはプラグインは介入のしようがありません。困りました。


ここであきらめるのも悔しいので、抜け道が無いかソースコードを読んでみます。
タブのアイコンを表示する処理はgtkプラグインのtab_update_icon()と言うシンプルなメソッドで行われています。

def tab_update_icon(i_tab)
  type_strict i_tab => Plugin::GUI::TabLike
  tab = widgetof(i_tab)
  if tab
    tab.remove(tab.child) if tab.child
    if i_tab.icon.is_a?(String)
      tab.add(::Gtk::WebIcon.new(i_tab.icon, 24, 24).show) # ここの24が書き換えれれば・・・
    else
      tab.add(::Gtk::Label.new(i_tab.name).show) end end
  self end

直接gtk.rbを書き換えてしまえば話は早いのですが、これだけのためにgtkプラグインをフォークするのもアホらしいですし、ユーザにパッチ作業を要求するのも非常にアレです。

どうにかプラグインで実現出来ないか?

黒魔術ですべてを思いのままに


まどか「・・・私なら、何でも願いが叶うって言ったよね?」

QB「ああ、君ならどんな不可能も可能にできるだろう。さぁ、願いを言うんだ。まどか。」


すーっ・・・


まどか「すべてのメソッドを、生まれた後に書き換えたい!全てのインスタンス、クラスとモジュールのすべてを!この手で!!」


QB「そんな祈りが叶うとすれば、それはオーバーライドなんてものじゃない。オブジェクト指向そのものに対する叛逆だ・・・君は本当に神になるつもりなのかい!?」


なれちゃいます、神様。


思い出してください。
mikutterはRubyで作られています。

Rubyと言えば動的プログラミング。
別名「黒魔術」を使えば、任意のタイミングでクラスのメソッドを変える事すら、我々には不可能では無いのです。


早速、黒魔術でプラグインからtab_update_iconを上書きしてしまいましょう。

Plugin.create :tab_icon_size do
  Plugin[:gtk].instance_eval {
    # 独自のタブアイコンメソッドを上書き定義
    def tab_update_icon(i_tab)
      type_strict i_tab => Plugin::GUI::TabLike

      tab = widgetof(i_tab)
      if tab
        tab.remove(tab.child) if tab.child
        if i_tab.icon.is_a?(String)
          tab.add(::Gtk::WebIcon.new(i_tab.icon, 12, 12).show) # 半分の大きさになれっ!
        else
          tab.add(::Gtk::Label.new(i_tab.name).show) end end
      self
    end
  }
end

このコードが実行されて以降、tab_update_icon()が呼ばれると、上書きした方のメソッドが実行される様になります。
すげぇぜRuby


この手法は、巷では「モンキーパッチ」と呼ばれている様です。
元のソースコードを一切触らずパッチが充てられるので、アプリケーションのHotFixなどに有効活用されています。
オブジェクト指向が流行った時に言われてた「差分プログラミング」って奴ですね。

でも、モンキーパッチは便利な反面、どこぞのプラグインがこっそりメソッドの挙動を変更した場合、非常に分かりにくいバグを生む恐れもあります。

mikutterに於いては、複数のプラグインが同じメソッドをモンキーパッチした場合、先にロードされたプラグインが正常に動作しない事になります。
また、モンキーパッチによってmikutterのコアの動作を阻害する可能性もあります。

(後、mikutterの薄い本vol.4でとしぁさんがモンキーパッチをちらっとdisってたのもちょい気になります。)


複数のプラグインが共存できないと言う点で、もはやこれはプラグインではなく「MOD」とか呼んで区別した方がいいかもしれません。


しかしながら有益な技には違いないので、何とか副作用を抑えて活用して行きたいところですね。


例えば、何かしらモンキーパッチを検出する機構を作って競合を発見可能にすれば上記の事故は起こらないかもしれません。


・・・


さて、エントリがやたらと長くなってきたので、今回はこれ位で。
次回はこれまた黒魔術を使って、モンキーパッチ検出機構を構築して見ようと思います。

(そのうち続く)