at2opml.rb
#!/usr/bin/env ruby
require "open-uri"
require "csv"
require "kconv"
require "rexml/document"
$stdout.sync = true########################################
class Page
def initialize(url)
@url = url
enddef feed
hrss = hatena(@url)
return hrss if hrss
open(@url) {|f|
f.read.scan(/<link\b[^>]+>/i) {|m|
if attr(m, "rel") == "alternate" || attr(m, "type") == "application/rss+xml"
return attr(m, "href")
end
}
}
return nil
endprivate
def hatena(url)
return (url =~ %r|^(http://d.hatena.ne.jp/[^/]+)/?$|) ? $1 + "/rss" : nil
enddef attr(elem, name)
elem.slice(Regexp.new('\b' + name + '="?([^"\s]+)"?\b'), 1)
end
end########################################
class OPML
def initialize(title)
@doc = REXML::Document.new
@doc << REXML::XMLDecl.new("1.0", "UTF-8")
root = @doc.add_element("opml", "version"=>"1.0")
root.add_element("head").add_element("title").text = title
@body = root.add_element("body")
enddef add(title, url)
page = Page.new(url)
feed = page.feed
if feed
puts title + " => " + feed
attrs = {"title"=>title, "htmlUrl"=>url, "xmlUrl"=>feed, "type"=>"rss"}
@body.add_element("outline", attrs)
else
puts "warning: #{title}のフィードが見つかりませんでした"
end
enddef write(output, indent=-1, transitive=false)
@doc.write(output, indent, transitive)
enddef to_s
return @doc.to_s
end
end########################################
def get_lirs(id)
lirs = nil
begin
puts "#{id}のアンテナを開きます..."
f = open("http://a.hatena.ne.jp/#{id}/source?mode=lirs")
lirs = CSV.parse(f.read.tosjis)
ensure
f.close if f
end
return lirs
end########################################
unless ARGV.length == 1
puts "at2opml.rb はてなID"
exit
endid = ARGV[0]
filename = "antenna.xml"
lirs = get_lirs(id)
opml = OPML.new("はてなアンテナ - #{id}のアンテナ")
lirs.each {|row| opml.add(row[6], row[5])}
puts "#{filename}を書き出します..."
File.open(filename, "w") {|f|
opml.write(f, 0)
}
実行結果
~$ ./at2opml.rb winebarrel
winebarrelのアンテナを開きます...
a-sanの日記 => http://d.hatena.ne.jp/a-san/rss
chibafの日記 => http://d.hatena.ne.jp/chibaf/rss
...
antenna.xmlを書き出します...
~$