Twitterの新しいStreaming API「ChirpUserStreams」がすごすぎる件

最近発表されて、一部で話題を呼んでいるTwitterの新しいStreaming API「ChirpUserStreams」。
まだdeveloperへのpreviewリリースということでプロダクトに使うようなことはできないけど。
http://apiwiki.twitter.com/ChirpUserStreams
今までのStreaming APIでは基本的に

  • public timelineから、指定したキーワードを含む発言を拾う
  • 指定したユーザーの発言を拾う

というものだった(はず)。検索系としては便利だけど、home_timelineのように自分がフォローしているユーザーの発言をStreamingで得ようとすると全idを繋げたものをリクエストパラメータとして送らないといけなかったりで、あまりカッコよくない形になってしまっていた。
ところが今回使えるようになった「ChirpUserStreams」は、自分がフォローしているユーザーのアクティビティをStreamingで取得できるらしい。素晴らしい!
さっそくこんなのを書いてみた。

#!/usr/bin/perl
use strict;
use warnings;

use AnyEvent::HTTP 'http_request';
use Config::Pit 'pit_get';
use Encode 'encode_utf8';
use MIME::Base64 'encode_base64';

my $config = pit_get(
    "twitter.com",
    require => {
        "username" => "your username on Twitter",
        "password" => "your password on Twitter",
    }
);

my $cv = AE::cv;
http_request(
    'GET', 'http://chirpstream.twitter.com/2b/user.json',
    headers => {
        Authorization => "Basic " . encode_base64(join ':', @$config{qw/username password/}),
    },
    want_body_handle => 1,
    sub {
        my $hdl = shift;

        my $r = sub {
            my (undef, $json) = @_;
            if (my $text = $json->{text}) {
                print encode_utf8 "$json->{user}{screen_name}: $text\n";
            }
        };
        $hdl->on_read(sub { $hdl->push_read( json => $r ); });
    }
);
$cv->recv;

たったこれだけのコードで、home_timelineのように自分のfriendsの発言をStreamingで取得できる!
AnyEvent::HTTPでBASIC認証でアクセスして、want_body_handleを使用してAnyEvent::Handleオブジェクトを取得、それを使ってJSONデータを取得し続けるようにしてみた。


statuses/home_timeline REST APIとは違い、自分がフォローしているユーザーから自分がフォローしていないユーザーへのリプライなんかもここにすべて流れてくることになる。それを見る必要がない場合は一番最初にfriendsのid一覧を取得できるので、それを元にフィルタリングするのが良いかも。


そして、発言だけでなく自分のfriendsが「Retweetした」「favoriteした」「followした」といった情報もstreamingでリアルタイムに取得できる。これはマジですごい!
「誰が誰をfollowした」とか「誰が誰のどの発言をfavoriteした」なんてのは今までほとんど取ることができなかったはず。unfollowされたときは残念ながら取れないようだ。これはいずれ追加されるのかな…?


これを使えば、メール監視などをしなくてもAPI経由で瞬間フォロー返しを行うこともできるはず。
Twitter でイチイチ follow するのが面倒くさい - にぽたん研究所


というわけで、こんなのを書いてみたよ。

#!/usr/bin/perl
use strict;
use warnings;

use AnyEvent::HTTP 'http_request';
use Config::Pit 'pit_get';
use Encode 'encode_utf8';
use JSON::XS 'decode_json';
use LWP::UserAgent;
use MIME::Base64 'encode_base64';

my $config = pit_get(
    "twitter.com",
    require => {
        username => "your username on Twitter",
        password => "your password on Twitter",
    }
);

# BASIC認証に使用するヘッダ情報
my $auth_header = HTTP::Headers->new(
    Authorization => "Basic " . encode_base64(join ':', @$config{qw/username password/}),
);

# 自分自身のユーザーIDを取得
my $res = LWP::UserAgent->new(
    default_headers => $auth_header,
)->get('http://twitter.com/account/verify_credentials.json');
my $self_id = decode_json($res->content)->{id};

# Streamingからデータを得た際の挙動
my $callback = sub {
    my (undef, $json) = @_;

    my $event = $json->{event} or return;
    if ($event eq 'follow' && $json->{target}{id} == $self_id) {
        reply_with($json->{source}{id}, '@%s followありがとうございます!');
    }
    if ($event eq 'favorite' && $json->{target}{id} == $self_id) {
        reply_with($json->{source}{id}, '@%s favありがとうございます!');
    }
    if ($event eq 'retweet' &&  $json->{target}{id} == $self_id) {
        reply_with($json->{source}{id}, '@%s RTありがとうございます!');
    }
};

# Streaming APIに接続する
my $cv = AE::cv;
http_request(
    GET     => 'http://chirpstream.twitter.com/2b/user.json',
    headers => $auth_header,
    want_body_handle => 1,
    sub {
        shift->on_read(sub { shift->push_read( json => $callback ); });
    }
);
$cv->recv;

# idから相手のscreen_nameを取得してreplyする
sub reply_with {
    my ($id, $message) = @_;
    http_request(
        GET     => "http://twitter.com/users/show/$id.json",
        headers => $auth_header,
        sub {
            my $data = shift;
            my $screen_name = decode_json($data)->{screen_name};
            my $status = sprintf $message, $screen_name;
            my $uri = URI->new('http://twitter.com/statuses/update.json');
            $uri->query_form( status => $status ),

            http_request(
                POST    => $uri->as_string,
                headers => $auth_header,
                sub {},
            );
        }
    )
}

follow、favorite、RTされた瞬間に毎回お礼を言います。


まだ正式リリースでもないので仕様変更などされるかも知れないけど、大いに期待できる便利なAPIですね!