require 'date' require 'astro/moon' class MoonPlugin < Plugin def help(plugin, topic="") "moon => shows the phase of the moon; moon on => announce full/new moon; moon off => don't announce full/new moon" end def initialize(*a) super @timers = Array.new self.init_timers end def init_timers now = DateTime.now ph = Astro::Moon.phasehunt add_timers(ph.moon_start, 'New', now) add_timers(ph.moon_full, 'Full', now) add_timers(ph.moon_end, 'New', now) end def add_timers(date, msg, now) [ [-12 * 3600, "Be advised, #{msg} Moon tonight!"], [-15 * 60, "Be advised, #{msg} Moon in 15 minutes!"], [0, "The Moon is #{msg} *NOW*!"], [12 * 3600, "#{msg} Moon is over (12 hours ago)"] ].each do |_| delta = ((date - now) * 86400).to_i + _[0] next if delta <= 0 @timers.push @bot.timer.add_once(delta) { self.announce(_[1]) @timers.shift or self.init_timers } end end def cleanup(*a) super @timers.each { |_| @bot.timer.remove(_) } end def announce(msg) @registry['clients'].each_key { |c| @bot.say(c, msg) } end def p2s(p) case p when 0.00 .. 0.01 'New (%.2f%%)' when 0.24 .. 0.26 'First Quarter (%.2f%%)' when 0.49 .. 0.51 'Full (%.2f%%)' when 0.74 .. 0.76 'Last Quarter (%.2f%%)' when 0.99 .. 1.0 'New (%.2f%%)' when 0.0 .. 0.25 'Waxing Crescent (%.2f%% Full)' when 0.25 .. 0.5 'Waxing Gibbous (%.2f%% Full)' when 0.5 .. 0.75 'Waning Gibbous (%.2f%% Full)' else 'Waning Crescent (%.2f%% Full)' end end def human_delta(dt) d = dt - DateTime.now return '' if d < -1 || d > 1 d = (d * 86400).to_i return "(*NOW*!)" if d > -60 && d < 60 fmt = " \002(in %s)\002" if d < 0 d = -d fmt = " \002(%s ago)\002" end s = Time.at(d).utc.strftime(' %Hh %Mm %Ss') s.gsub!(/ 0/, ' ') s.gsub!(/ 0./, '') s.sub!(/^ /, '') fmt % s end def moon(m, params) begin p = Astro::Moon.phase ph = Astro::Moon.phasehunt s = ("moon age is %.1f, the moon is " + p2s(p.phase)) % [p.age, p.illumination * 100] s << ". last new moon: #{ph.moon_start.strftime('%b %d %Y, %H:%M')}" s << human_delta(ph.moon_start) s << ", full moon: #{ph.moon_full.strftime('%b %d %Y, %H:%M')}" s << human_delta(ph.moon_full) s << ", next new moon: #{ph.moon_end.strftime('%b %d %Y, %H:%M')}" s << human_delta(ph.moon_end) m.reply s rescue Exception => e m.reply "error: #{e.message}" error e.backtrace.join("\n") end end def moon_on(m, params) on = nil target = m.private? ? m.sourcenick : m.channel.to_s clients = @registry['clients'] || Hash.new if params[:on] =~ /^(on|yes|true)$/i on = true clients[target] = true elsif params[:on] =~ /^(off|no|false)$/i on = false clients.delete(target) else on = clients[target] m.reply "should be 'on' or 'off' (#{on ? 'on' : 'off'} for #{target})" return end @registry['clients'] = clients m.reply "moon phases will#{on ? '' : ' not'} be announced to #{target}" end end plugin = MoonPlugin.new plugin.map 'moon' plugin.map 'moon :on', :action => 'moon_on'