天然パーマです。

Facebookのポスト内容をWebアプリケーションとして実行する

元★ネタ

前書き

またまた、なんだかよく分からないと思われる記事のタイトルだと思うけど、間違ってはいないと思う。 miyagawaさんがTwitterのツイート内容をPerlスクリプトとして実行するっていう変態的クールなことを やっていたのですよってのは前回の記事のおさらい。

Perlコードを書いたツイートのURLを(ちょっと編集して)-e の引数に渡すとそれが実行出来ちゃう。

perl -Mtwitter -e http://m.twitter.com/yusukebe/status/279638603611664384

でも、Twitterは140文字まで。どうしてもそれを超えるコードをなんとなくどこかに張ってから実行するという 誰得 なことをしたくなったのでFacebookで似たようなことが出来ないか考えてみた。

やること

Facebookの場合、ポストの内容を取得するのにOAuth認証が必要になるので、ならば!いっそのこと Webアプリにしてしまえばいい。Facebookの投稿がそのままWebアプリとして実行されてブラウザで確認が出来る という具合だ。フローはこうなる。

  1. コードをFacebookに投稿
  2. これから紹介するfacebook.pmをロードしつつポストのURLを引数で指定する
  3. サーバが立ち上がるので「http://localhost:5000/」とかにアクセスする
  4. OAuth認証ダイアログが開くので許可する
  5. コールバックされるとFacebookの投稿が実行されて標準出力部分がページに描画される

facebook.pm

とりあえず以下のfacebook.pmを用意する。

package facebook;
use Plack::Request;
use Plack::Response;
use Plack::Runner;
use Plack::App::URLMap;
use URI::Escape;
use LWP::Simple;
use JSON;
use HTML::Entities;
use Encode;

my $id;
use overload "/" => sub { $id = $_[1]; $_[0] }, fallback => 1;

sub import {
    my $pkg = caller;
    *{"$pkg\::com"} = *{"$pkg\::posts"} = sub() { bless {}, __PACKAGE__ };
}

my $app_id     = $ENV{RUNFB_APP_ID};
my $app_secret = $ENV{RUNFB_APP_SECRET};

my $app_redirect = sub {
    my $req          = Plack::Request->new(shift);
    my $uri          = uri_escape_utf8( $req->base . 'callback' );
    my $redirect_url = "http://www.facebook.com/dialog/oauth?"
      . "client_id=$app_id&redirect_uri=$uri&scope=read_stream";
    my $res = Plack::Response->new(302);
    $res->redirect($redirect_url);
    return $res->finalize;
};

my $app_callback = sub {
    my $req       = Plack::Request->new(shift);
    my $code      = $req->param('code');
    my $uri       = uri_escape_utf8( $req->base );
    my $token_url = "https://graph.facebook.com/oauth/access_token?"
      . "client_id=$app_id&redirect_uri=$uri&client_secret=$app_secret&code=$code";
    my $access_token = get($token_url);
    my $json         = get("https://graph.facebook.com/$id?$access_token");

    my $data    = decode_json($json);
    my $message = $data->{message};
    my $result;
    {
        local *STDOUT;
        open STDOUT, '>', \$result;
        eval $message;
    }
    my $res = Plack::Response->new(200);
    $res->content_type('text/html');
    $res->body( encode_utf8($result) );
    return $res->finalize;
};

END {
    my $urlmap = Plack::App::URLMap->new;
    $urlmap->map( '/'         => $app_redirect );
    $urlmap->map( '/callback' => $app_callback );
    my $app    = $urlmap->to_app;
    my $runner = Plack::Runner->new;
    $runner->parse_options(@ARGV);
    $runner->run($app);
}

gistにも上げておきました。

ああ、そういえば実行するにはFacebookアプリの登録が必要なんで、ソレをアレしたら

RUNFB_APP_ID
RUNFB_APP_SECRET

を環境変数に設定しておくとよいでしょう。

やってみる

例えば、こんなポストをしたとします。

スクリーンショット 2012-12-15 11.16.49.png

内容はこういう簡単な出力するコード。

my $message = 'Good Morning!!';
print "<big>$message</big>";

で、こいつのパーマリンクURLが「https://www.facebook.com/yusuke.wada/posts/10151373772205030」なのを 覚えておく。上記のfacebook.pmをある場所に置いたら、URLを少しいじって「-e」の引数にして実行してみましょう!

$ perl -Mfacebook -e https://m.facebook.com/yusuke.wada/posts/10151373772205030

すると、Webアプリケーションが立ち上がるので、デフォルトでは「http://localhost:5000/」にブラウザがからアクセス!認証画面に飛んで、最終的には...

スクリーンショット 2012-12-15 11.21.38.png

Facebookポストが実行され、標準出力部分がページで見れるはずです! これで、アイドルの水着をひたすら表示するスクリプトをFacebookにポストしたらすぐ、Webアプリになりますね!

まとめ

作ってて楽しかったのですが、誰得感満載ですね。 これも例によってむやみに危険なポストを実行しないように気をつけましょう!