当前位置: 首页 > 知识库问答 >
问题:

如何狙击来自特定通道的消息(discord.py)

狄信然
2023-03-14

结果

狙击在X频道发送的消息,而不是不和谐公会内的所有频道。也就是说,它应该只跟踪该通道中的消息删除(由其ID标识),并且只响应!在同一通道中执行Snipe命令。我这里的当前代码狙击了不和谐公会内发送的每一条消息。

问题

我如何狙击在X通道而不是整个公会发送的消息?

我主要打算在一个行会中运行这个机器人。然而,如果需要的话,它可以扩展到多个公会,那就太好了。

到目前为止,我的代码如下。

import discord
from discord.ext import commands
from tokens import token

client = commands.Bot(command_prefix="!", self_bot=False)
client.sniped_messages = {}


@client.event
async def on_ready():
    print("Your bot is ready.")


@client.event
async def on_message_delete(message):
    print(f'sniped message {message}')
    client.sniped_messages[message.guild.id] = (
        message.content, message.author, message.channel.name, message.created_at)


@client.command()
async def snipe(ctx):
    try:
        contents, author, channel_name, time = client.sniped_messages[ctx.guild.id]

    except:
        await ctx.channel.send("Couldn't find a message to snipe!")
        return

    embed = discord.Embed(description=contents,
                          color=discord.Color.purple(), timestamp=time)
    embed.set_author(
        name=f"{author.name}#{author.discriminator}", icon_url=author.avatar_url)
    embed.set_footer(text=f"Deleted in : #{channel_name}")

    await ctx.channel.send(embed=embed)

client.run(token, bot=True)

共有1个答案

鱼宜
2023-03-14

我将建议两种稍微不同的解决方案,因为如果您只在一个公会上运行此bot,代码可能会更简单。两者的共同点是,您需要检查哪些频道的消息被删除,以及在哪个频道中被删除!snipe命令已发送。

如果你在一个公会上只监视/狙击一个频道,那么你只能记录一条被删除的消息。因此,您不需要像您发布的代码中那样的字典;您可以只保留一条消息,也可以不保留任何消息。

您已经从一个单独的文件导入了您的令牌,所以为了方便起见,您不妨将通道ID(与bot令牌不同,它是一个int)放在那里。请注意,按照惯例,常量(您不打算更改的变量)通常以Python中的所有大写命名。tokens.py看起来像这样:

TOKEN = 'string of characters here'
CHANNEL_ID = 123456789 # actually a 17- or 18-digit integer

而机器人本身:

import discord
from discord.ext import commands
from tokens import TOKEN, CHANNEL_ID

client = commands.Bot(command_prefix='!')
client.sniped_message = None

@client.event
async def on_ready():
    print("Your bot is ready.")

@client.event
async def on_message_delete(message):
    # Make sure it's in the watched channel, and not one of the bot's own
    # messages.
    if message.channel.id == CHANNEL_ID and message.author != client.user:
        print(f'sniped message: {message}')
        client.sniped_message = message

@client.command()
async def snipe(ctx):
    # Only respond to the command in the watched channel.
    if ctx.channel.id != CHANNEL_ID:
        return

    if client.sniped_message is None:
        await ctx.channel.send("Couldn't find a message to snipe!")
        return

    message = client.sniped_message

    embed = discord.Embed(
        description=message.content,
        color=discord.Color.purple(),
        timestamp=message.created_at
    )
    embed.set_author(
        name=f"{message.author.name}#{message.author.discriminator}",
        icon_url=message.author.avatar_url
    )
    embed.set_footer(text=f"Deleted in: #{message.channel.name}")

    await ctx.channel.send(embed=embed)

client.run(TOKEN)

如果你在多个公会中监控每个频道,那么你需要分别跟踪它们。很容易,通道ID是全球唯一的,而不仅仅是在一个公会内。因此,您可以通过ID单独跟踪他们,而不必包括公会ID。

你可以把它们放在一个列表中,但我推荐一个集合,因为检查集合中是否有东西更快。帮助自己记住哪一个是哪一个可能也是一个好主意。

TOKEN = 'string of characters here'
# Not a dictionary, even though it uses {}
CHANNEL_IDS = {
    # That one guild
    123456789,
    # The other guild
    987654322,
}

然后,您可以检查它是否在多个ID的集合中,而不是检查单个通道ID。

import discord
from discord.ext import commands
from tokens import TOKEN, CHANNEL_IDS

client = commands.Bot(command_prefix='!')
client.sniped_messages = {}

@client.event
async def on_ready():
    print("Your bot is ready.")

@client.event
async def on_message_delete(message):
    # Make sure it's in a watched channel, and not one of the bot's own
    # messages.
    if message.channel.id in CHANNEL_IDS and message.author != client.user:
        print(f'sniped message: {message}')
        client.sniped_messages[message.channel.id] = message

@client.command()
async def snipe(ctx):
    # Only respond to the command in a watched channel.
    if ctx.channel.id not in CHANNEL_IDS:
        return

    try:
        message = client.sniped_messages[ctx.channel.id]
    # See note below
    except KeyError:
        await ctx.channel.send("Couldn't find a message to snipe!")
        return

    embed = discord.Embed(
        description=message.content,
        color=discord.Color.purple(),
        timestamp=message.created_at
    )
    embed.set_author(
        name=f"{message.author.name}#{message.author.discriminator}",
        icon_url=message.author.avatar_url
    )
    embed.set_footer(text=f"Deleted in: #{message.channel.name}")

    await ctx.channel.send(embed=embed)

client.run(TOKEN)

注意:像原始代码中那样的裸子句通常不是一个好主意。在这里,我们只想捕获KeyError,这是如果请求的键不在字典中时引发的。

您可以选择以不同的方式实现相同的逻辑:

message = client.sniped_messages.get(ctx.channel.id)
if message is None:
    await ctx.channel.send("Couldn't find a message to snipe!")
    return

字典的。get()方法返回相应的项,就像普通索引一样。但是,如果没有这样的键,它将返回一个默认值,而不是引发异常(如果在调用get时未指定一个值,则返回一个默认值None)。

如果您使用的是Python 3.8,那么前两行也可以使用赋值表达式(使用“walrus运算符”)进行组合,该表达式一次赋值并检查所有内容:

if (message := client.sniped_messages.get(ctx.channel.id)) is None:
    await ctx.channel.send("Couldn't find a message to snipe!")
    return

提及这些备选方案是为了完整性;所有这些方法都非常好。

 类似资料:
  • 有人能帮我弄清楚这件事吗。 谢了!

  • 我正在为多人游戏实现简单的网络服务器。我只是想搞清楚Netty 我通过telnet测试服务器。我所做的是向所有频道广播信息。工作很顺利。此外,我从地图上删除通道关闭事件,这是罚款。 但问题是,如果其中一个客户端意外断开连接,则在关闭回调之前,MessageRec的回调调用其发送方断开连接的信道。 如何正确忽略来自断开连接的客户端的消息?我在中使用,但用于也不是正确的字符串。在断开连接的通道结束时,

  • 我目前正在使用Java和jda为discord制作一个机器人。我想让机器人向特定的通道发送消息。我该怎么做?

  • 我一直在四处寻找,似乎找不到我用Typescript制作的不和谐机器人的这个问题的答案。我的所有命令都放在它们自己的文件夹中,每个命令都有一个单独的文件。有助于保持井井有条。 我见过有人说 但这给了我并且 实际上,每当有人运行重启命令时,我会尝试在每个文本频道(从列表中给出)发送一条机器人消息,因为不管出于什么原因,人们总是重启机器人。我把它实现为一件有趣的事情,如果有人需要使用它,我会时不时地以

  • 我正在创建一个不和谐机器人,它每天在某个时间向公会发送消息。我使用为预定的消息,但不确定为机器人编写什么代码来将消息发送到公会的一般频道,如果他们没有一般频道,则发送到带有大多数活动或消息。 由于已被删除,我不确定该如何执行此操作。另外,我不想使用通道id将消息发送到特定的通道,因为我想将此bot公开,以便许多不同的协会可以使用。 它不一定要发送到“默认”频道或包含大多数消息的频道。这些正是我想到

  • 我在Discord.py上做了一个机器人,我试图设置我想用参数发送消息的频道。代码是这样的: 当我键入通道id而不是arg1时,它可以工作,但是当我键入命令时,不和谐(!发送282772187812)它不工作,我得到这个错误:discord.ext.commands.errors.命令InvokeError:命令引发了一个异常:属性错误:'NoneType'对象没有属性'发送' 提前谢谢。