redone configuration: is now in an external file, parsed with configobj
redone logging, now using module logging of the standard library added argument "checkconf" for viewing the configuration added configuration options for external apis added option to wait between channel privmsgs added DuckDuckGo command prepared Forecast command
This commit is contained in:
parent
644da76873
commit
e1b0e83e98
3 changed files with 248 additions and 140 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
*.conf
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.nogit
|
91
bot.conf.example
Normal file
91
bot.conf.example
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
###########
|
||||||
|
### BOT ###
|
||||||
|
###########
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
|
||||||
|
# The Server name to connect to. Duh!
|
||||||
|
Server = fanir.de
|
||||||
|
|
||||||
|
# "Default" is 6667. An often used port for SSL would be 6697, if SSL would be
|
||||||
|
# supported. Maybe in a future, far far away...
|
||||||
|
Port = 6667
|
||||||
|
|
||||||
|
# Serverpassword. Empty in most cases.
|
||||||
|
ServerPasswd =
|
||||||
|
|
||||||
|
# A comma-seperated list of channels to join.
|
||||||
|
# The channels must be enclosed with quotation marks ("")!
|
||||||
|
Channels = "#bots", "#your_channel"
|
||||||
|
|
||||||
|
# The encodings to try when getting messages from IRC. Will be tried in the given order.
|
||||||
|
# The first one is used to encode data when sending stuff.
|
||||||
|
# The list given shoud do just fine in most networks, I assume.
|
||||||
|
# Also comma seperated.
|
||||||
|
Encodings = utf-8, latin-1, iso-8859-1, cp1252
|
||||||
|
|
||||||
|
|
||||||
|
[Bot]
|
||||||
|
# The list of nicknames to try. If the first one is not aviable, it will
|
||||||
|
# try the second, and so on...
|
||||||
|
# You should specfy at least two nicks.
|
||||||
|
Nicknames = chalkbot, chalkbot_, chalkbot__
|
||||||
|
|
||||||
|
# Also known as username. Some IRC-internal.
|
||||||
|
# By default, the nickname will be used as ident.
|
||||||
|
Ident = chalkbot
|
||||||
|
|
||||||
|
Realname = A ChalkBot Instance
|
||||||
|
|
||||||
|
# Command for registering with nickserv, without leading slash.
|
||||||
|
NickservCommand =
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
yournickname\!yourusername@.* = *,
|
||||||
|
\!@some other user = join, part, invite
|
||||||
|
.*\!murderer@(localhost|127(\.0){2}\.1) = die,
|
||||||
|
|
||||||
|
|
||||||
|
[Behavior]
|
||||||
|
# The prefix for commands for the bot.
|
||||||
|
CommandPrefix = !
|
||||||
|
|
||||||
|
# Which way should be used to speak to users?
|
||||||
|
# "" (Nothing) means the type of the incoming message should be used.
|
||||||
|
# One of: NOTICE, PRIVMSG, "" (Nothing)
|
||||||
|
QueryType =
|
||||||
|
|
||||||
|
# With how much information do you want to be annoyed?
|
||||||
|
# DEBUG spams most, FATAL least. WARNING should be a good tradeoff.
|
||||||
|
# One of: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||||
|
Loglevel = WARNING
|
||||||
|
|
||||||
|
# Time to wait between two PRIVMSGS in seconds.
|
||||||
|
# Can prevent the bot from running into flood limits.
|
||||||
|
MsgWaitTime = 0.1
|
||||||
|
|
||||||
|
# The time the parser for incoming data should wait between each attempt to read new data in seconds.
|
||||||
|
# High values will certainly make the bot reply slowly while very low values increads cpu load and therefore will perform badly on slow machines.
|
||||||
|
# You should keep it between 1 and 0.001 seconds.
|
||||||
|
# For gods sake, don't ever set it to 0!
|
||||||
|
ParserWaitTime = 0.05
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
### EXTERNAL SERVICES ###
|
||||||
|
#########################
|
||||||
|
|
||||||
|
[DuckDuckGo]
|
||||||
|
Active = True
|
||||||
|
|
||||||
|
[Forecast.io]
|
||||||
|
Active = False
|
||||||
|
ApiKey = your_api_key
|
292
main.py
292
main.py
|
@ -26,53 +26,60 @@
|
||||||
# SETTINGS CAN BE FOUND AT THE BOTTOM OF THE FILE
|
# SETTINGS CAN BE FOUND AT THE BOTTOM OF THE FILE
|
||||||
|
|
||||||
|
|
||||||
import sys, string, socket, re, signal
|
import sys, string, socket, re, signal, json, logging
|
||||||
from random import choice
|
from random import choice
|
||||||
from time import sleep
|
from time import sleep, time
|
||||||
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
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from urllib.parse import quote_plus
|
||||||
|
from configobj import ConfigObj
|
||||||
|
|
||||||
bot = None
|
bot = None
|
||||||
|
|
||||||
|
logging.basicConfig(format="[%(asctime)s] %(levelname)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||||
class log():
|
|
||||||
DEBUG, INFO, WARNING, ERROR, FATAL, SILENT =\
|
|
||||||
0, 1, 2, 3, 4, 5
|
|
||||||
|
|
||||||
levels = {
|
|
||||||
0: "[DEBUG] ", 1: "[INFO] ", 2: "[WARNING] ",
|
|
||||||
3: "[ERROR] ", 4: "[FATAL] ", 5: "[SILENT] "
|
|
||||||
}
|
|
||||||
|
|
||||||
def show(level, msg):
|
|
||||||
if level in range(log.DEBUG, log.SILENT):
|
|
||||||
if LOGLEVEL <= level: print("".join((log.levels[level], msg)))
|
|
||||||
else:
|
|
||||||
raise ValueError("That's not a loglevel!")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class pircbot():
|
class pircbot():
|
||||||
def __init__(self, nicknames, server, port=6667,
|
def __init__( self,
|
||||||
ident="pircbot", realname="pircbot", serverpasswd="",
|
server,
|
||||||
encodings=("utf-8", "latin-1"), users="",
|
nicknames,
|
||||||
query_type="", command_prefix=".",
|
ident = "pircbot",
|
||||||
parser_wait_time=0.1):
|
realname = "pircbot",
|
||||||
self.server = server
|
port = 6667,
|
||||||
self.port = port
|
serverpasswd = "",
|
||||||
self.serverpasswd = serverpasswd
|
encodings = ("utf-8", "latin-1"),
|
||||||
self.encodings = encodings
|
query_type = "",
|
||||||
|
command_prefix = "!",
|
||||||
|
msg_wait_time = 0,
|
||||||
|
parser_wait_time = 0.1,
|
||||||
|
users = "",
|
||||||
|
duckduckgo_cfg = {"Active": "0"},
|
||||||
|
forecast_cfg = {"Active": "0"},
|
||||||
|
logger = logging.getLogger(logging.basicConfig())
|
||||||
|
):
|
||||||
self.nicknames = nicknames
|
self.nicknames = nicknames
|
||||||
self.ident = ident
|
self.ident = ident
|
||||||
self.realname = realname
|
self.realname = realname
|
||||||
|
|
||||||
self.users = users
|
self.server = server
|
||||||
self.cmdprefix = command_prefix
|
self.port = int(port)
|
||||||
self.query_type = query_type.upper()
|
self.serverpasswd = serverpasswd
|
||||||
|
self.encodings = encodings
|
||||||
|
|
||||||
|
self.query_type = query_type.upper()
|
||||||
|
self.cmdprefix = command_prefix
|
||||||
|
self.msg_wait_time = float(msg_wait_time)
|
||||||
|
self.parser_wait_time = float(parser_wait_time)
|
||||||
|
|
||||||
|
self.users = users
|
||||||
|
|
||||||
|
self.duckduckgo_cfg = duckduckgo_cfg
|
||||||
|
self.forecast_cfg = forecast_cfg
|
||||||
|
|
||||||
|
self.log = logger
|
||||||
|
|
||||||
self.parser_wait_time=parser_wait_time
|
|
||||||
|
|
||||||
self.user = {}
|
self.user = {}
|
||||||
|
|
||||||
|
@ -86,15 +93,17 @@ class pircbot():
|
||||||
self.ready = False
|
self.ready = False
|
||||||
|
|
||||||
self.mode_reply = {}
|
self.mode_reply = {}
|
||||||
|
|
||||||
|
self.last_msg_ts = time()
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
# connect
|
# connect
|
||||||
self.socket = socket.socket()
|
self.socket = socket.socket()
|
||||||
log.show(log.DEBUG, "--- SOCKET OPENING ---")
|
self.log.debug("--- SOCKET OPENING ---")
|
||||||
try:
|
try:
|
||||||
self.socket.connect((self.server, self.port))
|
self.socket.connect((self.server, self.port))
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
log.show(log.FATAL, "Fehler: %s" % e)
|
self.log.critical("Fehler: %s" % e)
|
||||||
return
|
return
|
||||||
|
|
||||||
# start getting data
|
# start getting data
|
||||||
|
@ -120,7 +129,7 @@ class pircbot():
|
||||||
while self.recvloop.is_alive() and self.parseloop.is_alive() and ctr < 15:
|
while self.recvloop.is_alive() and self.parseloop.is_alive() and ctr < 15:
|
||||||
ctr += 1
|
ctr += 1
|
||||||
sleep(1)
|
sleep(1)
|
||||||
log.show(log.DEBUG, "--- SOCKET CLOSING ---")
|
self.log.debug("--- SOCKET CLOSING ---")
|
||||||
try:
|
try:
|
||||||
self.socket.shutdown(socket.SHUT_RDWR)
|
self.socket.shutdown(socket.SHUT_RDWR)
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
|
@ -134,7 +143,7 @@ class pircbot():
|
||||||
"""
|
"""
|
||||||
Loop for reciving data
|
Loop for reciving data
|
||||||
"""
|
"""
|
||||||
log.show(log.DEBUG, "--- RECVLOOP STARTING ---")
|
self.log.debug("--- RECVLOOP STARTING ---")
|
||||||
self.parseloop = Thread(target=self.parser, name="parser")
|
self.parseloop = Thread(target=self.parser, name="parser")
|
||||||
p = poll()
|
p = poll()
|
||||||
p.register(self.socket.fileno(), POLLIN)
|
p.register(self.socket.fileno(), POLLIN)
|
||||||
|
@ -145,14 +154,14 @@ class pircbot():
|
||||||
if not self.parseloop.is_alive():
|
if not self.parseloop.is_alive():
|
||||||
self.parseloop = Thread(target=self.parser, name="parser")
|
self.parseloop = Thread(target=self.parser, name="parser")
|
||||||
self.parseloop.start()
|
self.parseloop.start()
|
||||||
log.show(log.DEBUG, "--- RECVLOOP EXITING ---")
|
self.log.debug("--- RECVLOOP EXITING ---")
|
||||||
|
|
||||||
# loop for parsing incoming data
|
# loop for parsing incoming data
|
||||||
def parser(self):
|
def parser(self):
|
||||||
"""
|
"""
|
||||||
Loop for parsing incoming data
|
Loop for parsing incoming data
|
||||||
"""
|
"""
|
||||||
log.show(log.DEBUG, "--- PARSELOOP STARTING ---")
|
self.log.debug("--- PARSELOOP STARTING ---")
|
||||||
while not self.die_event.is_set():# and self.recvbuffer.endswith(b"\r\n"):# != b"":
|
while not self.die_event.is_set():# and self.recvbuffer.endswith(b"\r\n"):# != b"":
|
||||||
if self.recvbuffer.endswith(b"\r\n"):
|
if self.recvbuffer.endswith(b"\r\n"):
|
||||||
# get and decode line from buffer
|
# get and decode line from buffer
|
||||||
|
@ -179,7 +188,7 @@ class pircbot():
|
||||||
params = head
|
params = head
|
||||||
params.append(larg.strip())
|
params.append(larg.strip())
|
||||||
|
|
||||||
log.show(log.DEBUG, " > %s" % rawline)
|
self.log.debug(" > %s" % rawline)
|
||||||
|
|
||||||
# PING
|
# PING
|
||||||
if command == "PING":
|
if command == "PING":
|
||||||
|
@ -213,11 +222,11 @@ class pircbot():
|
||||||
self.send("NICK %s" % self.nicknames.pop(0))
|
self.send("NICK %s" % self.nicknames.pop(0))
|
||||||
# KILL
|
# KILL
|
||||||
elif command == "KILL":
|
elif command == "KILL":
|
||||||
log.show(log.WARNING, "Got killed by %s: %s" % (params[0], params[1:]))
|
self.log.warning("Got killed by %s: %s" % (params[0], params[1:]))
|
||||||
self.disconnect(send_quit=False)
|
self.disconnect(send_quit=False)
|
||||||
else:
|
else:
|
||||||
sleep(self.parser_wait_time)
|
sleep(self.parser_wait_time)
|
||||||
log.show(log.DEBUG, "--- PARSELOOP EXITING ---")
|
self.log.debug("--- PARSELOOP EXITING ---")
|
||||||
|
|
||||||
|
|
||||||
### helper functions ###
|
### helper functions ###
|
||||||
|
@ -259,12 +268,12 @@ class pircbot():
|
||||||
cnt = 0
|
cnt = 0
|
||||||
while not self.ready and cnt<retry_times: sleep(interval)
|
while not self.ready and cnt<retry_times: sleep(interval)
|
||||||
if not self.ready:
|
if not self.ready:
|
||||||
log.show(log.WARNING, "Connection did not get ready in time (%sx %s seconds), \"%s\" not executed" % (retry_times, interval, command))
|
self.log.warning("Connection did not get ready in time (%sx %s seconds), \"%s\" not executed" % (retry_times, interval, command))
|
||||||
return True
|
return True
|
||||||
exec("ret = %s" % command)
|
exec("ret = %s" % command)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
log.show(log.FATAL, "exec_on_ready() called with an invalid command: %s" % command)
|
self.log.critical("exec_on_ready() called with an invalid command: %s" % command)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def exec_retry(self, command, times=5, interval=1, wait_for_ready=True):
|
def exec_retry(self, command, times=5, interval=1, wait_for_ready=True):
|
||||||
|
@ -273,14 +282,14 @@ class pircbot():
|
||||||
while not self.ready: sleep(interval)
|
while not self.ready: sleep(interval)
|
||||||
cnt = 0
|
cnt = 0
|
||||||
exec("while %s and cnt<times: sleep(interval)" % command)
|
exec("while %s and cnt<times: sleep(interval)" % command)
|
||||||
else: log.show(log.FATAL, "exec_retry() called with an invalid command.")
|
else: self.log.critical("exec_retry() called with an invalid command.")
|
||||||
|
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
log.show(log.DEBUG, "< %s" % data)
|
self.log.debug("< %s" % data)
|
||||||
try: self.socket.send(self.encode("".join((data, "\r\n"))))
|
try: self.socket.send(self.encode("".join((data, "\r\n"))))
|
||||||
except BrokenPipeError as e:
|
except Exception as e:
|
||||||
log.show(log.FATAL, e)
|
self.log.critical(e)
|
||||||
self.disconnect(send_quit=False)
|
self.disconnect(send_quit=False)
|
||||||
|
|
||||||
# decides whether to reply to user or to channel
|
# decides whether to reply to user or to channel
|
||||||
|
@ -295,6 +304,9 @@ class pircbot():
|
||||||
|
|
||||||
# replies to channel by PRIVMSG
|
# replies to channel by PRIVMSG
|
||||||
def chanmsg(self, channel, msg):
|
def chanmsg(self, channel, msg):
|
||||||
|
while self.last_msg_ts + self.msg_wait_time > time():
|
||||||
|
sleep(0.1)
|
||||||
|
self.last_msg_ts = time()
|
||||||
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
|
||||||
|
@ -330,6 +342,7 @@ class pircbot():
|
||||||
Command is the command for the bot.
|
Command is the command for the bot.
|
||||||
Params contains a list of originally space separated parameters.
|
Params contains a list of originally space separated parameters.
|
||||||
"""
|
"""
|
||||||
|
numparams = len(params)
|
||||||
# hello
|
# hello
|
||||||
if command == "hello":
|
if command == "hello":
|
||||||
greeting = "".join(("Hi " + origin["nick"] +"!"))
|
greeting = "".join(("Hi " + origin["nick"] +"!"))
|
||||||
|
@ -337,30 +350,68 @@ class pircbot():
|
||||||
# say
|
# say
|
||||||
if command == "say":
|
if command == "say":
|
||||||
return " ".join(params)
|
return " ".join(params)
|
||||||
|
|
||||||
|
# DuckDuckGo, ddg <query>
|
||||||
|
elif command in ("duckduckgo", "ddg") and self.duckduckgo_cfg["Active"] == "1":
|
||||||
|
if numparams==0:
|
||||||
|
return "You didn't ask anything..."
|
||||||
|
try: rp = urlopen("https://api.duckduckgo.com/?q=%s&format=json&no_html=1&no_redirect=1&t=pircbot:chalkbot"
|
||||||
|
% quote_plus(" ".join(params)))
|
||||||
|
except Exception as e:
|
||||||
|
self.log.error("Error while querying DuckDuckGo: %s" % e)
|
||||||
|
return "Error while querying DuckDuckGo: %s" % e
|
||||||
|
if rp.getcode() == 200:
|
||||||
|
used_fields = (
|
||||||
|
"Heading", "AbstractText", "AbstractSource", "AbstractURL",
|
||||||
|
"AnswerType", "Answer",
|
||||||
|
"Definition", "DefinitionSource", "DefinitionURL",
|
||||||
|
)
|
||||||
|
rj = json.loads(str(rp.readall(), "utf-8"))
|
||||||
|
empty_field_counter = 0
|
||||||
|
for elem in [rj for rj in used_fields]:
|
||||||
|
if rj[elem] not in ("", []):
|
||||||
|
self.reply(origin, source, "%s: %s" % (elem, rj[elem]), in_query_type)
|
||||||
|
else:
|
||||||
|
empty_field_counter+=1
|
||||||
|
if empty_field_counter == len(used_fields):
|
||||||
|
return "No suitable reply from DuckDuckGo for query %s" % " ".join(params)
|
||||||
|
else:
|
||||||
|
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":
|
||||||
|
if numparams==2:
|
||||||
|
|
||||||
|
return "(Powered by Forecast <http://forecast.io/>)"
|
||||||
|
else:
|
||||||
|
return "Usage: %s <lat> <lon>" % command
|
||||||
|
|
||||||
# join <channel>
|
# join <channel>
|
||||||
elif command == "join":
|
elif command == "join":
|
||||||
if len(params)>0:
|
if numparams>0:
|
||||||
if self.check_privileges(origin["mask"], command): self.join(params[0])
|
if self.check_privileges(origin["mask"], command): self.join(params[0])
|
||||||
else: self.query(origin["nick"], "You cannot do that!", in_query_type)
|
else: self.query(origin["nick"], "You cannot do that!", in_query_type)
|
||||||
# part <channel>
|
# part <channel>
|
||||||
elif command == "part":
|
elif command == "part":
|
||||||
if len(params)>0:
|
if numparams>0:
|
||||||
if self.check_privileges(origin["mask"], command): self.part(params[0])
|
if self.check_privileges(origin["mask"], command): self.part(params[0])
|
||||||
else: self.query(origin["nick"], "You cannot do that!", in_query_type)
|
else: self.query(origin["nick"], "You cannot do that!", in_query_type)
|
||||||
# mode ±<modes>
|
# mode ±<modes>
|
||||||
elif command == "mode":
|
elif command == "mode":
|
||||||
if self.check_privileges(origin["mask"], command):
|
if self.check_privileges(origin["mask"], command):
|
||||||
if len(params)==0:
|
if numparams==0:
|
||||||
self.mode_reply["to"] = origin["nick"]
|
self.mode_reply["to"] = origin["nick"]
|
||||||
self.mode_reply["type"] = in_query_type
|
self.mode_reply["type"] = in_query_type
|
||||||
self.get_modes()
|
self.get_modes()
|
||||||
else:
|
else:
|
||||||
self.set_mode(" ".join(params) if len(params)>0 else params)
|
self.set_mode(" ".join(params) if numparams>0 else params)
|
||||||
else: self.query(origin["nick"], "You cannot do that!", in_query_type)
|
else: self.query(origin["nick"], "You cannot do that!", in_query_type)
|
||||||
|
|
||||||
# die [<quitmsg>]
|
# die [<quitmsg>]
|
||||||
elif command == "die":
|
elif command == "die":
|
||||||
if self.check_privileges(origin["mask"], command):
|
if self.check_privileges(origin["mask"], command):
|
||||||
self.disconnect("".join(params) if len(params)>0 else "".join((origin["nick"], " shot me, dying now... Bye...")))
|
self.disconnect("".join(params) if numparams>0 else "".join((origin["nick"], " shot me, dying now... Bye...")))
|
||||||
else: self.query(origin["nick"], "Go die yourself!", in_query_type)
|
else: self.query(origin["nick"], "Go die yourself!", in_query_type)
|
||||||
else:
|
else:
|
||||||
replies = [
|
replies = [
|
||||||
|
@ -375,21 +426,54 @@ class pircbot():
|
||||||
def parseargs():
|
def parseargs():
|
||||||
import argparse
|
import argparse
|
||||||
p = argparse.ArgumentParser(
|
p = argparse.ArgumentParser(
|
||||||
description = "i think my desc is missing")
|
description = "guess what? i think my desc is still missing!"
|
||||||
p.add_argument("action", default="help", choices = ["start", "stop"], help="What to do?")
|
)
|
||||||
|
p.add_argument("action",
|
||||||
|
default = "help",
|
||||||
|
choices = ["start", "stop", "checkconf"],
|
||||||
|
help = "What to do?"
|
||||||
|
)
|
||||||
|
p.add_argument("--loglevel", "-l",
|
||||||
|
choices = ["critical", "error", "warning", "info", "debug"],
|
||||||
|
help = "Verbosity of logging"
|
||||||
|
)
|
||||||
#p.add_argument("--daemon", "-d", type = bool, choices = [1, 0], default=1, help="Daemonize, Default: 1")
|
#p.add_argument("--daemon", "-d", type = bool, choices = [1, 0], default=1, help="Daemonize, Default: 1")
|
||||||
return p.parse_args()
|
return p.parse_args()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
global bot
|
global bot
|
||||||
args = parseargs()
|
args = parseargs()
|
||||||
|
cfg = ConfigObj("bot.conf")
|
||||||
|
|
||||||
|
nll = getattr(logging, cfg["Behavior"]["Loglevel"].upper(), None)
|
||||||
|
if not isinstance(nll, int):
|
||||||
|
raise ValueError('Invalid log level: %s' % cfg["Behavior"]["Loglevel"])
|
||||||
|
if args.loglevel != None: nll = getattr(logging, args.loglevel.upper(), None)
|
||||||
|
if not isinstance(nll, int):
|
||||||
|
raise ValueError('Invalid log level: %s' % args.loglevel)
|
||||||
|
log.setLevel(nll)
|
||||||
|
|
||||||
if args.action == "start":
|
if args.action == "start":
|
||||||
try:
|
try:
|
||||||
bot = pircbot(nicknames=NICKNAMES, ident=IDENT, realname=REALNAME,
|
bot = pircbot(
|
||||||
server=SERVER, port=PORT, serverpasswd=SERVERPASSWD,
|
nicknames = cfg["Bot"]["Nicknames"],
|
||||||
encodings=ENCODINGS, users=USERS,
|
ident = cfg["Bot"]["Ident"],
|
||||||
query_type=QUERY_TYPE, command_prefix=COMMAND_PREFIX,
|
realname = cfg["Bot"]["Realname"],
|
||||||
parser_wait_time=PARSER_WAIT_TIME)
|
server = cfg["Network"]["Server"],
|
||||||
|
port = cfg["Network"]["Port"],
|
||||||
|
serverpasswd = cfg["Network"]["ServerPasswd"],
|
||||||
|
encodings = cfg["Network"]["Encodings"],
|
||||||
|
query_type = cfg["Behavior"]["QueryType"],
|
||||||
|
command_prefix = cfg["Behavior"]["CommandPrefix"],
|
||||||
|
msg_wait_time = cfg["Behavior"]["MsgWaitTime"],
|
||||||
|
parser_wait_time = cfg["Behavior"]["ParserWaitTime"],
|
||||||
|
users = cfg["Permissions"],
|
||||||
|
duckduckgo_cfg = cfg["DuckDuckGo"],
|
||||||
|
forecast_cfg = cfg["Forecast.io"],
|
||||||
|
logger = log,
|
||||||
|
)
|
||||||
bot.connect()
|
bot.connect()
|
||||||
# wait for the bot to become ready
|
# wait for the bot to become ready
|
||||||
while bot.ready and not bot.die_event.is_set() == False:
|
while bot.ready and not bot.die_event.is_set() == False:
|
||||||
|
@ -397,97 +481,25 @@ def main():
|
||||||
|
|
||||||
if not bot.die_event.is_set():
|
if not bot.die_event.is_set():
|
||||||
# set modes and join channels
|
# set modes and join channels
|
||||||
bot.set_mode(MODES)
|
bot.set_mode(cfg["Bot"]["Modes"])
|
||||||
for channel in CHANNELS:
|
for channel in cfg["Network"]["Channels"]:
|
||||||
bot.join(channel)
|
bot.join(channel)
|
||||||
|
|
||||||
# while bot is active, do nothing
|
# while bot is active, do nothing
|
||||||
while not bot.die_event.is_set():
|
while not bot.die_event.is_set():
|
||||||
sleep(1)
|
sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
log.show(log.INFO, "Got Ctrl-C, dying now...")
|
log.info("Got Ctrl-C, dying now...")
|
||||||
bot.disconnect("Ouch! Got shot by Ctrl-C, dying now... See you!")
|
bot.disconnect("Ouch! Got shot by Ctrl-C, dying now... See you!")
|
||||||
|
log.debug("--- MAIN EXITING ---")
|
||||||
elif args.action == "stop": print("nope!")
|
elif args.action == "stop": print("nope!")
|
||||||
log.show(log.DEBUG, "--- MAIN EXITING ---")
|
elif args.action == "checkconf":
|
||||||
|
for section, settings in cfg.items():
|
||||||
|
print("".join(("[", section, "]")))
|
||||||
|
for e in settings:
|
||||||
|
print("%20s : %s" % (e, settings[e]))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
################
|
|
||||||
### SETTINGS ###
|
|
||||||
################
|
|
||||||
|
|
||||||
# Also known as username. Some IRC-internal.
|
|
||||||
# By default, the nickname will be used as ident.
|
|
||||||
IDENT = "chalkbot"
|
|
||||||
|
|
||||||
# The list of nicknames to try. If the first one is not aviable, it will
|
|
||||||
# try the second, and so on...
|
|
||||||
# You should specfy at least two nicks.
|
|
||||||
NICKNAMES = ["chalkbot", "chalkbot_", "chalkbot__"]
|
|
||||||
|
|
||||||
REALNAME = "A ChalkBot Instance"
|
|
||||||
|
|
||||||
# Command for registering with nickserv, without leading slash.
|
|
||||||
NICKSERVCMD = ""
|
|
||||||
|
|
||||||
MODES = "+iB"
|
|
||||||
|
|
||||||
|
|
||||||
# The Server name to connect to. Duh!
|
|
||||||
SERVER = "fanir.de"
|
|
||||||
#SERVER = "localhost"
|
|
||||||
|
|
||||||
# "Default" is 6667. An often used port for SSL would be 6697, if SSL would be
|
|
||||||
# supported. Maybe in a future, far far away...
|
|
||||||
PORT = 6667
|
|
||||||
|
|
||||||
# Serverpassword. Empty in most cases.
|
|
||||||
SERVERPASSWD = ""
|
|
||||||
|
|
||||||
# A comma-seperated list of channels to join, enclosed by braces.
|
|
||||||
CHANNELS = ["#bots"]
|
|
||||||
|
|
||||||
# The encodings to try when getting messages from IRC. Will be tried in the given order.
|
|
||||||
# The first one is used to encode data when sending stuff.
|
|
||||||
# The list given shoud do just fine in most networks, I assume.
|
|
||||||
# Also comma seperated and enclosed by braces.
|
|
||||||
ENCODINGS = ['utf-8', 'latin-1', 'iso-8859-1', 'cp1252']
|
|
||||||
|
|
||||||
|
|
||||||
# List of users (hostmasks as regex) and the commands they are allowed to execute.
|
|
||||||
# "*" Can be used instead of commands to allow every command.
|
|
||||||
# All command names should be lowercase.
|
|
||||||
USERS = {
|
|
||||||
"Fanir\!fanir@.*": ["*"],
|
|
||||||
"\!@some weird user that cannot exist": ["join", "part", "invite"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# The prefix for commands for the bot.
|
|
||||||
COMMAND_PREFIX = "."
|
|
||||||
|
|
||||||
# Which way should be used to speak to users?
|
|
||||||
# "" means the type of the incoming message should be used.
|
|
||||||
# One of: "NOTICE", "PRIVMSG", ""
|
|
||||||
QUERY_TYPE = ""
|
|
||||||
|
|
||||||
|
|
||||||
# With how much information do you want to be annoyed?
|
|
||||||
# DEBUG spams most, FATAL least. WARNING should be a good tradeoff.
|
|
||||||
# One of: log.DEBUG, log.INFO, log.WARNING, log.ERROR, log.FATAL
|
|
||||||
LOGLEVEL = log.DEBUG
|
|
||||||
|
|
||||||
# The time the parser for incoming data should wait between each attempt to read new data in seconds.
|
|
||||||
# High values will certainly make the bot reply slowly while very low values increads cpu load and therefore will perform badly on slow machines.
|
|
||||||
# You should keep it between 1 and 0.001 seconds.
|
|
||||||
# For gods sake, don't set it to 0!
|
|
||||||
PARSER_WAIT_TIME = 0.05
|
|
||||||
|
|
||||||
#######################
|
|
||||||
### END OF SETTINGS ###
|
|
||||||
#######################
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in a new issue