‘Save This Page’ 件数表示の実装

今回の 表示機能 の実装は、

  • del.icio.us・はてブ の API をたたき、JSONP (JSON with Padding) 形式のデータを出力する Ruby スクリプト
  • JSONP 形式データを受け取り、整形・表示する JavaScript

の 2 つから構成される。実装にあたり、以下を参考にさせていただいた。

以下、個別にまとめておく。

はてなブックマーク の API をたたくスクリプト

はてなの場合、自分のブログに被ブックマーク数を表示する にあるような簡単な方法があるが、画像形式で表示され、デザインの調整がきかないことから、XML-RPC で API をたたく方法をとった。作成した getHatenaBookmarkCount.rbx の内容は以下のとおり。

#!/usr/bin/ruby -w
require 'cgi'
require 'xmlrpc/client'
require 'json/pure'

cgi = CGI.new
print cgi.header("type"=>"text/html")
end_point = 'http://b.hatena.ne.jp/xmlrpc'

url = cgi.params['url'][0] ? cgi.params['url'][0] : ""
callback = cgi.params['callback'][0] ? cgi.params['callback'][0] : nil

unless url =~ /^http:\\/\\/blog\\.shimazu\\.org\\//
	exit
end

urls = [ url ]
client = XMLRPC::Client.new2(end_point)
begin
	result = client.call('bookmark.getCount', *urls)
rescue XMLRPC::FaultException => e
	data = { 'error'=>e.faultCode, 'detailed'=>e.faultString }
	print data.to_json
	exit
end

data = [ { 'url'=>url, 'total_posts'=>result[url] } ]
if callback
	print callback ,'(', data.to_json ,')'
else
	print data.to_json
end

Ruby XMLRPC はてなブックマーク件数取得API というその名もずばりな参考資料があったので、それをベースにしている。

Ruby の json ライブラリは JSON implementation for Ruby から取得でき、rubygems でのインストールも可能。C で書かれたバージョン (json) と Pure Ruby のバージョン (json_pure) があるが、なぜか Debian GNU/Linux (Sarge) に前者 (json) がインストールできず、代わって後者 (json_pure) をインストールした。

del.icio.us の API をたたくスクリプト

del.icio.us / help / json / url にあるとおり、del.icio.us では普通に JSONP 形式の API が提供されてはいるものの、URL の指定に MD5 の暗号化が必要とのこと。Paul Johnson’s implementation of MD5 in JavaScript という凄腕ライブラリはあるものの、クライアント(ブラウザ)での処理は極力減らしたいので、MD5 処理する Ruby スクリプトをはさむかたちとした。作成した getDeliciousCount.rbx の内容は以下のとおり。

#!/usr/bin/ruby -w
require 'cgi'
require 'digest/md5'
require 'open-uri'

cgi = CGI.new
print cgi.header("type"=>"text/html")

api = 'http://badges.del.icio.us/feeds/json/url/data?hash='

url = cgi.params['url'][0] ? cgi.params['url'][0] : nil
callback = cgi.params['callback'][0] ? cgi.params['callback'][0] : nil

unless url =~ /^http:\\/\\/blog\\.shimazu\\.org\\//
	exit
end

request = api + Digest::MD5.hexdigest(url)
response = OpenURI.open_uri(request).read.chomp!

if callback
	print callback ,'(', response ,')'
else
	print response
end

出力結果

両者いずれも URL と callback 関数名 をパラメータ指定して、JSONP 形式のデータを出力するようになっている。出力例は以下のとおり(わかりやすくするため整形済み)。

例:getDeliciousCount?url=http://blog.shimazu.org/archives/95&callback=getDeliciousResponse

getDeliciousResponse([{
	"hash":"f021170bb35f553b70b7f392412babe4",
	"top_tags":{},"url":"http://blog.shimazu.org/archives/95",
	"total_posts":1
}])

例:getHatenaBookmarkCount?url=http://blog.shimazu.org/archives/89&callback=getHatenaBookmarkResponse

getHatenaBookmarkResponse([{
	"url":"http:\/\/blog.shimazu.org\/archives\/89",
	"total_posts":1
}])

なお、http://blog.shimazu.org/ で正規表現をかけているのは、http://blog.shimazu.org/ 以外のドメインでの利用を制限するため( XMLHttpRequest ではないので、クロスドメインでのアクセスが普通にできてしまうがそれを抑える目的)。

JSONP 形式データを受け取る JavaScript

データを受け取る処理を getcount.js としてまとめた。

function getDeliciousResponse(data){
if(!data||!data[0]||!data[0].total_posts){return false;}
var str = data[0].total_posts + (data[0].total_posts==1?'user':'users');
document.getElementById('delicious').innerHTML = '<a href="http://del.icio.us/url/' + data[0].hash + '">' + str + '</a>';
}
function getHatenaBookmarkResponse(data){
if(!data||!data[0]||!data[0].total_posts){return false;}
var str = data[0].total_posts + (data[0].total_posts==1?'user':'users');
document.getElementById('hatenabookmark').innerHTML = '<a href="http://b.hatena.ne.jp/entry/' + data[0].url + '">' + str + '</a>';
}
var el_delicious = document.createElement('script');
el_delicious.src = '/utils/getDeliciousCount?url=' + location.href + '&callback=getDeliciousResponse';
document.getElementsByTagName('head')[0].appendChild(el_delicious);
var el_hatena = document.createElement('script');
el_hatena.src = '/utils/getHatenaBookmarkCount?url=' + location.href + '&callback=getHatenaBookmarkResponse';
document.getElementsByTagName('head')[0].appendChild(el_hatena);

Leave a Reply