bunch of refactoring i guess

This commit is contained in:
= 2025-04-04 06:54:31 +00:00
parent ea79b23b28
commit 5f0c0b2182
2 changed files with 165 additions and 172 deletions

123
bot.py
View File

@ -3,8 +3,8 @@ from time import sleep, time
from json import load, dump from json import load, dump
import re import re
channel_re = re.compile(r"PRIVMSG (#*\w+)") privmsg_channel_re = re.compile(r"PRIVMSG (#*\w+)")
name_re = re.compile(r"^:([^!]*)!") nick_re = re.compile(r"^:([^!]*)!")
# timeout = 86400 # 24 hours # timeout = 86400 # 24 hours
timeout = 15 timeout = 15
@ -18,55 +18,52 @@ class IRCBot():
def __init__(self): def __init__(self):
try: try:
with open("config.json", "r") as f: with open("config.json", "r") as f:
self.config = load(f) self.state = load(f)
except FileNotFoundError: except FileNotFoundError:
exit("no config.json") exit("no config.json")
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect((host, port)) self.s.connect((host, port))
self.nick = self.config["nick"] self.nick = self.state["nick"]
self.sendline(f"NICK {self.nick}") self.send_raw_line(f"NICK {self.nick}")
self.sendline(f"USER {self.nick} 0 * :{self.config['realname']}") self.send_raw_line(f"USER {self.nick} 0 * :{self.state['realname']}")
for channel in self.config["channels"]: for channel in self.state["channels"]:
self.sendline(f"JOIN {channel}") self.send_raw_line(f"JOIN {channel}")
self.commands = [ self.commands = [
("invite", self.invite), ("invite", self.invite),
("kick", self.kick) ("kick", self.kick)
] ]
def write_config(self): def write_state(self):
with open("config.json", "w") as f: with open("state.json", "w") as f:
dump(self.config, f, indent=2) dump(self.state, f, indent=2)
def join_channel(self, channel): def join_channel(self, channel):
self.sendline(f"JOIN {channel}") self.send_raw_line(f"JOIN {channel}")
self.config["channels"].append(channel) self.state["channels"].append(channel)
self.write_config() self.write_state()
def part_channel(self, channel): def part_channel(self, channel):
if channel == "#tildetown": if channel in ("#tildetown", "#bots"):
self.sendline("i will not leave #tildetown. want to block me? see https://git.tilde.town/nebula/chatterbot") self.send_raw_line(f"i will not leave {channel}. want to block me? see https://git.tilde.town/nebula/chatterbot")
return return
elif channel == "#bots": self.send_raw_line(f"PART {channel}")
self.sendline("i will not leave #bots. want to block me? see https://git.tilde.town/nebula/chatterbot") self.state["channels"].remove(channel)
return del self.state["times"][channel]
self.sendline(f"PART {channel}") del self.state["counts"][channel]
self.config["channels"].remove(channel) self.write_state()
del self.config["times"][channel]
del self.config["counts"][channel]
self.write_config()
def sendline(self, line): def send_raw_line(self, line):
if line: if line:
return self.s.send(bytes(f"{line}\r\n", "UTF-8")) return self.s.send(bytes(f"{line}\r\n", "UTF-8"))
return None return
def send(self, channel, content): def send(self, channel, content):
if isinstance(content, list): if isinstance(content, list):
for line in content: for line in content:
self.sendline(f"PRIVMSG {channel} :{line}") self.send_raw_line(f"PRIVMSG {channel} :{line}")
sleep(0.5) sleep(0.5)
elif isinstance(content, str): elif isinstance(content, str):
self.sendline(f"PRIVMSG {channel} :{content}") self.send_raw_line(f"PRIVMSG {channel} :{content}")
def help(_, __): def help(_, __):
return helptext return helptext
@ -79,7 +76,7 @@ class IRCBot():
if not channel.startswith("#"): if not channel.startswith("#"):
lines.append("channel name must start with #") lines.append("channel name must start with #")
continue continue
elif channel in self.config["channels"]: elif channel in self.state["channels"]:
lines.append(f"i am already in {channel}!") lines.append(f"i am already in {channel}!")
else: else:
self.join_channel(channel) self.join_channel(channel)
@ -89,33 +86,33 @@ class IRCBot():
def kick(self, channel, arguments): def kick(self, channel, arguments):
if not arguments: if not arguments:
self.part_channel(channel) self.part_channel(channel)
return None return
for channel in arguments: for channel in arguments:
self.part_channel(channel) self.part_channel(channel)
def check_time(self, channel): def check_time(self, channel):
try: try:
this_time = self.config["times"][channel] this_time = self.state["times"][channel]
except KeyError: except KeyError:
this_time = self.config["times"][channel] = time() this_time = self.state["times"][channel] = time()
self.write_config() self.write_state()
return this_time return this_time
def set_time(self, channel, this_time): def set_time(self, channel, this_time):
self.config["times"][channel] = this_time self.state["times"][channel] = this_time
def counter(self, channel): def counter(self, channel):
try: try:
self.config["counts"][channel] += 1 self.state["counts"][channel] += 1
value = self.config["counts"][channel] value = self.state["counts"][channel]
except KeyError: except KeyError:
value = self.config["counts"][channel] = 1 value = self.state["counts"][channel] = 1
self.write_config() self.write_state()
return value return value
def reset_count(self, channel): def reset_count(self, channel):
self.config["counts"][channel] = 0 self.state["counts"][channel] = 0
self.write_config() self.write_state()
def command_loop(self): def command_loop(self):
while True: while True:
@ -130,25 +127,25 @@ class IRCBot():
line = line.decode("UTF-8").strip() line = line.decode("UTF-8").strip()
if line.startswith("PING"): if line.startswith("PING"):
pong = "PONG " + line[5:] pong = "PONG " + line[5:]
self.sendline(pong) self.send_raw_line(pong)
continue continue
channel_search = channel_re.search(line) privmsg_channel_search = privmsg_channel_re.search(line)
if not channel_search: if not privmsg_channel_search:
continue continue
channel = channel_search.group(1) channel = privmsg_channel_search.group(1)
name_search = name_re.search(line) nick_search = nick_re.search(line)
if name_search: if nick_search:
name = name_search.group(1) nick = nick_search.group(1)
else: else:
name = None nick = None
if name and not channel.startswith("#"): if nick and not channel.startswith("#"):
channel = name channel = nick
try: try:
message_body = line[line.index(" :") + 2:] message_body = line[line.index(" :") + 2:]
except (IndexError, ValueError): except (IndexError, ValueError):
message_body = "" message_body = ""
if message_body: if message_body:
if message_body.startswith("!rollcall"): if message_body.startswith("!rollcall") or message_body.startswith("!help"):
self.send(channel, helptext) self.send(channel, helptext)
continue continue
elif message_body.startswith("!chatterbot"): elif message_body.startswith("!chatterbot"):
@ -164,16 +161,20 @@ class IRCBot():
else: else:
if channel in ("#tildetown", "#bots"): if channel in ("#tildetown", "#bots"):
continue continue
channel_time = self.check_time(channel) # i have not figured out this part yet
now = time()
count = self.counter(channel) # channel_time = self.check_time(channel)
delta = now - channel_time # now = time()
if delta > timeout and count < messages_within_timeout: # count = self.counter(channel)
self.reset_count(channel) # delta = now - channel_time
self.send("#bots", f"i hear activity in {channel}...") # if delta > timeout:
elif count < messages_within_timeout and delta > timeout: # if count < messages_within_timeout:
self.reset_count # self.send("#bots", f"i hear activity in {channel}...")
self.set_time(channel, now) # self.reset_count(channel)
# elif and channel_time :
# self.reset_count
# self.set_time(channel, now)
if __name__ == "__main__": if __name__ == "__main__":
bot = IRCBot() bot = IRCBot()

View File

@ -1,8 +0,0 @@
{
"nick": "chatterbot",
"realname": "a bot by ~nebula",
"channels": ["#bots"],
"times": {},
"counts": {}
}