#!/usr/bin/env ruby

# Version 1.1
# Usage: lj2ics [birthdays.bml] > LJbirthdays.ics

# birthdays.bml has to be a local file; in your web browser, while 
# logged in to LJ, go to http://www.livejournal.com/birthdays.bml 
# and save it as an html document. You can get rid of it once you 
# have the ics file in hand. 

require 'rubygems'
require 'icalendar'
require 'date'
require 'hpricot' 


class Birthday
	def initialize(user, name, month, day)
		@user = user
		@name = name
		@month = month
		@day = day
	end

	def to_s()
		return "#{@user} (#{@name}) was born on #{@month} #{@day}."
	end
	
	def to_event(cal)
		# Okay, I think this is a better solution! The name of the 
		# destination calendar object must be sent as an argument to to_event.
		
		event = cal.event
		event.timestamp = DateTime.now
		event.summary = "(⚲)#{@user}'s birthday"
		event.description = "(⚲)#{@user} (#{@name})'s birthday"
		event.url = "http://#{@user}.livejournal.com/profile"
		
		# You'll note that we don't bother with the birth year. That's
		# 'cause doing that would require recursively following every
		# user back to their profile and scraping the year out of it,
		# which, since many people hide profile info from non-friends,
		# I can't figure out how to automate. (Anyone know how to log
		# in and retrieve subsequent LJ pages from within a ruby
		# script? This is also why birthdays.bml has to be locally
		# saved, if you're keeping track at home.) And then we'd have
		# to sanitize the year because some folk will inevitably enter
		# something perverse there.

		# Besides: I figure leaving the date out is only a bug for
		# under-25-ers. For anyone older than my own cohort, this
		# sucker's a killer feature!

		event.start = Date.parse("#{@month} #{@day.to_s}, 2008")
		event.end = Date.parse("#{@month} #{@day.to_s}, 2008").next
		event.recurrence_rules = ["FREQ=YEARLY"]
	end
end

$cal = Icalendar::Calendar.new
$birthdays = []
$bdayfile = ARGV.first

# --------------

bdaydoc = open($bdayfile) { |f| Hpricot(f) }

# Construct an array of Birthday objects from the source file:

bdaydoc.search("div#content-wrapper h2").each do |header|
	birthmonth = header.inner_text
	header.next_sibling.search(">b").each do |key|
		day = key.inner_text
		user = key.next_node.next_node.attributes['lj:user']
		name = key.next_node.next_node.next_node.to_s[/ - (.+)/, 1]
		$birthdays << Birthday.new(user, name, birthmonth, day)
	end
end

$birthdays.each do |bd|
	bd.to_event($cal)
end

puts $cal.to_ical


