Automated Google Reader Backups
I spend a lot of time in my RSS Reeder (see what I did there?). I still find Google Reader to be the best and easiest way to manage my subscriptions, although I've been wanting to switch to Fever for a while.
One thing I wanted to do when I launched my new site (the one you're reading) was to have a downloadable up to date export of my Google Reader OPML file (which of course I never did). I looked around for good ways to automate this and I found a simple Python script to do it with (sorry I couldn't find it again for this post). I decided to rewrite it in Ruby and set it up on my server as an automated cron job.
To run the script I came up with use something like:
ruby path/to/googleReaderOPML.rb username@gmail.com SekretPassword
To add it to your crontab (to run every Sunday at 1:01am) use something like:
1 1 * * 7 ruby path/to/googleReaderOPML.rb username@gmail.com SekretPassword
#!/usr/bin/env ruby
#
# => This script will authorize your Google credentials and download your Google Reader subscriptions
# => Usage: ./googleReaderOPML.rb GOOGLEUSERNAME PASSWORD
#
# The required networking shenanigans
require 'uri'
require 'net/http'
require 'open-uri'
require 'rubygems'
# This requires the 'colorize' gem. Install with '[sudo] gem install colorize'
require 'colorize'
# The base Google URLs for callback, authentication, and subscription export
$GOOGLE_URL = "http://www.google.com"
$LOGIN_URL = "https://www.google.com/accounts/ClientLogin"
$READER_URL = "http://www.google.com/reader/subscriptions/export"
# The user agent string, for some reason this is required, feel free to change it
$SOURCE = "keith.so"
# The default output filename, it is automatically overwritten if one already exists
$FILE_NAME = "googlereadersubscriptions.opml"
# Make sure there is the correct number of arguments
if ARGV.count != 2
# Print the instruction
puts "Usage: ./#{ File.basename(__FILE__) } USERNAME PASSWORD".red
exit
end
# Build the request URL
uri = URI.parse($LOGIN_URL)
# Setup the Parameters
params = { Email: ARGV.first, Passwd: ARGV.last, service: "reader", source: $SOURCE, continue: $GOOGLE_URL }
# Add the user-agent string, my website (feel free to replace it) to the headers
headers = { "User-agent" => $SOURCE }
# Encode the parameters into the url
uri.query = URI.encode_www_form(params)
# Create a new NET:HTTP object with the request URL
http = Net::HTTP.new(uri.host, uri.port)
# Require HTTPS without this net/http will not be happy with you
http.use_ssl = true
# Execute the request
request = Net::HTTP::Get.new(uri.request_uri, headers)
# Get the data from the request
response = http.request(request)
# Check for valid response code, should ONLY be 200
if response.code != '200'
puts "Google returned #{ response.code }, check your username and password".red
exit
end
# split each token into a different item then load them each into a hash with the key as the token key
auth_hash = Hash.new
response.body.split(/\n/).each do |token|
split_array = token.split('=')
auth_hash[split_array.first.downcase] = split_array.last
end
# Create a header hash for the request of the XML file
headers = { "user-agent" => $SOURCE, "cookie" => "Name=SID;SID=#{ auth_hash['sid'] };Domain=.google.com;Path=/;Expires=160000000000", "authorization" => "GoogleLogin auth=#{ auth_hash['auth'] }" }
# Open the URL for the Google Reader export with the setup headers
request = open($READER_URL, headers)
# Open the received XML feeds file
google_reader_file = File.open(request, 'r')
# Read the entire feeds file into 'subscriptions'
subscriptions = google_reader_file.read
# Close the downloaded file
google_reader_file.close()
# Open a new file with the global filename to write to, overwrite it if it exists
subscriptions_file = File.open($FILE_NAME, 'w')
# Verify the file was created
if File.exists?(subscriptions_file)
# Write the subscriptions to the file and close it
subscriptions_file.write(subscriptions)
subscriptions_file.close()
# Display a success message
puts "Wrote Google Reader subscriptions to #{ $FILE_NAME }".green
else
# If the file wasn't created print an error
puts "Couldn't write to #{ $FILE_NAME } (the process running this script may not have sufficient privileges".red
end