如何用Discord.py实现频道底部常驻Sticky message并删除旧消息?
实现Discord Bot的粘性消息(Sticky Message)功能
你当前代码的核心问题有两个:一是试图删除Embed对象而非实际发送的Message实例,二是没有持久化存储粘性消息的ID,导致无法动态追踪旧消息。以下是分步解决方案:
1. 修复基础删除逻辑
原代码中new_embed是嵌入消息的对象,并非发送到频道后的消息实例,调用delete()会报错。正确做法是先获取旧的粘性消息实例,发送新消息后删除旧消息:
import discord @bot.event async def on_message(message): target_channel_id = 1206246422324715580 if message.channel.id != target_channel_id: return if message.author == bot.user: return # 硬编码旧粘性消息ID(后续会优化) old_sticky_msg_id = 1208866913426473021 try: # 获取旧的粘性消息 old_sticky_msg = await message.channel.fetch_message(old_sticky_msg_id) # 复制嵌入内容 new_embed = old_sticky_msg.embeds[0].copy() # 发送新的粘性消息 await message.channel.send(embed=new_embed) # 删除旧的粘性消息 await old_sticky_msg.delete() except discord.NotFound: # 处理旧消息被手动删除的情况 await message.channel.send(embed=discord.Embed(title="默认粘性消息"))
2. 用JSON持久化优化(替代硬编码)
硬编码消息ID和频道ID扩展性差,用JSON文件存储每个频道对应的粘性消息ID,支持多频道且动态更新:
第一步:创建配置文件
新建sticky_config.json,结构如下:
{ "1206246422324715580": 1208866913426473021 }
第二步:优化代码
import discord import json # 加载配置文件 def load_sticky_config(): try: with open("sticky_config.json", "r", encoding="utf-8") as f: return json.load(f) except FileNotFoundError: return {} # 保存配置文件 def save_sticky_config(config): with open("sticky_config.json", "w", encoding="utf-8") as f: json.dump(config, f, indent=2, ensure_ascii=False) # 初始化配置 sticky_config = load_sticky_config() @bot.event async def on_message(message): channel_id_str = str(message.channel.id) # 只处理配置过的频道 if channel_id_str not in sticky_config: return # 忽略Bot自身发送的消息 if message.author == bot.user: return old_sticky_msg_id = sticky_config[channel_id_str] try: old_sticky_msg = await message.channel.fetch_message(old_sticky_msg_id) # 复制嵌入内容 new_embed = old_sticky_msg.embeds[0].copy() # 发送新消息并记录实例 new_sticky_msg = await message.channel.send(embed=new_embed) # 删除旧消息 await old_sticky_msg.delete() # 更新配置中的消息ID为新的 sticky_config[channel_id_str] = new_sticky_msg.id save_sticky_config(sticky_config) except discord.NotFound: # 旧消息不存在时,发送默认嵌入并更新配置 default_embed = discord.Embed( title="粘性消息", description="此消息会始终保持在频道底部" ) new_sticky_msg = await message.channel.send(embed=default_embed) sticky_config[channel_id_str] = new_sticky_msg.id save_sticky_config(sticky_config)
3. 进阶:用数据库存储(可选)
如果需要支持大量频道或更稳定的存储,可以用SQLite替代JSON,示例代码片段:
import sqlite3 # 初始化数据库 conn = sqlite3.connect("sticky_messages.db") cursor = conn.cursor() cursor.execute("CREATE TABLE IF NOT EXISTS sticky (channel_id TEXT PRIMARY KEY, message_id INTEGER)") conn.commit() # 获取频道对应的粘性消息ID def get_sticky_msg_id(channel_id): cursor.execute("SELECT message_id FROM sticky WHERE channel_id = ?", (str(channel_id),)) result = cursor.fetchone() return result[0] if result else None # 更新粘性消息ID def update_sticky_msg_id(channel_id, message_id): cursor.execute("REPLACE INTO sticky (channel_id, message_id) VALUES (?, ?)", (str(channel_id), message_id)) conn.commit()
将上述函数整合到之前的on_message事件中即可。
内容的提问来源于stack exchange,提问作者Radar Kolar
相关产品推荐
相关产品推荐

