@@ -296,24 +296,62 @@ async def sync_all_commands(self, delete_from_unused_guilds=False):
296296 Matches commands registered on Discord to commands registered here.
297297 Deletes any commands on Discord but not here, and registers any not on Discord.
298298 This is done with a `put` request.
299+ A PUT request will only be made if there are changes detected.
299300 If ``sync_commands`` is ``True``, then this will be automatically called.
300301
301302 :param delete_from_unused_guilds: If the bot should make a request to set no commands for guilds that haven't got any commands registered in :class:``SlashCommand``
302303 """
303304 cmds = await self .to_dict ()
304305 self .logger .info ("Syncing commands..." )
305- other_guilds = [x .id for x in self ._discord .guilds if x .id not in cmds ["guild" ]]
306- # This is an extremely bad way to do this, because slash cmds can be in guilds the bot isn't in
307- # But it's the only way until discord makes an endpoint to request all the guild with cmds registered.
306+ cmds_formatted = {None : cmds ['global' ]}
307+ for guild in cmds ['guild' ]:
308+ cmds_formatted [guild ] = cmds ['guild' ][guild ]
309+
310+ for scope in cmds_formatted :
311+ new_cmds = cmds_formatted [scope ]
312+ existing_cmds = await self .req .get_all_commands (guild_id = scope )
313+ existing_by_name = {}
314+ to_send = []
315+ changed = False
316+ for cmd in existing_cmds :
317+ existing_by_name [cmd ["name" ]] = model .CommandData (** cmd )
318+
319+ if len (new_cmds ) != len (existing_cmds ):
320+ changed = True
321+
322+ for command in new_cmds :
323+ cmd_name = command ["name" ]
324+ if cmd_name in existing_by_name :
325+ cmd_data = model .CommandData (** command )
326+ existing_cmd = existing_by_name [cmd_name ]
327+ if cmd_data != existing_cmd :
328+ changed = True
329+ to_send .append (command )
330+ else :
331+ command_with_id = command
332+ command_with_id ["id" ] = existing_cmd .id
333+ to_send .append (command_with_id )
334+ else :
335+ changed = True
336+ to_send .append (command )
308337
309- await self .req .put_slash_commands (slash_commands = cmds ["global" ], guild_id = None )
338+
339+ if changed :
340+ self .logger .debug (f"Detected changes on { scope if scope is not None else 'global' } , updating them" )
341+ await self .req .put_slash_commands (slash_commands = to_send , guild_id = scope )
342+ else :
343+ self .logger .debug (f"Detected no changes on { scope if scope is not None else 'global' } , skipping" )
310344
311- for x in cmds ["guild" ]:
312- await self .req .put_slash_commands (slash_commands = cmds ["guild" ][x ], guild_id = x )
313345 if delete_from_unused_guilds :
314- for x in other_guilds :
346+ other_guilds = [guild .id for guild in self ._discord .guilds if guild .id not in cmds ["guild" ]]
347+ # This is an extremly bad way to do this, because slash cmds can be in guilds the bot isn't in
348+ # But it's the only way until discord makes an endpoint to request all the guild with cmds registered.
349+
350+ for guild in other_guilds :
315351 with suppress (discord .Forbidden ):
316- await self .req .put_slash_commands (slash_commands = [], guild_id = x )
352+ existing = self .req .get_all_commands (guild_id = guild )
353+ if len (existing ) != 0 :
354+ await self .req .put_slash_commands (slash_commands = [], guild_id = guild )
317355
318356 self .logger .info ("Completed syncing all commands!" )
319357
0 commit comments