| Current Path : /home/mudbot/eggdrop/ |
| Current File : //home/mudbot/eggdrop/wunderweather.tcl |
###############################################################
## WunderWeather version 5.03 04/12/2017 ##
## Original Script by (lily@disorg.net) ##
## Version 5.0+ updates by SpiKe^^ www.mytclscripts.com ##
## ##
## -> NEW IN VERSION 5.03 <- ##
## - Users can now set/save their default weather location. ##
## example: !w set miami, fl ##
## To use that saved weather location, just type: !w ##
## Does Not use the Eggdrop user file (saves to a file) ##
## - Added metric conversion of most forecast strings. ##
## - Script now allows multiple public weather triggers. ##
## ##
################## - Version 5.0+ History - ###################
## VERSION 5.01 - 28/10/2017 ##
## - All processes and globals are now in a namespace ##
## - Replaced weather forecast (removed by Kiely Allen) ##
## - Replaced metric setting (removed by Kiely &/or David) ##
## - Added 3 new settings for removing colors and/or bolds ##
## - Added Throttle Users - Thanks to user & speechles ##
###############################################################
# Lilys Simple Weather (lily@disorg.net)
# International Weather script for Eggdrop.
# Displays in both F/C and MPH/KPH
# Will return weather from www.wunderground.com
# Requires TCL8.0 or greater
# Has been tested on Eggdrop 1.8.0 and 1.6.21
# You must ".chanset #channel +weather" for each chan
# you wish to use this in.
# Usage: !w <input>
# Input can be <zip> <city, st> <city, country> <airport code> <pws>
# To use PWS: !w pws:yourwundergroundpws
# VERSION 4.0 - output string rewrite
# VERSION 4.2 - http::cleanup, agent string update
# VERSION 4.3 - Single tag change in mobile.wunderground source
# (first in 4-ish years).
# VERSION 4.4 - fixed no windm var bug.
# VERSION 4.5 - Single tag change in mobile.wunderground source
# for forecast.
# VERSION 4.6 - Made default scale configurable
# VERSION 4.6+ - Edits/Updates by Kiely Allen and David Moore
# Edited Feb 01, 2014 - Kiely Allen:
# - Removed Forecast (may tidy up output later and add it again)
# - Added Barometer/Pressure (Rising & Falling)
# - Added Windchill & Fixed Output Tidyness
# Edited Feb 04, 2014 - David Moore:
# - Color Changing Temperature & Aliases
# - Don't Show Windchill If There Is None
# Edited Feb 09, 2014 - Kiely Allen/David Moore
# - Added Wind Gust, Cleaned Up Code, Fixed Multiple Choices Bug
# Edited Feb 10, 2014 - David Moore
# - Don't show windchill if $windcf/$windcc is <0.5F than $tempf
# Wind would often be 'calm' and windchill would show 0.1-0.5F±
# Edited Feb 13, 2014 - Kiely Allen/David Moore
# - Remove metric related config checks, all output includes
# both imperial and metric.
# - Don't show windchill if windchill is higher than $tempf,
# windchills under 1F of $tempf are insignificant
# Edited Feb 14, 2014 - Kiely Allen
# - Removed custom !ws as it didn't work as exoected,
# (need to fix missing $windgm error)
# Edited Jun 12, 2014 - Kiely Allen
# - Fixed $color extending to all text after $tempf with \003
# VERSION 4.7 - Edits/Updates made by SpiKe^^ - Oct 12, 2017
# Fixed two display issues with "Wind: ...gusting to..."
# - Added code to hide wind gusting string if have none.
# ( hides this: gusting to 0.0MPH (0.0KPH) )
# - Fixed a color-code issue in the display string used
# when showing "Wind: ...gusting to..."
####################################################################
package require http
setudef flag weather
namespace eval wunder {
variable cmds
##########################################################
## -- Begin Script Settings -- Begin Script Settings -- ##
##########################################################
# Command Char(s) to use for public binds
# Examples: "!" or "."
# Or a Space Separated List: "! . ?"
variable cmdchars "! ."
# Set public Weather Command(s) #
set cmds(wz) "w weather"
# Set route/filename for the users default weather locations #
variable userfile "scripts/wunderweather.users"
# Use Metric as the Primary in channel output?? #
# 1 = Yes, use metric as primary output. (0=no) #
variable metric 0
# Use Color Changing Temperatures?? (1=yes 0=no) #
variable colortemp 1
# Use the WunderWeather Logo Color?? (1=yes 0=no)#
variable colorlogo 1
# Show Weather Item Names in Bold?? (1=yes 0=no) #
variable boldnames 1
# amount user can issue before throttle
variable throttle_max 2
# throttle time (seconds)
variable throttle_time 30
#########################################################
## --- End Script Settings --- End Script Settings --- ##
#########################################################
variable ver "5.03"
variable name "WunderWeather"
proc pub_wz {nk uh hn ch tx} { pub_w $nk $uh $hn $ch $tx wz }
proc pub_w {nk uh hn ch input cmd} {
if {![channel get $ch weather]} { return 0 }
if {[::wunder::throttle $uh $nk $ch]} { return 0 }
set input [split [string trim $input]]
lassign [split [string trim $uh ~] @] user host
set id [string tolower "$nk,$user,$ch"]
variable wusers
if {[info exists wusers($id)]} { set wusers(updated) 1
set wusers($id) [lreplace $wusers($id) 0 0 [unixtime]]
set udata $wusers($id)
} else { set udata "" }
if {![llength $input] && $udata eq ""} {
puthelp "PRIVMSG $ch :You must provide a city or zip code or set a default location"
return 0
}
set opt [string tolower [lindex $input 0]] ; set isset 0
if {$opt in {set -set}} { set isset 1
set input [lrange $input 1 end]
if {![llength $input]} {
if {$udata eq ""} {
puthelp "PRIVMSG $ch :You must provide a city or zip code to set as default location"
} else { unset wusers($id)
puthelp "PRIVMSG $ch :Removed all custom settings for $nk"
}
return 0
}
} elseif {![llength $input]} { set input [lindex $udata 1] }
set agent "Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
set query "http://mobile.wunderground.com/cgi-bin/findweather/getForecast?brand=mobile&query="
append query [join $input "+"]
set input [join $input]
set http [::http::config -useragent $agent]
set http [::http::geturl $query]
set html [::http::data $http] ; ::http::cleanup $http
#set open [open source.html w] ;puts $open $html ;close $open
regsub -all "\n" $html "" html
regexp {City Not Found} $html - nf
if {[info exists nf]} {
puthelp "PRIVMSG $ch :$input Not Found"
return 0
}
# // Checks if there are multiple choices for the city eg. "detroit" which has 6 entries
regexp {Place: Temperature} $html - mc
if {[info exists mc]} {
puthelp "PRIVMSG $ch :There are multiple choices for $input on wunderground.com. Try adding state, country, province, etc"
return 0
}
regexp {Observed at<b>(.*)</b> </td} $html - loc
if {![info exists loc]} {
puthelp "PRIVMSG $ch :Conditions not available for $input (try adding state, country, province, etc)"
return 0
}
if {$isset==1} { set wusers(updated) 1
puthelp "PRIVMSG $ch :Set default weather query string to: $input"
set wusers($id) [list [unixtime] [split $input]]
return 0
}
regexp {Updated: <b>(.*?) on} $html - updated
regsub -all "\<.*?\>" $updated "" updated
regexp {Updated: <b>(.*?)Visibility</td} $html - data
regexp {Temperature</td>.*?<b>(.*?)</b>°F.*?<b>(.*?)</b>} $data - tempf tempc
if {![info exists tempf]} {
puthelp "PRIVMSG $ch :Weather for $loc is currently not available"
return 0
}
regexp {Conditions</td><td><b>(.*?)</b></td>} $data - cond
if {![info exists cond]} { set cond "Unknown" }
# // Wind Gust in MPH and KMH
regexp {Wind Gust</td>.*?<b>(.*?)</b> mph.*?<b>(.*?)</b>} $data - windgm windgk
# // Wind Chill in MPH and KMH
regexp {Windchill</td>.*?<b>(.*?)</b>°F.*?<b>(.*?)</b>} $data - windcf windcc
# // Pressure in inches and hPa
regexp {Pressure</td>.*?<b>(.*?)</b> in.*?<b>(.*?)</b>.*?<b>(.*?)</b>} $data - presi presh rifa
# // Humidity Percentage
regexp {Humidity</td><td><b>(.*?)</b>} $data - hum
# // Dew Point
# regexp {Dew Point</td>.*?<b>(.*?)</b>°F.*?<b>(.*?)</b>} $data - dewf dewc
#\002Dew Point:\002 ${dewf}F (${dewc}C)#
if {![info exists windgm]} { set windgm "0.0" }
if {![info exists windgk]} { set windgk "0.0" }
# // Wind Direction, Wind Speed.
regexp {Wind</td><td><b>(.*?)</b>.*?<b>(.*?)</b> mph.*?<b>(.*?)</b>} $data - windd windm windk
if {![info exists windm]} { set windm "0" }
if {$windm==0} {
set windout "Calm"
} else {
if {$::wunder::metric==1} { set windout "$windd @ ${windk}KPH (${windm}MPH)"
} else { set windout "$windd @ ${windm}MPH (${windk}KPH)" }
# hide wind gust if have none #
if {$windgm > $windm} {
if {$::wunder::metric==1} {
append windout " gusting to ${windgk}KPH (${windgm}MPH)"
} else { append windout " gusting to ${windgm}MPH (${windgk}KPH)" }
}
}
# // Build current weather string.
if {$::wunder::boldnames==0} { set b "" } else { set b "\002" }
if {$::wunder::colorlogo==0} { set logo "" ; set endl ""
} else { set logo "\00313" ; set endl "\003" }
set putthis ""
append putthis "${b}Temperature:$b[::wunder::color $tempf $tempc]"
if {$::wunder::metric==1} { append putthis " (${tempf}F) - "
} else { append putthis " (${tempc}C) - " }
if {[info exists windcf] && ($tempf > $windcf) && (abs($tempf - $windcf) > 1.0)} {
append putthis "${b}Windchill:$b[::wunder::color $windcf $windcc]"
if {$::wunder::metric==1} { append putthis " (${windcf}F) - "
} else { append putthis " (${windcc}C) - " }
}
append putthis "${b}Humidity:$b $hum - ${b}Wind:$b $windout - ${b}Pressure:$b "
if {$::wunder::metric==1} { append putthis "${presh}hPa (${presi}in) $rifa - "
} else { append putthis "${presi}in (${presh}hPa) $rifa - " }
append putthis "${b}Conditions:$b $cond - ${b}Updated:$b $updated"
puthelp "PRIVMSG $ch :${logo}$loc:$endl $putthis"
# // Build forecast string.
set x { Forecast as(.*?)<br /><b>(.*?)</b><br />.*?<br />(.*?)<br /><br />}
regexp $x $html - fdata next ncast
if {[info exists fdata]} {
regexp {<td align="left"><b>(.*?)</b>} $fdata - fday
regexp { alt="" /><br />(.*?)<br />} $fdata - fcast
set fcast [fix_fc [regsub -all -- {\s{2,}} [string trim $fcast] { }]]
set ncast [fix_fc [regsub -all -- {\s{2,}} [string trim $ncast] { }]]
puthelp "PRIVMSG $ch :${logo}Forecast:$endl $b$fday:$b $fcast - $b$next:$b $ncast"
} else {
set x {<a name="forecast">.*?<td align="left"><b>(.*?)</b><br />(.*?)</td></tr>}
set y {.*?<td align="left"><b>(.*?)</b><br />(.*?)</td></tr>}
set map [list \t " " "° " "" "°" "" ":" ""]
regexp $x$y [string map $map $html] - fday fcast next ncast
if {[info exists ncast]} {
set fcast [fix_fc [regsub -all -- {\s{2,}} [string trim $fcast] { }]]
set ncast [fix_fc [regsub -all -- {\s{2,}} [string trim $ncast] { }]]
puthelp "PRIVMSG $ch :${logo}Forecast:$endl $b$fday:$b $fcast - $b$next:$b $ncast"
}
}
}
# // End proc ::wunder::pub_w // #
#########################################################################
# // Fix forecast if default display is set to metric.
proc fix_fc {fc} {
if {$::wunder::metric!=1} { return $fc }
set ret ""
foreach item [split [string trim $fc "."] "."] {
if {![string match {*[0-9]*} $item]} {
append ret $item. ; continue
}
if {[regexp {(\d{1,})F .*? (\d{1,})} $item - f1 f2]} {
set c2 [f_to_c $f2]
set map [list ${f1}F [f_to_c $f1]C ${f2}F ${c2}C $f2 $c2]
} elseif {[regexp {(\d{1,})F} $item - f]} {
set map [list ${f}F [f_to_c $f]C]
} elseif {[regexp {(\d{1,}) to (\d{1,}) mph} $item - m1 m2]} {
set map [list $m1 [m_to_k $m1] $m2 [m_to_k $m2] mph kph]
} elseif {[regexp {Lows overnight in the upper (\d{1,})s$} $item - f]} {
set f2 [string range $f 0 end-1]8
set map [list "in the upper ${f}s" "around [f_to_c $f2]C"]
} elseif {[regexp {Lows overnight in the low (\d{1,})s$} $item - f]} {
set f2 [string range $f 0 end-1]2
set map [list "in the low ${f}s" "around [f_to_c $f2]C"]
} elseif {[regexp {Lows overnight in the mid (\d{1,})s$} $item - f]} {
set f2 [string range $f 0 end-1]5
set map [list "in the mid ${f}s" "around [f_to_c $f2]C"]
} else { append ret $item. ; continue }
append ret [string map $map $item.]
}
return [string trim $ret]
}
# // sub - convert mi to km
proc m_to_k {m} {
lassign [split [expr {$m / 0.62137}] "."] k d
if {[string index $d 0]>=5} { incr k }
return $k
}
# // sub - convert f to c
proc f_to_c {f} {
lassign [split [expr {($f - 32) * .5556}] "."] c d
if {[string index $d 0]>=5} { incr c }
return $c
}
#########################################################################
# // Primary Temperature Color Changing.
# // You can change colors based on fahrenheit temperatures.
# // IRC allows only 16 colors. See mIRC color chart.
proc color {temp tempc} {
set x "${temp}F"
if {$::wunder::metric==1} { set x "${tempc}C" }
if {$::wunder::colortemp==0} { return " $x" }
if {$temp < 20} { return "\00312 $x\003" }
if {$temp < 45} { return "\00311 $x\003" }
if {$temp < 70} { return "\00309 $x\003" }
if {$temp < 85} { return "\00307 $x\003" }
if {$temp < 100} { return "\00304 $x\003" }
return "\00313 $x\003"
}
#########################################################################
# // Throttle Proc (slightly altered, super action missles) - Thanks to user & speechles
# // See this post: http://forum.egghelp.org/viewtopic.php?t=9009&start=3
proc throttle {id nk ch} { set now [clock seconds]
if {[info exists ::wunder::throttle($id)]&&[lindex $::wunder::throttle($id) 0]>$now} {
lassign $::wunder::throttle($id) ut cnt
if {$cnt == $::wunder::throttle_max} {
puthelp "PRIVMSG $ch :$nk, you have been Throttled ([expr {$ut-$now}] secs)"
}
set ::wunder::throttle($id) [list $ut [incr cnt]]
if {$cnt > $::wunder::throttle_max} { set id 1 } { set id 0 }
} else {
set ::wunder::throttle($id) [list [expr {$now+$::wunder::throttle_time}] 1]
set id 0
}
}
# // sub - clean throttled users
proc throttleclean {} { set now [clock seconds]
foreach {id time} [array get ::wunder::throttle] {
if {[lindex $time 0]<=$now} {unset ::wunder::throttle($id)}
}
}
#########################################################################
proc savewusers {} { variable wusers
if {![info exists wusers(updated)]} { return }
unset wusers(updated)
if {![array size wusers]} {
file delete $::wunder::userfile
return
}
set open [open $::wunder::userfile w]
puts $open "array set wusers [list [array get wusers]]"
close $open
}
#########################################################################
proc wusersclean {} { variable wusers
if {![array size wusers]} { return }
set old [expr {[unixtime] - (86400 * 45)}] ;# 45 days #
foreach {key val} [array get wusers] {
if {$key eq "updated"} { continue }
if {[lindex $val 0] <= $old} {
unset wusers($key)
set wusers(updated) 1
}
}
}
#########################################################################
proc bindtime {args} { lassign $args mn hr
if {$mn eq "02" && $hr in {00 12}} { ::wunder::wusersclean }
::wunder::savewusers
if {[string match "*1" $mn]} { ::wunder::throttleclean }
}
#########################################################################
# // Script reset (unbind/rebind all triggers).
proc w_reset {} { variable cmds
set ::wunder::cmdchars [split $::wunder::cmdchars]
foreach x {tc w wz} {
if {$x eq "tc"} { set wproc "::wunder::throttleclean"
} else { set wproc "::wunder::pub_$x" }
foreach wbind [binds $wproc] {
lassign $wbind t f n h p
unbind $t $f $n $p
}
if {$x in {tc w}} { continue } ;# just remove v5.01 binds #
set cmds($x) [split $cmds($x)]
foreach cmd $cmds($x) {
foreach pre $::wunder::cmdchars {
bind pub - $pre$cmd $wproc
}
}
}
bind time - * ::wunder::bindtime
variable wusers
if {![array exists wusers]} {
array set wusers ""
if {[file exists $::wunder::userfile]} { source $::wunder::userfile }
}
}
::wunder::w_reset
}
# // End namespace eval wunder // #
putlog "\002W\002under\002W\002eather v$::wunder::ver Loaded"