From 699d8d493e10cc61f92c680e2a3577a2716ef385 Mon Sep 17 00:00:00 2001 From: Kami Date: Mon, 10 Feb 2025 21:05:20 +0100 Subject: [PATCH] Added latency to "ping" command Ongoing bugfix for slash commands (#6) --- bot_discord.py | 2 +- bots.py | 11 +---- cmd_discord.py | 123 ++++++++++++++++++++++++++++++++++++------------- cmd_twitch.py | 2 + globals.py | 15 ++++++ 5 files changed, 109 insertions(+), 44 deletions(-) diff --git a/bot_discord.py b/bot_discord.py index 81a73b6..e694a33 100644 --- a/bot_discord.py +++ b/bot_discord.py @@ -57,7 +57,7 @@ class DiscordBot(commands.Bot): log_func=self.log ) except Exception as e: - self.log(f"Error loading Discord commands: {e}", "ERROR") + self.log(f"Error loading Discord commands: {e}", "ERROR", True) async def on_message(self, message): diff --git a/bots.py b/bots.py index 0fc4632..1c2fad3 100644 --- a/bots.py +++ b/bots.py @@ -23,16 +23,7 @@ from modules import db, utility load_dotenv() # Load bot configuration -CONFIG_PATH = "config.json" -try: - with open(CONFIG_PATH, "r") as f: - config_data = json.load(f) -except FileNotFoundError: - print("Error: config.json not found.") - sys.exit(1) -except json.JSONDecodeError as e: - print(f"Error parsing config.json: {e}") - sys.exit(1) +config_data = globals.load_config_file() # Initiate logfile logfile_path = config_data["logging"]["logfile_path"] diff --git a/cmd_discord.py b/cmd_discord.py index 803c476..a04f794 100644 --- a/cmd_discord.py +++ b/cmd_discord.py @@ -1,15 +1,40 @@ # cmd_discord.py +import discord from discord.ext import commands +from typing import Optional from cmd_common import common_commands as cc from modules.permissions import has_permission from modules.utility import handle_help_command from modules.utility import monitor_cmds +import globals def setup(bot, db_conn=None, log=None): """ Attach commands to the Discord bot, store references to db/log. """ + + config_data = globals.load_config_file() + + @bot.command() + @monitor_cmds(bot.log) + @commands.is_owner() + async def sync_commands(ctx): + """ + Trigger manual command sync. OWNER ONLY + """ + if commands.is_owner(): + primary_guild_int = int(config_data["discord_guilds"][0]) + primary_guild = discord.Object(id=primary_guild_int) + await ctx.send(f"Initiating slash sync to Discord Guild '{primary_guild_int}' ...") + try: + await bot.tree.sync(guild=primary_guild) + reply = "... Commands synced!" + except Exception as e: + reply = f"... Commands failed to sync! Error message:\n{e}" + else: + reply = "You're not the registered owner of me!" + await ctx.send(reply) @monitor_cmds(bot.log) @bot.hybrid_command(name="available", description="List commands available to you") @@ -31,6 +56,15 @@ def setup(bot, db_conn=None, log=None): else: await ctx.send("No commands are available to you at this time.") + @monitor_cmds(bot.log) + @bot.hybrid_command(name="help", description="Get information about commands") + async def cmd_help(ctx, *, cmd_name: str = ""): + """ + e.g. !help + !help quote + """ + await handle_help_command(ctx, cmd_name, bot, is_discord=True, log_func=bot.log) + @monitor_cmds(bot.log) @bot.hybrid_command(name="greet", description="Make me greet you") @@ -42,6 +76,8 @@ def setup(bot, db_conn=None, log=None): @bot.hybrid_command(name="ping", description="Check my uptime") async def cmd_ping(ctx): result = cc.ping() + latency = round(float(bot.latency) * 1000) + result += f" (*latency: {latency}ms*)" await ctx.send(result) @monitor_cmds(bot.log) @@ -108,44 +144,75 @@ def setup(bot, db_conn=None, log=None): # get_twitch_game_for_channel=None # None for Discord # ) + # @monitor_cmds(bot.log) + # @bot.hybrid_group(name="quote", description="Interact with the quotes system", with_app_command=True) + # async def cmd_quote(ctx, query: str = None): + # """ + # Usage: + # !quote -> get a random quote + # !quote -> get a specific quote by number + # As a slash command, leave the query blank for a random quote or type a number. + # """ + # if not bot.db_conn: + # return await ctx.send("Database is unavailable, sorry.") + + # # Only process the base command if no subcommand was invoked. + # # When query is provided, split it into arguments (for a specific quote lookup). + # args = query.split() if query else [] + + # await cc.handle_quote_command( + # db_conn=bot.db_conn, + # log_func=bot.log, + # is_discord=True, + # ctx=ctx, + # args=args, + # get_twitch_game_for_channel=None # None for Discord + # ) + @monitor_cmds(bot.log) @bot.hybrid_group(name="quote", description="Interact with the quotes system", with_app_command=True) - async def cmd_quote(ctx, query: str = None): + async def cmd_quote(ctx, *, id: Optional[int] = None): """ - Usage: - !quote -> get a random quote - !quote -> get a specific quote by number - As a slash command, leave the query blank for a random quote or type a number. + Handles base quote commands. + - `!quote` -> Fetch a random quote + - `!quote ` -> Fetch a specific quote by ID + - `/quote` or `/quote ` -> Works for slash commands """ if not bot.db_conn: return await ctx.send("Database is unavailable, sorry.") - - # Only process the base command if no subcommand was invoked. - # When query is provided, split it into arguments (for a specific quote lookup). - args = query.split() if query else [] - + + # If no query is provided, fetch a random quote. + if not id: + args = [] + else: + args = id.split() # Split query into arguments + await cc.handle_quote_command( db_conn=bot.db_conn, log_func=bot.log, is_discord=True, ctx=ctx, args=args, - get_twitch_game_for_channel=None # None for Discord + get_twitch_game_for_channel=None ) - + @monitor_cmds(bot.log) @cmd_quote.command(name="add", description="Add a quote") async def cmd_quote_add(ctx, *, text: str): """ Usage: - !quote add - As a slash command, type /quote add text: + - `!quote add ` + - `/quote add text:` for slash commands. """ if not bot.db_conn: return await ctx.send("Database is unavailable, sorry.") - - args = ["add", text] - + + # Ensure text isn't empty + if not text.strip(): + return await ctx.send("You must provide a quote text.") + + args = ["add", text] # Properly format arguments + await cc.handle_quote_command( db_conn=bot.db_conn, log_func=bot.log, @@ -155,19 +222,19 @@ def setup(bot, db_conn=None, log=None): get_twitch_game_for_channel=None ) - + @monitor_cmds(bot.log) @cmd_quote.command(name="remove", description="Remove a quote by number") async def cmd_quote_remove(ctx, id: int): """ Usage: - !quote remove - As a slash command, type /quote remove id: + - `!quote remove ` + - `/quote remove id:` """ if not bot.db_conn: return await ctx.send("Database is unavailable, sorry.") - - args = ["remove", str(id)] - + + args = ["remove", str(id)] # Properly pass the ID as an argument + await cc.handle_quote_command( db_conn=bot.db_conn, log_func=bot.log, @@ -177,16 +244,6 @@ def setup(bot, db_conn=None, log=None): get_twitch_game_for_channel=None ) - - @monitor_cmds(bot.log) - @bot.hybrid_command(name="help", description="Get information about commands") - async def cmd_help(ctx, cmd_name: str = None): - """ - e.g. !help - !help quote - """ - await handle_help_command(ctx, cmd_name, bot, is_discord=True, log_func=bot.log) - ###################### # The following log entry must be last in the file to verify commands loading as they should ###################### diff --git a/cmd_twitch.py b/cmd_twitch.py index 5c0fa63..dbfbbd0 100644 --- a/cmd_twitch.py +++ b/cmd_twitch.py @@ -22,6 +22,8 @@ def setup(bot, db_conn=None, log=None): @monitor_cmds(bot.log) async def cmd_ping(ctx): result = cc.ping() + latency = round(float(bot.latency) * 1000) + result += f" (*latency: {latency}ms*)" await ctx.send(result) @bot.command(name="howl") diff --git a/globals.py b/globals.py index c2f3ef7..5e3e948 100644 --- a/globals.py +++ b/globals.py @@ -1,4 +1,6 @@ import time +import json +import sys # Store the start time globally _bot_start_time = time.time() @@ -6,3 +8,16 @@ _bot_start_time = time.time() def get_bot_start_time(): """Retrieve the bot's start time globally.""" return _bot_start_time + +def load_config_file(): + CONFIG_PATH = "config.json" + try: + with open(CONFIG_PATH, "r") as f: + config_data = json.load(f) + return config_data + except FileNotFoundError: + print("Error: config.json not found.") + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error parsing config.json: {e}") + sys.exit(1) \ No newline at end of file