From 4135cd4f98bf05b9031fa4d0f04594da043df7b8 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 14 Mar 2024 16:26:31 -0400 Subject: [PATCH] feat(pterodactyl): added support for changing channel topics --- pterodactyl/config.py | 3 ++ pterodactyl/mcsrvstatus.py | 10 ++++++ pterodactyl/pterodactyl.py | 72 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 pterodactyl/mcsrvstatus.py diff --git a/pterodactyl/config.py b/pterodactyl/config.py index 770c631..64079fb 100644 --- a/pterodactyl/config.py +++ b/pterodactyl/config.py @@ -14,6 +14,9 @@ def register_config(config_obj: Config) -> None: leave_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: ([^<\n]+) left the game$", achievement_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: (.*) has (made the advancement|completed the challenge) \[(.*)\]$", chat_command='tellraw @a ["",{"text":".$N ","color":".$C","insertion":"<@.$I>","hoverEvent":{"action":"show_text","contents":"Shift click to mention this user inside Discord"}},{"text":"(DISCORD):","color":"blue","clickEvent":{"action":"open_url","value":".$V"},"hoverEvent":{"action":"show_text","contents":"Click to join the Discord Server"}},{"text":" .$M","color":"white"}]', # noqa: E501 + topic='Server IP: .$H\nServer Players: .$P/.$M', + topic_hostname=None, + topic_port=25565, api_endpoint="minecraft", chat_channel=None, startup_msg='Server started!', diff --git a/pterodactyl/mcsrvstatus.py b/pterodactyl/mcsrvstatus.py new file mode 100644 index 0000000..689088b --- /dev/null +++ b/pterodactyl/mcsrvstatus.py @@ -0,0 +1,10 @@ +import aiohttp + + +async def get_status(host, port = 25565) -> tuple[bool, dict]: + async with aiohttp.ClientSession() as session: + async with session.get(f'https://api.mcsrvstat.us/2/{host}:{port}') as response: + response = await response.json() + if response['online']: + return (True, response) + return (False, response) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index a2522a8..445df26 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -4,6 +4,7 @@ from typing import Mapping, Optional, Union import discord import websockets +from discord.ext import tasks from pydactyl import PterodactylClient from redbot.core import app_commands, commands from redbot.core.app_commands import Choice @@ -11,6 +12,7 @@ from redbot.core.bot import Red from redbot.core.utils.chat_formatting import box, error from redbot.core.utils.views import ConfirmView +from pterodactyl import mcsrvstatus from pterodactyl.config import config, register_config from pterodactyl.logger import logger @@ -56,6 +58,16 @@ class Pterodactyl(commands.Cog): else: logger.info("Retry limit reached. Stopping task.") + @tasks.loop(minutes=6) + async def update_topic(self): + topic = await self.get_topic() + console = self.bot.get_channel(await config.console_channel()) + chat = self.bot.get_channel(await config.chat_channel()) + if console: + await console.edit(topic=topic) + if chat: + await chat.edit(topic=topic) + @commands.Cog.listener() async def on_message_without_command(self, message: discord.Message) -> None: if message.channel.id == await config.console_channel() and message.author.bot is False: @@ -83,6 +95,34 @@ class Pterodactyl(commands.Cog): self.retry_counter = 0 self.task = self.get_task() + async def get_topic(self) -> str: + topic: str = await config.topic() + placeholders = { + "H": await config.topic_hostname() or "unset", + "P": str(await config.topic_port()), + } + if await config.api_endpoint() == "minecraft": + status, response = await mcsrvstatus.get_status(await config.topic_ip(), await config.topic_port()) + if status: + placeholders += { + "I": response['ip'], + "M": str(response['players']['max']), + "P": str(response['players']['online']), + "V": response['version'], + "D": response['motd']['clean'][0] if response['motd']['clean'] else "unset", + } + else: + placeholders += { + "I": response['ip'], + "M": "0", + "P": "0", + "V": "Server Offline", + "D": "Server Offline", + } + for key, value in placeholders.items(): + topic = topic.replace('.$' + key, value) + return topic + async def get_chat_command(self, message: discord.Message) -> str: command: str = await config.chat_command() placeholders = { @@ -286,6 +326,38 @@ class Pterodactyl(commands.Cog): await config.invite.set(invite) await ctx.send(f"Invite link set to {invite}") + @pterodactyl_config.group(name = "topic") + async def pterodactyl_config_topic(self, ctx: commands.Context): + """Set the topic for the console and chat channels.""" + + @pterodactyl_config_topic.command(name = "host", aliases = ["hostname", "ip"]) + async def pterodactyl_config_topic_host(self, ctx: commands.Context, host: str) -> None: + """Set the hostname or IP address of your server.""" + await config.topic_hostname.set(host) + await ctx.send(f"Hostname/IP set to {host}") + + @pterodactyl_config_topic.command(name = "port") + async def pterodactyl_config_topic_port(self, ctx: commands.Context, port: int) -> None: + """Set the port of your server.""" + await config.topic_port.set(port) + await ctx.send(f"Port set to {port}") + + @pterodactyl_config_topic.command(name = "text") + async def pterodactyl_config_topic_text(self, ctx: commands.Context, *, text: str) -> None: + """Set the text for the console and chat channels. + + Available placeholders: + - `.$H` (hostname) + - `.$P` (port) + Available for Minecraft servers: + - `.$I` (ip) + - `.$M` (max players) + - `.$P` (players online) + - `.$V` (version) + - `.$D` (description / Message of the Day)""" + await config.topic.set(text) + await ctx.send(f"Topic set to:\n{box(text, 'yaml')}") + @pterodactyl_config.group(name = "chat") async def pterodactyl_config_chat(self, ctx: commands.Context): """Configure chat settings."""