Created
January 20, 2015 08:32
-
-
Save mdusher/9828d12fe652a00e5694 to your computer and use it in GitHub Desktop.
Crappy Weather plugin for toast (cinch bot)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env ruby | |
# | |
# Forecasts ftp://ftp2.bom.gov.au/anon/gen/fwo/IDA00001.dat | |
# | |
# | |
require 'cinch' | |
require 'nokogiri' | |
require 'open-uri' | |
require 'cgi' | |
require 'json' | |
require 'yaml' | |
module Cinch::Plugins | |
class MultiWeather2 | |
include Cinch::Plugin | |
match /^w\s(.*)/i | |
match /^w$/i, method: :execute | |
match /^fc$/i, method: :forecast | |
match /^fc\s(.*)$/i, method: :forecast | |
match /^7fc\s(.*)$/i, method: :forecast7day | |
match /^7fc$/i, method: :forecast7day | |
match /^setw$/i, method: :get_pref | |
match /^setw\s(.*)/i, method: :set_pref | |
def initialize(*) | |
super | |
@yaml = "/home/services/toast/prefs/openWeather.yaml" | |
@prefs = Hash.new | |
if File.exist?(@yaml) | |
@prefs = YAML.load_file(@yaml) | |
end | |
end | |
def execute(m, query=nil) | |
if (query.nil?) | |
query = @prefs[m.user.name] || nil | |
end | |
if (query) | |
m.reply weather(query) | |
end | |
end | |
def set_pref(m, query) | |
@prefs[m.user.name] = query | |
File.open(@yaml,'w') { |p| p.write YAML.dump(@prefs) } | |
m.user.send "Set weather preference for %s to: %s" % [m.user.name, query] | |
end | |
def get_pref(m) | |
m.user.send "Weather preference for %s is set to: %s" % [m.user.name, @prefs[m.user.name] || ""] | |
end | |
def weather(query) | |
case query | |
when /northam$/i then agricwa() #rescue openWeather("Northam, WA") | |
else openWeather(query) | |
end | |
end | |
def openWeatherCoords(query) | |
url = "http://api.openweathermap.org/data/2.5/weather?units=metric&mode=json&q=%s" % CGI.escape(query) | |
jsondata = JSON.load(open(url)) rescue nil | |
if (jsondata.nil?) | |
return nil | |
elsif (jsondata["cod"] == "404") | |
return nil | |
else | |
w = { | |
coords: "%s,%s" % [jsondata["coord"]["lat"],jsondata["coord"]["lon"]], | |
name: "%s" % jsondata["name"], | |
country: "%s" % [jsondata["sys"]["country"]] | |
} | |
end | |
end | |
def openWeather(query) | |
url = "http://api.openweathermap.org/data/2.5/weather?units=metric&mode=json&q=%s" % CGI.escape(query) | |
jsondata = JSON.load(open(url)) rescue nil | |
if (jsondata["cod"] == "404") | |
return "Unable to find co-ordinates for %s" % query | |
else | |
ow = { | |
name: "%s %s" % [jsondata["name"],jsondata["sys"]["country"]], | |
coords: "%s,%s" % [jsondata["coord"]["lat"],jsondata["coord"]["lon"]], | |
temp: "%s" % jsondata["main"]["temp"], | |
humidity: "%s" % jsondata["main"]["humidity"], | |
wind: "%sm/s" % jsondata["wind"]["speed"], | |
source: "OpenWeatherMap" | |
} | |
bw = bom ow[:coords] | |
if (!bw.nil?) | |
ow = bw | |
"%s: %s (feels %s) %s | humidity: %s | wind: %s %s [%s/%s]" % [ow[:station], ow[:temp], ow[:feels], ow[:summary], ow[:humidity], ow[:windspeed], ow[:winddirection], ow[:source], ow[:update]] | |
elsif (ow.nil?) | |
"Unable to find weather for %s" % [query] | |
else | |
"%s: %sC | humidity: %s | wind: %s [%s]" % [ow[:name],ow[:temp],ow[:humidity],ow[:wind],ow[:source]] | |
end | |
end | |
end | |
def checkText(obj,ret="N/A") | |
data = obj.respond_to?(:text) ? obj.text.strip : ret | |
if (!obj.nil?) | |
if data.include?("\u00B0".encode('utf-8')) && (data =~ /\d+\.\d+.$/) | |
data+"C" | |
else | |
data | |
end | |
end | |
end | |
def bom(query) | |
base = "http://www.bom.gov.au" | |
url = "/places/search/?q=%s" % CGI.escape(query) | |
nope = nil | |
w = Nokogiri::HTML(open(base+url)) rescue nil | |
if (!w.nil?) | |
obs = Nokogiri::HTML(open(base+w.at_css("ul.menu li.obs a").attr("href")), nil, "UTF-8") rescue nil | |
if (!obs.nil?) | |
fc = Nokogiri::HTML(open(base+w.at_css("ul.menu li.forecast a").attr("href")), nil, "UTF-8") rescue nil | |
if (!fc.nil?) | |
ow = { | |
temp: checkText(obs.at_css("div.obs-summary p")).gsub(/Current Temperature/,"").gsub(/ /,"").strip, | |
feels: checkText(obs.css("table.summary tr td")[1]).gsub(/ /,""), | |
humidity: checkText(obs.css("table.summary tr td")[0]), | |
winddirection: checkText(obs.css("table.wind tr td")[0]), | |
windspeed: checkText(obs.css("table.wind tr td")[1]).gsub(/\d+\sknot./,"").strip, | |
station: checkText(w.at_css("p.station-name a")), | |
summary: checkText(w.at_css("dl.forecast-summary dd.summary")), | |
update: checkText(w.at_css("div#summaries div.wrapper ul li.summary h3")).strip.split.last, | |
source: "BOM" | |
} | |
if (ow[:temp] == "N/A") | |
return nil | |
else | |
return ow | |
end | |
else | |
nope = 1 | |
end | |
else | |
nope = 3 | |
end | |
else | |
nope = 2 | |
end | |
if (!nope.nil?) | |
return nil | |
end | |
end | |
def agricwa | |
url = "https://www.agric.wa.gov.au/apex/edw/f?p=102:22:::::P22_STATION_CODE,P22_STATION_NAME:NO,Northam" | |
page = Nokogiri::HTML(openrh(url)) || "" | |
if (page.nil?) | |
openWeather("Northam, WA") | |
else | |
ow = {} | |
ow[:station] = "Northam, WA" | |
ow[:source] = "AgricWA" | |
rows = page.css("tr.highlight-row") | |
rows.each do |r| | |
key = r.css("td")[0].text | |
value = r.css("td")[1].text | |
if (key =~ /Air Temp/i) | |
ow[:temp] = value || "N/A" | |
elsif (key =~ /Feels Like/i) | |
ow[:feels] = value || "N/A" | |
elsif (key =~ /Humidity/i) | |
ow[:humidity] = value || "N/A" | |
elsif (key =~ /Rain from 9am/i) | |
ow[:rain] = value || "N/A" | |
elsif (key =~ /Wind @ 3m$/i) | |
ow[:wind] = value || "N/A" | |
elsif (key =~ /Last update/i) | |
ow[:update] = value || "N/A" | |
end | |
end | |
"%s: %s (feels like %s) | humidity: %s | wind: %s | rain: %s [%s - %s]" % [ow[:station],ow[:temp],ow[:feels],ow[:humidity],ow[:wind],ow[:rain],ow[:source],ow[:update]] | |
end | |
end | |
def forecast(m, query=nil) | |
if (query.nil?) | |
query = @prefs[m.user.name] || nil | |
end | |
if (query) | |
m.reply bomForecast(query) | |
else | |
m.reply "You need to set or provide a location (setw <location>|w <location>)" | |
end | |
end | |
def bomForecast(query) | |
l = openWeatherCoords(query) | |
nope = nil | |
if (!l[:coords].nil?) | |
base = "http://www.bom.gov.au" | |
url = "/places/search/?q=%s" % l[:coords] | |
w = Nokogiri::HTML(open(base+url), nil, "UTF-8") rescue nil | |
if (!w.nil?) | |
fc = Nokogiri::HTML(open(base+w.at_css("ul.menu li.forecast a").attr("href")), nil, "UTF-8") rescue nil | |
if (!fc.nil?) | |
fcday = fc.at_css("div.day") | |
ow = { | |
name: checkText(w.css("ul.breadcrumbs li").last).gsub(/Forecast/,"").gsub(/ Weather/,""), | |
fchead: checkText(fcday.at_css("h2"), nil).gsub(/Forecast for the rest of /,"").strip.split.first, | |
fcsumm: checkText(fcday.at_css("p"), nil), | |
fcmin: checkText(fcday.at_css("div.forecast dl dd.min"),nil), | |
fcmax: checkText(fcday.at_css("div.forecast dl dd.max"),nil) | |
} | |
if (ow[:name].include?("\u00B0".encode('utf-8'))) | |
ow[:name] = checkText(fc.at_css("div.day div.forecast h3")).gsub(/ area/,"") | |
end | |
if (!ow[:fcmin].nil? && !ow[:fcmax].nil?) | |
fcminmax = "(%s-%s) " % [ow[:fcmin].split[0], ow[:fcmax].gsub(/ /,"")] | |
elsif (ow[:fcmin].nil? && !ow[:fcmax].nil?) | |
fcminmax = "(Max: %s) " % [ow[:fcmax].gsub(/ /,"")] | |
else | |
fcminmax = "" | |
end | |
return "%s Forecast for %s: %s%s" % [ow[:name], ow[:fchead], fcminmax, ow[:fcsumm]] | |
else | |
nope = 1 | |
end | |
else | |
nope = 2 | |
end | |
else | |
nope = 3 | |
end | |
if (!nope.nil?) | |
return "Unable to retrieve forecast for %s (%s)" % [query, l[:coords] || "N/A"] | |
end | |
end | |
def forecast7day(m, query=nil) | |
if (query.nil?) | |
query = @prefs[m.user.name] || nil | |
end | |
if (query) | |
m.reply openForecast7day(query) | |
else | |
m.reply "You need to set or provide a location (setw <location>|w <location>)" | |
end | |
end | |
def openForecast7day(query) | |
url = "http://api.openweathermap.org/data/2.5/forecast/daily?units=metric&mode=json&cnt=7&q=%s" % CGI.escape(query) | |
jsondata = JSON.load(open(url)) rescue nil | |
if (jsondata["cod"] == "404") | |
return "Unable to find 7 day forecast data for \"%s\"" % query | |
else | |
msg = "%s, %s Forecast " % [jsondata["city"]["name"],jsondata["city"]["country"]] | |
days = jsondata["list"] | |
days.each do |d| | |
msg += "| %s %s-%sC %s " % [Time.at(d["dt"]).strftime("%a"), d["temp"]["min"].to_i, d["temp"]["max"].to_i, d["weather"].first["description"].capitalize] | |
end | |
b = bomForecast7day(jsondata["city"]["name"]) | |
if (b.include?("|")) | |
return "#{jsondata["city"]["name"]} Forecast "+b+" [BOM]" | |
else | |
return msg+" [OpenWeather]" | |
end | |
end | |
end | |
def bomForecast7day(query) | |
nope = nil | |
bomurl = "http://m.bom.gov.au" | |
url = bomurl+"/search/?q=%s" % CGI.escape(query) | |
w = Nokogiri::HTML(open(url),nil, "UTF-8") rescue nil | |
if (!w.nil?) | |
if (w.at_css("section.results") && w.at_css("section.results ul a")) | |
w = Nokogiri::HTML(open(bomurl+w.at_css("section.results ul a")[:href]), nil, "UTF-8") | |
end | |
if (!w.nil?) | |
fc = "" | |
w.css("div.forecast-day").each do |d| | |
fc += "| %s %s-%s %s " % [ d.at_css("div.text h3").text, | |
checkText(d.at_css("div.low")).gsub(/Min/,""), | |
checkText(d.at_css("div.high")).gsub(/Max/,""), | |
(!checkText(d.at_css("div.text p")).include?("Rainfall") ? checkText(d.at_css("div.text p")) : "") ] | |
end | |
return fc | |
else | |
nope = 1 | |
end | |
else | |
nope = 1 | |
end | |
if (!nope.nil?) | |
return "Unable to find 7 day forecast for %s" % query | |
end | |
end | |
def openrh(url) | |
begin | |
data = open(url, redirect: false, "Cookie" => ($cookie || "")) | |
rescue OpenURI::HTTPRedirect => e | |
$cookie = e.io.meta["set-cookie"] | |
data = open(url, "Cookie" => $cookie,) | |
end | |
data | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment