diff --git a/extensions/music.py b/extensions/music.py index 60943e3..8c3031c 100644 --- a/extensions/music.py +++ b/extensions/music.py @@ -6,6 +6,7 @@ from discord import ButtonStyle, Interaction, ui from discord.ext import commands +import utils from core import config from core.bot import Substiify @@ -72,7 +73,7 @@ async def ensure_voice(self, ctx: commands.Context): if wavelink.Pool.nodes is None: raise NoNodeAccessible() - if ctx.command.name in ["players", "cleanup"]: + if ctx.command.name in ["players", "cleanup", "lavalink"]: return True player: wavelink.Player = ctx.voice_client @@ -222,6 +223,39 @@ async def players(self, ctx: commands.Context): embed.description = players_string await ctx.send(embed=embed, delete_after=60) + @commands.is_owner() + @commands.command(name="lavalink", aliases=["lv"], hidden=True) + async def lavalink_stats(self, ctx: commands.Context): + """ + Shows the Lavalink stats. + """ + stats: wavelink.StatsResponsePayload = await wavelink.Pool.get_node().fetch_stats() + info: wavelink.InfoResponsePayload = await wavelink.Pool.get_node().fetch_info() + + players_str = f"[` {stats.players} | {stats.playing} `]" + version_str = f"[` {info.version.semver} `]" + uptime_str = f"[` {utils.seconds_to_human_readable(stats.uptime/1000)} `]" + memory_used = utils.bytes_to_human_readable(stats.memory.used) + memory_free = utils.bytes_to_human_readable(stats.memory.reservable) + memory_str = f"[` {memory_used} | {memory_free} `]" + system_load = round((stats.cpu.system_load * 100), 1) + cpu_str = f"[` {stats.cpu.cores} vCPU | {system_load} `]" + jvm_str = f"[` {info.jvm} `]" + sources_str = f"```ml\n{', '.join(info.source_managers).title()}\n```" + plugins_list_str = [f"({plugin.name} - {plugin.version})" for plugin in info.plugins] + plugins_str = f"```ml\n{', '.join(plugins_list_str).title()}\n```" + + embed = discord.Embed(title="Lavalink Info", color=EMBED_COLOR) + embed.add_field(name="Players", value=players_str) + embed.add_field(name="Uptime", value=uptime_str) + embed.add_field(name="Version", value=version_str) + embed.add_field(name="Memory", value=memory_str) + embed.add_field(name="CPU Usage", value=cpu_str) + embed.add_field(name="JVM", value=jvm_str) + embed.add_field(name="Sources", value=sources_str, inline=False) + embed.add_field(name="Plugins", value=plugins_str, inline=False) + await ctx.send(embed=embed) + @commands.hybrid_command() @commands.check_any(commands.has_permissions(manage_channels=True), commands.is_owner()) async def cleanup(self, ctx: commands.Context, enable: bool = None): diff --git a/extensions/util.py b/extensions/util.py index 05b7ad6..6efd031 100644 --- a/extensions/util.py +++ b/extensions/util.py @@ -1,7 +1,6 @@ import asyncio import datetime import logging -import math import platform from random import SystemRandom, shuffle @@ -9,11 +8,9 @@ import psutil from discord import MessageType, app_commands from discord.ext import commands, tasks -from pytz import timezone -from core import constants -from core.bot import Substiify -from utils import ux +import core +import utils logger = logging.getLogger(__name__) @@ -21,7 +18,7 @@ class Util(commands.Cog): COG_EMOJI = "📦" - def __init__(self, bot: Substiify): + def __init__(self, bot: core.Substiify): self.bot = bot self.giveaway_task.start() @@ -300,11 +297,9 @@ async def ping(self, ctx: commands.Context): """ Shows the ping of the bot """ - title = "Donk!" if "dink" in ctx.message.content.lower() else "Pong!" - embed = discord.Embed( - title=f"{title} 🏓", description=f"⏱️Ping: `{round(self.bot.latency*1000)}`ms", color=constants.PRIMARY_COLOR - ) - await ctx.message.delete() + title = "Donk! 🏓" if "dink" in ctx.message.content.lower() else "Pong! 🏓" + desc = f"⏱️Ping: `{round(self.bot.latency*1000)}`ms" + embed = discord.Embed(title=title, description=desc, color=core.constants.PRIMARY_COLOR) await ctx.send(embed=embed) @commands.command(name="specialThanks", hidden=True) @@ -320,23 +315,25 @@ async def special_thanks(self, ctx: commands.Context): embed = discord.Embed( title="Special thanks for any help to those people", description=" ".join(peeople_who_helped), - color=constants.PRIMARY_COLOR, + color=core.constants.PRIMARY_COLOR, ) await ctx.send(embed=embed) await ctx.message.delete() @commands.command() + @commands.cooldown(3, 30) async def info(self, ctx: commands.Context): """ Shows different technical information about the bot """ content = "" - bot_uptime = time_up((discord.utils.utcnow() - self.bot.start_time).total_seconds()) - last_commit_hash = ux.get_last_commit_hash() + uptime_in_seconds = (discord.utils.utcnow() - self.bot.start_time).total_seconds() + bot_uptime = utils.seconds_to_human_readable(uptime_in_seconds) + last_commit_hash = utils.ux.get_last_commit_hash() cpu_percent = psutil.cpu_percent() ram = psutil.virtual_memory() - ram_used = format_bytes((ram.total - ram.available)) + ram_used = utils.bytes_to_human_readable((ram.total - ram.available)) ram_percent = psutil.virtual_memory().percent proc = psutil.Process() @@ -348,42 +345,18 @@ async def info(self, ctx: commands.Context): f"**Python:** `{platform.python_version()}`\n" f"**discord.py:** `{discord.__version__}`\n\n" f"**CPU:** `{cpu_percent}%`\n" - f"**Process RAM:** `{format_bytes(memory.uss)}`\n" + f"**Process RAM:** `{utils.bytes_to_human_readable(memory.uss)}`\n" f"**Total RAM:** `{ram_used} ({ram_percent}%)`\n\n" f"**Made by:** <@{self.bot.owner_id}>" ) embed = discord.Embed( - title=f"Info about {self.bot.user.display_name}", - description=content, - color=constants.PRIMARY_COLOR, - timestamp=datetime.datetime.now(timezone("Europe/Zurich")), + title=f"Info about {self.bot.user.display_name}", description=content, color=core.constants.PRIMARY_COLOR ) embed.set_thumbnail(url=self.bot.user.display_avatar.url) embed.set_footer(text=f"Requested by {ctx.author}", icon_url=ctx.author.avatar) await ctx.send(embed=embed) -def time_up(seconds: int) -> str: - if seconds <= 60: - return "<1 minute" - elif 3600 > seconds > 60: - minutes = seconds // 60 - return f"{int(minutes)} minutes" - hours = seconds // 3600 # Seconds divided by 3600 gives amount of hours - minutes = (seconds % 3600) // 60 # The remaining seconds are looked at to see how many minutes they make up - if hours >= 24: - days = hours // 24 - hours = hours % 24 - return f"{int(days)} days, {int(hours)} hours, {int(minutes)} minutes" - return f"{int(hours)} hours, {int(minutes)} minutes" - - -def format_bytes(size_in_bytes: int) -> str: - units = ("B", "KiB", "MiB", "GiB", "TiB") - power = int(math.log(max(abs(size_in_bytes), 1), 1024)) - return f"{size_in_bytes / (1024 ** power):.2f} {units[power]}" - - -async def setup(bot: Substiify): +async def setup(bot: core.Substiify): await bot.add_cog(Util(bot)) diff --git a/pyproject.toml b/pyproject.toml index 898cd4b..2bdce74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ target-version = "py312" [tool.ruff.lint] # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. select = ["E4", "E7", "E9", "F"] -ignore = [] +ignore = ["F403"] # Allow fix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] diff --git a/utils/__init__.py b/utils/__init__.py index 47ac0c8..4f78838 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1 +1,2 @@ from . import ux as ux +from .general import * diff --git a/utils/general.py b/utils/general.py new file mode 100644 index 0000000..a564e54 --- /dev/null +++ b/utils/general.py @@ -0,0 +1,25 @@ +import math + +__all__ = ("seconds_to_human_readable", "bytes_to_human_readable") + + +def seconds_to_human_readable(seconds: int) -> str: + if seconds <= 60: + return "<1 minute" + elif 3600 > seconds > 60: + minutes = seconds // 60 + seconds = seconds % 60 + return f"{int(minutes)}m {int(seconds)}s" + hours = seconds // 3600 # Seconds divided by 3600 gives amount of hours + minutes = (seconds % 3600) // 60 # The remaining seconds are looked at to see how many minutes they make up + if hours >= 24: + days = hours // 24 + hours = hours % 24 + return f"{int(days)}d {int(hours)}h {int(minutes)}m" + return f"{int(hours)}h {int(minutes)}m" + + +def bytes_to_human_readable(size_in_bytes: int) -> str: + units = ("B", "KB", "MB", "GB", "TB") + power = int(math.log(size_in_bytes, 1024)) + return f"{size_in_bytes / (1024 ** power):.1f} {units[power]}"