From f966f2c69eb07897e4accdf396faa77d1364a31d Mon Sep 17 00:00:00 2001 From: LevaniVashadze Date: Tue, 26 Dec 2023 22:27:04 +0400 Subject: [PATCH] make command stats persistent --- cogs/Info.py | 28 ----------------- cogs/Stats.py | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ setup.sql | 14 ++++++++- utils/bot.py | 28 +++++++++-------- 4 files changed, 111 insertions(+), 42 deletions(-) create mode 100644 cogs/Stats.py diff --git a/cogs/Info.py b/cogs/Info.py index a47f7fd..69a8638 100644 --- a/cogs/Info.py +++ b/cogs/Info.py @@ -61,34 +61,6 @@ async def weather( else: await inter.send(embed=e) - @commands.slash_command(description="Stats about the commands that have been ran") - @commands.cooldown(1, 5, commands.BucketType.user) - async def cmdstats(self, inter): - cmdsran = self.bot.commands_ran - sortdict = dict(sorted(cmdsran.items(), key=lambda x: x[1], reverse=True)) - value_iterator = iter(sortdict.values()) - key_iterator = iter(sortdict.keys()) - emby = disnake.Embed( - title=f"{self.bot.user.display_name} command Stats", - description=f"{self.bot.total_commands_ran} Commands ran this boot\n", - color=disnake.Color.random(), - ) - emby.add_field( - name="Top 10 commands ran", - value=f"🥇: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🥈: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🥉: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n" - f"🏅: /{next(key_iterator)} ({next(value_iterator)} uses)\n", - ) - - await inter.send(embed=emby) - @commands.slash_command(description="Display current price of BTC") @commands.cooldown(1, 5, commands.BucketType.user) async def btc(self, inter): diff --git a/cogs/Stats.py b/cogs/Stats.py new file mode 100644 index 0000000..1685332 --- /dev/null +++ b/cogs/Stats.py @@ -0,0 +1,83 @@ +import disnake +from disnake.ext import commands, tasks + +from utils.bot import OGIROID + + +class Stats(commands.Cog): + def __init__(self, bot: OGIROID): + self.bot = bot + self.update_stats.start() + + def cog_unload(self): + self.update_stats.cancel() + + @tasks.loop(hours=1) + async def update_stats(self): + # add command usage to db + commands_ran = self.bot.commands_ran + total_commands_ran = self.bot.total_commands_ran + + for guild_id, guild_commands_ran in commands_ran.items(): + for command, count in guild_commands_ran.items(): + await self.bot.db.execute( + "INSERT INTO commands (guild_id, command, command_used) VALUES ($1, $2, $3) ON CONFLICT (guild_id, command) DO UPDATE SET command_used = commands.command_used + $3;", + guild_id, + command, + count, + ) + + for guild_id, count in total_commands_ran.items(): + await self.bot.db.execute( + "INSERT INTO total_commands (guild_id, total_commands_used) VALUES ($1, $2) ON CONFLICT (guild_id) DO UPDATE SET total_commands_used = total_commands.total_commands_used + $2;", + guild_id, + count, + ) + + # reset command usage + self.bot.commands_ran = {} + self.bot.total_commands_ran = {} + + @commands.slash_command(description="Stats about the commands that have been ran") + @commands.cooldown(1, 5, commands.BucketType.user) + async def cmdstats(self, inter): + await inter.response.defer() + cmdsran = await self.bot.db.fetch( + "SELECT command, command_used FROM commands WHERE guild_id = $1 ORDER BY command_used DESC LIMIT 10;", + inter.guild.id, + ) + cmdsran = dict(cmdsran) + + total_commands_ran = await self.bot.db.fetchval( + "SELECT total_commands_used FROM total_commands WHERE guild_id = $1;", + inter.guild.id, + ) + sortdict = dict(sorted(cmdsran.items(), key=lambda x: x[1], reverse=True)) + value_iterator = iter(sortdict.values()) + key_iterator = iter(sortdict.keys()) + emby = disnake.Embed( + title=f"{self.bot.user.display_name} command Stats", + description=f"{total_commands_ran} Commands ran in total.\n", + color=self.bot.config.colors.white, + ) + + text = ( + f"🥇: /{next(key_iterator)} ({next(value_iterator)} uses)\n" + + f"🥈: /{next(key_iterator)} ({next(value_iterator)} uses)\n" + + f"🥉: /{next(key_iterator)} ({next(value_iterator)} uses)\n" + ) + i = 2 + for key in key_iterator: + text += f"🏅: /{key} ({next(value_iterator)} uses)\n" + i += 1 + # total 10 + if i == 10: + break + + emby.add_field(name="Top 10 commands ran", value=text) + + await inter.send(embed=emby) + + +def setup(bot): + bot.add_cog(Stats(bot)) diff --git a/setup.sql b/setup.sql index fa802ab..cdc5cba 100644 --- a/setup.sql +++ b/setup.sql @@ -96,4 +96,16 @@ CREATE TABLE IF NOT EXISTS config UNIQUE(guild_id) ); -DROP TABLE IF EXISTS xp_boosts_user; \ No newline at end of file +CREATE TABLE IF NOT EXISTS commands +( + guild_id BIGINT, + command TEXT, + command_used INTEGER DEFAULT 0, + UNIQUE (guild_id, command) +); + +CREATE TABLE IF NOT EXISTS total_commands +( + guild_id BIGINT UNIQUE, + total_commands_used INTEGER DEFAULT 0 +); \ No newline at end of file diff --git a/utils/bot.py b/utils/bot.py index f36c224..55ad6b2 100644 --- a/utils/bot.py +++ b/utils/bot.py @@ -6,6 +6,7 @@ import disnake from disnake import ApplicationCommandInteraction, OptionType from disnake.ext import commands +from disnake.ext.commands.interaction_bot_base import CFT from utils.CONSTANTS import __VERSION__ from utils.DBhandlers import BlacklistHandler @@ -32,7 +33,7 @@ def __init__(self, *args, **kwargs): self.session = HTTPSession(loop=self.loop) self.config = Config() self.commands_ran = {} - self.total_commands_ran = 0 + self.total_commands_ran = {} self.db = None self.blacklist: BlacklistHandler = None self.add_app_command_check( @@ -49,13 +50,6 @@ async def blacklist_check(self, ctx): except AttributeError: pass # DB hasn't loaded yet - async def on_command(self, ctx): - self.total_commands_ran += 1 - try: - self.commands_ran[ctx.command.qualified_name] += 1 - except KeyError: - self.commands_ran[ctx.command.qualified_name] = 1 - @async_cache(maxsize=0) async def on_slash_command(self, inter: ApplicationCommandInteraction): COMMAND_STRUCT = [inter.data] @@ -84,11 +78,19 @@ async def on_slash_command(self, inter: ApplicationCommandInteraction): break COMMAND_NAME = " ".join([command.name for command in COMMAND_STRUCT]) - self.total_commands_ran += 1 + + try: + self.total_commands_ran[inter.guild.id] += 1 + except KeyError: + self.total_commands_ran[inter.guild.id] = 1 + + if self.commands_ran.get(inter.guild.id) is None: + self.commands_ran[inter.guild.id] = {} + try: - self.commands_ran[COMMAND_NAME] += 1 + self.commands_ran[inter.guild.id][COMMAND_NAME] += 1 except KeyError: - self.commands_ran[COMMAND_NAME] = 1 + self.commands_ran[inter.guild.id][COMMAND_NAME] = 1 async def on_ready(self): if not self._ready_: @@ -117,8 +119,8 @@ async def on_ready(self): print("Bot reconnected") async def _setup(self): - for command in self.application_commands: - self.commands_ran[f"{command.qualified_name}"] = 0 + # for command in self.application_commands: + # self.commands_ran[f"{command.qualified_name}"] = 0 self.blacklist: BlacklistHandler = BlacklistHandler(self, self.db) await self.blacklist.startup()