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] [Permissions]
# List of users (hostmasks as regex) and the commands they are allowed to execute. # 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. # * 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@.* = *, yournickname\!yourusername@.* = *,
\!@some other user = join, part, invite \!@some other user = join, part, invite
.*\!murderer@(localhost|127(\.0){2}\.1) = die, .*\!murderer@(localhost|127(\.0){2}\.1) = die,

122
main.py
View file

@ -28,7 +28,7 @@
import sys, string, socket, re, signal, json, logging import sys, string, socket, re, signal, json, logging
from random import choice from random import choice
from time import sleep, time from time import sleep, time, strftime, localtime
from select import poll, POLLIN, POLLPRI, POLLOUT,\ from select import poll, POLLIN, POLLPRI, POLLOUT,\
POLLERR, POLLHUP, POLLNVAL POLLERR, POLLHUP, POLLNVAL
from threading import Thread, Event from threading import Thread, Event
@ -59,6 +59,9 @@ class pircbot():
forecast_cfg = {"Active": "0"}, forecast_cfg = {"Active": "0"},
logger = logging.getLogger(logging.basicConfig()) logger = logging.getLogger(logging.basicConfig())
): ):
self.log = logger
self.nicknames = nicknames self.nicknames = nicknames
self.ident = ident self.ident = ident
self.realname = realname self.realname = realname
@ -71,6 +74,9 @@ class pircbot():
self.query_type = query_type.upper() self.query_type = query_type.upper()
self.cmdprefix = command_prefix self.cmdprefix = command_prefix
self.msg_wait_time = float(msg_wait_time) 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.parser_wait_time = float(parser_wait_time)
self.users = users self.users = users
@ -78,10 +84,8 @@ class pircbot():
self.duckduckgo_cfg = duckduckgo_cfg self.duckduckgo_cfg = duckduckgo_cfg
self.forecast_cfg = forecast_cfg self.forecast_cfg = forecast_cfg
self.log = logger
self.user = {"mask":"", "nick":"", "ident":"", "host":""}
self.user = {}
self.socket = None self.socket = None
self.recvbuffer = bytearray(1024) self.recvbuffer = bytearray(1024)
@ -210,11 +214,15 @@ class pircbot():
if command == "PING": if command == "PING":
self.send("PONG %s" % params[0]) self.send("PONG %s" % params[0])
# PRIVMSG and NOTICE # PRIVMSG and NOTICE
elif command == "PRIVMSG" or command == "NOTICE": elif command == "PRIVMSG" or command == "NOTICE" and self.ready:
if params[1][0] == self.cmdprefix: args = []
args = [] for v in params[1].split(" "):
for v in params[1][1:].split(" "): if v!="": args.append(v)
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:]) rp = self.on_command(command, prefix, origin, params[0], args[0].lower(), args[1:])
if rp not in (None, ""): if rp not in (None, ""):
self.reply(origin, params[0], rp, command) self.reply(origin, params[0], rp, command)
@ -326,8 +334,11 @@ class pircbot():
self.send("".join(("PRIVMSG ", channel, " :", msg))) self.send("".join(("PRIVMSG ", channel, " :", msg)))
# replies to user by NOTICE or PRIVMSG # replies to user by NOTICE or PRIVMSG
def query(self, nick, msg, in_query_type): def query(self, nick, msg, in_query_type="", force_query_type=""):
self.send("".join((self.query_type if self.query_type!="" else in_query_type, " ", nick, " :", msg))) 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): def nick(self, nick):
self.exec_on_ready("".join(('self.send("JOIN %s" % "', channel, '")'))) 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. Params contains a list of originally space separated parameters.
""" """
numparams = len(params) numparams = len(params)
# hello ### INTERNAL ###
if command == "hello": # 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"] +"!")) greeting = "".join(("Hi " + origin["nick"] +"!"))
return greeting return greeting
# say # say <text>
elif command == "say": elif command == "say":
return " ".join(params) return " ".join(params)
# choose # choose <choice1>, <choice2>[, <choice3>[, ...]]
elif command == "choose": elif command == "choose":
choices = " ".join(params).split(", ")# if numparams>1 else params.split(", ") choices = " ".join(params).split(", ")# if numparams>1 else params.split(", ")
if choices[0] == "": if choices[0] == "":
@ -376,6 +416,7 @@ class pircbot():
else: else:
return choice(choices) return choice(choices)
### EXTERNAL ###
# DuckDuckGo, ddg <query> # DuckDuckGo, ddg <query>
elif command in ("duckduckgo", "ddg") and self.duckduckgo_cfg["Active"] == "1": elif command in ("duckduckgo", "ddg") and self.duckduckgo_cfg["Active"] == "1":
if numparams==0: if numparams==0:
@ -393,7 +434,7 @@ class pircbot():
) )
rj = json.loads(str(rp.readall(), "utf-8")) rj = json.loads(str(rp.readall(), "utf-8"))
empty_field_counter = 0 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 ("", []): if rj[elem] not in ("", []):
self.reply(origin, source, "%s: %s" % (elem, rj[elem]), in_query_type) self.reply(origin, source, "%s: %s" % (elem, rj[elem]), in_query_type)
else: else:
@ -404,14 +445,55 @@ class pircbot():
return "(Results from DuckDuckGo <https://duckduckgo.com>)" return "(Results from DuckDuckGo <https://duckduckgo.com>)"
else: else:
return "Error while querying DuckDuckGo, got HTTP-Status %i" % rp.getcode() return "Error while querying DuckDuckGo, got HTTP-Status %i" % rp.getcode()
# Forecast, fc, weather # Forecast, fc <query>
elif command in ("weather", "forecast", "fc") and self.forecast_cfg["Active"] == "1": elif command in ("forecast", "fc") and self.forecast_cfg["Active"] == "1":
if numparams==2: if numparams==2:
try: rp = urlopen("https://api.forecast.io/forecast/%s/%s?units=si&exclude=minutely,hourly,daily"
return "(Powered by Forecast <http://forecast.io/>)" % (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: else:
return "Usage: %s <lat> <lon>" % command return "Usage: %s <lat> <lon>" % command
### IRC ###
# join <channel> # join <channel>
elif command == "join": elif command == "join":
if numparams>0: if numparams>0: