#!/bin/env python3 # SPDX-License-Identifier: MIT import asyncio, configparser from irctokens import build, Line from ircrobots import Bot as BaseBot from ircrobots import Server as BaseServer from ircrobots import ConnectionParams import pickle servers = [] match_players = {} connections = {} def update_file(name): with open(f"playerlist-{name}.txt", "wb") as file: pickle.dump(match_players, file) def read_file(name): try: with open(f"playerlist-{name}.txt", "rb") as file: temp = pickle.load(file) match_players[name] = temp[name] except EOFError: match_players[name] = {} print("Empty") class Server(BaseServer): async def line_read(self, line: Line): print("Line Params: ", line.params) if "PRIVMSG" in line.command and any(channel in line.params[0] for channel in self.params.autojoin): chan = self.channels[line.params[0].lstrip("@")].name if line.params[1].startswith(".match"): channel = self.channels[line.params[0].lstrip("@")] if len(line.params[1].split(" ")) < 2: await self.send(build("PRIVMSG", [chan, "ERROR: game not specified"])) else: game = " ".join(line.params[1].split(" ")[1:]).lower() ping = "" if game not in match_players[self.name + '-' + chan]: await self.send(build("PRIVMSG", [chan, "ERROR: no players in "+ game])) else: for player in match_players[self.name + '-' + chan][game]: pfold = self.casefold(player) if pfold in channel.users: ping += f"{channel.users[pfold].nickname} " await self.send(build("PRIVMSG", [chan, "Anyone ready for " + game + f" : {ping} ?"])) if connections[self.name]: for connection,address in connections[self.name].items(): if connection in line.params[1]: if ':' in address: realaddress = address.split(':')[0] port = address.split(':')[1] self.send(build("PRIVMSG", [chan, f"Connect using nc {realaddress} {port}"])) else: self.send(build("PRIVMSG", [chan, f"Connect using nc {address} 1234"])) elif line.params[1].startswith(".add"): user = line.source.split('!')[0] if len(line.params[1].split(" ")) < 2: await self.send(build("PRIVMSG", [chan, "ERROR: game not specified"])) else: game = " ".join(line.params[1].split(" ")[1:]).lower() if game not in match_players[self.name + '-' + chan]: match_players[self.name + '-' + chan][game] = set() if user in match_players[self.name + '-' + chan][game]: await self.send(build("PRIVMSG", [chan, "ERROR: player already in " + game + " list."])) else: match_players[self.name + '-' + chan][game].add(user) update_file(self.name + '-' + chan) await self.send(build("PRIVMSG", [chan, "Added " + user + " to the " + game + " match list."])) elif line.params[1].startswith(".list"): user = line.source.split('!')[0] if len(line.params[1].split(" ")) < 2: await self.send(build("PRIVMSG", [chan, "list: " + str(list(match_players[self.name + '-' + chan].keys()))])) else: game = " ".join(line.params[1].split(" ")[1:]).lower() if game not in match_players[self.name + '-' + chan]: await self.send(build("PRIVMSG", [chan, "ERROR: no players in " + game + " list."])) else: await self.send(build("PRIVMSG", [chan, game + " players: " + str(['_' + e for e in match_players[self.name + '-' + chan][game]])])) elif line.params[1].startswith(".del"): user = line.source.split('!')[0] if len(line.params[1].split(" ")) < 2: await self.send(build("PRIVMSG", [chan, "ERROR: game not specified"])) else: game = " ".join(line.params[1].split(" ")[1:]).lower() if game not in match_players[self.name + '-' + chan]: await self.send(build("PRIVMSG", [chan, "ERROR: no players in "+ game])) else: if user not in match_players[self.name + '-' + chan][game]: await self.send(build("PRIVMSG", [chan, "ERROR: player isn't in list."])) else: match_players[self.name + '-' + chan][game].remove(user) if len(match_players[self.name + '-' + chan][game]) == 0: del match_players[self.name + '-' + chan][game] update_file(self.name + '-' + chan) await self.send(build("PRIVMSG", [chan, "Removed " + user + " from the " + game + " match list."])) elif line.params[1].startswith(".help"): await self.send(build("PRIVMSG", [chan, " .add game: Add to list; .del game: Remove from list; .match game: Ping everyone on list; .list game: list people added to the game; .list: list games"])) async def line_send(self, line: Line): print(f"{self.name} > {line.format()}") class Bot(BaseBot): def create_server(self, name: str): return Server(self, name) async def main(): config = configparser.ConfigParser() with open('bot.ini', 'r') as configfile: config.read_file(configfile) for section in config.sections(): if not config[section]['server']: print(f"ERROR: The section {section} on your bot.ini doesn't have a 'server' parameter.") exit(1) elif not config[section]['nickname']: print(f"ERROR: The section {section} has no nickname defined.") exit(1) elif not config[section]['channels']: print(f"ERROR: You didn't define any channels in section {section}.") exit(1) server = config[section]['server'] nickname = config[section]['nickname'] channels = set(config[section]['channels'].split()) if config[section]['connections']: if len(config[section]['connections'].split()) % 2 != 0: # If connections isn't even print(f"ERROR: The section {section} has an invalid 'connections' defined.") exit(1) config_connections = config[section]['connections'].split() connections.update({section:{}}) for i in range(0, len(config_connections), 2): connections[section].update({config_connections[i]:config_connections[i+1]}) servers.append({'name':section, 'opts':{'server':server, 'nickname':nickname, 'channels':channels}}) # read_file() bot = Bot() for entry in servers: name = entry['name'] server = entry['opts']['server'] botnick = entry['opts']['nickname'] channels = entry['opts']['channels'] params = ConnectionParams(botnick, server, 6697, True) for channel in channels: params.autojoin.append(channel) print("Reading channel", channel) read_file(name + '-' + channel) print(match_players) await bot.add_server(name, params) print("Match players is: ", match_players) await bot.run() if __name__ == "__main__": asyncio.run(main())