hubotでslackにスタンプ機能を追加してみた

slack Advent Calendar 2015 の25日目の記事になります。

はじめに

つい最近触れる機会がありちょろちょろっと使っているのですがいいですねslack。
見た目もいいし、アプリとの連携とか、コードスニペットを貼れたりとか。
また僕が特に気に入ってるものとしてemoji機能があります。
感情を一発で表現できるし自分で好きなemojiを登録することもできます。

ただこれもうちょっと大きく表示したいなー、って時がありまして、そうLINEのスタンプの様に。
この辺については去年のアドカレでも触れられているのですがまた別のアプローチで攻めてみたいと思います。

というわけで作った

github.com

インストール
$ npm install hubot-slack-stamp
$ vim external-scripts.json # 配列内に"hubot-slack-stamp"を追加
必要なもの
  • hubot
  • Node.js >= v4.0.0 (or --harmony or --harmony-generators flag)
  • PhantomJS
  • ImageMagick
設定
  • HUBOT_SLACK_STAMP_TEAM_NAME - slackのチーム名
  • HUBOT_SLACK_STAMP_EMAIL - ログイン用のメールアドレス
  • HUBOT_SLACK_STAMP_PASSWORD - ログイン用のパスワード

使ってみよう

チャンネル内のhubotに対してスタンプ名と画像URL、そして分割数を入力することでスタンプが登録されます。

hubot makestamp <name(a-z,0-9,_,-)> <image_url> <split_num(2-10)>

例としてはこんな感じ。

f:id:saihoooooooo:20151225030624p:plain

登録したスタンプを表示させる時は

hubot stamp <name(a-z,0-9,_,-)>

とします。
さっき登録したmarieちゃんを呼び出してみましょう。

f:id:saihoooooooo:20151225030636p:plain

いい感じですね!!

動作原理

slackのemojiは連続で入力すると特にパディングやマージンもなくピッチリ隙間なく表示されます。
この動きを利用して、

  1. 指定されたURLの画像を取得
  2. 画像をタイル上に分割
  3. 分割した画像を一枚一枚登録
  4. 綺麗に並べて表示

ということを行っています。
今回の例でいうと実際の文字列は以下のようになっています。

:marie_3x3_1-1::marie_3x3_1-2::marie_3x3_1-3:
:marie_3x3_2-1::marie_3x3_2-2::marie_3x3_2-3:
:marie_3x3_3-1::marie_3x3_3-2::marie_3x3_3-3:

emojiのカスタマイズページに行くと分割された画像が登録されているのがわかりますね。

f:id:saihoooooooo:20151225030640p:plain

イラスト: http://seiga.nicovideo.jp/seiga/im4981228

苦労した点、課題

slackにはまだemoji登録のAPIがないのでphantomjsを使ってスクレイピングするのがちょっとつらみでした。
はよこいAPI
参考URL:oti/slack-reaction-decomoji · GitHub

あと課題としては一応スタンプの削除機能も用意しているのですがこれがまた遅い。。
正直5x5枚の削除とかになってくると遅すぎて嫌になってきます。
この辺も整備したかったのですがちょっと時間が足りなかったのでまた公開後に。。

プルリクも絶賛お待ちしております。

おまけ

今回のスクリプトは企業対抗スプラトゥーン大会ことSplathon(スプラソン)の連絡事項をslack上で交わしている際に皆のemojiのやりとりを見て思いつきました。
githubリポジトリもsplathon名義であげています。
スプラトゥーンも楽しめて開発も楽しめるsplathon、最高すぎるぜ!
第2回(締め切り済み?)、第3回と予定しているようなので気になった方はチェックしてみてください。

最後に

今日は楽しいクリスマス〜♪
ということで12/25になりました。
slack Advent Calendar 2015を書かれた皆さん、お疲れ様でした。
それではHave a nice Xmas!!!!!

skypeでp2p窓を作る自分用メモ

f:id:saihoooooooo:20151210170706p:plain:w200

僕が使ってるチャットツールはずーっとskypeです。
slackとかhipchatではありません、skypeです。

skypeってアレです「I’m indifferent. Slack/Hipchat. I don’t give a shit as long as it’s not Skype.(私は無関心です。 たるみ/Hipchat。 それがSkypeでない限り、私は全然構いません。(Yahoo!翻訳ママ))」に27%も投票されてしまうアレです。
たるみよりはマシだろうと思ってたけどそうでもないみたいです。

まぁ個人的にはそこまで恨み辛みも無いんですが、bot周りに少々難がありまして。
以前まではチャットがp2pベースで動いていたのにいつの間にかクラウドベースになってるんですね。
僕はhubotが好きで使っているのですが、それによってskype用アダプタが使えなくなってしまいました。
README.mdの先頭にもでかでかとWARNINGって書いてますね。

p2p時代に作られた部屋なら正常に動くので、古い部屋を使いまわしたりしてたんですがそのうち限界が出てきます。
そんなある日、ふとgoogle先生に聞いてみるとなんと今でもp2p部屋が作れるそうです。
えっ。

community.skype.com

その方法はどこの部屋でもいいからチャット欄に以下のコマンドを打つだけ。

/createmoderatedchat

空の部屋ができるのでそこにbotを呼びましょう。
そしたらあら不思議。

f:id:saihoooooooo:20151210165747p:plain

久しぶりじゃねぇかおめえ。
このあと滅茶苦茶(ry

phpスクリプトが最終行まで到達しているのにSEGVる件

f:id:saihoooooooo:20150409130821p:plain:w320

全く意味がわからず糞ハマってしまった。

phpバッチ処理を書いてたら突如「セグメンテーション違反です」と言われる。
にも関わらず処理は完了している???という謎の状況。
どうやらスクリプト自体は最終行まで到達しているようだが・・・。

Segmentation fault at end of PHP script | LogikDevelopment

色々探した結果上記のサイトに辿り着いた。
要はPHPがsoファイルを読み込むとき、mysql.soの前にcurl.soを読むと最後にSEGVる、と。

自分はRedshift使ってる時にハマったので試しにpgsql.soの後にcurl.soを読み込むようにしたところセグメンテーション違反は発生しなくなった。

単純にファイル名順に読み込んでるっぽいので下記で対応。

$ cd /etc/php.d
$ cat {mysql,pgsql,curl}.ini > zz_mysql_pgsql_curl.ini
$ mv curl.ini{,_bk}
$ mv mysql.ini{,_bk}
$ mv pgsql.ini{,_bk}

なんでこんなドバグな挙動が残っているんだろうかよくわからんけど、とりあえずよし。

Jersey(JAX-RS)でリストの要素が一つしかない場合にレスポンスのjson内の値が配列じゃなくなっちゃう問題の対応

f:id:saihoooooooo:20071226161622j:plain

タイトル長いですが、読んで字の如くです。
例えばこんなクラスがあるとします。

@XmlRootElement
public class MyResponse {

    private List<String> list;

    public List<String>getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

}

このクラスをレスポンスとして返した時、複数の要素がある場合はこうなりますが。

{
    "list": ["fukusu", "aruyo"]
}

要素が一つしかないとこうなる。

{
    "list": "hitotsudake"
}

お前リストやったんちゃうんかい、と。

まぁ別にデータが破損してるわけじゃないんだけど、読み取る側で分岐を入れないといけないとか割とクソ感あります。
「これ直すのに結構奥深くまで手入れないといけないんだろうなぁ・・・」と思いながらグーグル先生に訊いてみると、stackoverflowにそのものズバリな回答がありました。


How can I customize serialization of a list of JAXB objects to JSON? - Stack Overflow

要するにweb.xmlの<servlet>タグに以下のパラメータを追加するだけでいいと。
「your.project.packages」の部分は各自の環境に合わせて書き換えてください。

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>your.project.packages;org.codehaus.jackson.jaxrs</param-value>
</init-param>

たったこれだけで、ねんがんのレスポンスをてにいれることができました。

{
    "list": ["hitotsudake"]
}

コードの追加、修正が全くなくて得した気分です。