|
| 1 | +"""Discord Cog to keep a message "pinned" at the end of a discussion.""" |
| 2 | + |
| 3 | +import logging |
| 4 | + |
| 5 | +import discord |
| 6 | +from discord.ext import commands |
| 7 | + |
| 8 | +from cogs import base_cog |
| 9 | + |
| 10 | +logger = logging.getLogger(__name__) |
| 11 | + |
| 12 | + |
| 13 | +class PinnedMessage(base_cog.BaseCog): |
| 14 | + """Keep a message pinned to the end of a channel.""" |
| 15 | + |
| 16 | + qualified_name = "Pinned Message" |
| 17 | + |
| 18 | + def __init__( |
| 19 | + self, |
| 20 | + bot: commands.Bot, |
| 21 | + messages: dict[int, str], |
| 22 | + **kwargs, |
| 23 | + ) -> None: |
| 24 | + super().__init__(bot=bot, **kwargs) |
| 25 | + self.bot = bot |
| 26 | + self.messages: dict[int, str] = messages |
| 27 | + self.last_message: dict[int, discord.Message] = {} |
| 28 | + |
| 29 | + @commands.Cog.listener() |
| 30 | + async def on_ready(self) -> None: |
| 31 | + """Popular prior messages from channel histories.""" |
| 32 | + if self.bot.user: |
| 33 | + for channel_id, content in self.messages.items(): |
| 34 | + message = await self.find_prior_message(channel_id, content) |
| 35 | + if message: |
| 36 | + self.last_message[channel_id] = message |
| 37 | + |
| 38 | + async def find_prior_message(self, channel_id: int, content: str) -> None | discord.Message: |
| 39 | + """Return a prior message from a channel history.""" |
| 40 | + assert self.bot.user is not None |
| 41 | + for guild in self.bot.guilds: |
| 42 | + channel = guild.get_channel(channel_id) |
| 43 | + if isinstance(channel, discord.TextChannel): |
| 44 | + async for message in channel.history(limit=50, oldest_first=None): |
| 45 | + if message.author.id == self.bot.user.id and message.content == content: |
| 46 | + return message |
| 47 | + return None |
| 48 | + |
| 49 | + async def bump_message(self, channel: discord.TextChannel) -> None: |
| 50 | + """Bump a pinned message in a channel.""" |
| 51 | + if last := self.last_message.get(channel.id): |
| 52 | + await last.delete() |
| 53 | + |
| 54 | + msg = await channel.send(self.messages[channel.id], silent=True) |
| 55 | + self.last_message[channel.id] = msg |
| 56 | + |
| 57 | + @commands.Cog.listener() |
| 58 | + async def on_message(self, message: discord.Message) -> None: |
| 59 | + """Move message to the end of the channel.""" |
| 60 | + if message.author.bot: |
| 61 | + return |
| 62 | + if not isinstance(message.channel, discord.TextChannel): |
| 63 | + return |
| 64 | + if message.channel.id not in self.messages: |
| 65 | + return |
| 66 | + await self.bump_message(message.channel) |
0 commit comments