Twitterクライアントを改良

水曜日, 2月 9th, 2011 by

今日は、昨日作成したTwitterクライアントを改良しました。

まず最初におさらいですが、今作成しているTwitterクライアントは、GoogleAppEngine/Python環境で動作しています。OAuthでの認証を実現しており、興味をもたれた方は、自由に使っていただいて問題ありません。また、欲しい機能などがありましたら、意見頂けると中の人が喜びます。コメント大歓迎です!(自動公開にならないかもしれませんが、見つけ次第、公開します)

改良点は以下の通り

  • デザインを調整
    スタイルシートをつけてみました。
  • 空文字列の送信を防止
    何も入力していない状態での送信をJavaScriptで防止しました。
  • URLのリンク
    TL内のURLに自動リンクするようにしました。
  • @ユーザIDのリンク
    @の後ろに英数字が続く場合は、そのユーザにリンクするようにしました。
  • BadValueエラーの処理
    同一メッセージを2回連続で発言した際に発生していたBadValueエラーを隠しました。

スクリーンショット

スクリーンショットです。このスクリーンショットに映っているユーザは全員公開モードになっていたので、内容は伏せていません。

Nisetweet

Nisetweet

ソースコード


お約束のソースコードを貼り付けておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
HEADER = """<html><head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>nisetweet</title>
<style>
div.tweet{
  width:400px;
}
div.tweet{
  width:400px;
  margin:2px;
  padding:2px;
  border-width:1px;
  background-color:EEFFEE;
  word-break:break-all;
  border-style: solid; border-color: green;
}
div.tweet img{
float:left;margin:5px;
}
textarea#textarea_status{
width:355px;
height:80px;
}
input#say{
width:45px;
height:80px;
}
form{
margin:0;
padding:0;
}
</style>
<script>
function submitStatus(this){
  if(this.value != ""){
    form.submit();
  }
}
</script>
  </head><body>
  <h1>nisetweet</h1>
  """


FOOTER = "</body></html>"

class MainHandler(RequestHandler):
    """Demo Twitter App."""

    def get(self):
        client = OAuthClient('twitter', self)
        write = self.response.out.write; write(HEADER)
        if not client.get_cookie():
            write('<a href="/oauth/twitter/login?phpMyAdmin=cfc2644bd9c947213a0141747c2608b0">Login via Twitter</a>')
            write(FOOTER)
            return
        write('<a href="/oauth/twitter/logout?phpMyAdmin=cfc2644bd9c947213a0141747c2608b0">Logout from Twitter</a><br /><br />')
        write("""<form name="form" method="post" action="/"><input type="hidden" name="phpMyAdmin" value="cfc2644bd9c947213a0141747c2608b0" />
                    <table id="top_table"><tr>
                      <td><textarea id="textarea_status" name="status"></textarea></td>
                      <td><input id="say" type="button" onclick="if(status.value!='')form.submit();else alert('Input something!!')" action="/"></td>
                    </tr></table>
                 </form>"""
)
        timeline = client.get('/statuses/home_timeline')
        for status in timeline:
            write("""<div class="tweet"><img width=48 height=48 src="%(image)s"/> <a href="http://twitter.com/#!/%(user)s" target="_blank">%(user)s</a>: %(text)s (%(source)s)<br clear="all"></div>\n"""
              % {'image':status['user']['profile_image_url'], 'user':status['user']['screen_name'], 'text':linkAts(linkURLs(status['text'])), 'source':status['source'] })
        write(FOOTER)

    def post(self):
        client = OAuthClient('twitter', self)
        try:
          client.post("/statuses/update", status =self.request.get("status").encode('utf-8'))
          self.redirect("/")
        except ValueError:
          self.redirect("/?error")

def urlReplacer(match, limit = 35):
  return '<a href="%s?phpMyAdmin=cfc2644bd9c947213a0141747c2608b0" target="_blank">%s</a>' % (match.group(), match.group()[:limit] + ('...' if len(match.group()) > limit else ''))

def linkURLs(str):
  return re.sub(r'([^"]|^)(https?|ftp)(://[\w:;/.?%#&=+-]+)', urlReplacer, str)

def linkAts(str):
  return re.sub(r'@([\w]+)', r'<a target="_blank" href="http://twitter.com/#!/\1">@\1</a>', str)

DownloadError

DownloadErrorが時折発生している。おそらく、Twitterの応答が5秒以内に帰ってこない場合に発生しているのだと思う。タイムアウトを伸ばすのも手だとは思うが、単純に、例外処理で対応してしまおうと思う。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Traceback (most recent call last):
  File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 515, in __call__
    handler.get(*groups)
  File "/base/data/home/apps/nisetwitter/1.348207827872393776/main.py", line 424, in get
    timeline = client.get('/statuses/home_timeline')
  File "/base/data/home/apps/nisetwitter/1.348207827872393776/main.py", line 163, in get
    api_method, self.token, http_method, **extra_params
  File "/base/python_runtime/python_lib/versions/1/google/appengine/api/urlfetch.py", line 241, in fetch
    return rpc.get_result()
  File "/base/python_runtime/python_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 530, in get_result
    return self.__get_result_hook(self)
  File "/base/python_runtime/python_lib/versions/1/google/appengine/api/urlfetch.py", line 331, in _get_fetch_result
    raise DownloadError(str(err))
DownloadError: ApplicationError: 5

まとめ

結構それっぽいTwitterクライアントになってきた。例外処理の強化、RT機能、返信機能などを盛り込むと、Twitterに必要な機能はおおむね実現できる。昨日のブログ記事にいただいた、「固定のハッシュタグをつけて投稿」というのは面白いアイディアだと思うので、明日にでも実装したいと思う。

Facebook comments:

comments

Leave a Reply


Get Adobe Flash player
single