+ Added !help command
- Removed built-in Discord !help command NOTE: Basic implementation. Help text is defined in: - dictionary/help_twitch.json - dictionary/help_discord.jsonkami_dev
parent
780ec2e540
commit
28d22da0c1
|
@ -4,14 +4,17 @@ from discord.ext import commands
|
||||||
import importlib
|
import importlib
|
||||||
import cmd_discord
|
import cmd_discord
|
||||||
|
|
||||||
from modules import db
|
import modules
|
||||||
|
import modules.utility
|
||||||
|
|
||||||
class DiscordBot(commands.Bot):
|
class DiscordBot(commands.Bot):
|
||||||
def __init__(self, config, log_func):
|
def __init__(self, config, log_func):
|
||||||
super().__init__(command_prefix="!", intents=discord.Intents.all())
|
super().__init__(command_prefix="!", intents=discord.Intents.all())
|
||||||
|
self.remove_command("help") # Remove built-in help function
|
||||||
self.config = config
|
self.config = config
|
||||||
self.log = log_func # Use the logging function from bots.py
|
self.log = log_func # Use the logging function from bots.py
|
||||||
self.db_conn = None # We'll set this later
|
self.db_conn = None # We'll set this later
|
||||||
|
self.help_data = None # We'll set this later
|
||||||
self.load_commands()
|
self.load_commands()
|
||||||
|
|
||||||
def set_db_connection(self, db_conn):
|
def set_db_connection(self, db_conn):
|
||||||
|
@ -20,18 +23,29 @@ class DiscordBot(commands.Bot):
|
||||||
"""
|
"""
|
||||||
self.db_conn = db_conn
|
self.db_conn = db_conn
|
||||||
try:
|
try:
|
||||||
db.ensure_quotes_table(self.db_conn, self.log)
|
modules.db.ensure_quotes_table(self.db_conn, self.log)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Critical: unable to ensure quotes table: {e}", "FATAL")
|
self.log(f"Critical: unable to ensure quotes table: {e}", "FATAL")
|
||||||
|
|
||||||
def load_commands(self):
|
def load_commands(self):
|
||||||
"""
|
"""
|
||||||
Load all commands dynamically from cmd_discord.py.
|
Load all commands from cmd_discord.py
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
importlib.reload(cmd_discord)
|
importlib.reload(cmd_discord)
|
||||||
cmd_discord.setup(self)
|
cmd_discord.setup(self)
|
||||||
self.log("Discord commands loaded successfully.", "INFO")
|
self.log("Discord commands loaded successfully.", "INFO")
|
||||||
|
|
||||||
|
# Now load the help info from dictionary/help_discord.json
|
||||||
|
help_json_path = "dictionary/help_discord.json"
|
||||||
|
|
||||||
|
modules.utility.initialize_help_data(
|
||||||
|
bot=self,
|
||||||
|
help_json_path=help_json_path,
|
||||||
|
is_discord=True,
|
||||||
|
log_func=self.log
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Error loading Discord commands: {e}", "ERROR")
|
self.log(f"Error loading Discord commands: {e}", "ERROR")
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ from twitchio.ext import commands
|
||||||
import importlib
|
import importlib
|
||||||
import cmd_twitch
|
import cmd_twitch
|
||||||
|
|
||||||
from modules import db
|
import modules
|
||||||
|
import modules.utility
|
||||||
|
|
||||||
class TwitchBot(commands.Bot):
|
class TwitchBot(commands.Bot):
|
||||||
def __init__(self, config, log_func):
|
def __init__(self, config, log_func):
|
||||||
|
@ -16,7 +17,8 @@ class TwitchBot(commands.Bot):
|
||||||
self.refresh_token = os.getenv("TWITCH_REFRESH_TOKEN")
|
self.refresh_token = os.getenv("TWITCH_REFRESH_TOKEN")
|
||||||
self.log = log_func # Use the logging function from bots.py
|
self.log = log_func # Use the logging function from bots.py
|
||||||
self.config = config
|
self.config = config
|
||||||
self.db_conn = None # We'll set this later
|
self.db_conn = None # We'll set this
|
||||||
|
self.help_data = None # We'll set this later
|
||||||
|
|
||||||
# 1) Initialize the parent Bot FIRST
|
# 1) Initialize the parent Bot FIRST
|
||||||
super().__init__(
|
super().__init__(
|
||||||
|
@ -36,7 +38,7 @@ class TwitchBot(commands.Bot):
|
||||||
"""
|
"""
|
||||||
self.db_conn = db_conn
|
self.db_conn = db_conn
|
||||||
try:
|
try:
|
||||||
db.ensure_quotes_table(self.db_conn, self.log)
|
modules.db.ensure_quotes_table(self.db_conn, self.log)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Critical: unable to ensure quotes table: {e}", "FATAL")
|
self.log(f"Critical: unable to ensure quotes table: {e}", "FATAL")
|
||||||
|
|
||||||
|
@ -122,12 +124,22 @@ class TwitchBot(commands.Bot):
|
||||||
|
|
||||||
def load_commands(self):
|
def load_commands(self):
|
||||||
"""
|
"""
|
||||||
Load all commands dynamically from cmd_twitch.py.
|
Load all commands from cmd_twitch.py
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
importlib.reload(cmd_twitch)
|
importlib.reload(cmd_twitch)
|
||||||
cmd_twitch.setup(self)
|
cmd_twitch.setup(self)
|
||||||
self.log("Twitch commands loaded successfully.", "INFO")
|
self.log("Twitch commands loaded successfully.", "INFO")
|
||||||
|
|
||||||
|
# Now load the help info from dictionary/help_twitch.json
|
||||||
|
help_json_path = "dictionary/help_twitch.json"
|
||||||
|
modules.utility.initialize_help_data(
|
||||||
|
bot=self,
|
||||||
|
help_json_path=help_json_path,
|
||||||
|
is_discord=False, # Twitch
|
||||||
|
log_func=self.log
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Error loading Twitch commands: {e}", "ERROR")
|
self.log(f"Error loading Twitch commands: {e}", "ERROR")
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from cmd_common import common_commands as cc
|
from cmd_common import common_commands as cc
|
||||||
from modules.permissions import has_permission
|
from modules.permissions import has_permission
|
||||||
|
from modules.utility import handle_help_command
|
||||||
|
|
||||||
|
|
||||||
def setup(bot, db_conn=None, log=None):
|
def setup(bot, db_conn=None, log=None):
|
||||||
|
@ -16,24 +17,24 @@ def setup(bot, db_conn=None, log=None):
|
||||||
# Auto-create the quotes table if desired
|
# Auto-create the quotes table if desired
|
||||||
if db_conn and log:
|
if db_conn and log:
|
||||||
cc.create_quotes_table(db_conn, log)
|
cc.create_quotes_table(db_conn, log)
|
||||||
@bot.command()
|
@bot.command(name="greet")
|
||||||
async def greet(ctx):
|
async def cmd_greet(ctx):
|
||||||
result = cc.greet(ctx.author.display_name, "Discord")
|
result = cc.greet(ctx.author.display_name, "Discord")
|
||||||
await ctx.send(result)
|
await ctx.send(result)
|
||||||
|
|
||||||
@bot.command()
|
@bot.command(name="ping")
|
||||||
async def ping(ctx):
|
async def cmd_ping(ctx):
|
||||||
result = cc.ping()
|
result = cc.ping()
|
||||||
await ctx.send(result)
|
await ctx.send(result)
|
||||||
|
|
||||||
@bot.command()
|
@bot.command(name="howl")
|
||||||
async def howl(ctx):
|
async def cmd_howl(ctx):
|
||||||
"""Calls the shared !howl logic."""
|
"""Calls the shared !howl logic."""
|
||||||
result = cc.howl(ctx.author.display_name)
|
result = cc.howl(ctx.author.display_name)
|
||||||
await ctx.send(result)
|
await ctx.send(result)
|
||||||
|
|
||||||
@bot.command()
|
@bot.command(name="reload")
|
||||||
async def reload(ctx):
|
async def cmd_reload(ctx):
|
||||||
""" Dynamically reloads Discord commands. """
|
""" Dynamically reloads Discord commands. """
|
||||||
try:
|
try:
|
||||||
import cmd_discord
|
import cmd_discord
|
||||||
|
@ -44,8 +45,8 @@ def setup(bot, db_conn=None, log=None):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(f"Error reloading commands: {e}")
|
await ctx.send(f"Error reloading commands: {e}")
|
||||||
|
|
||||||
@bot.command()
|
@bot.command(name="hi")
|
||||||
async def hi(ctx):
|
async def cmd_hi(ctx):
|
||||||
user_id = str(ctx.author.id)
|
user_id = str(ctx.author.id)
|
||||||
user_roles = [role.name.lower() for role in ctx.author.roles] # Normalize to lowercase
|
user_roles = [role.name.lower() for role in ctx.author.roles] # Normalize to lowercase
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ def setup(bot, db_conn=None, log=None):
|
||||||
await ctx.send("Hello there!")
|
await ctx.send("Hello there!")
|
||||||
|
|
||||||
@bot.command(name="quote")
|
@bot.command(name="quote")
|
||||||
async def quote_command(ctx, *args):
|
async def cmd_quote(ctx, *args):
|
||||||
"""
|
"""
|
||||||
!quote
|
!quote
|
||||||
!quote add <text>
|
!quote add <text>
|
||||||
|
@ -74,4 +75,12 @@ def setup(bot, db_conn=None, log=None):
|
||||||
ctx=ctx,
|
ctx=ctx,
|
||||||
args=list(args),
|
args=list(args),
|
||||||
get_twitch_game_for_channel=None # None for Discord
|
get_twitch_game_for_channel=None # None for Discord
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@bot.command(name="help")
|
||||||
|
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)
|
|
@ -3,6 +3,7 @@
|
||||||
from twitchio.ext import commands
|
from twitchio.ext import commands
|
||||||
from cmd_common import common_commands as cc
|
from cmd_common import common_commands as cc
|
||||||
from modules.permissions import has_permission
|
from modules.permissions import has_permission
|
||||||
|
from modules.utility import handle_help_command
|
||||||
|
|
||||||
def setup(bot, db_conn=None, log=None):
|
def setup(bot, db_conn=None, log=None):
|
||||||
"""
|
"""
|
||||||
|
@ -15,22 +16,22 @@ def setup(bot, db_conn=None, log=None):
|
||||||
cc.create_quotes_table(bot.db_conn, bot.log)
|
cc.create_quotes_table(bot.db_conn, bot.log)
|
||||||
|
|
||||||
@bot.command(name="greet")
|
@bot.command(name="greet")
|
||||||
async def greet(ctx):
|
async def cmd_greet(ctx):
|
||||||
result = cc.greet(ctx.author.display_name, "Twitch")
|
result = cc.greet(ctx.author.display_name, "Twitch")
|
||||||
await ctx.send(result)
|
await ctx.send(result)
|
||||||
|
|
||||||
@bot.command(name="ping")
|
@bot.command(name="ping")
|
||||||
async def ping(ctx):
|
async def cmd_ping(ctx):
|
||||||
result = cc.ping()
|
result = cc.ping()
|
||||||
await ctx.send(result)
|
await ctx.send(result)
|
||||||
|
|
||||||
@bot.command(name="howl")
|
@bot.command(name="howl")
|
||||||
async def howl(ctx):
|
async def cmd_howl(ctx):
|
||||||
result = cc.howl(ctx.author.display_name)
|
result = cc.howl(ctx.author.display_name)
|
||||||
await ctx.send(result)
|
await ctx.send(result)
|
||||||
|
|
||||||
@bot.command(name="hi")
|
@bot.command(name="hi")
|
||||||
async def hi_command(ctx):
|
async def cmd_hi(ctx):
|
||||||
user_id = str(ctx.author.id) # Twitch user ID
|
user_id = str(ctx.author.id) # Twitch user ID
|
||||||
user_roles = [role.lower() for role in ctx.author.badges.keys()] # "roles" from Twitch badges
|
user_roles = [role.lower() for role in ctx.author.badges.keys()] # "roles" from Twitch badges
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ def setup(bot, db_conn=None, log=None):
|
||||||
await ctx.send("Hello there!")
|
await ctx.send("Hello there!")
|
||||||
|
|
||||||
@bot.command(name="quote")
|
@bot.command(name="quote")
|
||||||
async def quote(ctx: commands.Context):
|
async def cmd_quote(ctx: commands.Context):
|
||||||
if not bot.db_conn:
|
if not bot.db_conn:
|
||||||
return await ctx.send("Database is unavailable, sorry.")
|
return await ctx.send("Database is unavailable, sorry.")
|
||||||
|
|
||||||
|
@ -58,4 +59,10 @@ def setup(bot, db_conn=None, log=None):
|
||||||
ctx=ctx,
|
ctx=ctx,
|
||||||
args=args,
|
args=args,
|
||||||
get_twitch_game_for_channel=get_twitch_game_for_channel
|
get_twitch_game_for_channel=get_twitch_game_for_channel
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@bot.command(name="help")
|
||||||
|
async def help_command(ctx):
|
||||||
|
parts = ctx.message.content.strip().split()
|
||||||
|
cmd_name = parts[1] if len(parts) > 1 else None
|
||||||
|
await handle_help_command(ctx, cmd_name, bot, is_discord=False, log_func=bot.log)
|
|
@ -0,0 +1,68 @@
|
||||||
|
{
|
||||||
|
"commands": {
|
||||||
|
"help": {
|
||||||
|
"description": "Show information about available commands.",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": ["!help", "!help quote"]
|
||||||
|
},
|
||||||
|
"quote": {
|
||||||
|
"description": "Manage quotes (add, remove, fetch).",
|
||||||
|
"subcommands": {
|
||||||
|
"add": {
|
||||||
|
"args": "[quote_text]",
|
||||||
|
"desc": "Adds a new quote."
|
||||||
|
},
|
||||||
|
"remove": {
|
||||||
|
"args": "[quote_number]",
|
||||||
|
"desc": "Removes the specified quote by ID."
|
||||||
|
},
|
||||||
|
"[quote_number]": {
|
||||||
|
"desc": "Fetch a specific quote by ID."
|
||||||
|
},
|
||||||
|
"no subcommand": {
|
||||||
|
"desc": "Fetch a random quote."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
"!quote add This is my new quote : Add a new quote",
|
||||||
|
"!quote remove 3 : Remove quote # 3",
|
||||||
|
"!quote 5 : Fetch quote # 5",
|
||||||
|
"!quote : Fetch a random quote"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ping": {
|
||||||
|
"description": "Check my uptime.",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": ["!ping"]
|
||||||
|
},
|
||||||
|
"howl": {
|
||||||
|
"description": "Attempt a howl, measured 0-100%.\n(*Adventure Command*)",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": [
|
||||||
|
"!howl"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hi": {
|
||||||
|
"description": "Hello there.",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": [
|
||||||
|
"!hi"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"greet": {
|
||||||
|
"description": "Make me greet you to Discord!",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": [
|
||||||
|
"!greet"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"reload": {
|
||||||
|
"description": "Reload Discord commands dynamically. TODO.",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": [
|
||||||
|
"!reload"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"commands": {
|
||||||
|
"help": {
|
||||||
|
"description": "Show info about available commands in Twitch chat.",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": ["!help", "!help quote"]
|
||||||
|
},
|
||||||
|
"quote": {
|
||||||
|
"description": "Manage quotes (add, remove, fetch).",
|
||||||
|
"subcommands": {
|
||||||
|
"add": {
|
||||||
|
"args": "[quote_text]",
|
||||||
|
"desc": "Adds a new quote."
|
||||||
|
},
|
||||||
|
"remove": {
|
||||||
|
"args": "[quote_number]",
|
||||||
|
"desc": "Removes the specified quote by ID."
|
||||||
|
},
|
||||||
|
"[quote_number]": {
|
||||||
|
"desc": "Fetch a specific quote by ID."
|
||||||
|
},
|
||||||
|
"no subcommand": {
|
||||||
|
"desc": "Fetch a random quote."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
"!quote add This is my new quote",
|
||||||
|
"!quote remove 3",
|
||||||
|
"!quote 5",
|
||||||
|
"!quote"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ping": {
|
||||||
|
"description": "Check bot’s latency or respond with a pun.",
|
||||||
|
"subcommands": {},
|
||||||
|
"examples": ["!ping"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -171,3 +171,179 @@ def sanitize_user_input(
|
||||||
reason_string = "; ".join(reasons)
|
reason_string = "; ".join(reasons)
|
||||||
return (sanitized, sanitization_applied, reason_string, original_string)
|
return (sanitized, sanitization_applied, reason_string, original_string)
|
||||||
|
|
||||||
|
#####################
|
||||||
|
# Help command logic
|
||||||
|
#####################
|
||||||
|
|
||||||
|
async def handle_help_command(ctx, command_name, bot, is_discord, log_func):
|
||||||
|
"""
|
||||||
|
Called by the platform-specific help commands to provide the help text.
|
||||||
|
:param ctx: discord.py or twitchio context
|
||||||
|
:param command_name: e.g. "quote" or None if user typed just "!help"
|
||||||
|
:param bot: The current bot instance
|
||||||
|
:param is_discord: True for Discord, False for Twitch
|
||||||
|
:param log_func: The logging function
|
||||||
|
"""
|
||||||
|
|
||||||
|
# If there's no loaded help_data, we can't do much
|
||||||
|
if not hasattr(bot, "help_data") or not bot.help_data:
|
||||||
|
return await send_message(ctx, "No help data found.")
|
||||||
|
|
||||||
|
help_data = bot.help_data # The parsed JSON from e.g. help_discord.json
|
||||||
|
if "commands" not in help_data:
|
||||||
|
return await send_message(ctx, "Invalid help data structure (no 'commands' key).")
|
||||||
|
|
||||||
|
if not command_name:
|
||||||
|
# User typed just "!help" => list all known commands from this bot
|
||||||
|
loaded_cmds = get_loaded_commands(bot)
|
||||||
|
if not loaded_cmds:
|
||||||
|
return await send_message(ctx, "I have no commands loaded.")
|
||||||
|
else:
|
||||||
|
short_list = ", ".join(loaded_cmds)
|
||||||
|
# We can also mention "Use !help [command] for more info."
|
||||||
|
return await send_message(
|
||||||
|
ctx,
|
||||||
|
f"I currently offer these commands: {short_list}\nUse '!help <command>' for details."
|
||||||
|
)
|
||||||
|
|
||||||
|
# 1) Check if the command is loaded
|
||||||
|
loaded = (command_name in get_loaded_commands(bot))
|
||||||
|
# 2) Check if it has help info in the JSON
|
||||||
|
cmd_help = help_data["commands"].get(command_name, None)
|
||||||
|
|
||||||
|
if loaded and cmd_help:
|
||||||
|
# The command is loaded, and we have help info => show it
|
||||||
|
if is_discord:
|
||||||
|
msg = build_discord_help_message(command_name, cmd_help)
|
||||||
|
else:
|
||||||
|
msg = build_twitch_help_message(command_name, cmd_help)
|
||||||
|
await send_message(ctx, msg)
|
||||||
|
|
||||||
|
elif loaded and not cmd_help:
|
||||||
|
# The command is loaded but no help info => mention that
|
||||||
|
await send_message(ctx, f"The '{command_name}' command is loaded but has no help info yet.")
|
||||||
|
elif (not loaded) and cmd_help:
|
||||||
|
# The command is not loaded, but we have an entry => mention it's unloaded/deprecated
|
||||||
|
await send_message(ctx, f"The '{command_name}' command is not currently loaded (deprecated or unavailable).")
|
||||||
|
else:
|
||||||
|
# Not loaded, no help info => not found at all
|
||||||
|
await send_message(ctx, f"I'm sorry, I don't offer a command named '{command_name}'.")
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_help_data(bot, help_json_path, is_discord, log_func):
|
||||||
|
"""
|
||||||
|
Loads help data from a JSON file, stores it in bot.help_data,
|
||||||
|
then verifies each loaded command vs. the help_data.
|
||||||
|
Logs any mismatches:
|
||||||
|
- Commands in help file but not loaded => "deprecated"
|
||||||
|
- Loaded commands not in help file => "missing help"
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not os.path.exists(help_json_path):
|
||||||
|
log_func(f"Help file '{help_json_path}' not found. No help data loaded.", "WARNING")
|
||||||
|
bot.help_data = {}
|
||||||
|
return
|
||||||
|
|
||||||
|
# Load the JSON
|
||||||
|
try:
|
||||||
|
with open(help_json_path, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
log_func(f"Error parsing help JSON '{help_json_path}': {e}", "ERROR")
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
bot.help_data = data
|
||||||
|
|
||||||
|
# Now cross-check the loaded commands vs. the data
|
||||||
|
loaded_cmds = set(get_loaded_commands(bot))
|
||||||
|
if "commands" not in data:
|
||||||
|
log_func(f"No 'commands' key in {help_json_path}, skipping checks.", "ERROR")
|
||||||
|
return
|
||||||
|
|
||||||
|
file_cmds = set(data["commands"].keys())
|
||||||
|
|
||||||
|
# 1) Commands in file but not loaded
|
||||||
|
missing_cmds = file_cmds - loaded_cmds
|
||||||
|
for cmd in missing_cmds:
|
||||||
|
log_func(f"Help file has '{cmd}', but it's not loaded on this {'Discord' if is_discord else 'Twitch'} bot (deprecated?).", "WARNING")
|
||||||
|
|
||||||
|
# 2) Commands loaded but not in file
|
||||||
|
needed_cmds = loaded_cmds - file_cmds
|
||||||
|
for cmd in needed_cmds:
|
||||||
|
log_func(f"Command '{cmd}' is loaded on {('Discord' if is_discord else 'Twitch')} but no help info is provided in {help_json_path}.", "WARNING")
|
||||||
|
|
||||||
|
|
||||||
|
def get_loaded_commands(bot):
|
||||||
|
commands_list = []
|
||||||
|
|
||||||
|
# For Discord.py
|
||||||
|
if hasattr(bot, "commands"):
|
||||||
|
for c_obj in bot.commands:
|
||||||
|
commands_list.append(c_obj.name)
|
||||||
|
|
||||||
|
# For TwitchIO
|
||||||
|
if hasattr(bot, "all_commands"):
|
||||||
|
# each item is (command_name_str, command_object)
|
||||||
|
for cmd_name, cmd_obj in bot.all_commands.items():
|
||||||
|
commands_list.append(cmd_name)
|
||||||
|
|
||||||
|
return sorted(commands_list)
|
||||||
|
|
||||||
|
|
||||||
|
def build_discord_help_message(cmd_name, cmd_help_dict):
|
||||||
|
"""
|
||||||
|
A verbose multi-line string for Discord.
|
||||||
|
"""
|
||||||
|
description = cmd_help_dict.get("description", "No description available.\n")
|
||||||
|
subcommands = cmd_help_dict.get("subcommands", {})
|
||||||
|
examples = cmd_help_dict.get("examples", [])
|
||||||
|
|
||||||
|
lines = [f"**Help for `!{cmd_name}`**:",
|
||||||
|
f"Description: {description}"]
|
||||||
|
|
||||||
|
if subcommands:
|
||||||
|
lines.append("\n**Subcommands / Arguments:**")
|
||||||
|
for sub, detail in subcommands.items():
|
||||||
|
arg_part = detail.get("args", "")
|
||||||
|
desc_part = detail.get("desc", "")
|
||||||
|
lines.append(f"• **{sub}** {arg_part} **->** {desc_part}")
|
||||||
|
else:
|
||||||
|
lines.append("\n*No subcommands defined.*")
|
||||||
|
|
||||||
|
if examples:
|
||||||
|
lines.append("\nExample usage:")
|
||||||
|
for ex in examples:
|
||||||
|
ex_cmd = ex.split(" : ")[0]
|
||||||
|
ex_note = ex.split(" : ")[1]
|
||||||
|
lines.append(f"- `{ex_cmd}`\n {ex_note}")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def build_twitch_help_message(cmd_name, cmd_help_dict):
|
||||||
|
"""
|
||||||
|
A concise, possibly single-line help for Twitch.
|
||||||
|
"""
|
||||||
|
description = cmd_help_dict.get("description", "No description available.")
|
||||||
|
subcommands = cmd_help_dict.get("subcommands", {})
|
||||||
|
sub_line_parts = []
|
||||||
|
for sub, detail in subcommands.items():
|
||||||
|
if sub == "no subcommand":
|
||||||
|
sub_line_parts.append(f"!{cmd_name}")
|
||||||
|
else:
|
||||||
|
arg_part = detail.get("args", "")
|
||||||
|
if arg_part:
|
||||||
|
sub_line_parts.append(f"!{cmd_name} {sub} {arg_part}".strip())
|
||||||
|
else:
|
||||||
|
sub_line_parts.append(f"!{cmd_name} {sub}".strip())
|
||||||
|
|
||||||
|
usage_line = " | ".join(sub_line_parts) if sub_line_parts else f"!{cmd_name}"
|
||||||
|
|
||||||
|
return f"Help for !{cmd_name}: {description}. Usage: {usage_line}"
|
||||||
|
|
||||||
|
|
||||||
|
async def send_message(ctx, text):
|
||||||
|
"""
|
||||||
|
Minimal helper to send a message to either Discord or Twitch.
|
||||||
|
"""
|
||||||
|
await ctx.send(text)
|
Loading…
Reference in New Issue