Skip to content

Instantly share code, notes, and snippets.

@mislav
Created May 2, 2010 14:20
Show Gist options
  • Save mislav/387145 to your computer and use it in GitHub Desktop.
Save mislav/387145 to your computer and use it in GitHub Desktop.
Fetch full Atom feed from Google Reader
reader = Reader.new 'mislav.marohnic@gmail.com', PASSWORD
# fetch only unread items
feed = reader.fetch_all(FEED_URL, true) do |entry|
# something with each entry
end
puts feed
require 'curb'
require 'nokogiri'
require 'addressable/uri'
require 'addressable/template'
class Reader
LoginUrl = Addressable::URI.parse('https://www.google.com/accounts/ClientLogin')
FeedUrl = Addressable::Template.new 'https://www.google.com/reader/atom/feed/{feed}?{-join|&|n,client,ck,xt,c}'
Params = { :n => 1000, :client => 'ruby', :xt => 'user/-/state/com.google/read' }
def initialize(email, password)
@email, @password = email, password
@curl = nil
end
class Error < StandardError
attr_accessor :curl
end
def login
login_url = LoginUrl.dup
login_url.query_values = {
:Email => @email, :Passwd => @password,
:service => 'reader', :source => 'ruby',
:continue => 'http://www.google.com/'
}
curl = Curl::Easy.new(login_url)
perform_request(curl)
auth_data = curl.body_str.split("\n").inject({}) { |hash, line|
key, value = line.split('=')
hash[key] = value
hash
}
curl.encoding = 'gzip,deflate'
curl.cookies = "SID=#{auth_data['SID']};"
curl
end
def fetch_all(feed_url, unread = false, &block)
continuation = nil
timestamp = Time.now
main = nil
begin
doc = fetch(feed_url, unread, timestamp, continuation)
doc.at_xpath('//gr:continuation').tap { |el| continuation = el && el.text }
entries = doc.xpath('//xmlns:entry')
if main.nil?
main = doc
else
parent = main.at_xpath('./xmlns:feed')
entries.each { |entry| parent.add_child entry }
end
entries.each(&block) if block_given?
end while continuation
main
end
def fetch(feed_url, unread = false, timestamp = Time.now, continuation = nil)
params = Params.merge :ck => timestamp.utc.to_i, :feed => feed_url.to_s
params[:c] = continuation if continuation
params.delete(:xt) unless unread
@curl ||= login
@curl.url = FeedUrl.expand(params)
perform_request(@curl)
Nokogiri::XML @curl.body_str
end
def perform_request(curl)
curl.perform
unless curl.response_code == 200
raise Error.new("login failed").tap { |e| e.curl = curl }
end
curl
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment