You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
10 KiB
209 lines
10 KiB
#!/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 |
|
import json |
|
|
|
servers = [] |
|
match_players = {} |
|
connections = {} |
|
admins = {} |
|
lastPlayed = "" |
|
|
|
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 = "" |
|
user = line.source.split('!')[0] |
|
if game not in match_players[self.name + '-' + chan]: |
|
await self.send(build("PRIVMSG", [chan, "ERROR: no players in "+ game])) |
|
else: |
|
matches = match_players[self.name + '-' + chan][game] |
|
others = list(set(matches) - set([user])) # don't ping the user who .matched |
|
global lastPlayed |
|
lastPlayed = game |
|
|
|
if len(others) > 0: |
|
for player in others: |
|
pfold = self.casefold(player) |
|
if pfold in channel.users: |
|
ping += f"{channel.users[pfold].nickname} " |
|
else: |
|
ping += f"{player} " |
|
|
|
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"])) |
|
else: |
|
await self.send(build("PRIVMSG", [chan, user + ": you're the only one who plays this game :("])) |
|
|
|
|
|
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(".last"): |
|
await self.send(build("PRIVMSG", [chan, "Last game played: " + lastPlayed])) |
|
|
|
elif line.params[1].startswith(".list"): |
|
user = line.source.split('!')[0] |
|
if len(line.params[1].split(" ")) < 2: |
|
games = sorted(match_players[self.name + '-' + chan].keys()) |
|
while len(games): |
|
await self.send(build("PRIVMSG", [chan, "list: " + ', '.join(games[:20])])) |
|
del games[:20] |
|
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(".remove"): |
|
channel = self.channels[line.params[0].lstrip("@")].name |
|
if channel in admins[self.name]: |
|
fadmins = admins[self.name][channel] |
|
else: |
|
fadmins = [] |
|
user = line.source.split('!')[0] |
|
game = " ".join(line.params[1].split(" ")[1:]).lower() |
|
if game not in match_players[self.name + '-' + chan]: |
|
await self.send(build("PRIVMSG", [chan, "ERROR: game " + game + " not found"])) |
|
if user not in fadmins: |
|
|
|
await self.send(build("PRIVMSG", [chan, "ERROR: user " + user + " is not an admin"])) |
|
if user in fadmins and game in match_players[self.name + '-' + chan]: |
|
del match_players[self.name + '-' + chan][game] |
|
update_file(self.name + '-' + chan) |
|
await self.send(build("PRIVMSG", [chan, "Removed " + 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 user to the game list; .del game: Remove user from the game list; .match game: Ping everyone on the game list; .list game: list people added to the game; .list: list games; .remove game: removes the game from the list (admin command); .last: show last played game"])) |
|
|
|
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) |
|
elif not config[section]['admins']: |
|
print(f"ERROR: You didn't define any admins in section {section}.") |
|
exit(1) |
|
server = config[section]['server'] |
|
nickname = config[section]['nickname'] |
|
channels = set(config[section]['channels'].split()) |
|
try: |
|
admins[section] = json.loads(config[section]['admins']) |
|
except Exception as e: |
|
print(f"ERROR: Invalid admins in section {section}.") |
|
print(e) |
|
exit(1) |
|
|
|
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())
|
|
|