WassrTerm

職場のプロキシーがあれで、ブラウザからだとリロードしまくらないとちゃんと表示してくれないので、TwitTermベースでつくってみた。

urllib2でBasic認証のさせ方を覚えた。

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

username = "user"
password = "password"
interval = 240

from datetime import datetime, timedelta
import os
import sys
import re
import time
import types
from threading import Thread
import urllib
import urllib2
import webbrowser
from xml.dom.minidom import parse
import thread
import warnings
warnings.filterwarnings("ignore")

try:
  import readline
except ImportError:
  sys.stderr.write('INFO: For better line editing capability, '
      'install "readline" module.\n')

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, 'http://api.wassr.jp/', username, password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)

tagText = lambda node, tagName: \
  node.getElementsByTagName(tagName)[0].firstChild.nodeValue

class TwitterReader(Thread):
  target_url ='http://api.wassr.jp/statuses/friends_timeline.rss'
  def __init__(self):
    Thread.__init__(self)
    self.last_id = 0

  def run(self):
    while not TwitterWriter.already_exit:
      req = urllib2.Request(self.target_url)
      req.add_data("since_id=" + str(self.last_id))
      e = None
      try:
        e = parse(file=urllib2.urlopen(req))
      except Exception, ex: # HTTPError or ExpatError
        sys.stderr.write(str(ex) + " will retry after %s sec\n" % interval)

      if type(e) != types.NoneType:
        for status in reversed(e.getElementsByTagName("item")):
          screen_name = tagText(status, "author")
          text = tagText(status, "description")

          print_status(screen_name, text,
                       time_created_at(tagText(status, "dcterms:modified")))

      for i in range(interval):
        if TwitterWriter.already_exit:
          break
        time.sleep(1)


def print_status(screen_name, text, (rel_time, created_at)):
  print "[%s] %s (%s)" % (screen_name, text, rel_time)

plural = lambda n: n > 1 and "s" or ""

def time_created_at(s):
  """
  recieving text element of 'created_at' in the response of Twitter API,
  returns relative time string from now.
  """

  try:
    date = time.strptime(s, "%Y-%m-%dT%H:%M:%S+09:00")[:-2]
  except ValueError:
    return "", ""
  created_at = datetime(*date)
  d = datetime.now() - created_at

  if d.days:
    rel_time = "%s days ago" % d.days
  elif d.seconds > 3600:
    hours = d.seconds / 3600
    rel_time = "%s hour%s ago" % (hours, plural(hours))
  elif 60 <= d.seconds < 3600:
    minutes = d.seconds / 60
    rel_time = "%s minute%s ago" % (minutes, plural(minutes))
  elif 30 < d.seconds < 60:
    rel_time = "less than a minute ago"
  else:
    rel_time = "less than %s second%s ago" % (d.seconds, plural(d.seconds))

  return  rel_time, created_at.strftime("%H:%M:%S")

class TwitterWriter(Thread):
  target_url = "http://twitter.com/statuses/update.xml"
  already_exit = False
  def __init__(self):
    Thread.__init__(self)

  def run(self):
    while 1:
      try:
        update_text = raw_input().strip()
        if hasattr(sys, "winver"):
          update_text = update_text.decode("shift_jis", "replace").encode("utf-8")
      except EOFError: # EOFError
        TwitterWriter.already_exit = True
        break
      if len(update_text):
        params = {}
        params['status'] = update_text       
        up = urllib2.urlopen('http://api.wassr.jp/statuses/update.json', urllib.urlencode(params))
        if up.code == 200:
          print "(update) [%s] %s " % (username,update_text)

    TwitterWriter.already_exit = True

def main():
  if username == "" or password == "":
    print "Error: Please specify your twitter account info in", sys.argv[0]
    sys.exit(1)

  print "Note: CTRL-D (or CTRL-C) to exit"
  reader = TwitterReader()
  writer = TwitterWriter()

  reader.start()
  writer.start()

  reader.join()
  writer.join()

if __name__ == '__main__':
  main()

まだリプライとかできないけど快適だ。