AKB48おぼえたーというサービスを作ってみた

http://profo.jp/akb48
もうすぐ紅白だしAKB48の顔と名前を一致させたいけど面倒...というような微妙なフラストレーションを解消するためのサービス。あまり需要はない気がしてる。
作る経緯をざっくり説明すると、AKB4800てサイトがあってAKB48の画像が山のようにあったので(著作権的にはどうなのか知らないけど)選り好みした画像をTumblrに流して、溜まりに溜まった画像を使って何か出来ないか?と思ったところから。それから、いろんな媒体に移植しやすいようにAPIを作ってクライアントを作る感じでやろうと思った。

API作り

PHPを使って、typeパラメタを付けて e.g.)http://profo.jp/akb48/api?type=(img|tag) アクセスするとJSONを返してくれるようなAPIを作る。調べてみると、JSONで返すようにするには

header('Content-Type: application/json');

を書いて

$callback = htmlspecialchars($_GET['callback'], ENT_QUOTES);
if (is_array($list)) {
	print $callback . "({list:";
	print json_encode($list);
	print "})";
}

こんな感じに書いてやればいいっぽい。

α版のつくりかた

TumblrAPIが微妙で、APIを使ってAKB48のタグのついたpostを拾ってこようとしても最大50件しか拾ってこれないのでhttp://e-jigsaw.tumblr.com/tagged/AKB48/page/[1-20]のページをスクレイピングすれば全部拾える...と思ったのが大きな間違いだった。PHPのpreg_matchをフル活用して一応完成したけど、よく考えてみたら最大200件しか拾えないことに気付いた。調べてみると、画像はだいたい400枚くらい。ぜんぜん足りていない。というわけで、ボツに。
この時点でクライアント*1も実装してみたんだけど、タグとリソースを取得するのに合わせて20秒かかってしまいイマイチな感じになってしまった。

β版のつくりかた

根本的に、TumblrAPIがしっかりしていないのである程度こっちでやるしかない。というわけで、一番枚数の多い藤江れいなちゃんが38枚なので、個別にタグを指定して取得してやればnum=50に設定すれば収まる。で、

$table = array("宮崎美穂", "高橋みなみ", "高城亜樹", "佐藤亜美菜", "篠田麻里子", "小嶋陽菜", "前田敦子", "藤江れいな", "板野友美", "峯岸みなみ", "北原里英", "中田ちさと", "指原莉乃", "仁藤萌乃", "多田愛佳", "中塚智実", "仲川遥香", "仲谷明香", "田名部生来", "渡辺麻友", "柏木由紀", "平嶋夏海", "米沢瑠美", "片山陽加", "奥真奈美", "河西智美", "宮澤佐江", "近野莉菜", "佐藤夏希", "秋元才加","小野恵令奈", "小林香菜", "松原夏海", "倉持明日香", "増田有華", "梅田彩佳", "大島優子");
foreach($table as $str) {
	$xml = SimpleXML_load_file("http://e-jigsaw.tumblr.com/api/read?num=50&tagged=".$str);
	foreach($xml->posts->post as $post) array_push($list, (string)$post->tag[1]);

}

というような、PHPの鑑ともいえる微妙なコーディングになってしまった。いや、α版のコードもひどいんだけどこれは...うん。や、でもこうするしかないしさ。
で、それぞれの読み込みに20sぐらいかかるので合わせて40s待たせることに。これはなんとかせねば

クライアント作り

クライアントはJsで作っているので、スクリプトの部分だけ載せてちょっと解説だけ。

var c = 0;
$(document).ready(function() { //読み込み時に実行
	$.getJSON("http://profo.jp/akb48/api?type=tag", function(data) { //APIからタグのJSON読み込み
		$.each(data, function(i, tag) { //詳しく分からないけど、each使わないとダメっぽい
			$.getJSON("http://profo.jp/akb48/api?type=img", function(data) { //APIからリソースJSON
				$.each(data, function(i, img) {
					main(img, tag); //読み込み終わったらメイン関数へ
				});
			});
		});
	});
});

function main(img, tag) {
	var r = Math.floor(Math.random() * img.length); //乱数発生
	c++;
	$("#main").text("").append("<img src='"+img[r]+"'><br><input id='name' type='text' /><img src='a.png' id='ar' />"); //<div id="main">の中身を消して画像と入力フォーム出力
	$("#ar").click(function() { //<img id="ar">がクリックされたら
		if($("#name").val() == tag[r]) main(img, tag); //名前と入力フォームの名前が一致してたら
		else {
			c--;
			$("#main").text("")
			  .prepend("<h2>GAME OVER!!!</h2>あなたはAKB"+c+
		        "です! <a href='http://twitter.com/?status=%e3%81%82%e3%81%aa%e3%81%9f%e3%81%afAKB"+(c++)+"%e3%81%a7%e3%81%97%e3%81%9f%ef%bc%81%20http://bit.ly/5I6r07%20%23akboboet'><img src='t.png' id='tw'>結果をツイート</a><br>"+tag[r]+"ちゃんでした<br><img src='"+img[r]+"'>"); //ついったーにつぶやくリンク貼付け
		}
	});
}

うーん、やっつけ感が...

総括

  • APIなんとかしないと
  • Jsクライアントもうちょいブラッシュアップ必要?

改善案としては、
ローカルにデータを保存しておいてhttp://profo.jp/akb48/api?type=rdmみたいなリクエストしてタグとデータを1セット返す、みたいな。それだと味気ないんだけどなぁ、うぅむ。