From d24b8101646c84548b3b95c7eccb1377a067b2bf Mon Sep 17 00:00:00 2001 From: TheOnlyMace <0815cracky@gmail.com> Date: Tue, 21 Jul 2026 22:59:25 +0200 Subject: [PATCH] Refactor command definitions across various cogs to replace hybrid commands with regular commands for improved consistency and clarity. Update command structures in moderation, music, and other cogs to enhance user experience and streamline command handling. --- bot/cogs/__init__.py | 3 +- bot/cogs/commands/Games.py | 63 +++++---- bot/cogs/commands/Media.py | 8 +- bot/cogs/commands/anti_wl.py | 30 +++- bot/cogs/commands/automod.py | 10 +- bot/cogs/commands/customrole.py | 26 +++- bot/cogs/commands/extra.py | 7 +- bot/cogs/commands/filters.py | 7 +- bot/cogs/commands/giveaway.py | 25 +++- bot/cogs/commands/logging.py | 7 +- bot/cogs/commands/music.py | 50 ++++--- bot/cogs/commands/ticket.py | 7 +- bot/cogs/commands/welcome.py | 8 +- bot/cogs/moderation/ban.py | 2 +- bot/cogs/moderation/hide.py | 2 +- bot/cogs/moderation/kick.py | 2 +- bot/cogs/moderation/lock.py | 2 +- bot/cogs/moderation/mod_hub.py | 224 ++++++++++++++++++++++++++++++ bot/cogs/moderation/moderation.py | 29 ++-- bot/cogs/moderation/timeout.py | 2 +- bot/cogs/moderation/unban.py | 2 +- bot/cogs/moderation/unhide.py | 2 +- bot/cogs/moderation/unlock.py | 2 +- bot/cogs/moderation/unmute.py | 2 +- bot/cogs/moderation/warn.py | 4 +- 25 files changed, 436 insertions(+), 90 deletions(-) create mode 100644 bot/cogs/moderation/mod_hub.py diff --git a/bot/cogs/__init__.py b/bot/cogs/__init__.py index e974cb5..997f0ee 100644 --- a/bot/cogs/__init__.py +++ b/bot/cogs/__init__.py @@ -161,6 +161,7 @@ from .moderation.warn import Warn from .moderation.role import Role from .moderation.message import Message from .moderation.moderation import Moderation +from .moderation.mod_hub import ModHub from .moderation.topcheck import TopCheck from .moderation.snipe import Snipe @@ -187,7 +188,7 @@ COG_CLASSES: tuple[type, ...] = ( AntiWebhookCreate, AntiWebhookDelete, AntiSpam, AntiCaps, AntiInvite, AntiLink, AntiMassMention, AntiEmojiSpam, Ban, Unban, Mute, Unmute, Lock, Unlock, Hide, Unhide, Kick, Warn, Role, - Message, Moderation, TopCheck, Snipe, + Message, Moderation, ModHub, TopCheck, Snipe, ) diff --git a/bot/cogs/commands/Games.py b/bot/cogs/commands/Games.py index b365a19..a60deb9 100644 --- a/bot/cogs/commands/Games.py +++ b/bot/cogs/commands/Games.py @@ -30,10 +30,25 @@ class Games(Cog): def __init__(self, client: Axiom): self.client = client + @commands.hybrid_group( + name="game", + description="Play mini-games with friends or the bot.", + fallback="help", + invoke_without_command=True, + ) + @blacklist_check() + @ignore_check() + @commands.cooldown(1, 3, commands.BucketType.user) + @commands.guild_only() + async def game(self, ctx: Context): + """Games root — use `/game ` or `>game `.""" + if ctx.subcommand_passed is None: + await ctx.send_help(ctx.command) + ctx.command.reset_cooldown(ctx) - @commands.hybrid_command(name="chess", + @game.command(name="chess", help="Play Chess with a user.", - usage="Chess ") + usage="game chess ") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -49,10 +64,10 @@ class Games(Cog): await game.start(ctx) - @commands.hybrid_command(name="rps", + @game.command(name="rps", help="Play Rock Paper Scissor with bot/user.", aliases=["rockpaperscissors"], - usage="Rockpaperscissors") + usage="game rps [user]") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -62,10 +77,10 @@ class Games(Cog): game = btn.BetaRockPaperScissors(player) await game.start(ctx, timeout=120) - @commands.hybrid_command(name="tic-tac-toe", + @game.command(name="tictactoe", help="play tic-tac-toe game with a user.", - aliases=["ttt", "tictactoe"], - usage="Ticktactoe ") + aliases=["ttt", "tic-tac-toe"], + usage="game tictactoe ") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -80,9 +95,9 @@ class Games(Cog): game = btn.BetaTictactoe(cross=ctx.author, circle=player) await game.start(ctx, timeout=30) - @commands.hybrid_command(name="wordle", + @game.command(name="wordle", help="Wordle Game | Play with bot.", - usage="Wordle") + usage="game wordle") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -92,10 +107,10 @@ class Games(Cog): game = games.Wordle() await game.start(ctx, timeout=120) - @commands.hybrid_command(name="2048", + @game.command(name="2048", help="Play 2048 game with bot.", aliases=["twenty48"], - usage="2048") + usage="game 2048") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -105,10 +120,10 @@ class Games(Cog): game = btn.BetaTwenty48() await game.start(ctx, win_at=2048) - @commands.hybrid_command(name="memory-game", + @game.command(name="memory", help="How strong is your memory?", - aliases=["memory"], - usage="memory-game") + aliases=["memory-game"], + usage="game memory") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -118,10 +133,10 @@ class Games(Cog): game = btn.MemoryGame() await game.start(ctx) - @commands.hybrid_command(name="number-slider", + @game.command(name="slider", help="slide numbers with bot", - aliases=["slider"], - usage="slider") + aliases=["number-slider"], + usage="game slider") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -131,10 +146,10 @@ class Games(Cog): game = btn.NumberSlider() await game.start(ctx) - @commands.hybrid_command(name="battleship", + @game.command(name="battleship", help="Play battleship game with your friend.", aliases=["battle-ship"], - usage="battleship ") + usage="game battleship ") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -164,10 +179,10 @@ class Games(Cog): async def _end_country_guesser(self, ctx: Context): await self.country_guesser_game.end_game_manually(ctx)""" - @commands.hybrid_command(name="connectfour", + @game.command(name="connectfour", help="Play Connect Four game with user.", aliases=["c4", "connect-four", "connect4"], - usage="connectfour ") + usage="game connectfour ") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -184,10 +199,10 @@ class Games(Cog): - @commands.hybrid_command(name="lights-out", + @game.command(name="lightsout", help="Play Lights Show game with bot.", - aliases=["lightsout"], - usage="Lights-out") + aliases=["lights-out"], + usage="game lightsout") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) diff --git a/bot/cogs/commands/Media.py b/bot/cogs/commands/Media.py index 9154b5d..197caa7 100644 --- a/bot/cogs/commands/Media.py +++ b/bot/cogs/commands/Media.py @@ -47,7 +47,13 @@ class Media(commands.Cog): async def on_ready(self): await self.set_db() - @commands.hybrid_group(name="media", help="Setup Media channel, Media channel will not allow users to send messages other than media files.", invoke_without_command=True) + @commands.hybrid_group( + name="media", + description="Setup Media channel; only media files are allowed.", + help="Setup Media channel, Media channel will not allow users to send messages other than media files.", + fallback="help", + invoke_without_command=True, + ) @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) diff --git a/bot/cogs/commands/anti_wl.py b/bot/cogs/commands/anti_wl.py index 88f221d..fc614b0 100644 --- a/bot/cogs/commands/anti_wl.py +++ b/bot/cogs/commands/anti_wl.py @@ -57,16 +57,34 @@ class Whitelist(commands.Cog): ''') await self.db.commit() - @commands.hybrid_command(name='whitelist', aliases=['wl'], help="Whitelists a user from antinuke for a specific action.") - + @commands.hybrid_group( + name="whitelist", + aliases=["wl"], + description="Manage antinuke whitelist.", + fallback="help", + invoke_without_command=True, + help="Whitelists a user from antinuke for a specific action.", + ) @blacklist_check() @ignore_check() @commands.cooldown(1, 5, commands.BucketType.user) @commands.max_concurrency(1, per=commands.BucketType.default, wait=False) @commands.guild_only() @commands.has_permissions(administrator=True) + async def whitelist(self, ctx): + """Whitelist root — use `/whitelist ` or `>whitelist `.""" + if ctx.subcommand_passed is None: + await ctx.send_help(ctx.command) + ctx.command.reset_cooldown(ctx) - async def whitelist(self, ctx, member: discord.Member = None): + @whitelist.command(name="add", help="Whitelists a user from antinuke for a specific action.") + @blacklist_check() + @ignore_check() + @commands.cooldown(1, 5, commands.BucketType.user) + @commands.max_concurrency(1, per=commands.BucketType.default, wait=False) + @commands.guild_only() + @commands.has_permissions(administrator=True) + async def whitelist_add(self, ctx, member: discord.Member = None): if ctx.guild.member_count < 2: view = CV2(f"{CROSS} Error", "Your Server Doesn't Meet My 30 Member Criteria") return await ctx.send(view=view) @@ -101,7 +119,7 @@ class Whitelist(commands.Cog): view = CV2( "__Whitelist Commands__", "**Adding a user to the whitelist means that no actions will be taken against them if they trigger the Anti-Nuke Module.**", - f"**Usage**\n{ARROWRED} `{prefix}whitelist @user/id`\n{ARROWRED} `{prefix}wl @user`" + f"**Usage**\n{ARROWRED} `{prefix}whitelist add @user/id`\n{ARROWRED} `{prefix}wl add @user`" ) return await ctx.send(view=view) @@ -252,7 +270,7 @@ class Whitelist(commands.Cog): await msg.edit(view=None) - @commands.hybrid_command(name='whitelisted', aliases=['wlist'], help="Shows the list of whitelisted users.") + @whitelist.command(name="list", aliases=["whitelisted", "wlist"], help="Shows the list of whitelisted users.") @blacklist_check() @ignore_check() @commands.cooldown(1, 5, commands.BucketType.user) @@ -308,7 +326,7 @@ class Whitelist(commands.Cog): await ctx.send(view=view) - @commands.hybrid_command(name="whitelistreset", aliases=['wlreset'], help="Resets the whitelisted users.") + @whitelist.command(name="reset", aliases=["whitelistreset", "wlreset"], help="Resets the whitelisted users.") @blacklist_check() @ignore_check() @commands.cooldown(1, 10, commands.BucketType.user) diff --git a/bot/cogs/commands/automod.py b/bot/cogs/commands/automod.py index 59f6fa3..22983b1 100644 --- a/bot/cogs/commands/automod.py +++ b/bot/cogs/commands/automod.py @@ -183,11 +183,19 @@ class Automod(commands.Cog): """) await db.commit() - @commands.hybrid_group(invoke_without_command=True) + @commands.hybrid_group( + name="automod", + aliases=["am"], + invoke_without_command=True, + with_app_command=True, + description="Configure server Automod (enable, disable, punishments, ignores).", + fallback="help", + ) @blacklist_check() @ignore_check() @commands.cooldown(1, 4, commands.BucketType.user) async def automod(self, ctx): + """Automod root — use `/automod ` or `>automod `.""" if ctx.subcommand_passed is None: await ctx.send_help(ctx.command) ctx.command.reset_cooldown(ctx) diff --git a/bot/cogs/commands/customrole.py b/bot/cogs/commands/customrole.py index 2db74ac..9d30fb0 100644 --- a/bot/cogs/commands/customrole.py +++ b/bot/cogs/commands/customrole.py @@ -500,7 +500,23 @@ class Customrole(commands.Cog): - @commands.hybrid_command(name="staff", + @commands.hybrid_group( + name="customrole", + aliases=["cr"], + description="Assign or remove custom roles for members.", + fallback="help", + invoke_without_command=True, + ) + @blacklist_check() + @ignore_check() + @commands.cooldown(1, 3, commands.BucketType.user) + async def customrole(self, context: Context): + """Customrole root — use `/customrole ` or `>customrole `.""" + if context.subcommand_passed is None: + await context.send_help(context.command) + context.command.reset_cooldown(context) + + @customrole.command(name="staff", description="Gives the staff role to the user.", aliases=['official'], help="Gives the staff role to the user.") @@ -511,7 +527,7 @@ class Customrole(commands.Cog): async def _staff(self, context: Context, member: discord.Member) -> None: await self.handle_role_command(context, member, 'staff') - @commands.hybrid_command(name="girl", + @customrole.command(name="girl", description="Gives the girl role to the user.", aliases=['qt'], help="Gives the girl role to the user.") @@ -522,7 +538,7 @@ class Customrole(commands.Cog): async def _girl(self, context: Context, member: discord.Member) -> None: await self.handle_role_command(context, member, 'girl') - @commands.hybrid_command(name="vip", + @customrole.command(name="vip", description="Gives the VIP role to the user.", help="Gives the VIP role to the user.") @blacklist_check() @@ -532,7 +548,7 @@ class Customrole(commands.Cog): async def _vip(self, context: Context, member: discord.Member) -> None: await self.handle_role_command(context, member, 'vip') - @commands.hybrid_command(name="guest", + @customrole.command(name="guest", description="Gives the guest role to the user.", help="Gives the guest role to the user.") @blacklist_check() @@ -542,7 +558,7 @@ class Customrole(commands.Cog): async def _guest(self, context: Context, member: discord.Member) -> None: await self.handle_role_command(context, member, 'guest') - @commands.hybrid_command(name="friend", + @customrole.command(name="friend", description="Gives the friend role to the user.", aliases=['frnd'], help="Gives the friend role to the user.") diff --git a/bot/cogs/commands/extra.py b/bot/cogs/commands/extra.py index f2f904d..5157d85 100644 --- a/bot/cogs/commands/extra.py +++ b/bot/cogs/commands/extra.py @@ -125,7 +125,12 @@ class Extra(commands.Cog): self.color = 0xFF0000 self.start_time = datetime.datetime.now() - @commands.hybrid_group(name="banner") + @commands.hybrid_group( + name="banner", + description="Show user or server banners.", + fallback="help", + invoke_without_command=True, + ) @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) diff --git a/bot/cogs/commands/filters.py b/bot/cogs/commands/filters.py index 558c6c5..0c6d2a0 100644 --- a/bot/cogs/commands/filters.py +++ b/bot/cogs/commands/filters.py @@ -66,7 +66,12 @@ class FilterCog(commands.Cog): self.active_filters[ctx.guild.id] = filter_name await ctx.send(embed=discord.Embed(description=f"Filter set to **{filter_name}**.", color=discord.Color.green())) - @commands.hybrid_group(invoke_without_command=True) + @commands.hybrid_group( + name="filter", + description="Enable or disable audio filters for music.", + fallback="help", + invoke_without_command=True, + ) @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) diff --git a/bot/cogs/commands/giveaway.py b/bot/cogs/commands/giveaway.py index 8038565..194cd61 100644 --- a/bot/cogs/commands/giveaway.py +++ b/bot/cogs/commands/giveaway.py @@ -159,7 +159,24 @@ class Giveaway(commands.Cog): - @commands.hybrid_command(description="Starts a new giveaway.") + @commands.hybrid_group( + name="giveaway", + aliases=["g"], + description="Manage server giveaways.", + fallback="help", + invoke_without_command=True, + ) + @blacklist_check() + @ignore_check() + @commands.cooldown(1, 5, commands.BucketType.user) + @commands.has_guild_permissions(manage_guild=True) + async def giveaway(self, ctx): + """Giveaway root — use `/giveaway ` or `>giveaway `.""" + if ctx.subcommand_passed is None: + await ctx.send_help(ctx.command) + ctx.command.reset_cooldown(ctx) + + @giveaway.command(name="start", aliases=["gstart"], description="Starts a new giveaway.") @blacklist_check() @ignore_check() @commands.cooldown(1, 5, commands.BucketType.user) @@ -244,7 +261,7 @@ class Giveaway(commands.Cog): print(f"Giveaway message deleted in {message.guild.name} - {message.guild.id}") await self.connection.commit() - @commands.hybrid_command(name="gend", description="Ends a giveaway before its ending time.", help="Ends a giveaway before its ending time.") + @giveaway.command(name="end", aliases=["gend"], description="Ends a giveaway before its ending time.", help="Ends a giveaway before its ending time.") @blacklist_check() @ignore_check() @commands.cooldown(1, 5, commands.BucketType.user) @@ -329,7 +346,7 @@ class Giveaway(commands.Cog): await ctx.send("Please reply to the giveaway message or provide the giveaway ID.") await self.connection.commit() - @commands.hybrid_command(description="Rerolls a giveaway on replying the giveaway message.", help="Rerolls a giveaway on replying the giveaway message.") + @giveaway.command(name="reroll", aliases=["greroll"], description="Rerolls a giveaway on replying the giveaway message.", help="Rerolls a giveaway on replying the giveaway message.") @blacklist_check() @ignore_check() @commands.cooldown(1, 5, commands.BucketType.user) @@ -389,7 +406,7 @@ class Giveaway(commands.Cog): return val * time_dict[unit] - @commands.hybrid_command(name="glist", description="Lists all ongoing giveaways.") + @giveaway.command(name="list", aliases=["glist"], description="Lists all ongoing giveaways.") @blacklist_check() @ignore_check() @commands.cooldown(1, 5, commands.BucketType.user) diff --git a/bot/cogs/commands/logging.py b/bot/cogs/commands/logging.py index 94500f1..7c38b7d 100644 --- a/bot/cogs/commands/logging.py +++ b/bot/cogs/commands/logging.py @@ -1598,7 +1598,12 @@ class Logging(commands.Cog): embeds.append(config_embed) return embeds - @commands.hybrid_group(invoke_without_command=True, name="log") + @commands.hybrid_group( + invoke_without_command=True, + name="log", + description="Configure server logging channels and events.", + fallback="help", + ) async def log(self, ctx: commands.Context): """Main logging command group. Works with both slash (/) and prefix (!) commands.""" diff --git a/bot/cogs/commands/music.py b/bot/cogs/commands/music.py index d0d710e..2b0d835 100644 --- a/bot/cogs/commands/music.py +++ b/bot/cogs/commands/music.py @@ -585,7 +585,23 @@ class Music(commands.Cog): bar = '█' * filled_length + '░' * (length - filled_length) return bar - @commands.command(name="play", aliases=['p'], usage="play ", help="Plays a song or playlist.") + @commands.hybrid_group( + name="music", + aliases=["m"], + description="Music player commands.", + fallback="help", + invoke_without_command=True, + ) + @blacklist_check() + @ignore_check() + @commands.cooldown(1, 3, commands.BucketType.user) + async def music(self, ctx: commands.Context): + """Music root — use `/music ` or `>music `.""" + if ctx.subcommand_passed is None: + await ctx.send_help(ctx.command) + ctx.command.reset_cooldown(ctx) + + @music.command(name="play", aliases=['p'], usage="music play ", help="Plays a song or playlist.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -594,7 +610,7 @@ class Music(commands.Cog): await self.play_source(ctx, query) - @commands.command(name="search", usage="search ", help="Searches music from multiple platforms.") + @music.command(name="search", usage="music search ", help="Searches music from multiple platforms.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -606,7 +622,7 @@ class Music(commands.Cog): await ctx.send(view=PlatformSelectView(ctx, query)) - @commands.command(name="nowplaying", aliases=["nop"], usage="nowplaying", help="Shows the info about current playing song.") + @music.command(name="nowplaying", aliases=["nop"], usage="music nowplaying", help="Shows the info about current playing song.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -659,7 +675,7 @@ class Music(commands.Cog): await ctx.send(view=view) - @commands.command(name="autoplay", usage="autoplay", help="Toggles autoplay mode.") + @music.command(name="autoplay", usage="music autoplay", help="Toggles autoplay mode.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -679,7 +695,7 @@ class Music(commands.Cog): ) await ctx.send(view=CV2(f"{TICK} Autoplay {'enabled' if vc.autoplay == wavelink.AutoPlayMode.enabled else 'disabled'} by {ctx.author.mention}.")) - @commands.command(name="loop", usage="loop", help="Toggles loop mode.") + @music.command(name="loop", usage="music loop", help="Toggles loop mode.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -700,7 +716,7 @@ class Music(commands.Cog): await ctx.send(view=CV2("I'm not connected to a voice channel.")) - @commands.command(name="pause", usage="pause", help="Pauses the current song.") + @music.command(name="pause", usage="music pause", help="Pauses the current song.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -721,7 +737,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2(f"{WARNING} Nothing is playing or already paused.")) - @commands.command(name="resume", usage="resume", help="Resumes the paused song.") + @music.command(name="resume", usage="music resume", help="Resumes the paused song.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -742,7 +758,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("Player is not paused.")) - @commands.command(name="skip", usage="skip", help="Skips the current song.") + @music.command(name="skip", usage="music skip", help="Skips the current song.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -767,7 +783,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2(f"{WARNING} No song is playing or in the queue to skip.")) - @commands.command(name="shuffle", usage="shuffle", help="Shuffles the queue.") + @music.command(name="shuffle", usage="music shuffle", help="Shuffles the queue.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -787,7 +803,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("Queue is empty.")) - @commands.command(name="stop", usage="stop", help="Stops the current song and clears the queue.") + @music.command(name="stop", usage="music stop", help="Stops the current song and clears the queue.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -810,7 +826,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("Nothing is playing to stop.")) - @commands.command(name="volume", aliases=["vol"], usage="volume ", help="Sets the volume of the player.") + @music.command(name="volume", aliases=["vol"], usage="music volume ", help="Sets the volume of the player.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -834,7 +850,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("Bot is not connected to a voice channel.")) - @commands.command(name="queue", usage="queue", help="Shows the current queue.") + @music.command(name="queue", usage="music queue", help="Shows the current queue.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -860,7 +876,7 @@ class Music(commands.Cog): ctx=ctx) await paginator.paginate() - @commands.command(name="clearqueue", usage="clearqueue", help="Clears the queue.") + @music.command(name="clearqueue", usage="music clearqueue", help="Clears the queue.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -881,7 +897,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("No queue to clear.")) - @commands.command(name="replay", usage="replay", help="Replays the current song.") + @music.command(name="replay", usage="music replay", help="Replays the current song.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -902,7 +918,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("No track is currently playing.")) - @commands.command(name="join", aliases=["connect"], usage="join", help="Joins the voice channel.") + @music.command(name="join", aliases=["connect"], usage="music join", help="Joins the voice channel.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -913,7 +929,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("You need to join a voice channel first.")) - @commands.hybrid_command(name="disconnect", aliases=["dc", "leave"], usage="disconnect", help="Disconnects the bot from the voice channel.") + @music.command(name="disconnect", aliases=["dc", "leave"], usage="music disconnect", help="Disconnects the bot from the voice channel.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) @@ -933,7 +949,7 @@ class Music(commands.Cog): else: await ctx.send(view=CV2("Bot is not connected to any voice channel.")) - @commands.command(name="seek", usage="seek ", help="Seeks to a specific percentage of the song.") + @music.command(name="seek", usage="music seek ", help="Seeks to a specific percentage of the song.") @blacklist_check() @ignore_check() @commands.cooldown(1, 3, commands.BucketType.user) diff --git a/bot/cogs/commands/ticket.py b/bot/cogs/commands/ticket.py index dd19e3c..a84cd85 100644 --- a/bot/cogs/commands/ticket.py +++ b/bot/cogs/commands/ticket.py @@ -378,7 +378,12 @@ class TicketCog(commands.Cog, name="Ticket System"): await ch.send(content=" ".join(pings), embed=ticket_embed, view=TicketActionsView(self, ch.id, cat_id)) await inter.followup.send(f"Your ticket has been successfully created: {ch.mention}", ephemeral=True) - @commands.hybrid_group(name="ticket", description="Main command group for the ticket system.") + @commands.hybrid_group( + name="ticket", + description="Main command group for the ticket system.", + fallback="help", + invoke_without_command=True, + ) @commands.guild_only() async def ticket(self, ctx): if ctx.invoked_subcommand is None: await ctx.send_help(ctx.command) diff --git a/bot/cogs/commands/welcome.py b/bot/cogs/commands/welcome.py index e523e19..b7a1840 100644 --- a/bot/cogs/commands/welcome.py +++ b/bot/cogs/commands/welcome.py @@ -78,7 +78,13 @@ class Welcomer(commands.Cog): """) await db.commit() - @commands.hybrid_group(invoke_without_command=True, name="greet", help="Shows all the greet commands.") + @commands.hybrid_group( + invoke_without_command=True, + name="greet", + description="Configure welcome/greet messages for new members.", + help="Shows all the greet commands.", + fallback="help", + ) @blacklist_check() @ignore_check() async def greet(self, ctx: commands.Context): diff --git a/bot/cogs/moderation/ban.py b/bot/cogs/moderation/ban.py index e9b5d40..612204f 100644 --- a/bot/cogs/moderation/ban.py +++ b/bot/cogs/moderation/ban.py @@ -25,7 +25,7 @@ class Ban(commands.Cog): def get_user_avatar(self, user): return user.avatar.url if user.avatar else user.default_avatar.url - @commands.hybrid_command( + @commands.command( name="ban", help="Bans a user from the Server", usage="ban ", diff --git a/bot/cogs/moderation/hide.py b/bot/cogs/moderation/hide.py index d866f8d..8242c42 100644 --- a/bot/cogs/moderation/hide.py +++ b/bot/cogs/moderation/hide.py @@ -20,7 +20,7 @@ class Hide(commands.Cog): self.bot = bot self.color = discord.Color.from_rgb(255, 0, 0) # Red color for embeds - @commands.hybrid_command( + @commands.command( name="hide", help="Hides a channel from the default role (@everyone).", usage="hide [channel]", diff --git a/bot/cogs/moderation/kick.py b/bot/cogs/moderation/kick.py index 5c8c01d..ae57cd1 100644 --- a/bot/cogs/moderation/kick.py +++ b/bot/cogs/moderation/kick.py @@ -22,7 +22,7 @@ class Kick(commands.Cog): # Color is set to Red (255, 0, 0) as requested self.color = discord.Color.from_rgb(255, 0, 0) - @commands.hybrid_command( + @commands.command( name="kick", help="Kicks a member from the server.", usage="kick [reason]", diff --git a/bot/cogs/moderation/lock.py b/bot/cogs/moderation/lock.py index 71bc72d..a09303e 100644 --- a/bot/cogs/moderation/lock.py +++ b/bot/cogs/moderation/lock.py @@ -20,7 +20,7 @@ class Lock(commands.Cog): self.bot = bot self.color = discord.Color.red() - @commands.hybrid_command( + @commands.command( name="lock", description="Locks a channel to prevent sending messages.", aliases=["lockchannel"] diff --git a/bot/cogs/moderation/mod_hub.py b/bot/cogs/moderation/mod_hub.py new file mode 100644 index 0000000..3fa14ab --- /dev/null +++ b/bot/cogs/moderation/mod_hub.py @@ -0,0 +1,224 @@ +# ╔══════════════════════════════════════════════════════════════════╗ +# ║ ║ +# ║ +-+-+-+-+-+-+-+-+ ║ +# ║ |H|e|x|a|H|o|s|t| ║ +# ║ +-+-+-+-+-+-+-+-+ ║ +# ║ ║ +# ║ © 2026 HexaHost — All Rights Reserved ║ +# ║ ║ +# ║ discord ── https://discord.gg/hexahost ║ +# ║ github ── https://github.com/theoneandonlymace ║ +# ║ ║ +# ╚══════════════════════════════════════════════════════════════════╝ + +from __future__ import annotations + +import discord +from discord.ext import commands + + +class ModHub(commands.Cog): + """Slash/prefix hub that exposes moderation actions under `/mod `.""" + + def __init__(self, bot): + self.bot = bot + + async def _get_cog(self, ctx: commands.Context, name: str): + cog = self.bot.get_cog(name) + if not cog: + await ctx.send(f"{name} module unavailable.") + return None + return cog + + @commands.hybrid_group( + name="mod", + description="Moderation commands", + fallback="help", + invoke_without_command=True, + ) + @commands.guild_only() + async def mod(self, ctx: commands.Context): + """Moderation root — use `/mod ` or `>mod `.""" + if ctx.subcommand_passed is None: + await ctx.send_help(ctx.command) + + @mod.command(name="ban", description="Ban a user") + @commands.has_permissions(ban_members=True) + @commands.bot_has_permissions(ban_members=True) + @commands.guild_only() + async def mod_ban(self, ctx: commands.Context, user: discord.User, *, reason: str = None): + cog = await self._get_cog(ctx, "Ban") + if not cog: + return + await cog.ban(ctx, user, reason=reason) + + @mod.command(name="unban", description="Unban a user") + @commands.has_permissions(ban_members=True) + @commands.bot_has_permissions(ban_members=True) + @commands.guild_only() + async def mod_unban(self, ctx: commands.Context, user: discord.User, *, reason: str = None): + cog = await self._get_cog(ctx, "Unban") + if not cog: + return + await cog.unban(ctx, user, reason=reason) + + @mod.command(name="kick", description="Kick a member") + @commands.has_permissions(kick_members=True) + @commands.bot_has_permissions(kick_members=True) + @commands.guild_only() + async def mod_kick(self, ctx: commands.Context, member: discord.Member, *, reason: str = None): + cog = await self._get_cog(ctx, "Kick") + if not cog: + return + await cog.kick_command(ctx, member, reason=reason) + + @mod.command(name="mute", description="Mute / timeout a member") + @commands.has_permissions(moderate_members=True) + @commands.bot_has_permissions(moderate_members=True) + @commands.guild_only() + async def mod_mute( + self, + ctx: commands.Context, + user: discord.Member, + time: str = None, + *, + reason: str = None, + ): + cog = await self._get_cog(ctx, "Mute") + if not cog: + return + await cog.mute(ctx, user, time, reason=reason) + + @mod.command(name="unmute", description="Remove a timeout from a member") + @commands.has_permissions(moderate_members=True) + @commands.bot_has_permissions(moderate_members=True) + @commands.guild_only() + async def mod_unmute(self, ctx: commands.Context, user: discord.Member): + cog = await self._get_cog(ctx, "Unmute") + if not cog: + return + await cog.unmute(ctx, user) + + @mod.command(name="warn", description="Warn a member") + @commands.has_permissions(moderate_members=True) + @commands.guild_only() + async def mod_warn(self, ctx: commands.Context, user: discord.Member, *, reason: str = None): + cog = await self._get_cog(ctx, "Warn") + if not cog: + return + await cog.warn(ctx, user, reason=reason) + + @mod.command(name="clearwarns", description="Clear warnings for a member") + @commands.has_permissions(moderate_members=True) + @commands.guild_only() + async def mod_clearwarns(self, ctx: commands.Context, user: discord.Member): + cog = await self._get_cog(ctx, "Warn") + if not cog: + return + await cog.clearwarns(ctx, user) + + @mod.command(name="lock", description="Lock a channel") + @commands.has_permissions(manage_channels=True) + @commands.bot_has_permissions(manage_channels=True) + @commands.guild_only() + async def mod_lock(self, ctx: commands.Context, channel: discord.TextChannel = None): + cog = await self._get_cog(ctx, "Lock") + if not cog: + return + await cog.lock_command(ctx, channel) + + @mod.command(name="unlock", description="Unlock a channel") + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(manage_roles=True) + @commands.guild_only() + async def mod_unlock(self, ctx: commands.Context, channel: discord.TextChannel = None): + cog = await self._get_cog(ctx, "Unlock") + if not cog: + return + await cog.unlock_command(ctx, channel) + + @mod.command(name="hide", description="Hide a channel") + @commands.has_permissions(manage_channels=True) + @commands.bot_has_permissions(manage_channels=True) + @commands.guild_only() + async def mod_hide(self, ctx: commands.Context, channel: discord.TextChannel = None): + cog = await self._get_cog(ctx, "Hide") + if not cog: + return + await cog.hide_command(ctx, channel) + + @mod.command(name="unhide", description="Unhide a channel") + @commands.has_permissions(manage_channels=True) + @commands.bot_has_permissions(manage_channels=True) + @commands.guild_only() + async def mod_unhide(self, ctx: commands.Context, channel: discord.TextChannel = None): + cog = await self._get_cog(ctx, "Unhide") + if not cog: + return + await cog.unhide_command(ctx, channel) + + @mod.command(name="lockall", description="Lock all channels") + @commands.has_permissions(administrator=True) + @commands.guild_only() + async def mod_lockall(self, ctx: commands.Context): + cog = await self._get_cog(ctx, "Moderation") + if not cog: + return + await cog.lockall(ctx) + + @mod.command(name="unlockall", description="Unlock all channels") + @commands.has_permissions(administrator=True) + @commands.guild_only() + async def mod_unlockall(self, ctx: commands.Context): + cog = await self._get_cog(ctx, "Moderation") + if not cog: + return + await cog.unlockall(ctx) + + @mod.command(name="nuke", description="Nuke the current channel") + @commands.has_permissions(manage_channels=True) + @commands.guild_only() + async def mod_nuke(self, ctx: commands.Context): + cog = await self._get_cog(ctx, "Moderation") + if not cog: + return + await cog._nuke(ctx) + + @mod.command(name="slowmode", description="Set channel slowmode") + @commands.has_permissions(manage_messages=True) + @commands.guild_only() + async def mod_slowmode(self, ctx: commands.Context, seconds: int = 0): + cog = await self._get_cog(ctx, "Moderation") + if not cog: + return + await cog._slowmode(ctx, seconds) + + @mod.command(name="nick", description="Change a member's nickname") + @commands.has_permissions(manage_nicknames=True) + @commands.bot_has_permissions(manage_nicknames=True) + @commands.guild_only() + async def mod_nick( + self, + ctx: commands.Context, + member: discord.Member, + *, + name: str = None, + ): + cog = await self._get_cog(ctx, "Moderation") + if not cog: + return + await cog.changenickname(ctx, member, name=name) + + @mod.command(name="audit", description="View recent audit log entries") + @commands.has_permissions(view_audit_log=True) + @commands.bot_has_permissions(view_audit_log=True) + @commands.guild_only() + async def mod_audit(self, ctx: commands.Context, limit: int): + cog = await self._get_cog(ctx, "Moderation") + if not cog: + return + await cog.auditlog(ctx, limit) + + +async def setup(bot): + await bot.add_cog(ModHub(bot)) diff --git a/bot/cogs/moderation/moderation.py b/bot/cogs/moderation/moderation.py index cad7914..a05082d 100644 --- a/bot/cogs/moderation/moderation.py +++ b/bot/cogs/moderation/moderation.py @@ -126,7 +126,7 @@ class Moderation(commands.Cog): - @commands.hybrid_command(name="unlockall", + @commands.command(name="unlockall", help="Unlocks all channels in the Guild.", usage="unlockall") @blacklist_check() @@ -211,7 +211,7 @@ class Moderation(commands.Cog): - @commands.hybrid_command(name="lockall", + @commands.command(name="lockall", help="locks all the channels in Guild.", usage="lockall") @blacklist_check() @@ -294,7 +294,7 @@ class Moderation(commands.Cog): await ctx.send(embed=denied, mention_author=False) - @commands.hybrid_command(name="give", + @commands.command(name="give", help="Gives the mentioned user a role.", usage="give ", aliases=["addrole"]) @@ -364,7 +364,7 @@ class Moderation(commands.Cog): - @commands.hybrid_command(name="hideall", help="Hides all the channels .", + @commands.command(name="hideall", help="Hides all the channels .", usage="hideall") @blacklist_check() @ignore_check() @@ -442,7 +442,7 @@ class Moderation(commands.Cog): icon_url=ctx.author.avatar.url if ctx.author.avatar else ctx.author.default_avatar.url) await ctx.send(embed=denied, mention_author=False) - @commands.hybrid_command(name="unhideall", help="Unhides all the channels in the server.", + @commands.command(name="unhideall", help="Unhides all the channels in the server.", usage="unhideall") @blacklist_check() @ignore_check() @@ -522,7 +522,7 @@ class Moderation(commands.Cog): - @commands.hybrid_command( + @commands.command( name="prefix", aliases=["setprefix", "prefixset"], help="Allows you to change the prefix of the bot for this server" @@ -560,7 +560,7 @@ class Moderation(commands.Cog): - @commands.hybrid_command(name="clone", help="Clones a channel.") + @commands.command(name="clone", help="Clones a channel.") @blacklist_check() @ignore_check() @commands.has_permissions(manage_channels=True) @@ -604,7 +604,7 @@ class Moderation(commands.Cog): await ctx.send(embed=error) - @commands.hybrid_command(name="nick", + @commands.command(name="nick", aliases=['setnick'], help="To change someone's nickname.", usage="nick [member]") @@ -680,7 +680,7 @@ class Moderation(commands.Cog): await ctx.send(embed=error) - @commands.hybrid_command(name="nuke", help="Nukes a channel", usage="nuke") + @commands.command(name="nuke", help="Nukes a channel", usage="nuke") @blacklist_check() @ignore_check() @top_check() @@ -744,7 +744,7 @@ class Moderation(commands.Cog): - @commands.hybrid_command(name="slowmode", + @commands.command(name="slowmode", help="Changes the slowmode", usage="slowmode [seconds]", aliases=["slow"]) @@ -774,7 +774,7 @@ class Moderation(commands.Cog): await ctx.send(embed=embed) - @commands.hybrid_command(name="unslowmode", + @commands.command(name="unslowmode", help="Disables slowmode", usage="unslowmode", aliases=["unslow"]) @@ -976,11 +976,10 @@ class Moderation(commands.Cog): - @commands.hybrid_command(name="unbanall", + @commands.command(name="unbanall", help="Unbans Everyone In The Guild!", aliases=['massunban'], - usage="Unbanall", - with_app_command=True) + usage="Unbanall") @blacklist_check() @ignore_check() @commands.cooldown(1, 30, commands.BucketType.user) @@ -1041,7 +1040,7 @@ class Moderation(commands.Cog): view.add_item(button1) await ctx.reply(embed=embed, view=view, mention_author=False) - @commands.hybrid_command(name="audit", + @commands.command(name="audit", help="See recents audit log action in the server .") @blacklist_check() @ignore_check() diff --git a/bot/cogs/moderation/timeout.py b/bot/cogs/moderation/timeout.py index 6ee0ec0..a4f7c01 100644 --- a/bot/cogs/moderation/timeout.py +++ b/bot/cogs/moderation/timeout.py @@ -132,7 +132,7 @@ class Mute(commands.Cog): return timedelta(days=time_value), f"{time_value} days" return None, None - @commands.hybrid_command( + @commands.command( name="mute", help="Mutes a user with optional time and reason", usage="mute [time] [reason]", diff --git a/bot/cogs/moderation/unban.py b/bot/cogs/moderation/unban.py index 5619b70..b2942db 100644 --- a/bot/cogs/moderation/unban.py +++ b/bot/cogs/moderation/unban.py @@ -132,7 +132,7 @@ class Unban(commands.Cog): def get_user_avatar(self, user): return user.avatar.url if user.avatar else user.default_avatar.url - @commands.hybrid_command( + @commands.command( name="unban", help="Unbans a user from the Server", usage="unban ", diff --git a/bot/cogs/moderation/unhide.py b/bot/cogs/moderation/unhide.py index 1fb2212..be82999 100644 --- a/bot/cogs/moderation/unhide.py +++ b/bot/cogs/moderation/unhide.py @@ -20,7 +20,7 @@ class Unhide(commands.Cog): self.bot = bot self.color = discord.Color.from_rgb(255,0, 0) # Green color for success - @commands.hybrid_command( + @commands.command( name="unhide", help="Unhides a channel for the default role (@everyone).", usage="unhide [channel]", diff --git a/bot/cogs/moderation/unlock.py b/bot/cogs/moderation/unlock.py index f57dfd7..ac460a7 100644 --- a/bot/cogs/moderation/unlock.py +++ b/bot/cogs/moderation/unlock.py @@ -69,7 +69,7 @@ class Unlock(commands.Cog): self.bot = bot self.color = discord.Color.from_rgb(255, 0, 0) - @commands.hybrid_command( + @commands.command( name="unlock", help="Unlocks a channel to allow sending messages.", usage="unlock ", diff --git a/bot/cogs/moderation/unmute.py b/bot/cogs/moderation/unmute.py index 84456ae..87ff019 100644 --- a/bot/cogs/moderation/unmute.py +++ b/bot/cogs/moderation/unmute.py @@ -140,7 +140,7 @@ class Unmute(commands.Cog): def get_user_avatar(self, user): return user.avatar.url if user.avatar else user.default_avatar.url - @commands.hybrid_command( + @commands.command( name="unmute", help="Unmutes a user from the Server", usage="unmute ", diff --git a/bot/cogs/moderation/warn.py b/bot/cogs/moderation/warn.py index 52addee..bf7ba42 100644 --- a/bot/cogs/moderation/warn.py +++ b/bot/cogs/moderation/warn.py @@ -94,7 +94,7 @@ class Warn(commands.Cog): except Exception as e: print(f"Error during database setup: {e}") - @commands.hybrid_command( + @commands.command( name="warn", help="Warn a user in the server", usage="warn [reason]", @@ -156,7 +156,7 @@ class Warn(commands.Cog): await ctx.send(f"An error occurred: {str(e)}") print(f"Error during warn command: {e}") - @commands.hybrid_command( + @commands.command( name="clearwarns", help="Clear all warnings for a user", aliases=["clearwarn" , "clearwarnings"],