#python #discord #discord.py
Вопрос:
Задача моего кода: Когда модератор выдает или удаляет роли с любого участника сервера, бот считывает журналы, а затем отправляет сообщение на указанный канал о том, какая роль была изменена и на какую, и так далее.
Моя проблема: когда модератор добавляет или удаляет сразу несколько ролей, бот отправляет сообщение с информацией сразу для каждой роли. Но я хочу, чтобы при отправке события была задержка. Это засоряет журналы чатов и раздражает.
Например: я удаляю сразу 5 ролей, у бота задержка отправки сообщения 30 секунд. И в этом сообщении он добавляет все 5 ролей, а не по одной за раз.
код:
@Bot.event
async def on_member_update(before, after):
if before.roles != after.roles:
channel = Bot.get_channel(827986763606786099)
emb = discord.Embed(description = f'**Updating user roles - {before.mention}**', colour = discord.Color.red())
emb.add_field(name = '**Roles before**', value = ", ".join([r.mention for r in before.roles]))
emb.add_field(name = '**Roles after**', value = ", ".join([r.mention for r in after.roles]))
async for event in before.guild.audit_logs(limit=1, action=discord.AuditLogAction.member_role_update):
if getattr(event.target, "id", None) != before.id:
continue
emb.add_field(name="Changed roles", value = ", ".join([getattr(r, "mention", r.id) for r in event.before.roles or event.after.roles]))
emb.add_field(name="Moderator", value = event.user)
break
await channel.send(embed = emb)
Ответ №1:
Перед запуском обязательно импортируйте asyncio import asyncio
cooldown = []
@bot.event()
async def on_member_update(before, after):
if before.roles != after.roles:
global cooldown
if before in cooldown:
return
cooldown.append(before)
await asyncio.sleep(10) #here you can change how long the cooldown should be
cooldown.remove(before)
channel = bot.get_channel(688344722082627686)
emb = discord.Embed(description=f'**Updating user roles - {before.mention}**', colour=discord.Color.red())
emb.add_field(name='**Roles before**', value=", ".join([r.mention for r in before.roles]))
emb.add_field(name='**Roles after**', value=", ".join([r.mention for r in after.roles]))
changed_roles = []
for role in before.roles:
if role in after.roles:
pass
else:
changed_roles.append(role)
for role in after.roles:
if role in before.roles:
pass
else:
if role in changed_roles:
pass
else:
changed_roles.append(role)
text = ""
for role in changed_roles:
text = text role.mention
emb.add_field(name="Changed roles", value=text)
async for event in before.guild.audit_logs(limit=1, action=discord.AuditLogAction.member_role_update):
if getattr(event.target, "id", None) != before.id:
continue
emb.add_field(name="Moderator", value=event.user)
break
await channel.send(embed=emb)
Пришлось немного изменить получение измененных ролей, так как я не смог получить, сколько журналов аудита я должен был получить.
Итак, что происходит: пользователь добавляется в список восстановления, бот ждет 10 секунд, чтобы модератор мог закончить удаление/добавление ролей, после этого бот собирает их всех, удаляет пользователя из восстановления и отправляет встраивание.
Комментарии:
1. Я хотел спросить, можно ли сделать так, чтобы были роли, на которые бот не обращает внимания? Например: у меня есть отключенная роль и несколько других ролей, которые им автоматически назначаются. Но бот также читает их. Поэтому я бы хотел, чтобы бот не читал определенные роли. Например, создайте новую переменную и добавьте туда все ненужные роли, а затем как-то поработайте с переменной. Возможно ли это сделать?
2. Просто добавьте список с идентификаторами ролей, которые вы хотите игнорировать, а затем выполните простую проверку, например
if role.id not in list:
3. И вот, то, что я хотел сделать, я сделал. Но вот в чем загвоздка, у меня новая проблема. Когда я хочу удалить или добавить совершенно другие роли, сообщение об этом выглядит совсем не так. Я понимаю, что код, который у меня сейчас есть, выглядит совсем не очень хорошо, но я не мог сделать это по-другому. Как я могу это решить?
Ответ №2:
Вот полностью рабочий код:
@Bot.event
async def on_member_update(before, after):
if before.roles != after.roles:
global cooldown
if before in cooldown:
return
cooldown.append(before)
await asyncio.sleep(5) # here you can change how long the cooldown should be
cooldown.remove(before)
channel = Bot.get_channel(ID log channel)
emb = discord.Embed(description=f'**Updating user roles - {before.mention}**', colour=discord.Color.orange())
emb.add_field(name='Roles before', value=", ".join([r.mention for r in before.roles][1:]), inline=False)
emb.add_field(name='Roles after', value=", ".join([r.mention for r in after.roles][1:]), inline=False)
changed_roles = []
for role in before.roles:
if role in after.roles:
pass
else:
changed_roles.append(role)
for role in after.roles:
if role in before.roles:
pass
else:
if role in changed_roles:
pass
else:
changed_roles.append(role)
text = ""
blacklist=[797920206407598098,817750571330961410,797916381621256202] # list roles, that should not be read
for role in changed_roles:
if role.id in blacklist:
return
text = text role.mention
emb.add_field(name="Changed roles", value=text, inline=False)
async for event in before.guild.audit_logs(limit=1, action=discord.AuditLogAction.member_role_update):
if getattr(event.target, "id", None) != before.id:
continue
emb.add_field(name="Moderator", value=f"{event.user} n**ID**: {event.user.id}")
break
await channel.send(embed=emb)
Большое вам спасибо за помощь @NimVrod