2011/06/05

Twitterのお気に入りをランダムに表示して楽しむ



指定したTwitterユーザーのお気に入り(favorite)からランダムに1つ選んで表示するGaucheスクリプトです。

9LISPで作っているquotuneというWebサービス(現在のところ公開していません)の一部としてcgiを書いたのですが、shellからも使えるようにしました。私は
alias fav='/hoge/fuga/favorite.scm'
というようにして使っています。自分がふぁぼったものから見るのも他人のふぁぼりを見るのも結構面白いです。

実は以前、twitter botとして運用していたのですが、いつの間にか動かなくなって放置していました。この際これに置き換えようかと思います。

shell

適当なところに保存して以下のように呼び出します。
./favorite twitter-user-id
例えば
./favorite valvallow

cgi

cgiが動くところに保存して以下のようにアクセスします。
http://example.com/favorite/twitter-user-id

json

twitterのapiから返ってくるjsonをそのまま返すこともできます。
./favorite -j twitter-user-id
http://example.com/favorite/twitter-user-id/json

code

Gauche 0.9.1、CentOS/Cygwinで動作確認しています。
#!/usr/local/bin/gosh
(use srfi-19) ; date
(use srfi-43) ; vector
(use rfc.822) ; rfc822-date->date
(use rfc.http) ; http-get
(use rfc.json) ; parse-json-string
(use util.list) ; assoc-ref
(use util.list) ; intersperse
(use math.mt-random) ; <mersenne-twister>, mt-random-integer
(use gauche.parseopt) ; let-args
(define (usage)
(print "usage:")
(print " - shell : favorite [-j|json] <twitter-id>")
(print " - cgi : http://example.com/favorite/twitter-id"))
(define *twitter-api-server* "api.twitter.com")
(define rand
(let1 m (make <mersenne-twister> :seed (sys-time))
(^n (mt-random-integer m n))))
;; http://valvallow.blogspot.com/2011/02/query-string.html
(define (query-compose query)
(string-join (map (cut string-join <> "=") query) "&"))
(define (twitter-api-get server url params)
(receive (status header body)
(http-get server
(string-append url "." "json"
"?" (query-compose params)))
(rlet1 r (parse-json-string body)
(when (and (not (vector? r))
(string=? "error" (caar r)))
(raise "user not found."))
)))
(define (twitter-api-user-show id)
(twitter-api-get *twitter-api-server*
"/1/users/show" `(("id" ,id))))
(define (twitter-api-random-favorite-page-number id)
(let* ((total-fav-count (assoc-ref (twitter-api-user-show id)
"favourites_count"))
(pages (quotient total-fav-count 20)))
(rand (+ pages 1)))) ;; favorite page index started 1;
(define (twitter-api-favorites id :optional (page 1))
(twitter-api-get *twitter-api-server*
"/1/favorites"
`(("id" ,id)("page" ,(x->string page)))))
(define (twitter-api-random-favorite id)
(let ((favs (twitter-api-favorites
id (twitter-api-random-favorite-page-number id))))
(when (equal? favs #())
(raise #`",id has no favorite."))
(vector-ref favs (rand (vector-length favs)))))
(define (twitter-date->date str)
(define (list-join delim ls)
(apply string-append (intersperse delim ls)))
(let* ((ls (string-split str " "))
(date-string (list-join " " (map (pa$ list-ref ls)
'(0 2 1 5 3 4)))))
(rfc822-date->date date-string)))
(define (print-favorite fav)
(define (twitter-date-format str)
(date->string (twitter-date->date str) "~Y/~m/~d ~H:~M:~S"))
(let* ((fav-id (assoc-ref fav "id"))
(text (assoc-ref fav "text"))
(user (assoc-ref fav "user"))
(screen-name (assoc-ref user "screen_name"))
(name (assoc-ref user "name"))
(retweets (assoc-ref fav "retweet_count"))
(created (assoc-ref fav "created_at")))
(let ((fav-url (format "http://twitter.com/~a/status/~a"
screen-name fav-id)))
(print #`"id : ,name (@,screen-name)")
(print #`"url : ,fav-url")
(print #`"date : ,(twitter-date-format created)")
(print #`"retweet count : ,retweets")
(print text))))
(define (path-info->alist str keys)
(and str (map cons keys (cdr (string-split str "/")))))
(define (print-random-favorite id)
(guard (e (else (print e)))
(print-favorite (twitter-api-random-favorite id))))
(define (cgi-main)
(let* ((path-info (path-info->alist (sys-getenv "PATH_INFO")
'(user-id format)))
(user-id (and path-info (assoc-ref path-info 'user-id)))
(format (and path-info (assoc-ref path-info 'format)))
(type (if (and format (string=? "json" format))
"application/json"
"text/plain"))
(header #`"Content-Type: ,type; charset=UTF-8"))
(print header)
(newline)
(if path-info
(if (and format (string=? "json" format))
(print (construct-json-string (twitter-api-random-favorite user-id)))
(print-random-favorite user-id))
(usage))))
(define (main args)
(if (null? (cdr args))
(if (sys-getenv "HTTP_HOST")
(cgi-main)
(usage))
(let-args (cdr args)
((json "j|json")
. rest)
(if json
(print (construct-json-string (twitter-api-random-favorite (car rest))))
(print-random-favorite (car rest))))))


追記

こっちが新しいソース
Scheme手習い

0 件のコメント:

コメントを投稿