# hatena_bookmark.rb $Id$ # # usage: # <%=hatena_bookmark%> # # Copyright (c) 2005 MATSUOKA Kohei # Distributed under the GPL # require 'xmlrpc/client' require 'pstore' require 'open-uri' require 'rss/1.0' require 'kconv' class HatenaBookmark def initialize(base_url, options = {}) options[:sort] ||= 'hot' # eid|hot|count options[:threshold] ||= 5 options[:cache_file] ||= 'cache_rss.xml' options[:cache_time] ||= 60 # minutes options[:max_item] ||= 5 @items = get_items(base_url, options) end def each(&block) @items.each(&block) end private def get_items(base_url, options) items = [] hatena_open(base_url, options) do |f| rss = RSS::Parser.parse(f) comments = get_comment_count(rss.items.map {|item| item.about }) rss.items.each do |item| items.push({ :url => item.about, :title => item.title.strip.toeuc, :comment => comments[item.about] }) end end options[:max_item] > 0 ? items[0...options[:max_item]] : items end def get_comment_count(urls) # STDERR.puts 'get count' begin server = XMLRPC::Client.new('b.hatena.ne.jp', '/xmlrpc') server.call('bookmark.getCount', *urls) rescue XMLRPC::FaultException => e # STDERR.puts "Error: (#{e.faultCode}) #{e.faultString}", $@.join("\n") {} end end def hatena_open(base_url, options, &block) unless File.exist?(options[:cache_file]) && File.atime(options[:cache_file]) + options[:cache_time] * 60 > Time.now # STDERR.puts 'get RSS' rss_url = 'http://b.hatena.ne.jp/entrylist?mode=rss&url=' rss_url << URI.escape(base_url.untaint, /[^a-zA-Z._~]/n) rss_url << "&sort=#{options[:sort]}&threshold=#{options[:threshold]}" open(options[:cache_file], 'w') {|fout| open(rss_url).each {|line| fout.puts line } } end open(options[:cache_file], &block) end end def shorten(body, length = 120) matched = body.gsub(/\n/, ' ').scan(/^.{0,#{length - 2}}/)[0] $'.empty? ? matched : matched + '..' end def hatena_bookmark cache_dir = "#{@cache_path}/hatena" Dir::mkdir(cache_dir) unless File::directory?(cache_dir) cache_file = "#{cache_dir}/bookmark.dat" cache_time = 1 * 60 * 60 # 1 hour body = nil PStore.new(cache_file).transaction do |db| # STDERR.puts db['expire'] if db['body'] && db['expire'] && db['expire'] > Time.now # STDERR.puts 'use cache' body = db['body'] db.abort else bookmark = HatenaBookmark.new(@conf.base_url, {:cache_file => "#{cache_dir}/cache-rss.xml"}) body = %Q|| db['body'] = body db['expire'] = Time.now + cache_time db.commit end end body end