diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 484eef5..88b9c20 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -1,7 +1,9 @@ import json import logging import re +from typing import Optional, Union +import aiohttp import discord import websockets from pydactyl import PterodactylClient, exceptions @@ -22,7 +24,10 @@ class Pterodactyl(commands.Cog): console_channel=None, startup_jar=None, startup_arguments=None, - power_action_in_progress=False + power_action_in_progress=False, + chat_regex=r"\[(\d{2}:\d{2}:\d{2})\sINFO\]:\s<(\w+)>\s(.*)", + api_endpoint="minecraft", + chat_channel=None ) self.logger = logging.getLogger('red.sea.pterodactyl') self.client = None @@ -84,6 +89,11 @@ class Pterodactyl(commands.Cog): if content.startswith('['): await channel.send(content=content) #TODO - Add pagification for long messages to prevent Discord API errors + chat_message = self.check_if_chat_message(content) + if chat_message: + info = await self.get_info(chat_message['username']) + if info is not None: + await self.send_chat_discord(info['username'], info['message'], info['avatar']) if json.loads(message)['event'] == 'status': current_status = json.loads(message)['args'][0] @@ -95,11 +105,36 @@ class Pterodactyl(commands.Cog): websocket_credentials = client.servers.get_websocket(server_id) continue - def remove_ansi_escape_codes(self, text: str): + def remove_ansi_escape_codes(self, text: str) -> str: ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') #NOTE - https://chat.openai.com/share/d92f9acf-d776-4fd6-a53f-b14ac15dd540 return ansi_escape.sub('', text) + def check_if_chat_message(self, text: str) -> Union[bool, dict]: + regex = self.config.chat_regex() + match: Optional[re.Match[str]] = re.match(regex, text) + if match: + return {"time": match.group(1), "username": match.group(2), "message": match.group(3)} + return False + + async def get_info(self, username: str) -> Optional[dict]: + endpoint = await self.config.endpoint() + async with aiohttp.ClientSession() as session: + async with session.get(f"https://playerdb.co/api/player/{endpoint}/{username}") as response: + if response.status == 200: + return await response.json() + else: + return None + + async def send_chat_discord(self, username: str, message: str, avatar_url: str) -> None: + channel = self.bot.get_channel(await self.config.chat_channel()) + if channel is not None: + webhooks = await channel.webhooks() + webhook = discord.utils.get(webhooks, name="Pterodactyl Chat") + if webhook is None: + webhook = await channel.create_webhook(name="Pterodactyl Chat") + await webhook.send(content=message, username=username, avatar_url=avatar_url) + def get_task(self): return self.bot.loop.create_task(self.establish_websocket_connection(), name="Pterodactyl Websocket Connection") @@ -156,3 +191,9 @@ class Pterodactyl(commands.Cog): """Set the channel to send console output to.""" await self.config.console_channel.set(channel.id) await ctx.send(f"Console channel set to {channel.mention}") + + @pterodactyl_config.command(name = "chatchannel") + async def pterodactyl_config_chat_channel(self, ctx: commands.Context, channel: discord.TextChannel): + """Set the channel to send chat output to.""" + await self.config.chat_channel.set(channel.id) + await ctx.send(f"Chat channel set to {channel.mention}")