44from discord .ext import commands
55from . import http
66from . import model
7+ from . import error
78from .utils import manage_commands
89from inspect import iscoroutinefunction
910
@@ -24,21 +25,26 @@ class SlashCommand:
2425 :ivar req: :class:`.http.SlashCommandRequest` of this client.
2526 :ivar logger: Logger of this client.
2627 :ivar auto_register: Whether to register commands automatically.
28+ :ivar auto_delete: Whether to delete commands not found in the project automatically.
2729 :ivar has_listener: Whether discord client has listener add function.
2830 """
2931
3032 def __init__ (self ,
3133 client : typing .Union [discord .Client , commands .Bot ],
3234 auto_register : bool = False ,
35+ auto_delete : bool = False ,
3336 override_type : bool = False ):
3437 self ._discord = client
3538 self .commands = {}
3639 self .subcommands = {}
3740 self .logger = logging .getLogger ("discord_slash" )
3841 self .req = http .SlashCommandRequest (self .logger , self ._discord )
3942 self .auto_register = auto_register
43+ self .auto_delete = auto_delete
4044 if self .auto_register :
4145 self ._discord .loop .create_task (self .register_all_commands ())
46+ if self .auto_delete :
47+ self ._discord .loop .create_task (self .delete_unused_commands ())
4248 if not isinstance (client , commands .Bot ) and not isinstance (client ,
4349 commands .AutoShardedBot ) and not override_type :
4450 self .logger .info ("Detected discord.Client! Overriding on_socket_response." )
@@ -166,6 +172,45 @@ async def register_all_commands(self):
166172 selected .options )
167173 self .logger .info ("Completed registering all commands!" )
168174
175+ async def delete_unused_commands (self ):
176+ """
177+ Unregisters all slash commands which are not used by the project to Discord API.\n
178+ This might take some time because for every guild the bot is on an API call is made.\n
179+ If ``auto_delete`` is ```True``, then this will be automatically called.
180+ """
181+ await self ._discord .wait_until_ready ()
182+ self .logger .info ("Deleting unused commands..." )
183+ registered_commands = {}
184+ global_commands = await manage_commands .get_all_commands (self ._discord .user .id ,
185+ self ._discord .http .token ,
186+ None )
187+ for cmd in global_commands :
188+ registered_commands [cmd ["name" ]] = {"id" : cmd ["id" ], "guild_id" : None }
189+
190+ for guild in self ._discord .guilds :
191+ # Since we can only get commands per guild we need to loop through every one
192+ try :
193+ guild_commands = await manage_commands .get_all_commands (self ._discord .user .id ,
194+ self ._discord .http .token ,
195+ guild .id )
196+ except error .RequestFailure :
197+ # In case a guild has not granted permissions to access commands
198+ continue
199+
200+ for cmd in guild_commands :
201+ registered_commands [cmd ["name" ]] = {"id" : cmd ["id" ], "guild_id" : guild .id }
202+
203+ for x in registered_commands .keys ():
204+ if x not in self .commands .keys ():
205+ # Delete command if not found locally
206+ selected = registered_commands [x ]
207+ await manage_commands .remove_slash_command (self ._discord .user .id ,
208+ self ._discord .http .token ,
209+ selected ["guild_id" ],
210+ selected ["id" ])
211+
212+ self .logger .info ("Completed deleting unused commands!" )
213+
169214 def add_slash_command (self ,
170215 cmd ,
171216 name : str = None ,
0 commit comments