IFTTTからslackに投稿した内容をpythonのslackbotライブラリが拾えない現象について


現象

pypi経由でpythonのslackbotライブラリをインストールした場合、IFTTTからslackに投稿した内容を拾えない。

pip install slackbot
run.py
# -*- encoding: utf-8 -*-
from slackbot.bot import Bot
from slackbot.bot import listen_to

@listen_to('てすと')
def listen_func(message):
    message.send('ぽん')

def main():
    bot = Bot()
    bot.run()

if __name__ == '__main__':
    main()

# 理由
こちらの記事にあるように、通常の投稿とIFTTT経由の投稿ではフォーマットが違うためです。
データの取得はslackbotの「dispacher.py」というソースがやっているのですが、
ここで取得したデータをprintするソースを仕込んで、中身を見てみると...

dispacher.py
    def dispatch_msg(self, msg):
        category = msg[0]
        msg = msg[1]
        print(msg)  # <- 44行目にprintを仕込む
        if not self._dispatch_msg_handler(category, msg):
            if category == u'respond_to':
                if not self._dispatch_msg_handler('default_reply', msg):
                    self._default_reply(msg)
python run.py

# 普通に投稿した場合
{
  'type': 'message', 
  'user': ‘XXXXXXXX’, 
  'text': 'てすと', 
  'client_msg_id': ‘XXXXXXX’, 
  (略)
}

# IFTTT経由で投稿した場合
{
  'username': 'IFTTT', 
  'icons': {'image_36': 'https://a.slack-edge.com/8f51/img/services/ifttt_36.png', 
  'image_48': 'https://a.slack-edge.com/8f51/img/services/ifttt_48.png', 'image_72': 
  'https://a.slack-edge.com/8f51/img/services/ifttt_72.png'}, 
  'attachments': [
    {
     'pretext': 'しゅっしゃ', 
     'fallback': 'しゅっしゃ', 
     'mrkdwn_in': ['text', 'pretext']
    }
   ], 
  (略)
}

全然違いますね。
で、通常投稿のデータ形式にしか対応していないため、
IFTTTからの投稿はdispacher.pyで拾えてないということです。

対策

dispacherのmsgを取得する部分を書き換えます。
以下は、dispacher.pyの49行目〜です
(2019/9/15更新: どうもメッセージの形式が微妙に変わったようです、コメントありがとうございました!)

(編集前)dispacher.py
    def _dispatch_msg_handler(self, category, msg):
        responded = False
        for func, args in self._plugins.get_plugins(category, msg.get('text', None)):
            if func:
                responded = True
                try:
(編集後)dispacher.py
    def _dispatch_msg_handler(self, category, msg):
        responded = False
        text = None
        if 'attachments' in msg and len(msg.get('attachments')) > 0:
            text = msg['attachments'][0].get('pretext', None)
        elif 'text' in msg:
            text = msg.get('text', None)

        for func, args in self._plugins.get_plugins(category, text):
            if func:
                responded = True
                try:

差分:
https://github.com/lins05/slackbot/compare/develop...yakan10:develop

これを書き換えて、python run.pyすると、ちゃんとIFTTTにも反応するようになります。

修正済みコード

https://github.com/yakan10/slackbot/tree/develop/slackbot
(※コード本体の修正のみで特にテストは追加してません...)

参考記事