今日は、昨日作成したTwitterクライアントを改良しました。
まず最初におさらいですが、今作成しているTwitterクライアントは、GoogleAppEngine/Python環境で動作しています。OAuthでの認証を実現しており、興味をもたれた方は、自由に使っていただいて問題ありません。また、欲しい機能などがありましたら、意見頂けると中の人が喜びます。コメント大歓迎です!(自動公開にならないかもしれませんが、見つけ次第、公開します)
改良点は以下の通り
- デザインを調整
スタイルシートをつけてみました。 - 空文字列の送信を防止
何も入力していない状態での送信をJavaScriptで防止しました。 - URLのリンク
TL内のURLに自動リンクするようにしました。 - @ユーザIDのリンク
@の後ろに英数字が続く場合は、そのユーザにリンクするようにしました。 - BadValueエラーの処理
同一メッセージを2回連続で発言した際に発生していたBadValueエラーを隠しました。
スクリーンショット
スクリーンショットです。このスクリーンショットに映っているユーザは全員公開モードになっていたので、内容は伏せていません。
ソースコード
お約束のソースコードを貼り付けておきます。
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に必要な機能はおおむね実現できる。昨日のブログ記事にいただいた、「固定のハッシュタグをつけて投稿」というのは面白いアイディアだと思うので、明日にでも実装したいと思う。