#---------------------------------------------------------------------#
# incith:weather $Rev:: 107 $ #
# $Id:: incith-weather.tcl 107 2009-02-12 01:28:44Z incith $ #
# #
# retrieves weather and forecast data from www.wunderground.com #
# tested on Eggdrop v1.6.19 & Windrop v1.6.17 #
# #
# Usage: #
# .chanset #channel +weather #
# !weather #
# returns the current conditions #
# !forecast #
# returns a 3-5day forecast (depends on data) #
# !sky #
# returns the astronomy data (sun/moonrise, daylight, etc) #
# !time #
# returns the time and date #
# #
# Forum Support: #
# http://forum.egghelp.org/viewtopic.php?t=10466 #
# #
# ChangeLog (m/d/y): #
# 1/17/09: license changed to GPLv3. tweaks for svn. added !time. #
# #
# TODO: #
# - locales for output (languages) #
# + fix multiple results, take best match, etc #
# + user defaults (so we can just !weather) #
# - separate proc for forecast fetching, to speed up results #
# - theoretically :) #
# - forecast updated time #
# - merge _handlers, allow all %var% in all _formats, max_results #
# - limit size of output, check length of variables? #
# - Suggestions/Thanks/Bugs/Ideas, e-mail at bottom of header. #
# #
# LICENSE (GPLv3): #
# This program is free software: you can redistribute it and/or #
# modify it under the terms of the GNU General Public License as #
# published by the Free Software Foundation, either version 3 of #
# the License, or (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# See the GNU General Public License for more details. #
# (http://www.gnu.org/licenses/gpl-3.0.txt) #
# #
# Copyright (C) 2009, Jordan #
# http://incith.com ~ incith@gmail.com ~ irc.freenode.net/#incith #
#---------------------------------------------------------------------#
package require http 2.3
setudef flag weather
# 0 (zero) will disable an optional variable, 1 or above enables
#
namespace eval incith {
namespace eval weather {
# the bind prefix/command char ("!" or ".", etc)
variable command_char "!"
# binds ("one two three") as many as you need, "" to disable one
variable weather_binds "w weather"
variable forecast_binds "f fc forecast"
variable astronomy_binds "sky astronomy"
variable time_binds "time"
# if you want to change the order or remove some items that are sent
# w0 - location, w1 - updated, w2 - conditions, w3 - temperature, w4 - windchill
# w5 - high/low, w6 - humidity, w7 - dew point, w8 - UV index, w9 - pressure
# w10 - wind
variable weather_format "%w0% %w1% %w2% %w3% %w4% %w5% %w8% %w6% %w7% %w9% %w10%"
# some control over the forecast format, too
# f0 - location, f1 - updated, f2 - first day high/low, f3 - second day high/low
# f4 - third day, f5 - fourth day, f6 - fifth day
variable forecast_format "%f0% %f1% %f2% %f3% %f4% %f5% %f6%"
# show latitude and longitude for locations?
variable show_lat_lon 1
# symbol to put beside temperature numbers
variable degree_symbol "°"
# display celsius temperatures first, and fahrenheit in ()
variable celsius_first 0
# allow binds to be used in /msg's to the bot?
variable private_messages 1
# send public/channel replies to the user instead of to the channel?
variable public_to_private 0
# send replies as notices instead of messages?
variable notices 0
variable notice_errors_only 0
# this will be used to separate items (Foo; Bar; Baz)
# setting this to "\n" will have *everything* on a new line
variable separator "; "
# use this if you would only like to break results into 3 new lines
variable separate_lines 0
# convert update time into 24-hour time
variable 24hour_time 0
# make use of bolding where appropriate?
variable bold 1
# the maximum length a line sent should be
variable split_length "440"
# if you're using a proxy, enter it here (proxy.example.com:3128)
variable proxy ""
# how long (in seconds) before the http request times out?
variable timeout 15
# number of minute(s) to ignore flooders, 0 to disable flood protection
variable ignore 1
# how many requests in how many seconds is considered flooding?
# by default, this allows 3 queries in 10 seconds, the 4th being ignored
# and ignoring requests for 'variable ignore' minutes
variable flood 4:10
}
}
# script begings
namespace eval incith::weather {
variable version "incith:weather-SVN"
variable debug 0
# language testing
variable language en
if {[file exists "scripts/lang/incith-weather-${incith::weather::language}.txt"]} {
putlog " - Reading language file"
source scripts/lang/incith-weather-${incith::weather::language}.txt
} elseif {[file exists "${incith::weather::language}"]} {
# specifying a direct path to the language file
putlog " - Reading language file"
source ${incith::weather::language}
} else {
putlog " - Language '${incith::weather::language}' not found, defaulting to English."
namespace eval incith::weather::lang {
variable temperature "Temperature_default"
}
}
}
# bind the binds
if {${incith::weather::weather_binds} != ""} {
foreach bind [split ${incith::weather::weather_binds} " "] {
# public message binds
bind pub -|- "${incith::weather::command_char}${bind}" incith::weather::weather_handler
# private message binds
if {${incith::weather::private_messages} >= 1} {
bind msg -|- "${incith::weather::command_char}${bind}" incith::weather::weather_handler
}
} }
if {${incith::weather::forecast_binds} != ""} {
foreach bind [split ${incith::weather::forecast_binds} " "] {
# public message binds
bind pub -|- "${incith::weather::command_char}${bind}" incith::weather::forecast_handler
# private message binds
if {${incith::weather::private_messages} >= 1} {
bind msg -|- "${incith::weather::command_char}${bind}" incith::weather::forecast_handler
}
} }
if {${incith::weather::astronomy_binds} != ""} {
foreach bind [split ${incith::weather::astronomy_binds} " "] {
# public message binds
bind pub -|- "${incith::weather::command_char}${bind}" incith::weather::astronomy_handler
# private message binds
if {${incith::weather::private_messages} >= 1} {
bind msg -|- "${incith::weather::command_char}${bind}" incith::weather::astronomy_handler
}
} }
if {${incith::weather::time_binds} != ""} {
foreach bind [split ${incith::weather::time_binds} " "] {
# public message binds
bind pub -|- "${incith::weather::command_char}${bind}" incith::weather::time_handler
# private message binds
if {${incith::weather::private_messages} >= 1} {
bind msg -|- "${incith::weather::command_char}${bind}" incith::weather::time_handler
}
} }
namespace eval incith {
namespace eval weather {
# [custom_format] : converts a string to the desired output
#
proc custom_format {htmla type input} {
array set html $htmla
# for separate line results option
if {${incith::weather::separate_lines} >= 1} {
set alternate_sep "\n"
} else {
set alternate_sep ${incith::weather::separator}
}
# spaces make things look wrong
regsub -all {\s+} $input {} input
if {$type == "weather"} {
if {[info exists html(location)]} {
if {[info exists html(latitude)] && [info exists html(longitude)] && $incith::weather::show_lat_lon >= 1} {
set input [string map "{%w0%} {${incith::weather::separator}[ibold $html(location)] ($html(latitude)\/$html(longitude))}" $input]
} else {
set input [string map "{%w0%} {${incith::weather::separator}[ibold $html(location)]}" $input]
}
} else {
set input [string map "{%w0%} {}" $input]
}
if {[info exists html(update_time)] && [info exists html(update_date)]} {
set input [string map "{%w1%} {${incith::weather::separator}[ibold "Updated:"] $html(update_time) $html(update_timezone) ($html(update_date))}" $input]
} else {
set input [string map "{%w1%} {}" $input]
}
if {[info exists html(conditions)] && [string length $html(conditions)] >= 1} {
set input [string map "{%w2%} {${incith::weather::separator}[ibold "Conditions:"] $html(conditions)}" $input]
} else {
set input [string map "{%w2%} {}" $input]
}
if {[info exists html(tempf)] && [info exists html(tempc)]} {
set input [string map "{%w3%} {${alternate_sep}[ibold "Temperature:"] [i2fac $html(tempf) $html(tempc)]}" $input]
} else {
set input [string map "{%w3%} {}" $input]
}
if {[info exists html(windchillf)] && [info exists html(windchillc)]} {
set input [string map "{%w4%} {${incith::weather::separator}[ibold "Windchill:"] [i2fac $html(windchillf) $html(windchillc)]}" $input]
} else {
set input [string map "{%w4%} {}" $input]
}
# compare the date the weather was updated to output todays high/low
if {([info exists html(fc1d)]) && $html(fc1d) == $html(todays_day)} {
set input [string map "%w5% {${incith::weather::separator}[ibold "High/Low:"] [if2c $html(fc1hf) $html(fc1lf)]}" $input]
} elseif {([info exists html(fc2d)]) && $html(fc2d) == $html(todays_day)} {
set input [string map "%w5% {${incith::weather::separator}[ibold "High/Low:"] [if2c $html(fc2hf) $html(fc2lf)]}" $input]
} elseif {([info exists html(fc3d)]) && $html(fc3d) == $html(todays_day)} {
set input [string map "%w5% {${incith::weather::separator}[ibold "High/Low:"] [if2c $html(fc3hf) $html(fc3lf)]}" $input]
} elseif {([info exists html(fc4d)]) && $html(fc4d) == $html(todays_day)} {
set input [string map "%w5% {${incith::weather::separator}[ibold "High/Low:"] [if2c $html(fc4hf) $html(fc4lf)]}" $input]
} elseif {([info exists html(fc5d)]) && $html(fc5d) == $html(todays_day)} {
set input [string map "%w5% {${incith::weather::separator}[ibold "High/Low:"] [if2c $html(fc5hf) $html(fc5lf)]}" $input]
} else {
set input [string map "%w5% {${incith::weather::separator}[ibold "High/Low:"] Unavailable}" $input]
}
if {[info exists html(humidity)]} {
set input [string map "{%w6%} {${incith::weather::separator}[ibold "Humidity:"] $html(humidity)%}" $input]
} else {
set input [string map "{%w6%} {}" $input]
}
if {[info exists html(dewf)] && [info exists html(dewc)]} {
set input [string map "{%w7%} {${alternate_sep}[ibold "Dew Point:"] [i2fac $html(dewf) $html(dewc)]}" $input]
} else {
set input [string map "{%w7%} {}" $input]
}
if {[info exists html(uv_min)] && [info exists html(uv_max)]} {
set input [string map "{%w8%} {${incith::weather::separator}[ibold "UV:"] $html(uv_min)\/$html(uv_max)}" $input]
} else {
set input [string map "{%w8%} {}" $input]
}
if {[info exists html(pressure_hpa)] && [info exists html(pressure_in)]} {
set input [string map "{%w9%} {${incith::weather::separator}[ibold "Pressure:"] ${html(pressure_in)} in\/${html(pressure_hpa)} hPa}" $input]
} else {
set input [string map "{%w9%} {}" $input]
}
if {[info exists html(windd)]} {
set temp_wind "${incith::weather::separator}[ibold "Wind:"] $html(windd)"
if {[info exists html(windm)] && [info exists html(windk)]} {
if {${incith::weather::celsius_first} >= 1} {
append temp_wind " at $html(windk) KPH ($html(windm) MPH)"
} else {
append temp_wind " at $html(windm) MPH ($html(windk) KPH)"
}
}
set input [string map "{%w10%} {${temp_wind}}" $input]
} else {
set input [string map "{%w10%} {}" $input]
}
regsub -- "^\\s*${incith::weather::separator}" $input {} input
return $input
} elseif {$type == "forecast"} {
if {[info exists html(location)]} {
set input [string map "{%f0%} {${incith::weather::separator}[ibold "$html(location) Forecast"] (High/Low)}" $input]
} else {
set input [string map "{%f0%} {}" $input]
}
if {[info exists html(update_time)] && [info exists html(update_date)]} {
set input [string map "{%f1%} {${incith::weather::separator}[ibold "Updated:"] $html(update_time) $html(update_timezone) ($html(update_date))}" $input]
} else {
set input [string map "{%f1%} {}" $input]
}
# prepend the chance of precipitation if necessary
if {[info exists html(fc1chance)]} {
set html(fc1c) "$html(fc1chance) $html(fc1c)"
}
if {[info exists html(fc2chance)]} {
set html(fc2c) "$html(fc2chance) $html(fc2c)"
}
if {[info exists html(fc3chance)]} {
set html(fc3c) "$html(fc3chance) $html(fc3c)"
}
if {[info exists html(fc4chance)]} {
set html(fc4c) "$html(fc4chance) $html(fc4c)"
}
if {[info exists html(fc5chance)]} {
set html(fc5c) "$html(fc5chance) $html(fc5c)"
}
if {[info exists html(fc1hf)] && [info exists html(fc1lf)] && [info exists html(fc1c)]} {
set input [string map "{%f2%} {${incith::weather::separator}[ibold "$html(fc1d):"] $html(fc1c), [if2c $html(fc1hf) $html(fc1lf)]}" $input]
} else {
set input [string map "{%f2%} {}" $input]
}
if {[info exists html(fc2hf)] && [info exists html(fc2lf)] && [info exists html(fc2c)]} {
set input [string map "{%f3%} {${alternate_sep}[ibold "$html(fc2d):"] $html(fc2c), [if2c $html(fc2hf) $html(fc2lf)]}" $input]
} else {
set input [string map "{%f3%} {}" $input]
}
if {[info exists html(fc3hf)] && [info exists html(fc3lf)] && [info exists html(fc3c)]} {
set input [string map "{%f4%} {${incith::weather::separator}[ibold "$html(fc3d):"] $html(fc3c), [if2c $html(fc3hf) $html(fc3lf)]}" $input]
} else {
set input [string map "{%f4%} {}" $input]
}
if {[info exists html(fc4hf)] && [info exists html(fc4lf)] && [info exists html(fc4c)]} {
set input [string map "{%f5%} {${incith::weather::separator}[ibold "$html(fc4d):"] $html(fc4c), [if2c $html(fc4hf) $html(fc4lf)]}" $input]
} else {
set input [string map "{%f5%} {}" $input]
}
if {[info exists html(fc5hf)] && [info exists html(fc5lf)] && [info exists html(fc5c)]} {
set input [string map "{%f6%} {${incith::weather::separator}[ibold "$html(fc5d):"] $html(fc5c), [if2c $html(fc5hf) $html(fc5lf)]}" $input]
} else {
set input [string map "{%f6%} {}" $input]
}
regsub -- "^\\s*${incith::weather::separator}" $input {} input
return $input
} else {
return 0
}
}
# [weather_handler] : handles public & private messages for !weather
#
proc weather_handler {nick uhand hand args} {
global lastbind
if {[llength $args] >= 2} { # public message
if {${incith::weather::public_to_private} >= 1} {
set where $nick
} else {
set where [lindex $args 0]
if {[lsearch -exact [channel info $where] +weather] == -1} {
return
}
}
set chan [lindex $args 0]
set input [lindex $args 1]
} else { # private message
if {${incith::weather::private_messages} <= 0} {
return
}
set where $nick
set chan "private"
set input [lindex $args 0]
}
# flood protection
if {[flood $nick $uhand $hand $where]} {
return
}
# user defaults, user must exist as a user on the bot
if {[lindex $input 0] == "-set"} {
if {[validuser $hand]} {
setuser $hand XTRA incith:weather.location "[lrange $input 1 end]"
send_output $nick "Default weather location set to [lrange $input 1 end]"
return
} else {
send_output $nick "Sorry, your bot handle was not found. Unable to set a default."
return
}
set input [lrange $input 1 end]
} elseif {[regexp -- "^\\s*$" $input] && [validuser $hand]} {
set input [getuser $hand XTRA incith:weather.location]
}
# log it
putlog "${incith::weather::version}: <${nick}/${chan}> ${lastbind} $input"
# no input given
if {[regexp -- "^\\s*$" $input]} {
send_output $where "Please visit http://www.wunderground.com for more details on searching methods."
return
}
# fetch the html
array set html [fetch_html $input]
# check for html's existence
if {[info exists html(error)]} {
send_output $where $html(error)
return
}
# for separate line results option
if {${incith::weather::separate_lines} >= 1} {
set alternate_sep "\n"
} else {
set alternate_sep ${incith::weather::separator}
}
# make sure we have data to send, and send it
set reply [custom_format [array get html] "weather" $incith::weather::weather_format]
if {$reply == "0" || [string length $reply] >= 750} { unset reply }
if {[info exists reply]} {
send_output $where $reply
} else {
send_output $where "There was a problem while attempting to parse the data."
}
}
# [forecast_handler] : handles forecast requests
#
proc forecast_handler {nick uhand hand args} {
global lastbind
if {[llength $args] >= 2} { # public message
if {${incith::weather::public_to_private} >= 1} {
set where $nick
} else {
set where [lindex $args 0]
if {[lsearch -exact [channel info $where] +weather] == -1} {
return
}
}
set chan [lindex $args 0]
set input [lindex $args 1]
} else { # private message
if {${incith::weather::private_messages} <= 0} {
return
}
set where $nick
set chan "private"
set input [lindex $args 0]
}
# flood protection
if {[flood $nick $uhand $hand $where]} {
return
}
# user defaults, user must exist as a user on the bot
if {[lindex $input 0] == "-set"} {
if {[validuser $hand]} {
setuser $hand XTRA incith:weather.location "[lrange $input 1 end]"
send_output $nick "Default weather location set to [lrange $input 1 end]."
return
} else {
send_output $nick "Sorry, your bot handle was not found. Unable to set a default."
}
set input [lrange $input 1 end]
} elseif {[regexp -- "^\\s*$" $input] && [validuser $hand]} {
set input [getuser $hand XTRA incith:weather.location]
}
# log it
putlog "${incith::weather::version}: <${nick}/${chan}> ${lastbind} $input"
# no input given
if {[regexp -- "^\\s*$" $input]} {
send_output $where "Please visit http://www.wunderground.com for more details on searching methods."
return
}
# fetch the html
array set html [fetch_html $input]
# check for html's existence
if {[info exists html(error)]} {
send_output $where $html(error)
return
}
# for separate line results option
if {${incith::weather::separate_lines} >= 1} {
set alternate_sep "\n"
} else {
set alternate_sep ${incith::weather::separator}
}
# make sure we have data to send, and send it
set reply [custom_format [array get html] "forecast" $incith::weather::forecast_format]
if {$reply == "0" || [string length $reply] >= 750} { unset reply }
if {[info exists reply]} {
send_output $where $reply
} else {
send_output $where "There was a problem while attempting to parse the data."
}
}
# [astronomy_handler] : handles public & private messages for !sky
#
proc astronomy_handler {nick uhand hand args} {
global lastbind
if {[llength $args] >= 2} { # public message
if {${incith::weather::public_to_private} >= 1} {
set where $nick
} else {
set where [lindex $args 0]
if {[lsearch -exact [channel info $where] +weather] == -1} {
return
}
}
set chan [lindex $args 0]
set input [lindex $args 1]
} else { # private message
set where $nick
set chan "private"
set input [lindex $args 0]
if {${incith::weather::private_messages} <= 0} {
return
}
}
# flood protection
if {[flood $nick $uhand $hand $where]} {
return
}
# user defaults, user must exist as a user on the bot
if {[lindex $input 0] == "-set"} {
if {[validuser $hand]} {
setuser $hand XTRA incith:weather.location "[lrange $input 1 end]"
send_output $nick "Default weather location set to [lrange $input 1 end]."
return
} else {
send_output $nick "Sorry, your bot handle was not found. Unable to set a default."
return
}
set input [lrange $input 1 end]
} elseif {[regexp -- "^\\s*$" $input] && [validuser $hand]} {
set input [getuser $hand XTRA incith:weather.location]
}
# log it
putlog "${incith::weather::version}: <${nick}/${chan}> ${lastbind} $input"
# no input given
if {[regexp -- "^\\s*$" $input]} {
send_output $where "Please visit http://www.wunderground.com for more details on searching methods."
return
}
# fetch the html
array set html [fetch_html $input]
# check for html's existence
if {[info exists html(error)]} {
send_output $where $html(error)
return
}
# for separate line results option
if {${incith::weather::separate_lines} >= 1} {
set alternate_sep "\n"
} else {
set alternate_sep ${incith::weather::separator}
}
# make sure we have data to send, and send it
if {[info exists html(location)]} {
set reply "[ibold "$html(location) Astronomy"]"
if {[info exists html(sun_rise)] && [info exists html(sun_set)]} {
append reply "${incith::weather::separator}[ibold "Sunrise:"] $html(sun_rise)${incith::weather::separator}[ibold "Sunset:"] $html(sun_set)"
}
if {[info exists html(moon_rise)] && [info exists html(moon_set)]} {
if {[info exists html(moon_phase)] && [info exists html(moon_percent)]} {
append reply "${incith::weather::separator}[ibold "Moon:"] $html(moon_phase) ($html(moon_percent))"
}
append reply "${incith::weather::separator}[ibold "Moonrise:"] $html(moon_rise)"
append reply "${incith::weather::separator}[ibold "Moonset:"] $html(moon_set)"
}
if {[info exists html(length_light)]} {
append reply "${incith::weather::separator}[ibold "Visible Light:"] $html(length_light)"
}
if {[info exists html(length_day)]} {
append reply "${incith::weather::separator}[ibold "Daylight Length:"] $html(length_day)"
}
if {[info exists html(length_tomorrow)]} {
append reply "${incith::weather::separator}[ibold "Tomorrow:"] $html(length_tomorrow)"
}
send_output $where $reply
} else {
send_output $where "There was a problem while attempting to parse the data."
}
}
# [time_handler] : handles public & private messages for !time
#
proc time_handler {nick uhand hand args} {
global lastbind
if {[llength $args] >= 2} { # public message
if {${incith::weather::public_to_private} >= 1} {
set where $nick
} else {
set where [lindex $args 0]
if {[lsearch -exact [channel info $where] +weather] == -1} {
return
}
}
set chan [lindex $args 0]
set input [lindex $args 1]
} else { # private message
if {${incith::weather::private_messages} <= 0} {
return
}
set where $nick
set chan "private"
set input [lindex $args 0]
}
# flood protection
if {[flood $nick $uhand $hand $where]} {
return
}
# user defaults, user must exist as a user on the bot
if {[lindex $input 0] == "-set"} {
if {[validuser $hand]} {
setuser $hand XTRA incith:weather.location "[lrange $input 1 end]"
send_output $nick "Default weather location set to [lrange $input 1 end]"
return
} else {
send_output $nick "Sorry, your bot handle was not found. Unable to set a default."
return
}
set input [lrange $input 1 end]
} elseif {[regexp -- "^\\s*$" $input] && [validuser $hand]} {
set input [getuser $hand XTRA incith:weather.location]
}
# log it
putlog "${incith::weather::version}: <${nick}/${chan}> ${lastbind} $input"
# no input given
if {[regexp -- "^\\s*$" $input]} {
send_output $where "Please visit http://www.wunderground.com for more details on searching methods."
return
}
# fetch the html
array set html [fetch_html $input]
# check for html's existence
if {[info exists html(error)]} {
send_output $where $html(error)
return
}
# for separate line results option
if {${incith::weather::separate_lines} >= 1} {
set alternate_sep "\n"
} else {
set alternate_sep ${incith::weather::separator}
}
# make sure we have data to send, and send it
set reply ""
if {[info exists html(location)]} {
set reply "[ibold "$html(location)"]"
if {[info exists html(local_time)] && [info exists html(local_timezone)]} {
append reply "${incith::weather::separator}[ibold "Time:"] $html(local_time) $html(local_timezone)"
}
if {![info exists html(local_date)] && [info exists html(update_date)]} { set html(local_date) $html(update_date) }
if {![info exists html(local_date)] && ![info exists html(update_date)] && [info exists html(fupdate_date)]} { set html(local_date) $html(fupdate_date) }
if {[info exists html(local_date)]} {
append reply "${incith::weather::separator}[ibold "Date:"] $html(local_date)"
}
}
if {$reply != ""} {
send_output $where $reply
} else {
send_output $where "There was a problem while attempting to parse the data."
}
}
# [fetch_html] : fetches and returns a list of usable data
#
proc fetch_html {query {query_url "http://www.wunderground.com/cgi-bin/findweather/getForecast?query="} {no_format 0}} {
set multiple_results 0
# store the website we are retrieving
set output(query) $query
if {$no_format != 1} {
set output(query) [::http::formatQuery $query]
set output(query) [string trimleft $output(query) "+"]
}
# setup proxy information, if any
if {[string match {*:*} ${incith::weather::proxy}] == 1} {
set proxy_info [split ${incith::weather::proxy} ":"]
}
# the "browser" we are using
set ua "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7e"
if {[info exists proxy_info] == 1} {
set http [::http::config -useragent $ua -proxyhost [lindex $proxy_info 0] -proxyport [lindex $proxy_info 1]]
} else {
set http [::http::config -useragent $ua]
}
# retrieve the html; round()'ed because -timeout likes integers. [catch] for error messages
catch {set http [::http::geturl "${query_url}$output(query)" -headers {Cookie "Units=both"} -timeout [expr round(1000 * ${incith::weather::timeout})]]} output(status)
# make sure the http request succeeded
if {![string match {::http::*} $output(status)]} {
set output(error) "Failed to connect."
} elseif {[::http::status $http] == "timeout"} {
set output(error) "The operation timed out after ${incith::weather::timeout} seconds."
} elseif {[::http::status $http] != "ok"} {
set output(error) "The server could not complete our request (server error)."
}
# in case we're erroring out, close the socket and report why
if {[info exists output(error)]} {
::http::cleanup $http
return [array get output]
}
# $html will contain our html source code
set html [::http::data $http]
# we no longer require the connection
::http::cleanup $http
# debug: output the html to a file
if {${incith::weather::debug} >= 1} {
set fopen [open incith-weather-pre.txt w]
puts $fopen $html
close $fopen
}
if {[regexp {Search Results} $html] || [regexp {Scroll down to view a list of all all cities} $html]} {
set multiple_results 1
}
# html cleanups
regsub -all {\n} $html {} html
regsub -all {\t} $html {} html
regsub -all { } $html { } html
regsub -all {°} $html {} html
regsub -all {>} $html {>} html
regsub -all {<} $html {<} html
regsub -all {
.*?
} $html {} html
regsub -all {
} $html {} html
# debug: output the html to a file
if {${incith::weather::debug} >= 1} {
set fopen [open incith-weather-post.txt w]
puts $fopen $html
close $fopen
}
# check for problems
set multiple 0
if {[regexp {City Not Found
} $html]} {
set output(error) "The requested city was not found."
} elseif {[regexp {Redirect page
There is nothing} $html] || [regexp {Choose the first letter of a city or search for any location.} $html] || [regexp {
Europe
Choose a Country
} $html] || [regexp {
Australia
Select a country or Australian province below.
} $html] || [regexp {
Africa
Choose a Country
} $html]} {
set multiple_results 0
set output(error) "Please refine your search."
} elseif {$multiple_results == 1} {
# todo: store bad results too in case duplicate results both have no data
# e.g., first bad result put to bad_list, second matching bad result put to good list
set i 1; set multiple 2; set num_results 0
set loop_reply ""; set loop_loc ""; set loop_url ""
# skip down a bit in the html
regsub -- {.*?Search Results} $html {} html
regsub -- {.*?Scroll down to view a list of all all cities} $html {} html
# this regexp removes locations with no data
foreach {- row} [regexp -inline -all -- {
(.+?)
} $html] {
if {[string match "*
*" $row]} {
regsub -all -- $row $html {} html
}
}
while {$i <= 1} {
# grab a search result
regexp -- {
Tomorrow will be (.+?)} $html - output(length_light) output(length_day) output(length_tomorrow)
regexp -- {
(.+?)\, (\d+\%) of the Moon is Illuminated
} $html - output(moon_phase) output(moon_percent)
# some locations have spaces, some don't
if {[info exists output(moon_rise)] && [info exists output(moon_set)]} {
set output(moon_rise) [string trim $output(moon_rise)]
set output(moon_set) [string trim $output(moon_set)]
}
# forecast
# skip down to the actual forecast data
regsub -- {.*?5-Day Forecast} $html {} html
# fixes for % chance of precipitation
regsub -all -- {Chance of T-storms} $html {Chance of Thunderstorms} html
regsub -all -- {Chance of a Thunderstorm} $html {Chance of Thunderstorms} html
regsub -all -- {T-storms} $html {Chance of Thunderstorms} html
regsub -all -- {alt="Thunderstorm"} $html {alt="Chance of Thunderstorms"} html
set fc_regexp_day {
(.+?) at (.+?) mph / (.+?) km/h} $html - foutput(windd) foutput(windm) foutput(windk)
# forecast
# todo: update to grab 1 by 1
regexp -- {Forecast as of (.+?) on (.+?)\ ?} $html - foutput(fupdate_time) foutput(fupdate_date)
# the Night-named days get removed, to parse the non-Night days easier
regsub -all {
(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday) Night } $html {} html
if {$incith::weather::debug >= 1} {
putlog "in mobile, fc1hf = $foutput(fc1hf)\nfc1chance = $foutput(fc1chance)\n"
}
if {![info exists foutput(fc1d)] || ![info exists foutput(fc1hf)]} {
if {$incith::weather::debug >= 1} {
putlog "fetching forecast in mobile"
}
set fc_regexp_day {