Skype4Py をいじってみた

Skype が公開している Public API を Python からいじれる Skype4Py というライブラリが存在するので、すこしいじっていました。

感想としては、各クラス名やメソッド名が Pythonic では全然ありません。 個人的に、作者は JavaScript が好きなのではという印象も持っています。

ついでなので、チャットで特定の単語から始まる発言に反応する Bot 的な何かのフレームワーク ( とは言えない何か ) を簡単に作りました。

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

import Skype4Py
import functools
import time


class SkypeBot(object):

    def __init__(self):
        self.skype = Skype4Py.Skype(Transport='x11')
        self.skype.Attach()
        self.skype.OnMessageStatus = self.status_handler
        self.processors = {}

    def status_handler(self, msg, event):
        if event == Skype4Py.enums.cmsReceived:
            for line in msg.Body.split('\n'):
                body = line.split() + ['']
                cmd, args = body[0].lower(), body[1:-1]

                processor = self.processors.get(cmd, lambda args: None)
                self.send_message(processor(args), msg.Chat)

    def send_message(self, body, chat):
        if body:
            chat.SendMessage(body)

    def add_processor(self, cmd):
        def receive_processor(processor):
            @functools.wraps(processor)
            def wrapper(*args, **kwargs):
                return processor(*args, **kwargs)
            self.processors[cmd] = wrapper
            return wrapper
        return receive_processor

    def run(self):
        while True:
            time.sleep(1)

使い方

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

from skypebot import SkypeBot
import urlparse
import urllib
bot = SkypeBot()


@bot.add_processor(u'ping')
def process_ping(args):
    return u'pong'

@bot.add_processor(u'expand')
def process_expand(args):
    if not len(args) == 1:
        return

    url = args[0]
    parsed_url = urlparse.urlparse(args[0])

    if parsed_url.netloc == 'ux.nu':
        query = urllib.urlencode(
            [('id', parsed_url.path[1:]), ('format', 'plain')])
        request = urlparse.urlunparse(
            ['http', 'ux.nu', '/api/expand', '', query, ''])
    else:
        query = urllib.urlencode([('url', url), ('format', 'plain')])
        request = urlparse.urlunparse(
            ['http', 'ux.nu', '/hugeurl', '', query, ''])

    result = urllib.urlopen(request)
    expanded = result.read()
    if result.code == 200 and expanded:
        return expanded


@bot.add_processor('shorten')
def process_shorten(args):
    if not len(args) == 1:
        return

    url = args[0]
    query = urllib.urlencode([('url', url), ('format', 'plain')])
    request = urlparse.urlunparse(
        ['http', 'ux.nu', '/api/short', '', query, ''])

    result = urllib.urlopen(request)
    shortened = result.read()
    if result.code == 200 and shortened:
        return shortened


if __name__ == '__main__':
    bot.run()

適当な processor 関数を定義して SkypeBot インスタンスの add_processor メソッドに反応したい単語を渡してデコレートしてやればいい感じです。

processor 関数が文字列を返すと発言のあったチャットにその文字列を投下します。

processor 関数の args 引数には反応対象の単語の後に書かれていた文字列のスペース区切りリストが渡されます。

# 詳しいことはコード嫁

動かすには Skype を起動しておく必要があります。 Bot の初回起動時には Skype に「このアプリのアクセスを許可するか」的な事を訊かれるので許可してあげてください。 「選択を保存」風なチェックボックスをチェックしておくと便利です。

skypebot.py は Linux 上で動かすことを前提に書かれています。

Python を 32bit モードで動かし Skype4Py.Skype を引数なしで呼ぶと Mac でも動きます。 32bit モードでの動かし方は Skype4Pyがsegmentation fault する - mfumiの日記をご参照ください。 Windows のことは知りません。

本格的に Bot として動かすなら Skype のデーモン化が必要になります。 これについては Linux上で動くSkype用のbotを作る方法 - muddy brown thang をご参照ください。