I really love RTM because of its deep integration into existing services. You can create tasks by tweeting, sending emails, sending IMs, on your Google Calendar, on your Gmail, etc. Now, to the heart of the post: RTM gives you an atom feed of your tasks via some generated URL. So we can use this and massage the data into whatever we want :D
Geektool, on the other hand, is a dandy Mac tool that lets you, among other things, run scripts and display the results on your desktop. So basically, our workflow to display RTM tasks on a Mac desktop is simple:
- Install Geektool.
- Grab your RTM tasks atom feed url. There's one for each list, I'd get one for "All Tasks".
- And setup Geektool to run the following ruby script. Done!
The only configuration you need to do for the script is change the URL and TEMP_FILE to point to your atom feed url and to a temporary file which the script will create to cache the last-fetched atom feed.
#!/usr/bin/env ruby
require 'rexml/document'
require 'open-uri'
require 'date'
URL ="YOUR_ATOM_FEED_URL_GOES_HERE"
TEMP_FILE = "ABSOLUTE_PATH_FOR_THE_CACHED_ATOM_FEED_GOES_HERE"
doc = nil
begin
doc = REXML::Document.new(open(URL).read)
rescue SocketError
File.new(TEMP_FILE).each_line { |line|
puts line
}
exit
end
tasks = {}
dates = []
REXML::XPath.each(doc, "//entry") { |node|
title = REXML::XPath.first(node, "title/text()").to_s
title = title[0..91] + "..." if title.size > 95
date = REXML::XPath.first(node, "content/div/div/span[@class='rtm_due_value']/text()").to_s
list = REXML::XPath.first(node, "content/div/div/span[@class='rtm_list_value']/text()").to_s
short_date = date
unless short_date.match(/\sat\s/).nil?
short_date = date.scan(/^(.*)\sat/).first.first
end
break if (Date.strptime(short_date, "%a %d %b %y") - Date.today).to_i > 7
break if date == "never"
if tasks[short_date].nil?
dates << short_date
tasks[short_date] = [] if tasks[short_date].nil?
end
tasks[short_date] << {
:title => title,
:list => list,
:date => date
}
}
File.open(TEMP_FILE, 'w') { |f|
dates.each { |d|
f.puts d
puts d
tasks[d].each { |val|
time = " - "
unless val[:date].match(/\sat\s/).nil?
time = val[:date].scan(/\sat\s(.+)$/).first.first.gsub(/^(\d):/,'0\1:') + " - "
end
f.puts "#{time}#{val[:title]} (#{val[:list]})"
puts "#{time}#{val[:title]} (#{val[:list]})"
}
f.puts ""
puts ""
}
f.puts "[Updated: #{Time.now.to_s}]"
puts "[Updated: #{Time.now.to_s}]"
}