#!/usr/bin/env ruby require 'getoptlong' require 'pp' require 'vpim/icalendar' require 'vpim/duration' HELP =<... Shows events and todos occuring soon. By default, the calendar files from ~/Library/Calendars are used (the location of Apple's iCal calendars). Options -h,--help Print this helpful message. -n,--days N How many of the next days are considered to be "soon", default is seven. -v,--verbose Print more information about upcoming events. EOF opt_debug = nil opt_verbose = nil opt_days = 7 opts = GetoptLong.new( [ "--help", "-h", GetoptLong::NO_ARGUMENT ], [ "--days", "-n", GetoptLong::REQUIRED_ARGUMENT ], [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], [ "--debug", "-d", GetoptLong::NO_ARGUMENT ] ) opts.each do |opt, arg| case opt when "--help" then puts HELP exit 0 when "--days" then opt_days = arg.to_i when "--verbose" then opt_verbose = true when "--debug" then opt_verbose = true opt_debug = true end end if ARGV.length > 0 calendars = ARGV else calendars = Dir[ File.expand_path("~/Library/Calendars/*.ics") ] end if opt_debug pp ARGV pp calendars end SECSPERDAY = (24 * 60 * 60) t0 = Time.new.to_a t0[0] = t0[1] = t0[2] = 0 # sec,min,hour = 0 t0 = Time.local(*t0) t1 = t0 + opt_days * SECSPERDAY if opt_debug puts "to: #{t0}" puts "t1: #{t1}" end if opt_verbose puts "Events in the next #{opt_days} days:" end # Collect all events, then all todos. allEvents = [] allTodos = [] def Fu(a, b) pp a pp b end calendars.each do |file| if opt_debug; puts file; end next if File.basename(file) =~ /^x-/ cals = Vpim::Icalendar.decode(File.open(file)) cals.each do |cal| cal.events.each do |e| if opt_debug; pp e; end if e.occurs_in?(t0, t1) if e.summary allEvents.push(e) end end end allTodos.concat(cal.todos) end end def StartOfFirstOccurence(t0, t1, e) e.occurences.each_until(t1).each do |t| # An event might start before t0, but end after it..., in which case # we are still interested. if (t + (e.duration || 0)) >= t0 return t end end nil end allEvents.sort! do |lhs, rhs| StartOfFirstOccurence(t0, t1, lhs) <=> StartOfFirstOccurence(t0, t1, rhs) end allEvents.each do |e| puts "#{e.summary}:" if opt_verbose if e.description; puts " description=#{e.description}"; end if e.comment; puts " comment=#{e.comment}"; end if e.location; puts " location=#{e.location}"; end if e.status; puts " status=#{e.status}"; end if e.rrule; puts " rrule=#{e.rrule}"; end if e.dtstart; puts " dtstart=#{e.dtstart}"; end if e.duration; puts " duration=#{Vpim::Duration.new(e.duration).to_s}"; end end i = 1 e.occurences.each_until(t1).each do |t| # An event might start before t0, but end after it..., in which case # we are still interested. dstr = '' if e.duration d = e.duration dstr = " for #{Vpim::Duration.new(e.duration).to_s}" end if (t + (e.duration || 0)) >= t0 puts " ##{i} on #{t}#{dstr}" i += 1 end end end =begin def fix_priority(vtodo) p = vtodo.priority if !p p = 10 end =end allTodos.sort! do |x,y| x = x.priority y = y.priority # 0 means no priority, put these last, not first x = 10 if x == 0 y = 10 if y == 0 x <=> y end priorities = [ 'no importance', 'very important', 'very important', 'very important', 'important', 'important', 'important', 'not important', 'not important', 'not important' ] allTodos.each do |e| status = e.status || 'Todo' if status != 'COMPLETED' puts "#{status.capitalize}: #{e.summary}" # (#{priorities[e.priority]})" end end