更新されたTLを取得してGmailを介してメールで送るPython3.0スクリプト

昨日のエントリで書いた変更か、あるいは別の smtplib.py の変更がなされていることが前提。
そもそもなんで不慣れな Python3.0 で書いたかというと、まぁ新しいもの好きというのと JSONSMTP を扱うライブラリが標準で用意されているからだったり。


使い方としては、

  • 引数を与えないか、引数として mail が与えられたときには、更新分をGmailで送信。
  • 引数として update が与えられたときには、時刻の更新だけする
  • 引数として dump が与えられたときには、更新分を標準出力へ出す

となっていて、定期的にメールを送ってほしいときには最初に update してから、cron で mail 付きで定期的に動かすのがいいと思う。
dump はまぁ他のスクリプトと組み合わせたりするときに便利なんじゃないかな。
個人的な嗜好により、最新のつぶやきが一番下になるようにしている。
普通に最新のつぶやきが一番上にするには new_tl.reverse() をコメントアウトすればいい。

#!/usr/bin/env python3.0
#vim:set fileencoding=utf-8:
import sys, json, re, os, time
from urllib.request import Request, urlopen
from urllib.parse import urlencode
from base64 import b64encode
from email.mime.text import MIMEText
from email.utils import parsedate_tz, mktime_tz, formatdate
from html.entities import name2codepoint
from smtplib import SMTP

# settings
twitter_user = 'your-twitter-account'
twitter_pw = 'your-twitter-password'
gmail_addr = 'your-google-account@gmail.com'
gmail_pw = 'your-google-password'
send_addr = 'send-to@example.com'
path = os.environ['HOME'] + '/.config/twitter-latest.txt'

# load latest
latest = 0
try:
  f = open(path)
  latest = int(f.read())
  f.close()
except:
  pass

def update(user, pw, latest):
  # retrieve friends_timeline in JSON format
  modified = formatdate(latest+1, False, True)
  q = urlencode({'since': modified})
  req = Request('http://twitter.com/statuses/friends_timeline.json?' + q)
  req.add_header('If-Modified-Since', modified)

  b = b64encode('{0}:{1}'.format(user, pw).encode())
  auth = 'Basic ' + b.decode()
  req.add_header('Authorization', auth)

  h = urlopen(req)
  statuses = json.loads(h.read().decode('utf-8'))
  h.close()

  # check update
  new_latest = -1
  new_tl = []
  for st in statuses:
    created = int(mktime_tz(parsedate_tz(st['created_at'])))
    if new_latest == -1:
      new_latest = created
    
    # replace html entities
    text = re.sub(r'&([a-z]+);', lambda m: chr(name2codepoint[m.group(1)]), st['text'])
    # replace U+FF5E(FULLWIDTH TILDE) to U+301C(WAVE DASH)
    text = text.replace('\uff5e', '\u301c')
    # replace U+FF0D(FULLWIDTH HYPHEN-MINUS) to U+2212(MINUS SIGN)
    text = text.replace('\uff0d', '\u2212')
    new_tl.append('{0}:{1}'.format(st['user']['screen_name'], text))
  new_tl.reverse()
  return new_latest, new_tl

def mail(to_addr, from_addr, pw, body, latest):
  # build message
  msg = MIMEText(body, 'plain', 'iso-2022-jp')
  msg['Subject'] = 'twitter'
  msg['From'] = from_addr
  msg['To'] = to_addr
  msg['Date'] = formatdate(latest)

  # send message
  s = SMTP('smtp.gmail.com', 587)
  s.ehlo()
  s.starttls()
  s.ehlo()
  s.login(gmail_addr, gmail_pw)
  s.sendmail(gmail_addr, send_addr, msg.as_string())
  s.quit()

# main
new_latest, new_tl = update(twitter_user, twitter_pw, latest)
if new_latest == -1:
  sys.exit(0)

# save latest
f = open(path, 'w')
f.write(str(new_latest))
f.close()

if len(sys.argv) == 1 or sys.argv[1] == 'mail':
  mail(gmail_addr, send_addr, gmail_pw, '\n'.join(new_tl), new_latest)
elif sys.argv[1] == 'update':
  pass
elif sys.argv[1] == 'dump':
  print('\n'.join(new_tl))
else:
  print('unknown command: ' + sys.argv[1], file=stderr)
  sys.exit(1)