Google App EngineからTwitterのreplyなどをim.kayac.com for iPhoneに通知させる

前提条件:http://im.kayac.com/
ちょっと引っ越す予定なので自宅サーバーを止めていて、tiarraが動いていない。
今までtiarraからim.kayac.comiPhoneに通知させていたTwitterのリプライなどが来なくなってしまって寂しいので、Twitterの情報はGoogleAppEngineを使ってAPI経由で情報を取得して通知するようにしてみた。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import base64
import logging
import urllib
import yaml
from django.utils import simplejson
from google.appengine.api import memcache
from google.appengine.api import urlfetch
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util

# 以下のような config.yaml を用意しておく
# ---
# username: sugyan
# password: ********
# search_words:
#   - 検索したいワード。
#   - ORで検索するので
#   - 複数指定でもおk
config = yaml.load(open('config.yaml'))


def get_fetch_result(url):
    auth_header = {
        'Authorization' : 'Basic ' + base64.b64encode(
            '%s:%s' % (config['username'], config['password'])
            )
        }
    response = urlfetch.fetch(
        url     = url,
        headers = auth_header,
        )
    if response.status_code == 200:
        return simplejson.loads(response.content)
    else:
        logging.error(response.content)
        return []

def post_im(message):
    logging.debug(message)
    response = urlfetch.fetch(
        url     = 'http://im.kayac.com/api/post/sugyan',
        method  = urlfetch.POST,
        payload = 'message=%s' % message.encode('utf-8'),
        )
    if response.status_code == 200:
        logging.debug(response.content)
        return simplejson.loads(response.content)['result']
    else:
        logging.error(response.content)

class Mentions(webapp.RequestHandler):
    def get(self):
        since_id = memcache.get('reply')
        if since_id:
            query = 'since_id=%s' % since_id
        else:
            query = ''
        
        result = get_fetch_result(
            'http://twitter.com/statuses/mentions.json?%s' % query)
        if len(result) > 0:
            memcache.set('reply', result[0]['id'])

        for status in result:
            message = '@%s: %s' % (status['user']['screen_name'], status['text'])
            post_result = post_im(message)
            logging.debug(post_result)


class DirectMessage(webapp.RequestHandler):
    def get(self):
        since_id = memcache.get('message')
        if since_id:
            query = 'since_id=%s' % since_id
        else:
            query = ''
        
        result = get_fetch_result(
            'http://twitter.com/direct_messages.json?%s' % query)
        if len(result) > 0:
            memcache.set('message', result[0]['id'])

        for status in result:
            logging.debug(status)
            message = '[DM] @%s: %s' % (status['sender']['screen_name'], status['text'])
            post_result = post_im(message)
            logging.debug(post_result)


class Search(webapp.RequestHandler):
    def get(self):
        parameter = {
            'q' : ' OR '.join([x.encode('utf-8') for x in config['search_words']]),
            }
        since_id = memcache.get('search')
        if since_id:
            parameter['since_id'] = since_id
        
        result = get_fetch_result(
            'http://search.twitter.com/search.json?%s' % urllib.urlencode(parameter)
            )['results']
        if len(result) > 0:
            memcache.set('search', result[0]['id'])

        for status in result:
            message = '@%s: %s' % (status['from_user'], status['text'])
            post_result = post_im(message)
            logging.debug(post_result)


def main():
    logging.getLogger().setLevel(logging.DEBUG)
    application = webapp.WSGIApplication([
            ('/mentions', Mentions),
            ('/message', DirectMessage),
            ('/search', Search),
            ], debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()


app.yamlではいちおうadmin指定だけしておく

application: ********
version: 1
runtime: python
api_version: 1

handlers:
- url: .*
  script: main.py
  login: admin


で、cronでそれぞれ叩く

cron:
- description: mentions
  url: /mentions
  schedule: every 1 minutes
- description: direct messages
  url: /message
  schedule: every 2 minutes
- description: search
  url: /search
  schedule: every 5 minutes


おしまい。一応since_idをmemcacheで記録しながら使っているので重複はない、はず。初回起動時には一気にきてしまうけどw