mirror of
https://github.com/jlu5/SupyPlugins.git
synced 2025-04-30 07:21:12 -05:00
Massive refactor. Moved internal db over to sqlite. MUST READ README IF USING OLDER VERSION.
This commit is contained in:
parent
f435bcc004
commit
194ae52481
65
README.md
65
README.md
@ -4,40 +4,59 @@ Supybot-Weather
|
|||||||
Overview
|
Overview
|
||||||
|
|
||||||
This is a Supybot plugin for displaying Weather via Weather Underground (http://www.wunderground.com)
|
This is a Supybot plugin for displaying Weather via Weather Underground (http://www.wunderground.com)
|
||||||
They've got a nice JSON api that is free to use when you register and grab an API key. You will need
|
They've got a nice JSON api that is free to use when you register and grab an API key.
|
||||||
an API key to use this plugin. Configure it via:
|
|
||||||
|
|
||||||
/msg bot config plugin.Weather.apiKey <apiKey>
|
|
||||||
|
|
||||||
I made this plugin because quite a few Weather plugins didn't work well and WunderWeather, which uses
|
I made this plugin because quite a few Weather plugins didn't work well and WunderWeather, which uses
|
||||||
this API, is on their older XML api that they don't have documented anymore and, one would assume, will
|
this API, is on their older XML api that they don't have documented anymore and, one would assume, will
|
||||||
be depreciated at some point.
|
be depreciated at some point.
|
||||||
|
|
||||||
There are a ton of options to configure. You can look through these via /msg <bot> config search Weather
|
Besides a few of the ideas like having a user database, colorized temp, most of the code is mine.
|
||||||
Many of these are also available via --options when calling the wunderground command.
|
|
||||||
|
Instructions
|
||||||
|
|
||||||
|
NOTICE: If you were using the older version of this plugin, you _MUST_ delete the older Weather.db
|
||||||
|
file in the Supybot data directory. Normally, this is at <supybotdir>/data/Weather.db
|
||||||
|
The internal DB is not compatable and must be deleted before.
|
||||||
|
|
||||||
|
First, you will need to register for a free API key. Signup takes less than a minute at:
|
||||||
|
|
||||||
|
http://www.wunderground.com/weather/api/
|
||||||
|
|
||||||
|
You will need an API key to use this plugin. Configure it via:
|
||||||
|
|
||||||
|
/msg <bot> config plugin.Weather.apiKey <apiKey>
|
||||||
|
|
||||||
|
Now reload the plugin:
|
||||||
|
|
||||||
|
/msg <bot> reload Weather
|
||||||
|
|
||||||
|
You can now use the basic functionality by:
|
||||||
|
|
||||||
|
/msg <bot> wunderground 10012 (or your zipcode)
|
||||||
|
|
||||||
I suggest adding an alias to this command to make it easier.
|
I suggest adding an alias to this command to make it easier.
|
||||||
|
|
||||||
/msg bot Alias add weather wunderground
|
/msg <bot> Alias add weather wunderground
|
||||||
|
/msg <bot> Alias add w wunderground
|
||||||
|
|
||||||
|
Options
|
||||||
|
|
||||||
|
There are a ton of options to configure. You can look through these via /msg <bot> config search Weather
|
||||||
|
Many of these are also available via --help when calling the wunderground command.
|
||||||
|
|
||||||
|
|
||||||
Another feature that will make you and your users happy is an internal database that can remember your
|
Another feature that will make you and your users happy is an internal database that can remember your
|
||||||
location and setting for metric. I've seen this before with another bot and wanted to implement this.
|
location, setting for metric, and color temperature.
|
||||||
Basically, instead of having to type wunderground 10152 (or wherever you are), you can just type in
|
Basically, instead of having to type wunderground 10152 (or wherever you are), you can just type in
|
||||||
wunderground. This can be done via setting a location with the setweather command.
|
wunderground. This can be done via setting a location with the setweather command.
|
||||||
|
|
||||||
/msg <bot> setweather 10152
|
/msg <bot> setweather 10152
|
||||||
/msg <bot> setmetric False (to use imperial units)
|
/msg <bot> setmetric False (to use imperial units)
|
||||||
|
/msg <bot> setcolortemp False (or true)
|
||||||
|
|
||||||
The bot's db is very simple and only remembers a nick and setting. So, if you change nicks, it will not
|
The bot's db is very simple and only remembers a nick and setting. So, if you change nicks, it will not
|
||||||
remember you unless you set it on this new nick.
|
remember you unless you set it on this new nick.
|
||||||
|
|
||||||
Use:
|
|
||||||
/msg <bot> getweather
|
|
||||||
/msg <bot> getmetric
|
|
||||||
|
|
||||||
To check settings here. This is optional but a neat feature. This only works if you don't give it an input.
|
|
||||||
So, if you /msg bot wunderground --metric, it will display the weather you set in setweather but in --metric.
|
|
||||||
|
|
||||||
Options
|
Options
|
||||||
|
|
||||||
This plugin has a bit of configuration that can be done with it. We'll start with the basics:
|
This plugin has a bit of configuration that can be done with it. We'll start with the basics:
|
||||||
@ -57,30 +76,20 @@ Options
|
|||||||
|
|
||||||
/msg <bot> config plugins.Weather.lang EN (replace EN with the 2 letter language code)
|
/msg <bot> config plugins.Weather.lang EN (replace EN with the 2 letter language code)
|
||||||
|
|
||||||
- disableANSI:
|
|
||||||
By default, ANSI is on. Color/bold on output makes things a bit easier to read.
|
|
||||||
If you do not want any color or bold in the output for a specific channel, you can:
|
|
||||||
|
|
||||||
/msg <bot> channel #channelname plugins.Weather.disableANSI True
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
/msg <bot> config plugins.Weather.disableANSI True
|
|
||||||
|
|
||||||
- disableColorTemp
|
- disableColorTemp
|
||||||
On a similar note, I coded a neat "color" to temperature function that will color any temperature
|
On a similar note, I coded a neat "color" to temperature function that will color any temperature
|
||||||
on a basis of what it is (works for metric, too). Think of how temperature maps are done where
|
on a basis of what it is (works for metric, too). Think of how temperature maps are done where
|
||||||
you would see red/orange/yellow if it's "hot", green if "moderate", and blue if its "cold".
|
you would see red/orange/yellow if it's "hot", green if "moderate", and blue if its "cold".
|
||||||
By default, I have this ON. You can turn it off like this:
|
By default, I have this ON. This can also be personalized via /msg <bot> setcolortemp True/False
|
||||||
|
once a user is in the database. You can turn it off like this:
|
||||||
|
|
||||||
/msg <bot> config plugins.Weather.disableColorTemp True
|
/msg <bot> config plugins.Weather.disableColorTemp True
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
|
|
||||||
Some links:
|
Some links:
|
||||||
- Main documentation: http://www.wunderground.com/weather/api/
|
# Main documentation: http://www.wunderground.com/weather/api/
|
||||||
# https://github.com/davidwilemski/Weather/blob/master/weather.py
|
# https://github.com/davidwilemski/Weather/blob/master/weather.py
|
||||||
# https://bitbucket.org/rizon/pypsd/src/8f975a375ab4/modules/internets/api/weather.py
|
# https://bitbucket.org/rizon/pypsd/src/8f975a375ab4/modules/internets/api/weather.py
|
||||||
# http://ronie.googlecode.com/svn-history/r283/trunk/weather.wunderground/default.py
|
# http://ronie.googlecode.com/svn-history/r283/trunk/weather.wunderground/default.py
|
||||||
# http://www.wunderground.com/weather/api/
|
|
||||||
|
|
||||||
|
@ -21,8 +21,7 @@ def configure(advanced):
|
|||||||
Weather = conf.registerPlugin('Weather')
|
Weather = conf.registerPlugin('Weather')
|
||||||
conf.registerGlobalValue(Weather,'apiKey', registry.String('', ("""Your wunderground.com API key."""), private=True))
|
conf.registerGlobalValue(Weather,'apiKey', registry.String('', ("""Your wunderground.com API key."""), private=True))
|
||||||
conf.registerChannelValue(Weather,'useImperial', registry.Boolean(True, ("""Use imperial units? Defaults to yes.""")))
|
conf.registerChannelValue(Weather,'useImperial', registry.Boolean(True, ("""Use imperial units? Defaults to yes.""")))
|
||||||
conf.registerChannelValue(Weather,'disableANSI', registry.Boolean(False, """Do not display any ANSI (color/bold) for channel."""))
|
conf.registerChannelValue(Weather,'disableColoredTemp', registry.Boolean(False, """If True, this will disable coloring temperatures based on values."""))
|
||||||
conf.registerChannelValue(Weather,'disableColoredTemp', registry.Boolean(False, """If disableANSI is True, this will color temperatures based on values."""))
|
|
||||||
conf.registerChannelValue(Weather,'useWeatherSymbols', registry.Boolean(False, """Use unicode symbols with weather conditions and for wind direction."""))
|
conf.registerChannelValue(Weather,'useWeatherSymbols', registry.Boolean(False, """Use unicode symbols with weather conditions and for wind direction."""))
|
||||||
conf.registerGlobalValue(Weather,'forecast', registry.Boolean(True, ("""Display forecast in output by default?""")))
|
conf.registerGlobalValue(Weather,'forecast', registry.Boolean(True, ("""Display forecast in output by default?""")))
|
||||||
conf.registerGlobalValue(Weather,'alerts', registry.Boolean(False, ("""Display alerts by default?""")))
|
conf.registerGlobalValue(Weather,'alerts', registry.Boolean(False, ("""Display alerts by default?""")))
|
||||||
|
544
plugin.py
544
plugin.py
@ -3,19 +3,14 @@
|
|||||||
# Copyright (c) 2012-2013, spline
|
# Copyright (c) 2012-2013, spline
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
###
|
###
|
||||||
|
|
||||||
# my libs
|
# my libs
|
||||||
import urllib2
|
|
||||||
import json
|
import json
|
||||||
import re
|
from math import floor # for wind.
|
||||||
from math import floor
|
import sqlite3 # userdb.
|
||||||
from urllib import quote
|
import os
|
||||||
|
|
||||||
# extra supybot libs
|
# extra supybot libs
|
||||||
import supybot.conf as conf
|
import supybot.conf as conf
|
||||||
import supybot.ircdb as ircdb
|
import supybot.log as log
|
||||||
import supybot.world as world
|
|
||||||
|
|
||||||
# supybot libs
|
# supybot libs
|
||||||
import supybot.utils as utils
|
import supybot.utils as utils
|
||||||
from supybot.commands import *
|
from supybot.commands import *
|
||||||
@ -25,77 +20,113 @@ import supybot.callbacks as callbacks
|
|||||||
from supybot.i18n import PluginInternationalization, internationalizeDocstring
|
from supybot.i18n import PluginInternationalization, internationalizeDocstring
|
||||||
|
|
||||||
_ = PluginInternationalization('Weather')
|
_ = PluginInternationalization('Weather')
|
||||||
|
# @internationalizeDocstring
|
||||||
|
|
||||||
@internationalizeDocstring
|
class WeatherDB():
|
||||||
class WeatherDB(plugins.ChannelUserDB):
|
"""WeatherDB class to store our users and their settings."""
|
||||||
"""WeatherDB class to store our users locations and metric."""
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
plugins.ChannelUserDB.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def serialize(self, v):
|
def __init__(self):
|
||||||
return list(v)
|
self.filename = conf.supybot.directories.data.dirize("Weather.db")
|
||||||
|
self.log = log.getPluginLogger('Weather')
|
||||||
|
self._conn = sqlite3.connect(self.filename, check_same_thread=False)
|
||||||
|
self._conn.text_factory = str
|
||||||
|
self.makeDb()
|
||||||
|
|
||||||
def deserialize(self, channel, id, L):
|
def makeDb(self):
|
||||||
(id, metric) = L
|
"""Create our DB."""
|
||||||
return (id, metric)
|
|
||||||
|
|
||||||
def getId(self, nick):
|
self.log.info("WeatherDB: Checking/Creating DB.")
|
||||||
return self['x', nick.lower()][0]
|
with self._conn as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""CREATE TABLE IF NOT EXISTS users (
|
||||||
|
nick TEXT PRIMARY KEY,
|
||||||
|
location TEXT NOT NULL,
|
||||||
|
metric INTEGER DEFAULT 0,
|
||||||
|
colortemp INTEGER DEFAULT 1)""")
|
||||||
|
self._conn.commit()
|
||||||
|
|
||||||
def getMetric(self, nick):
|
def setweather(self, username, location):
|
||||||
return self['x', nick.lower()][1]
|
"""Stores or update a user's location. Adds user if not found."""
|
||||||
|
with self._conn as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
if self.getuser(username): # username exists.
|
||||||
|
cursor.execute("""UPDATE users SET location=? WHERE nick=?""", (location, username,))
|
||||||
|
else: # username does not exist so add it in.
|
||||||
|
cursor.execute("""INSERT OR REPLACE INTO users (nick, location) VALUES (?,?)""", (username, location,))
|
||||||
|
self._conn.commit() # commit.
|
||||||
|
|
||||||
def setId(self, nick, id):
|
def setmetric(self, username, metric):
|
||||||
try:
|
"""Sets a user's metric value."""
|
||||||
metric = self['x', nick.lower()][1]
|
with self._conn as conn:
|
||||||
except KeyError:
|
cursor = conn.cursor()
|
||||||
metric = 'False'
|
cursor.execute("""UPDATE users SET metric=? WHERE nick=?""", (metric, username,))
|
||||||
self['x', nick.lower()] = (id, metric,)
|
self._conn.commit()
|
||||||
|
|
||||||
|
def setcolortemp(self, username, colortemp):
|
||||||
|
"""Sets a user's colortemp value."""
|
||||||
|
with self._conn as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""UPDATE users SET colortemp=? WHERE nick=?""", (colortemp, username))
|
||||||
|
self._conn.commit()
|
||||||
|
|
||||||
|
def getweather(self, user):
|
||||||
|
"""Return a dict of user's settings."""
|
||||||
|
self._conn.row_factory = sqlite3.Row
|
||||||
|
with self._conn as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""SELECT * from users where nick=?""", (user,))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if not row: # user does not exist.
|
||||||
|
return None
|
||||||
|
else: # user exists.
|
||||||
|
return row
|
||||||
|
|
||||||
|
def getuser(self, user):
|
||||||
|
"""Returns a boolean if a user exists."""
|
||||||
|
with self._conn as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""SELECT location from users where nick=?""", (user,))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def setMetric(self, nick, metric):
|
|
||||||
try:
|
|
||||||
id = self['x', nick.lower()][0]
|
|
||||||
except:
|
|
||||||
id = '10121'
|
|
||||||
self['x', nick.lower()] = (id, metric,)
|
|
||||||
|
|
||||||
class Weather(callbacks.Plugin):
|
class Weather(callbacks.Plugin):
|
||||||
"""Add the help for "@plugin help Weather" here
|
"""Add the help for "@plugin help Weather" here
|
||||||
This should describe *how* to use this plugin."""
|
This should describe *how* to use this plugin."""
|
||||||
threaded = True
|
threaded = True
|
||||||
|
|
||||||
# BASICS/WeatherDB
|
|
||||||
def __init__(self, irc):
|
def __init__(self, irc):
|
||||||
self.__parent = super(Weather, self)
|
self.__parent = super(Weather, self)
|
||||||
self.__parent.__init__(irc)
|
self.__parent.__init__(irc)
|
||||||
self.db = WeatherDB(conf.supybot.directories.data.dirize("Weather.db"))
|
|
||||||
self.APIKEY = self.registryValue('apiKey')
|
self.APIKEY = self.registryValue('apiKey')
|
||||||
world.flushers.append(self.db.flush)
|
self.db = WeatherDB()
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
if self.db.flush in world.flushers:
|
|
||||||
world.flushers.remove(self.db.flush)
|
|
||||||
self.db.close()
|
|
||||||
self.__parent.die()
|
self.__parent.die()
|
||||||
|
|
||||||
# COLORING
|
##############
|
||||||
|
# FORMATTING #
|
||||||
|
##############
|
||||||
|
|
||||||
def _bold(self, string):
|
def _bold(self, string):
|
||||||
return ircutils.bold(string)
|
return ircutils.bold(string)
|
||||||
|
|
||||||
def _bu(self, string):
|
def _bu(self, string):
|
||||||
return ircutils.underline(ircutils.bold(string))
|
return ircutils.underline(ircutils.bold(string))
|
||||||
|
|
||||||
def _blue(self, string):
|
|
||||||
return ircutils.mircColor(string, 'blue')
|
|
||||||
|
|
||||||
def _red(self, string):
|
|
||||||
return ircutils.mircColor(string, 'red')
|
|
||||||
|
|
||||||
def _strip(self, string):
|
def _strip(self, string):
|
||||||
return ircutils.stripFormatting(string)
|
return ircutils.stripFormatting(string)
|
||||||
|
|
||||||
# WEATHER SYMBOLS
|
############################
|
||||||
|
# INTERNAL WEATHER HELPERS #
|
||||||
|
############################
|
||||||
|
|
||||||
def _weatherSymbol(self, code):
|
def _weatherSymbol(self, code):
|
||||||
|
"""Return a unicode symbol based on weather status."""
|
||||||
|
|
||||||
table = {'partlycloudy':'~☁',
|
table = {'partlycloudy':'~☁',
|
||||||
'cloudy':'☁',
|
'cloudy':'☁',
|
||||||
'tstorms':'⚡',
|
'tstorms':'⚡',
|
||||||
@ -114,15 +145,17 @@ class Weather(callbacks.Plugin):
|
|||||||
'chancesleet':'?❄',
|
'chancesleet':'?❄',
|
||||||
'chancesnow':'?❄',
|
'chancesnow':'?❄',
|
||||||
'chancetstorms':'?☔',
|
'chancetstorms':'?☔',
|
||||||
'unknown':''}
|
'unknown':'unknown'}
|
||||||
|
# return symbol from table.
|
||||||
try:
|
try:
|
||||||
return table[code]
|
return table[code]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# MOON PHASE
|
|
||||||
def _moonphase(self, phase):
|
def _moonphase(self, phase):
|
||||||
"""Returns a moon phase based on the %."""
|
"""Returns a moon phase based on the %."""
|
||||||
|
|
||||||
|
# depending on the phase float, we have an ascii picture+text to represent it.
|
||||||
if phase < 0.05:
|
if phase < 0.05:
|
||||||
symbol = "[ ( ) ] (fullmoon)"
|
symbol = "[ ( ) ] (fullmoon)"
|
||||||
elif phase < 0.20:
|
elif phase < 0.20:
|
||||||
@ -139,16 +172,18 @@ class Weather(callbacks.Plugin):
|
|||||||
symbol = "[ D ] (half moon)"
|
symbol = "[ D ] (half moon)"
|
||||||
else:
|
else:
|
||||||
symbol = "[ D ] (waxing moon)"
|
symbol = "[ D ] (waxing moon)"
|
||||||
|
# return.
|
||||||
return symbol
|
return symbol
|
||||||
|
|
||||||
# COLOR TEMPERATURE
|
|
||||||
def _temp(self, x):
|
def _temp(self, x):
|
||||||
"""Returns a colored string based on the temperature."""
|
"""Returns a colored string based on the temperature."""
|
||||||
if x.endswith('C'):
|
|
||||||
x = float(str(x).replace('C','')) * 9 / 5 + 32
|
# first, convert into F so we only have one table.
|
||||||
|
if x.endswith('C'): # c.
|
||||||
|
x = float(str(x).replace('C', '')) * 9 / 5 + 32 # remove C + math into float(F).
|
||||||
unit = "C"
|
unit = "C"
|
||||||
else:
|
else: # f.
|
||||||
x = float(str(x).replace('F',''))
|
x = float(str(x).replace('F', '')) # remove F. str->float.
|
||||||
unit = "F"
|
unit = "F"
|
||||||
# determine color.
|
# determine color.
|
||||||
if x < 10.0:
|
if x < 10.0:
|
||||||
@ -170,122 +205,113 @@ class Weather(callbacks.Plugin):
|
|||||||
else:
|
else:
|
||||||
color = 'light grey'
|
color = 'light grey'
|
||||||
# return.
|
# return.
|
||||||
if unit == "F":
|
if unit == "F": # no need to convert back.
|
||||||
return ircutils.mircColor(("{0:.0f}F".format(x)), color)
|
return ircutils.mircColor(("{0:.0f}F".format(x)), color)
|
||||||
else:
|
else: # temp is in F and we need to go back to C.
|
||||||
return ircutils.mircColor(("{0:.0f}C".format((x - 32) * 5 / 9)),color)
|
return ircutils.mircColor(("{0:.0f}C".format((x - 32) * 5 / 9)),color)
|
||||||
|
|
||||||
# DEGREES TO DIRECTION (wind)
|
|
||||||
def _wind(self, angle, useSymbols=False):
|
def _wind(self, angle, useSymbols=False):
|
||||||
if not useSymbols:
|
"""Converts degrees to direction for wind. Can optionally return a symbol."""
|
||||||
|
|
||||||
|
if not useSymbols: # ordinal names.
|
||||||
direction_names = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
|
direction_names = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
|
||||||
else:
|
else: # symbols.
|
||||||
direction_names = ['↑', '↗', '→', '↘', '↓', '↙', '←', '↖']
|
direction_names = ['↑', '↗', '→', '↘', '↓', '↙', '←', '↖']
|
||||||
|
# do math below to figure the angle->direction out.
|
||||||
directions_num = len(direction_names)
|
directions_num = len(direction_names)
|
||||||
directions_step = 360./directions_num
|
directions_step = 360./directions_num
|
||||||
index = int(round((angle/360. - floor(angle/360.)*360.)/directions_step))
|
index = int(round((angle/360. - floor(angle/360.)*360.)/directions_step))
|
||||||
index %= directions_num
|
index %= directions_num
|
||||||
|
# return.
|
||||||
return direction_names[index]
|
return direction_names[index]
|
||||||
|
|
||||||
# PUBLIC FUNCTIONS TO WORK WITH WEATHERDB.
|
##############################################
|
||||||
def weatherusers(self, irc, msg, args):
|
# PUBLIC FUNCTIONS TO WORK WITH THE DATABASE #
|
||||||
"""
|
##############################################
|
||||||
Returns the amount of users we know about.
|
|
||||||
"""
|
|
||||||
output = str(len(self.db.keys()))
|
|
||||||
irc.reply("I know about {0} users in my weather database.".format(str(output)))
|
|
||||||
weatherusers = wrap(weatherusers)
|
|
||||||
|
|
||||||
def setmetric(self, irc, msg, args, optboolean):
|
def setcolortemp(self, irc, msg, args, opttemp):
|
||||||
|
"""<True|False>
|
||||||
|
Sets the user's colortemp setting to True or False.
|
||||||
|
If True, will color temperature. If False, will not color.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if opttemp: # handle opttemp
|
||||||
|
metric = 1
|
||||||
|
else: # False.
|
||||||
|
metric = 0
|
||||||
|
|
||||||
|
# check user first.
|
||||||
|
if self.db.getuser(msg.nick.lower()): # user exists
|
||||||
|
# perform op.
|
||||||
|
self.db.setcolortemp(msg.nick.lower(), metric)
|
||||||
|
irc.reply("I have changed {0}'s colortemp setting to {1}".format(msg.nick, metric))
|
||||||
|
else: # user is NOT In the database.
|
||||||
|
irc.reply("ERROR: You're not in the database. You must setweather first.")
|
||||||
|
|
||||||
|
setcolortemp = wrap(setcolortemp, [('boolean')])
|
||||||
|
|
||||||
|
def setmetric(self, irc, msg, args, optmetric):
|
||||||
"""<True|False>
|
"""<True|False>
|
||||||
Sets the user's use metric setting to True or False.
|
Sets the user's use metric setting to True or False.
|
||||||
If True, will use netric. If False, will use imperial.
|
If True, will use netric. If False, will use imperial.
|
||||||
"""
|
"""
|
||||||
# first, title case and cleanup as helper. Still must be True or False.
|
|
||||||
optboolean = optboolean.title().strip() # partial helpers.
|
|
||||||
if optboolean != "True" and optboolean != "False":
|
|
||||||
irc.reply("metric setting must be True or False")
|
|
||||||
return
|
|
||||||
# now, test if we have a username. setmetric for an unknown username = error
|
|
||||||
try:
|
|
||||||
self.db.getId(msg.nick)
|
|
||||||
except KeyError:
|
|
||||||
irc.reply("I have no user in the DB named {0}. Try setweather first.".format(msg.nick))
|
|
||||||
return
|
|
||||||
# now change it.
|
|
||||||
self.db.setMetric(msg.nick, optboolean)
|
|
||||||
irc.reply("I have changed {0}'s metric setting to {1}".format(msg.nick, optboolean))
|
|
||||||
setmetric = wrap(setmetric, [('somethingWithoutSpaces')])
|
|
||||||
|
|
||||||
def setweather(self, irc, msg, args, optid):
|
if optmetric: # handle opttemp
|
||||||
|
metric = 1
|
||||||
|
else: # False.
|
||||||
|
metric = 0
|
||||||
|
|
||||||
|
# check user first.
|
||||||
|
if self.db.getuser(msg.nick.lower()): # user exists
|
||||||
|
# perform op.
|
||||||
|
self.db.setmetric(msg.nick.lower(), metric)
|
||||||
|
irc.reply("I have changed {0}'s metric setting to {1}".format(msg.nick, metric))
|
||||||
|
else: # user is NOT In the database.
|
||||||
|
irc.reply("ERROR: You're not in the database. You must setweather first.")
|
||||||
|
|
||||||
|
setmetric = wrap(setmetric, [('boolean')])
|
||||||
|
|
||||||
|
def setweather(self, irc, msg, args, optlocation):
|
||||||
"""<location code>
|
"""<location code>
|
||||||
Set's weather location code for your nick as <location code>.
|
Set's weather location code for your nick as location code.
|
||||||
Use your zip/postal code to keep it simple. Ex: setweather 03062
|
|
||||||
|
Use your zip/postal code to keep it simple.
|
||||||
|
Ex: setweather 10012
|
||||||
"""
|
"""
|
||||||
# set the weather id based on nick.
|
|
||||||
optid = optid.replace(' ','')
|
# set the weather id based on nick. This will update or set.
|
||||||
self.db.setId(msg.nick, optid)
|
self.db.setweather(msg.nick.lower(), optlocation)
|
||||||
irc.reply("I have changed {0}'s weather ID to {1}".format(msg.nick, optid))
|
irc.reply("I have changed {0}'s weather ID to {1}".format(msg.nick.lower(), optlocation))
|
||||||
|
|
||||||
setweather = wrap(setweather, [('text')])
|
setweather = wrap(setweather, [('text')])
|
||||||
|
|
||||||
def getmetric(self, irc, msg, args, optnick):
|
|
||||||
"""[nick]
|
|
||||||
Get the metric setting of your or [nick].
|
|
||||||
"""
|
|
||||||
# allows us to specify the nick.
|
|
||||||
if not optnick:
|
|
||||||
optnick = msg.nick
|
|
||||||
# now try to fetch the metric. Tests if we have a username.
|
|
||||||
try:
|
|
||||||
irc.reply("The metric setting for {0} is {1}".format(optnick, self.db.getMetric(optnick)))
|
|
||||||
except KeyError:
|
|
||||||
irc.reply('I have no weather metric setting for {0}'.format(optnick))
|
|
||||||
getmetric = wrap(getmetric, [optional('somethingWithoutSpaces')])
|
|
||||||
|
|
||||||
def getweather(self, irc, msg, args, optnick):
|
|
||||||
"""[nick]
|
|
||||||
Get the weather ID of your or [nick].
|
|
||||||
"""
|
|
||||||
# allow us to specify the nick if we don't have it.
|
|
||||||
if not optnick:
|
|
||||||
optnick = msg.nick
|
|
||||||
# now try and fetch the metric setting. error if it's broken.
|
|
||||||
try:
|
|
||||||
irc.reply("The weather ID for {0} is {1}".format(optnick, self.db.getId(optnick)))
|
|
||||||
except KeyError:
|
|
||||||
irc.reply('I have no weather ID for %s.' % optnick)
|
|
||||||
getweather = wrap(getweather, [optional('somethingWithoutSpaces')])
|
|
||||||
|
|
||||||
# CHECK FOR API KEY. (NOT PUBLIC)
|
|
||||||
def keycheck(self, irc):
|
|
||||||
"""Check and make sure we have an API key."""
|
|
||||||
if len(self.APIKEY) < 1 or not self.APIKEY or self.APIKEY == "Not set":
|
|
||||||
irc.reply("ERROR: Need a Wunderground API key. Set config plugins.Weather.apiKey.")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# PUBLIC FUNCTIONS #
|
# PUBLIC FUNCTIONS #
|
||||||
####################
|
####################
|
||||||
|
|
||||||
def wunderground(self, irc, msg, args, optlist, optinput):
|
def wunderground(self, irc, msg, args, optlist, optinput):
|
||||||
"""[--options] [location]
|
"""[--options] <location>
|
||||||
|
|
||||||
|
Fetch weather and forcast information for <location>
|
||||||
|
|
||||||
Location must be one of: US state/city (CA/San_Francisco), zipcode, country/city (Australia/Sydney), airport code (KJFK)
|
Location must be one of: US state/city (CA/San_Francisco), zipcode, country/city (Australia/Sydney), airport code (KJFK)
|
||||||
For options:
|
Use --help to list all options.
|
||||||
|
Ex: 10021 or Sydney, Australia or KJFK
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# first, check if we have an API key. Useless w/o this.
|
# first, check if we have an API key. Useless w/o this.
|
||||||
if not self.keycheck(irc):
|
if len(self.APIKEY) < 1 or not self.APIKEY or self.APIKEY == "Not set":
|
||||||
return False
|
irc.reply("ERROR: Need a Wunderground API key. Set config plugins.Weather.apiKey and reload Weather.")
|
||||||
|
return
|
||||||
|
|
||||||
# urlargs will be used to build the url to query the API.
|
# urlargs will be used to build the url to query the API.
|
||||||
urlArgs = {'features':['conditions', 'forecast'],
|
urlArgs = {'features':['conditions', 'forecast'],
|
||||||
'lang':self.registryValue('lang'),
|
'lang':self.registryValue('lang'),
|
||||||
'bestfct':'1',
|
'bestfct':'1',
|
||||||
'pws':'0'
|
'pws':'0' }
|
||||||
}
|
|
||||||
# now, start our dict for output formatting.
|
# now, start our dict for output formatting.
|
||||||
args = {'imperial':self.registryValue('useImperial', msg.args[0]),
|
args = {'imperial':self.registryValue('useImperial', msg.args[0]),
|
||||||
|
'nocolortemp':self.registryValue('disableColoredTemp', msg.args[0]),
|
||||||
'alerts':self.registryValue('alerts'),
|
'alerts':self.registryValue('alerts'),
|
||||||
'almanac':self.registryValue('almanac'),
|
'almanac':self.registryValue('almanac'),
|
||||||
'astronomy':self.registryValue('astronomy'),
|
'astronomy':self.registryValue('astronomy'),
|
||||||
@ -296,23 +322,7 @@ class Weather(callbacks.Plugin):
|
|||||||
'strip':False,
|
'strip':False,
|
||||||
'uv':False,
|
'uv':False,
|
||||||
'visibility':False,
|
'visibility':False,
|
||||||
'dewpoint':False
|
'dewpoint':False }
|
||||||
}
|
|
||||||
|
|
||||||
# now check if we have a location. if no location, use the userdb. also set for metric variable.
|
|
||||||
# autoip.json?geo_ip=38.102.136.138
|
|
||||||
if not optinput:
|
|
||||||
try:
|
|
||||||
optinput = self.db.getId(msg.nick)
|
|
||||||
optmetric = self.db.getMetric(msg.nick) # set our imperial units here.
|
|
||||||
if optmetric == "True":
|
|
||||||
args['imperial'] = False
|
|
||||||
else:
|
|
||||||
args['imperial'] = True
|
|
||||||
except KeyError:
|
|
||||||
irc.reply("I did not find a preset location for you. Set via: setweather location or specify a location")
|
|
||||||
return
|
|
||||||
|
|
||||||
# handle optlist (getopts). this will manipulate output via args dict.
|
# handle optlist (getopts). this will manipulate output via args dict.
|
||||||
if optlist:
|
if optlist:
|
||||||
for (key, value) in optlist:
|
for (key, value) in optlist:
|
||||||
@ -336,9 +346,33 @@ class Weather(callbacks.Plugin):
|
|||||||
args['dewpoint'] = True
|
args['dewpoint'] = True
|
||||||
if key == 'astronomy':
|
if key == 'astronomy':
|
||||||
args['astronomy'] = True
|
args['astronomy'] = True
|
||||||
|
if key == 'nocolortemp':
|
||||||
|
args['nocolortemp'] = True
|
||||||
|
if key == 'help': # make shift help because the docstring is overloaded above.
|
||||||
|
irc.reply("Options: --metric --alerts --forecast --almanac --pressure --wind --uv --visibility --dewpoint --astronomy --nocolortemp")
|
||||||
|
irc.reply("WeatherDB options: setweather <location> (set user's location). setmetric True/False (set metric option) setcolortemp True/False (display color temp?")
|
||||||
|
return
|
||||||
|
|
||||||
|
# now check if we have a location. if no location, use the WeatherDB.
|
||||||
|
if not optinput: # no location on input.
|
||||||
|
userloc = self.db.getweather(msg.nick.lower()) # check the db.
|
||||||
|
if userloc: # found a user so we change args w/info.
|
||||||
|
optinput = userloc['location'] # grab location.
|
||||||
|
# setmetric.
|
||||||
|
if userloc['metric'] == 0: # 0 = False for metric.
|
||||||
|
args['imperial'] = True # so we make sure we're using imperial.
|
||||||
|
elif userloc['metric'] == 1: # do the inverse.
|
||||||
|
args['imperial'] = False
|
||||||
|
# setcolortemp.
|
||||||
|
if userloc['colortemp'] == 0: # 0 = False for colortemp.
|
||||||
|
args['nocolortemp'] = True # disable
|
||||||
|
elif userloc['colortemp'] == 1: # do the inverse.
|
||||||
|
args['nocolortemp'] = False # show color temp.
|
||||||
|
else: # no user NOR optinput found. error msg.
|
||||||
|
irc.reply("ERROR: I did not find a preset location for you. Set via setweather <location>")
|
||||||
|
return
|
||||||
|
|
||||||
# build url now. first, apikey. then, iterate over urlArgs and insert.
|
# build url now. first, apikey. then, iterate over urlArgs and insert.
|
||||||
# urlArgs['features'] also manipulated via what's in args.
|
|
||||||
url = 'http://api.wunderground.com/api/%s/' % (self.APIKEY) # first part of url, w/APIKEY
|
url = 'http://api.wunderground.com/api/%s/' % (self.APIKEY) # first part of url, w/APIKEY
|
||||||
# now we need to set certain things for urlArgs based on args.
|
# now we need to set certain things for urlArgs based on args.
|
||||||
for check in ['alerts','almanac','astronomy']:
|
for check in ['alerts','almanac','astronomy']:
|
||||||
@ -351,42 +385,36 @@ class Weather(callbacks.Plugin):
|
|||||||
if key == "lang" or key == "bestfct" or key == "pws": # rest added with key:value
|
if key == "lang" or key == "bestfct" or key == "pws": # rest added with key:value
|
||||||
url += "{0}:{1}/".format(key, value)
|
url += "{0}:{1}/".format(key, value)
|
||||||
# finally, attach the q/input. url is now done.
|
# finally, attach the q/input. url is now done.
|
||||||
url += 'q/%s.json' % quote(optinput)
|
url += 'q/%s.json' % utils.web.urlquote(optinput)
|
||||||
|
|
||||||
#self.log.info(url)
|
# try and query url.
|
||||||
# try and query.
|
|
||||||
try:
|
try:
|
||||||
request = urllib2.Request(url)
|
page = utils.web.getUrl(url)
|
||||||
u = urllib2.urlopen(request)
|
except utils.web.Error as e:
|
||||||
except Exception as e:
|
self.log.error("ERROR: Trying to open {0} message: {1}".format(url, e))
|
||||||
self.log.info("Error loading {0} message {1}".format(url, e))
|
irc.reply("ERROR: Failed to load Weather Underground API: {0}".format(e))
|
||||||
irc.reply("Failed to load wunderground API: %s" % e)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# process the json, check (in orders) for errors, multiple results, and one last
|
# process json.
|
||||||
# sanity check. then we can process it.
|
data = json.loads(page.decode('utf-8'))
|
||||||
data = json.load(u)
|
|
||||||
|
|
||||||
# check if we got errors and return.
|
# now, a series of sanity checks before we process.
|
||||||
if 'error' in data['response']:
|
if 'error' in data['response']: # check if there are errors.
|
||||||
errortype = data['response']['error']['type']
|
errortype = data['response']['error']['type'] # type. description is below.
|
||||||
errordesc = data['response']['error'].get('description', 'no description')
|
errordesc = data['response']['error'].get('description', 'no description')
|
||||||
irc.reply("{0} I got an error searching for {1}. ({2}: {3})".format(self._red("ERROR:"), optinput, errortype, errordesc))
|
irc.reply("ERROR: I got an error searching for {0}. ({1}: {2})".format(optinput, errortype, errordesc))
|
||||||
return
|
return
|
||||||
|
|
||||||
# if there is more than one city matching.
|
# if there is more than one city matching.
|
||||||
if 'results' in data['response']:
|
if 'results' in data['response']: # results only comes when location matches more than one.
|
||||||
output = [item['city'] + ", " + item['state'] + " (" + item['country_name'] + ")" for item in data['response']['results']]
|
output = [i['city'] + ", " + i['state'] + " (" + i['country_name'] + ")" for i in data['response']['results']]
|
||||||
irc.reply("More than 1 city matched your query, try being more specific: {0}".format(" | ".join(output)))
|
irc.reply("ERROR: More than 1 city matched your query, try being more specific: {0}".format(" | ".join(output)))
|
||||||
return
|
return
|
||||||
|
|
||||||
# last sanity check
|
# last sanity check
|
||||||
if not data.has_key('current_observation'):
|
if not data.has_key('current_observation'):
|
||||||
irc.reply("{0} something went horribly wrong looking up weather for {1}. Contact the plugin owner.".format(self._red("ERROR:"), optinput))
|
irc.reply("ERROR: something went horribly wrong looking up weather for {0}. Contact the plugin owner.".format(optinput))
|
||||||
return
|
return
|
||||||
|
|
||||||
# done with error checking.
|
# no errors so we start the main part of processing.
|
||||||
# now, put everything into outdata dict for output later.
|
|
||||||
outdata = {}
|
outdata = {}
|
||||||
outdata['weather'] = data['current_observation']['weather']
|
outdata['weather'] = data['current_observation']['weather']
|
||||||
outdata['location'] = data['current_observation']['display_location']['full']
|
outdata['location'] = data['current_observation']['display_location']['full']
|
||||||
@ -394,28 +422,26 @@ class Weather(callbacks.Plugin):
|
|||||||
outdata['uv'] = data['current_observation']['UV']
|
outdata['uv'] = data['current_observation']['UV']
|
||||||
|
|
||||||
# handle wind. check if there is none first.
|
# handle wind. check if there is none first.
|
||||||
if args['imperial']:
|
|
||||||
if data['current_observation']['wind_mph'] < 1: # no wind.
|
if data['current_observation']['wind_mph'] < 1: # no wind.
|
||||||
outdata['wind'] = "None"
|
outdata['wind'] = "None"
|
||||||
else:
|
else: # we do have wind. process differently.
|
||||||
|
if args['imperial']: # imperial units for wind.
|
||||||
outdata['wind'] = "{0}@{1}mph".format(self._wind(data['current_observation']['wind_degrees']), data['current_observation']['wind_mph'])
|
outdata['wind'] = "{0}@{1}mph".format(self._wind(data['current_observation']['wind_degrees']), data['current_observation']['wind_mph'])
|
||||||
if data['current_observation']['wind_gust_mph'] > 0:
|
if data['current_observation']['wind_gust_mph'] > 0: # gusts?
|
||||||
outdata['wind'] += " ({0}mph gusts)".format(data['current_observation']['wind_gust_mph'])
|
outdata['wind'] += " ({0}mph gusts)".format(data['current_observation']['wind_gust_mph'])
|
||||||
else:
|
else: # handle metric units for wind.
|
||||||
if data['current_observation']['wind_kph'] < 1: # no wind.
|
|
||||||
outdata['wind'] = "None"
|
|
||||||
else:
|
|
||||||
outdata['wind'] = "{0}@{1}kph".format(self._wind(data['current_observation']['wind_degrees']),data['current_observation']['wind_kph'])
|
outdata['wind'] = "{0}@{1}kph".format(self._wind(data['current_observation']['wind_degrees']),data['current_observation']['wind_kph'])
|
||||||
if data['current_observation']['wind_gust_kph'] > 0:
|
if data['current_observation']['wind_gust_kph'] > 0: # gusts?
|
||||||
outdata['wind'] += " ({0}kph gusts)".format(data['current_observation']['wind_gust_kph'])
|
outdata['wind'] += " ({0}kph gusts)".format(data['current_observation']['wind_gust_kph'])
|
||||||
|
|
||||||
# handle the time. concept/method from WunderWeather plugin.
|
# handle the time. concept/method from WunderWeather plugin.
|
||||||
observationTime = data['current_observation'].get('observation_epoch', None)
|
observationTime = data['current_observation'].get('observation_epoch')
|
||||||
localTime = data['current_observation'].get('local_epoch', None)
|
localTime = data['current_observation'].get('local_epoch')
|
||||||
if not observationTime or not localTime: # if we don't have the epoches from above, default to obs_time
|
# if we don't have the epoches from above, default to obs_time
|
||||||
|
if not observationTime or not localTime:
|
||||||
outdata['observation'] = data.get('observation_time', 'unknown').lstrip('Last Updated on ')
|
outdata['observation'] = data.get('observation_time', 'unknown').lstrip('Last Updated on ')
|
||||||
else: # format for relative time.
|
else: # we do have so format for relative time.
|
||||||
s = int(localTime) - int(observationTime)
|
s = int(localTime) - int(observationTime) # format into seconds.
|
||||||
if s <= 1:
|
if s <= 1:
|
||||||
outdata['observation'] = 'just now'
|
outdata['observation'] = 'just now'
|
||||||
elif s < 60:
|
elif s < 60:
|
||||||
@ -429,8 +455,8 @@ class Weather(callbacks.Plugin):
|
|||||||
else:
|
else:
|
||||||
outdata['observation'] = '{0}hrs ago'.format(s/3600)
|
outdata['observation'] = '{0}hrs ago'.format(s/3600)
|
||||||
|
|
||||||
# all conditionals for imperial/metric
|
# handle basics like temp/pressure/dewpoint.
|
||||||
if args['imperial']:
|
if args['imperial']: # assigns the symbol based on metric.
|
||||||
outdata['temp'] = str(data['current_observation']['temp_f']) + 'F'
|
outdata['temp'] = str(data['current_observation']['temp_f']) + 'F'
|
||||||
outdata['pressure'] = data['current_observation']['pressure_in'] + 'in'
|
outdata['pressure'] = data['current_observation']['pressure_in'] + 'in'
|
||||||
outdata['dewpoint'] = str(data['current_observation']['dewpoint_f']) + 'F'
|
outdata['dewpoint'] = str(data['current_observation']['dewpoint_f']) + 'F'
|
||||||
@ -438,7 +464,7 @@ class Weather(callbacks.Plugin):
|
|||||||
outdata['windchill'] = str(data['current_observation']['windchill_f']) + 'F'
|
outdata['windchill'] = str(data['current_observation']['windchill_f']) + 'F'
|
||||||
outdata['feelslike'] = str(data['current_observation']['feelslike_f']) + 'F'
|
outdata['feelslike'] = str(data['current_observation']['feelslike_f']) + 'F'
|
||||||
outdata['visibility'] = str(data['current_observation']['visibility_mi']) + 'mi'
|
outdata['visibility'] = str(data['current_observation']['visibility_mi']) + 'mi'
|
||||||
else:
|
else: # metric.
|
||||||
outdata['temp'] = str(data['current_observation']['temp_c']) + 'C'
|
outdata['temp'] = str(data['current_observation']['temp_c']) + 'C'
|
||||||
outdata['pressure'] = data['current_observation']['pressure_mb'] + 'mb'
|
outdata['pressure'] = data['current_observation']['pressure_mb'] + 'mb'
|
||||||
outdata['dewpoint'] = str(data['current_observation']['dewpoint_c']) + 'C'
|
outdata['dewpoint'] = str(data['current_observation']['dewpoint_c']) + 'C'
|
||||||
@ -447,31 +473,30 @@ class Weather(callbacks.Plugin):
|
|||||||
outdata['feelslike'] = str(data['current_observation']['feelslike_c']) + 'C'
|
outdata['feelslike'] = str(data['current_observation']['feelslike_c']) + 'C'
|
||||||
outdata['visibility'] = str(data['current_observation']['visibility_km']) + 'km'
|
outdata['visibility'] = str(data['current_observation']['visibility_km']) + 'km'
|
||||||
|
|
||||||
# handle forecast data part. output will be below.
|
# handle forecast data part. output will be below. (not --forecast)
|
||||||
# this is not the --forecast part.
|
forecastdata = {} # key = int(day), value = forecast dict.
|
||||||
forecastdata = {}
|
|
||||||
for forecastday in data['forecast']['txt_forecast']['forecastday']:
|
for forecastday in data['forecast']['txt_forecast']['forecastday']:
|
||||||
tmpdict = {}
|
tmpdict = {}
|
||||||
tmpdict['day'] = forecastday['title']
|
tmpdict['day'] = forecastday['title']
|
||||||
tmpdict['symbol'] = self._weatherSymbol(forecastday['icon'])
|
tmpdict['symbol'] = self._weatherSymbol(forecastday['icon'])
|
||||||
if args['imperial']:
|
if args['imperial']: # imperial.
|
||||||
tmpdict['text'] = forecastday['fcttext']
|
tmpdict['text'] = forecastday['fcttext']
|
||||||
else:
|
else: # metric.
|
||||||
tmpdict['text'] = forecastday['fcttext_metric']
|
tmpdict['text'] = forecastday['fcttext_metric']
|
||||||
forecastdata[int(forecastday['period'])] = tmpdict
|
forecastdata[int(forecastday['period'])] = tmpdict
|
||||||
|
|
||||||
# now this is the --forecast part.
|
# now this is the --forecast part.
|
||||||
if args['forecast']:
|
if args['forecast']: # only if we get this in getopts.
|
||||||
fullforecastdata = {}
|
fullforecastdata = {} # key = day (int), value = dict of forecast data.
|
||||||
for forecastday in data['forecast']['simpleforecast']['forecastday']:
|
for forecastday in data['forecast']['simpleforecast']['forecastday']:
|
||||||
tmpdict = {}
|
tmpdict = {}
|
||||||
tmpdict['day'] = forecastday['date']['weekday_short']
|
tmpdict['day'] = forecastday['date']['weekday_short']
|
||||||
tmpdict['symbol'] = self._weatherSymbol(forecastday['icon'])
|
tmpdict['symbol'] = self._weatherSymbol(forecastday['icon'])
|
||||||
tmpdict['text'] = forecastday['conditions']
|
tmpdict['text'] = forecastday['conditions']
|
||||||
if args['imperial']:
|
if args['imperial']: # imperial.
|
||||||
tmpdict['high'] = forecastday['high']['fahrenheit'] + "F"
|
tmpdict['high'] = forecastday['high']['fahrenheit'] + "F"
|
||||||
tmpdict['low'] = forecastday['low']['fahrenheit'] + "F"
|
tmpdict['low'] = forecastday['low']['fahrenheit'] + "F"
|
||||||
else:
|
else: # metric.
|
||||||
tmpdict['high'] = forecastday['high']['celsius'] + "C"
|
tmpdict['high'] = forecastday['high']['celsius'] + "C"
|
||||||
tmpdict['low'] = forecastday['low']['celsius'] + "C"
|
tmpdict['low'] = forecastday['low']['celsius'] + "C"
|
||||||
fullforecastdata[int(forecastday['period'])] = tmpdict
|
fullforecastdata[int(forecastday['period'])] = tmpdict
|
||||||
@ -480,12 +505,12 @@ class Weather(callbacks.Plugin):
|
|||||||
if args['almanac']:
|
if args['almanac']:
|
||||||
outdata['highyear'] = data['almanac']['temp_high']['recordyear']
|
outdata['highyear'] = data['almanac']['temp_high']['recordyear']
|
||||||
outdata['lowyear'] = data['almanac']['temp_low']['recordyear']
|
outdata['lowyear'] = data['almanac']['temp_low']['recordyear']
|
||||||
if args['imperial']:
|
if args['imperial']: # imperial.
|
||||||
outdata['highnormal'] = data['almanac']['temp_high']['normal']['F'] + "F"
|
outdata['highnormal'] = data['almanac']['temp_high']['normal']['F'] + "F"
|
||||||
outdata['highrecord'] = data['almanac']['temp_high']['record']['F'] + "F"
|
outdata['highrecord'] = data['almanac']['temp_high']['record']['F'] + "F"
|
||||||
outdata['lownormal'] = data['almanac']['temp_low']['normal']['F'] + "F"
|
outdata['lownormal'] = data['almanac']['temp_low']['normal']['F'] + "F"
|
||||||
outdata['lowrecord'] = data['almanac']['temp_low']['record']['F'] + "F"
|
outdata['lowrecord'] = data['almanac']['temp_low']['record']['F'] + "F"
|
||||||
else:
|
else: # metric.
|
||||||
outdata['highnormal'] = data['almanac']['temp_high']['normal']['C'] + "C"
|
outdata['highnormal'] = data['almanac']['temp_high']['normal']['C'] + "C"
|
||||||
outdata['highrecord'] = data['almanac']['temp_high']['record']['C'] + "C"
|
outdata['highrecord'] = data['almanac']['temp_high']['record']['C'] + "C"
|
||||||
outdata['lownormal'] = data['almanac']['temp_low']['normal']['C'] + "C"
|
outdata['lownormal'] = data['almanac']['temp_low']['normal']['C'] + "C"
|
||||||
@ -499,99 +524,86 @@ class Weather(callbacks.Plugin):
|
|||||||
sunrisem = int(data['moon_phase']['sunrise']['minute'])
|
sunrisem = int(data['moon_phase']['sunrise']['minute'])
|
||||||
sunseth = int(data['moon_phase']['sunset']['hour'])
|
sunseth = int(data['moon_phase']['sunset']['hour'])
|
||||||
sunsetm = int(data['moon_phase']['sunset']['minute'])
|
sunsetm = int(data['moon_phase']['sunset']['minute'])
|
||||||
outdata['sunrise'] = "{0}:{1}".format(sunriseh,sunrisem)
|
outdata['sunrise'] = "{0}:{1}".format(sunriseh, sunrisem) # construct sunrise.
|
||||||
outdata['sunset'] = "{0}:{1}".format(sunseth,sunsetm)
|
outdata['sunset'] = "{0}:{1}".format(sunseth, sunsetm) # construct sunset. calc "time of day" below.
|
||||||
outdata['lengthofday'] = "%dh%dm" % divmod((((sunseth-sunriseh)+float((sunsetm-sunrisem)/60.0))*60),60)
|
outdata['lengthofday'] = "%dh%dm" % divmod((((sunseth-sunriseh)+float((sunsetm-sunrisem)/60.0))*60),60)
|
||||||
|
|
||||||
# handle alerts
|
# handle alerts
|
||||||
if args['alerts']:
|
if args['alerts']: # only look for alerts if there.
|
||||||
if data['alerts']:
|
if data['alerts']: # alerts is a list. it can also be empty.
|
||||||
outdata['alerts'] = data['alerts'][:300] # alert limit to 300.
|
outdata['alerts'] = data['alerts'][:300] # limit chars to 300.
|
||||||
else:
|
else: # no alerts found (empty).
|
||||||
outdata['alerts'] = "No alerts."
|
outdata['alerts'] = "No alerts."
|
||||||
|
|
||||||
# OUTPUT
|
# OUTPUT.
|
||||||
# now, build output object with what to output. ° u" \u00B0C"
|
# we go step-by-step to build the proper string. ° u" \u00B0C"
|
||||||
if self.registryValue('disableColoredTemp'):
|
output = "Weather for {0} :: {1}".format(self._bold(outdata['location'].encode('utf-8')), outdata['weather'].encode('utf-8'))
|
||||||
output = "Weather for {0} :: {1} ({2})".format(self._bold(outdata['location']),\
|
if args['nocolortemp']: # don't color temp.
|
||||||
outdata['weather'],outdata['temp'])
|
output += " {0}".format(outdata['temp'])
|
||||||
else:
|
else: # colored temperature.
|
||||||
output = "Weather for {0} :: {1} ({2})".format(self._bold(outdata['location']),\
|
output += " {0}".format(self._temp(outdata['temp']))
|
||||||
outdata['weather'],self._temp(outdata['temp']))
|
|
||||||
# windchill/heatindex are conditional on season but test with startswith to see what to include
|
# windchill/heatindex are conditional on season but test with startswith to see what to include
|
||||||
if not outdata['windchill'].startswith("NA"):
|
if not outdata['windchill'].startswith("NA"): # windchill.
|
||||||
if self.registryValue('disableColoredTemp'):
|
if args['nocolortemp']: # don't color windchill.
|
||||||
output += " | {0} {1}".format(self._bold('Wind Chill:'), outdata['windchill'])
|
output += " | {0} {1}".format(self._bold('Wind Chill:'), outdata['windchill'])
|
||||||
else:
|
else: # color wind chill.
|
||||||
output += " | {0} {1}".format(self._bold('Wind Chill:'), self._temp(outdata['windchill']))
|
output += " | {0} {1}".format(self._bold('Wind Chill:'), self._temp(outdata['windchill']))
|
||||||
if not outdata['heatindex'].startswith("NA"):
|
if not outdata['heatindex'].startswith("NA"): # heatindex.
|
||||||
if self.registryValue('disableColoredTemp'):
|
if args['nocolortemp']: # don't color heatindex.
|
||||||
output += " | {0} {1}".format(self._bold('Heat Index:'), outdata['heatindex'])
|
output += " | {0} {1}".format(self._bold('Heat Index:'), outdata['heatindex'])
|
||||||
else:
|
else: # color heat index.
|
||||||
output += " | {0} {1}".format(self._bold('Heat Index:'), self._temp(outdata['heatindex']))
|
output += " | {0} {1}".format(self._bold('Heat Index:'), self._temp(outdata['heatindex']))
|
||||||
# now get into the args dict for what to include (extras)
|
# now get into the args dict for what to include (extras)
|
||||||
for (k, v) in args.items():
|
for (k, v) in args.items():
|
||||||
if k in ['wind', 'visibility', 'uv', 'pressure', 'dewpoint']: # if key is in extras
|
if k in ['wind', 'visibility', 'uv', 'pressure', 'dewpoint']: # if key is in extras
|
||||||
if v: # if that key's value is True
|
if v: # if that key's value is True, we add it.
|
||||||
output += " | {0}: {1}".format(self._bold(k.title()), outdata[k])
|
output += " | {0}: {1}".format(self._bold(k.title()), outdata[k].encode('utf-8'))
|
||||||
# add in the first forecast item in conditions + updated time.
|
# add in the first two forecast item in conditions + updated time.
|
||||||
output += " | {0}: {1} {2}: {3}".format(self._bold(forecastdata[0]['day']),\
|
output += " | {0}: {1}".format(self._bold(forecastdata[0]['day'].encode('utf-8')), forecastdata[0]['text'].encode('utf-8'))
|
||||||
forecastdata[0]['text'],self._bold(forecastdata[1]['day']),forecastdata[1]['text'])
|
output += " {0}: {1}".format(self._bold(forecastdata[1]['day'].encode('utf-8')), forecastdata[1]['text'].encode('utf-8'))
|
||||||
# show Updated?
|
# show Updated?
|
||||||
if args['updated']:
|
if args['updated']:
|
||||||
output += " | {0} {1}".format(self._bold('Updated:'), outdata['observation'])
|
output += " | {0} {1}".format(self._bold('Updated:'), outdata['observation'].encode('utf-8'))
|
||||||
# output.
|
# finally, output the basic weather.
|
||||||
if self.registryValue('disableANSI', msg.args[0]):
|
|
||||||
irc.reply(self._strip(output))
|
|
||||||
else:
|
|
||||||
irc.reply(output)
|
irc.reply(output)
|
||||||
|
|
||||||
# next, for outputting, handle the extras like alerts, almanac, etc.
|
# next, for outputting, handle the extras like alerts, almanac, astronomy, forecast.
|
||||||
if args['alerts']:
|
if args['alerts']: # if --alerts issued.
|
||||||
output = "{0} :: {1}".format(self._bu("Alerts:"),outdata['alerts'])
|
irc.reply("{0} :: {1}".format(self._bu("Alerts:"), outdata['alerts'].encode('utf-8')))
|
||||||
if self.registryValue('disableANSI', msg.args[0]):
|
# handle almanac if --almanac is given.
|
||||||
irc.reply(self._strip(output))
|
|
||||||
else:
|
|
||||||
irc.reply(output)
|
|
||||||
# handle almanac
|
|
||||||
if args['almanac']:
|
if args['almanac']:
|
||||||
if self.registryValue('disableColoredTemp'):
|
if args['nocolortemp']: # disable colored temp?
|
||||||
output = "{0} :: Normal High: {1} (Record: {2} in {3}) | Normal Low: {4} (Record: {5} in {6})".format(\
|
output = "{0} :: Normal High: {1} (Record: {2} in {3}) | Normal Low: {4} (Record: {5} in {6})".format(\
|
||||||
self._bu('Almanac:'),outdata['highnormal'],outdata['highrecord'],\
|
self._bu('Almanac:'), outdata['highnormal'], outdata['highrecord'], outdata['highyear'],\
|
||||||
outdata['highyear'],outdata['lownormal'],outdata['lowrecord'],outdata['lowyear'])
|
outdata['lownormal'], outdata['lowrecord'], outdata['lowyear'])
|
||||||
else:
|
else: # colored temp.
|
||||||
output = "{0} :: Normal High: {1} (Record: {2} in {3}) | Normal Low: {4} (Record: {5} in {6})".format(\
|
output = "{0} :: Normal High: {1} (Record: {2} in {3}) | Normal Low: {4} (Record: {5} in {6})".format(\
|
||||||
self._bu('Almanac:'), self._temp(outdata['highnormal']), self._temp(outdata['highrecord']),\
|
self._bu('Almanac:'), self._temp(outdata['highnormal']), self._temp(outdata['highrecord']),\
|
||||||
outdata['highyear'], self._temp(outdata['lownormal']), self._temp(outdata['lowrecord']), outdata['lowyear'])
|
outdata['highyear'], self._temp(outdata['lownormal']), self._temp(outdata['lowrecord']), outdata['lowyear'])
|
||||||
if self.registryValue('disableANSI', msg.args[0]):
|
# now output to irc.
|
||||||
irc.reply(self._strip(output))
|
|
||||||
else:
|
|
||||||
irc.reply(output)
|
irc.reply(output)
|
||||||
# handle astronomy
|
# handle astronomy if --astronomy is given.
|
||||||
if args['astronomy']:
|
if args['astronomy']:
|
||||||
output = "{0} Moon illum: {1}% Moon age: {2}d Sunrise: {3} Sunset: {4} Length of Day: {5}".format(self._bu('Astronomy:'),outdata['moonilluminated'],\
|
output = "{0} Moon illum: {1}% Moon age: {2}d Sunrise: {3} Sunset: {4} Length of Day: {5}".format(\
|
||||||
outdata['moonage'],outdata['sunrise'],outdata['sunset'], outdata['lengthofday'])
|
self._bu('Astronomy:'), outdata['moonilluminated'], outdata['moonage'],outdata['sunrise'],\
|
||||||
if self.registryValue('disableANSI', msg.args[0]):
|
outdata['sunset'], outdata['lengthofday'])
|
||||||
irc.reply(self._strip(output))
|
# irc output now.
|
||||||
else:
|
|
||||||
irc.reply(output)
|
irc.reply(output)
|
||||||
# handle main forecast if --forecast is given.
|
# handle main forecast if --forecast is given.
|
||||||
if args['forecast']:
|
if args['forecast']:
|
||||||
outforecast = [] # prep string for output.
|
outforecast = [] # prep string for output.
|
||||||
for (k, v) in fullforecastdata.items(): # iterate through forecast data.
|
for (k, v) in fullforecastdata.items(): # iterate through forecast data.
|
||||||
if self.registryValue('disableColoredTemp'):
|
if args['nocolortemp']:
|
||||||
outforecast.append("{0}: {1} ({2}/{3})".format(self._bold(v['day']),v['text'],\
|
outforecast.append("{0}: {1} ({2}/{3})".format(self._bold(v['day'].encode('utf-8')),\
|
||||||
v['high'],v['low']))
|
v['text'].encode('utf-8'), v['high'], v['low']))
|
||||||
else:
|
|
||||||
outforecast.append("{0}: {1} ({2}/{3})".format(self._bold(v['day']),v['text'],\
|
|
||||||
self._temp(v['high']),self._temp(v['low'])))
|
|
||||||
output = "{0} :: {1}".format(self._bu('Forecast:'), " | ".join(outforecast)) # string to output
|
|
||||||
if self.registryValue('disableANSI', msg.args[0]):
|
|
||||||
irc.reply(self._strip(output))
|
|
||||||
else:
|
else:
|
||||||
|
outforecast.append("{0}: {1} ({2}/{3})".format(self._bold(v['day'].encode('utf-8')),\
|
||||||
|
v['text'].encode('utf-8'), self._temp(v['high']), self._temp(v['low'])))
|
||||||
|
# construct our string to output.
|
||||||
|
output = "{0} :: {1}".format(self._bu('Forecast:'), " | ".join(outforecast))
|
||||||
|
# now output to irc.
|
||||||
irc.reply(output)
|
irc.reply(output)
|
||||||
|
|
||||||
|
|
||||||
wunderground = wrap(wunderground, [getopts({'alerts':'',
|
wunderground = wrap(wunderground, [getopts({'alerts':'',
|
||||||
'almanac':'',
|
'almanac':'',
|
||||||
'astronomy':'',
|
'astronomy':'',
|
||||||
@ -601,7 +613,9 @@ class Weather(callbacks.Plugin):
|
|||||||
'uv':'',
|
'uv':'',
|
||||||
'visibility':'',
|
'visibility':'',
|
||||||
'dewpoint':'',
|
'dewpoint':'',
|
||||||
'metric':''}), optional('text')])
|
'metric':'',
|
||||||
|
'nocolortemp':'',
|
||||||
|
'help':''}), optional('text')])
|
||||||
|
|
||||||
Class = Weather
|
Class = Weather
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user