1
0
Fork 0

added commands help and forecast

implemented usage of bot-nick as cmdprefix
changed min time for waiting between channel privmsgs to 0.1sec
changed the way pircbot.query() chooses between NOTICE or PRIVMSG
some minor fixes and commenting
This commit is contained in:
fanir 2014-03-07 15:21:38 +01:00
parent 421c206719
commit f7289a1ac4
2 changed files with 104 additions and 21 deletions

View file

@ -47,7 +47,8 @@ Modes = +iB
[Permissions]
# List of users (hostmasks as regex) and the commands they are allowed to execute.
# * can be used instead of commands to allow every command. You should append a trailing comma.
# All command names should be lowercase.
# All command names should be lowercase. Add "help" as a command if you want the user
# to see all aviable commands in the help message (is automatically included with "*").
yournickname\!yourusername@.* = *,
\!@some other user = join, part, invite
.*\!murderer@(localhost|127(\.0){2}\.1) = die,

122
main.py
View file

@ -28,7 +28,7 @@
import sys, string, socket, re, signal, json, logging
from random import choice
from time import sleep, time
from time import sleep, time, strftime, localtime
from select import poll, POLLIN, POLLPRI, POLLOUT,\
POLLERR, POLLHUP, POLLNVAL
from threading import Thread, Event
@ -59,6 +59,9 @@ class pircbot():
forecast_cfg = {"Active": "0"},
logger = logging.getLogger(logging.basicConfig())
):
self.log = logger
self.nicknames = nicknames
self.ident = ident
self.realname = realname
@ -71,6 +74,9 @@ class pircbot():
self.query_type = query_type.upper()
self.cmdprefix = command_prefix
self.msg_wait_time = float(msg_wait_time)
if self.msg_wait_time < 0.1:
self.log.info("msg_wait_time ist zu klein, nutze 0.1 Sekunden")
self.msg_wait_time = 0.1
self.parser_wait_time = float(parser_wait_time)
self.users = users
@ -78,10 +84,8 @@ class pircbot():
self.duckduckgo_cfg = duckduckgo_cfg
self.forecast_cfg = forecast_cfg
self.log = logger
self.user = {}
self.user = {"mask":"", "nick":"", "ident":"", "host":""}
self.socket = None
self.recvbuffer = bytearray(1024)
@ -210,11 +214,15 @@ class pircbot():
if command == "PING":
self.send("PONG %s" % params[0])
# PRIVMSG and NOTICE
elif command == "PRIVMSG" or command == "NOTICE":
if params[1][0] == self.cmdprefix:
args = []
for v in params[1][1:].split(" "):
if v!="": args.append(v)
elif command == "PRIVMSG" or command == "NOTICE" and self.ready:
args = []
for v in params[1].split(" "):
if v!="": args.append(v)
if len(args)>1 and args[0][0:len(self.user["nick"])] == self.user["nick"]:
args.pop(0)
args[0] = "".join((self.cmdprefix, args[0]))
if args[0][0] == self.cmdprefix:
args[0] = args[0][1:]
rp = self.on_command(command, prefix, origin, params[0], args[0].lower(), args[1:])
if rp not in (None, ""):
self.reply(origin, params[0], rp, command)
@ -326,8 +334,11 @@ class pircbot():
self.send("".join(("PRIVMSG ", channel, " :", msg)))
# replies to user by NOTICE or PRIVMSG
def query(self, nick, msg, in_query_type):
self.send("".join((self.query_type if self.query_type!="" else in_query_type, " ", nick, " :", msg)))
def query(self, nick, msg, in_query_type="", force_query_type=""):
self.send("".join((force_query_type if force_query_type!="" else
(self.query_type if self.query_type!="" else
(in_query_type if in_query_type!="" else
"PRIVMSG")), " ", nick, " :", msg)))
def nick(self, nick):
self.exec_on_ready("".join(('self.send("JOIN %s" % "', channel, '")')))
@ -359,14 +370,43 @@ class pircbot():
Params contains a list of originally space separated parameters.
"""
numparams = len(params)
# hello
if command == "hello":
### INTERNAL ###
# help [me]
if command == "help":
if numparams == 1 and params[0].startswith("me"):
rply = "\
Nope, you're on your own."
else:
rply = "\
Command Prefix is \"%s\" or \"%s\"\n\
\n\
Commands:\n\
hello [<...>]\n\
say <text>\n\
choose <choice1>, <choice2>[, <choice3>[, ...]] -- Let the bot decide!\n\
DuckDuckGo, ddg <query> -- Ask the DuckDuckGo Instant Answer API\n\
Forecast, fc <query> -- Query Forecast.io\n\
" % (
self.cmdprefix,
self.user["nick"]
)
if self.check_privileges(origin["mask"], command):
rply += " \n\
~ For the aristocrats ~\n\
join <channel>\n\
part <channel>\n\
mode ±<modes>\n\
die [<quitmsg>]"
for line in rply.splitlines(): self.query(origin["nick"], line[20:], force_query_type="PRIVMSG")
# hello [<...>]
elif command == "hello":
greeting = "".join(("Hi " + origin["nick"] +"!"))
return greeting
# say
# say <text>
elif command == "say":
return " ".join(params)
# choose
# choose <choice1>, <choice2>[, <choice3>[, ...]]
elif command == "choose":
choices = " ".join(params).split(", ")# if numparams>1 else params.split(", ")
if choices[0] == "":
@ -376,6 +416,7 @@ class pircbot():
else:
return choice(choices)
### EXTERNAL ###
# DuckDuckGo, ddg <query>
elif command in ("duckduckgo", "ddg") and self.duckduckgo_cfg["Active"] == "1":
if numparams==0:
@ -393,7 +434,7 @@ class pircbot():
)
rj = json.loads(str(rp.readall(), "utf-8"))
empty_field_counter = 0
for elem in [rj for rj in used_fields]:
for elem in [v for v in used_fields if v in rj]:
if rj[elem] not in ("", []):
self.reply(origin, source, "%s: %s" % (elem, rj[elem]), in_query_type)
else:
@ -404,14 +445,55 @@ class pircbot():
return "(Results from DuckDuckGo <https://duckduckgo.com>)"
else:
return "Error while querying DuckDuckGo, got HTTP-Status %i" % rp.getcode()
# Forecast, fc, weather
elif command in ("weather", "forecast", "fc") and self.forecast_cfg["Active"] == "1":
# Forecast, fc <query>
elif command in ("forecast", "fc") and self.forecast_cfg["Active"] == "1":
if numparams==2:
return "(Powered by Forecast <http://forecast.io/>)"
try: rp = urlopen("https://api.forecast.io/forecast/%s/%s?units=si&exclude=minutely,hourly,daily"
% (self.forecast_cfg["ApiKey"], quote_plus(",".join(params))))
except Exception as e:
self.log.error("Error while querying Forecast.io: %s" % e)
return "Error while querying Forecast.io: %s" % e
if rp.getcode() == 200:
rj = json.loads(str(rp.readall(), "utf-8"))
self.reply(origin, source,
strftime("CURRENTLY (%d.%m.%Y %H:%M:%S)", localtime(rj["currently"]["time"])), in_query_type)
self.reply(origin, source,
"Summary: %s" % rj["currently"]["summary"], in_query_type)
self.reply(origin, source,
"Temperature: %s °C" % rj["currently"]["temperature"], in_query_type)
self.reply(origin, source,
"Apparent Temperature: %s °C" % rj["currently"]["apparentTemperature"], in_query_type)
self.reply(origin, source,
"Dew Point: %s °C" % rj["currently"]["dewPoint"], in_query_type)
self.reply(origin, source,
"Wind Speed: %s m/s" % rj["currently"]["windSpeed"], in_query_type)
self.reply(origin, source,
"Cloud Cover: %s %%" % rj["currently"]["cloudCover"], in_query_type)
self.reply(origin, source,
"Precipitation Probability: %s %%" % (rj["currently"]["precipProbability"]*100), in_query_type)
if "precipIntensity" in rj["currently"]: self.reply(origin, source,
"Precipitation Intensity: %s mm/h" % rj["currently"]["precipIntensity"], in_query_type)
if "precipType" in rj["currently"]: self.reply(origin, source,
"Precipitation Type: %s" % rj["currently"]["precipType"], in_query_type)
self.reply(origin, source,
"Visibility: %s km" % rj["currently"]["visibility"], in_query_type)
self.reply(origin, source,
"Humidity: %s %%" % (rj["currently"]["humidity"]*100), in_query_type)
self.reply(origin, source,
"Pressure: %s hPa" % rj["currently"]["pressure"], in_query_type)
self.reply(origin, source,
"Ozone: %s DU" % rj["currently"]["ozone"], in_query_type)
if "nearestStormDistance" in rj["currently"]: self.reply(origin, source,
"Nearest Storm Distance: %s km" % rj["currently"]["nearestStormDistance"], in_query_type)
self.reply(origin, source,
"Sources: %s" % ", ".join(rj["flags"]["sources"]), in_query_type)
return "(Powered by Forecast <http://forecast.io/>)"
else:
return "Error while querying Forecast.io, got HTTP-Status %i" % rp.getcode()
else:
return "Usage: %s <lat> <lon>" % command
### IRC ###
# join <channel>
elif command == "join":
if numparams>0: