You need to enable JavaScript to run this app. 如何在Discord.py中通过表情反应关闭消息删除监听等moderation事件
优惠活动
大模型
产品
解决方案
定价
更多

如何在Discord.py中通过表情反应关闭消息删除监听等moderation事件

功能实现指导

核心实现思路

你不需要复杂调用wait_for或dispatch即可实现需求,核心逻辑是给每个服务器单独存储删除消息日志的开关状态,通过点击❗表情切换开关即可:

  • 初始化时为Cog添加字典存储每个服务器的开关状态,默认开启删消息日志
  • 完善on_reaction_add中❗表情的触发逻辑,切换对应服务器的开关并给出提示
  • 修复原代码中on_message_delete里未定义的x变量,替换为开关状态判断

完整修改后代码

import discord
from discord.ext import commands
import datetime
import asyncio

class log(commands.Cog):
    def __init__(self,bot):
        self.bot = bot
        # 存储每个服务器的删除消息日志开关,key为guild id,value为bool值,默认开启
        self.delete_log_enabled = {}

    @commands.Cog.listener()
    async def on_reaction_add(self, reaction, user):
        channel = reaction.message.channel
        guild = channel.guild
        message = reaction.message
        if user != self.bot.user:
            # 初始化当前服务器的开关状态(如果不存在)
            if guild.id not in self.delete_log_enabled:
                self.delete_log_enabled[guild.id] = True

            if reaction.emoji == '1️⃣':
                check = discord.utils.get(guild.categories, name="Chilly Logs")
                if not check:
                    cat = await guild.create_category_channel('Chilly Logs')
                    await guild.create_text_channel("Message Logs", category=cat)
                    await guild.create_text_channel("Other Logs", category=cat)
                    await channel.send('**日志频道创建成功!**')
                    await message.remove_reaction('1️⃣', user)
                    return
                else: 
                    await channel.send('**日志频道已存在**')
                    await message.remove_reaction('1️⃣', user)

            if reaction.emoji == '2️⃣':
                channel1 = discord.utils.get(guild.channels, name="other-logs")
                channel2 = discord.utils.get(guild.channels, name="message-logs")
                category = discord.utils.get(guild.categories, name="Chilly Logs")
                if category is not None:
                    await channel1.delete()
                    await channel2.delete()
                    await category.delete()
                    await channel.send('**日志频道已移除**')
                    await message.remove_reaction('2️⃣', user)
                else:
                    await channel.send('**频道不存在或已被重命名**')
                    await message.remove_reaction('2️⃣', user)

            if reaction.emoji == '❗':
                # 切换删除日志开关状态
                self.delete_log_enabled[guild.id] = not self.delete_log_enabled[guild.id]
                status = "已开启" if self.delete_log_enabled[guild.id] else "已关闭"
                await channel.send(f'**删除消息日志{status}**')
                await message.remove_reaction('❗', user)
                return

    @commands.command()
    async def test(self, ctx):
        embed = discord.Embed(title = "Chilly 日志功能", description = "Chilly会记录所有编辑、删除的消息,更多功能正在开发中", colour = discord.Color.blurple())
        embed.add_field(name="日志操作指令", value="1️⃣ - 开启服务器日志", inline=True)
        embed.add_field(name="‎ ", value= "2️⃣ - 关闭日志并删除日志频道", inline=False)
        embed.add_field(name="‎ ", value= "❗ - 开启/关闭删除消息日志记录", inline=False)
        msg = await ctx.send(embed=embed)
        emoji = ['1️⃣', '2️⃣', '❗']
        for e in emoji:
            await msg.add_reaction(e)

    @commands.Cog.listener()
    async def on_message_delete(self, message):
        # 先判断当前服务器开关状态,默认开启
        guild_id = message.guild.id
        if guild_id not in self.delete_log_enabled:
            self.delete_log_enabled[guild_id] = True
        if not self.delete_log_enabled[guild_id]:
            return
        if not message.author.bot:
            channel = message.channel.name
            logchannel = discord.utils.get(message.guild.channels, name='message-logs')
            if not logchannel:
                return
            embed = discord.Embed(title="消息日志", description="", color= discord.Color.red())
            embed.add_field(name=f"{message.author.display_name} 发送的消息在 `{channel}` 频道被删除", value=message.content, inline=True)
            embed.set_footer(text=f'用户ID: {message.author.id} | 消息ID: {message.id}')          
            await logchannel.send(embed=embed)
    
    @commands.Cog.listener()
    async def on_message_edit(self, before, after):
        if not after.author.bot:    
            if before.content != after.content:
                channel = after.channel.name
                logchannel = discord.utils.get(after.guild.channels, name='message-logs')
                if not logchannel:
                    return
                embed = discord.Embed(title="消息日志", description=f"消息在 `{channel}` 频道被 {after.author.display_name} 编辑", color= discord.Color.red())
                embed.add_field(name="编辑前", value=before.content, inline=True)
                embed.add_field(name="编辑后", value=after.content, inline=False)
                embed.set_footer(text=f'用户ID: {after.author.id} | 消息ID: {before.id}')
                await logchannel.send(embed=embed)

def setup(bot):
    bot.add_cog(log(bot))

相关函数用法说明

你提到的两个函数用法如下:

  • wait_for:用于等待指定事件触发,适合单次等待用户操作场景,比如发送消息后等待指定用户添加反应,示例用法:
    # 等待60秒内用户对消息添加反应
    def check(reaction, user):
        return user == ctx.author and str(reaction.emoji) == '❗'
    try:
        reaction, user = await self.bot.wait_for('reaction_add', timeout=60.0, check=check)
    except asyncio.TimeoutError:
        await ctx.send('操作超时')
    else:
        await ctx.send('你点击了❗反应')
    
  • dispatch:用于手动触发指定事件,一般用于自定义事件或测试场景,比如手动触发一次消息删除事件:
    # 手动触发on_message_delete事件,传入要模拟删除的消息对象
    self.bot.dispatch("message_delete", message_obj)
    

内容的提问来源于stack exchange,提问作者Zyb3rWolfi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 21:24:01