@@ -296,24 +296,62 @@ async def sync_all_commands(self, delete_from_unused_guilds=False):
296
296
Matches commands registered on Discord to commands registered here.
297
297
Deletes any commands on Discord but not here, and registers any not on Discord.
298
298
This is done with a `put` request.
299
+ A PUT request will only be made if there are changes detected.
299
300
If ``sync_commands`` is ``True``, then this will be automatically called.
300
301
301
302
: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``
302
303
"""
303
304
cmds = await self .to_dict ()
304
305
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 )
308
337
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" )
310
344
311
- for x in cmds ["guild" ]:
312
- await self .req .put_slash_commands (slash_commands = cmds ["guild" ][x ], guild_id = x )
313
345
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 :
315
351
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 )
317
355
318
356
self .logger .info ("Completed syncing all commands!" )
319
357
0 commit comments