diff --git a/core/clients.py b/core/clients.py index 90f09b3b48..3826f55001 100644 --- a/core/clients.py +++ b/core/clients.py @@ -661,9 +661,18 @@ async def append_log( channel_id: str = "", type_: str = "thread_message", ) -> dict: + from core.utils import extract_forwarded_content + channel_id = str(channel_id) or str(message.channel.id) message_id = str(message_id) or str(message.id) + content = message.content or "" + if forwarded := extract_forwarded_content(message): + if content: + content += "\n" + forwarded + else: + content = forwarded + data = { "timestamp": str(message.created_at), "message_id": message_id, @@ -674,7 +683,7 @@ async def append_log( "avatar_url": message.author.display_avatar.url if message.author.display_avatar else None, "mod": not isinstance(message.channel, DMChannel), }, - "content": message.content, + "content": content, "type": type_, "attachments": [ { diff --git a/core/thread.py b/core/thread.py index bf77180f8c..672eefc2b4 100644 --- a/core/thread.py +++ b/core/thread.py @@ -205,7 +205,10 @@ async def snooze(self, moderator=None, command_used=None, snooze_for=None): "messages": [ { "author_id": m.author.id, - "content": m.content, + "content": ( + (m.content or "") + + (("\n" + extract_forwarded_content(m)) if extract_forwarded_content(m) else "") + ).strip(), "attachments": [a.url for a in m.attachments], "embeds": [e.to_dict() for e in m.embeds], "created_at": m.created_at.isoformat(), @@ -259,6 +262,9 @@ async def snooze(self, moderator=None, command_used=None, snooze_for=None): logging.info(f"[SNOOZE] DB update result: {result.modified_count}") + # Dispatch thread_snoozed event for plugins + self.bot.dispatch("thread_snoozed", self, moderator, snooze_for) + behavior = behavior_pre if behavior == "move": # Move the channel to the snoozed category (if configured) and optionally apply a prefix @@ -751,6 +757,9 @@ async def _ensure_genesis(force: bool = False): # Mark unsnooze as complete self._unsnoozing = False + # Dispatch thread_unsnoozed event for plugins + self.bot.dispatch("thread_unsnoozed", self) + # Process queued commands await self._process_command_queue() diff --git a/core/utils.py b/core/utils.py index dc8737ead6..9d3fc160ac 100644 --- a/core/utils.py +++ b/core/utils.py @@ -658,39 +658,49 @@ def extract_forwarded_content(message) -> typing.Optional[str]: try: # Handle multi-forward (message_snapshots) - if hasattr(message, "flags") and getattr(message.flags, "has_snapshot", False): - if hasattr(message, "message_snapshots") and message.message_snapshots: - forwarded_parts = [] - for snap in message.message_snapshots: - author = getattr(snap, "author", None) - author_name = getattr(author, "name", "Unknown") if author else "Unknown" - snap_content = getattr(snap, "content", "") - - if snap_content: - # Truncate very long messages to prevent spam - if len(snap_content) > 500: - snap_content = snap_content[:497] + "..." - forwarded_parts.append(f"**{author_name}:** {snap_content}") - elif getattr(snap, "embeds", None): - for embed in snap.embeds: - if hasattr(embed, "description") and embed.description: - embed_desc = embed.description - if len(embed_desc) > 300: - embed_desc = embed_desc[:297] + "..." - forwarded_parts.append(f"**{author_name}:** {embed_desc}") - break - elif getattr(snap, "attachments", None): - attachment_info = ", ".join( - [getattr(a, "filename", "Unknown") for a in snap.attachments[:3]] - ) - if len(snap.attachments) > 3: - attachment_info += f" (+{len(snap.attachments) - 3} more)" - forwarded_parts.append(f"**{author_name}:** [Attachments: {attachment_info}]") - else: - forwarded_parts.append(f"**{author_name}:** [No content]") - - if forwarded_parts: - return "\n".join(forwarded_parts) + # Check directly for snapshots as flags.has_snapshot can be unreliable in some versions + if getattr(message, "message_snapshots", None): + forwarded_parts = [] + for snap in message.message_snapshots: + author = getattr(snap, "author", None) + # If author is missing, we can try to rely on the container message context or just omit. + # Since we can't reliably get the original author from snapshot in this state, we focus on content. + + snap_content = getattr(snap, "content", "") + + formatted_part = "📨 **Forwarded Message**\n" + + if snap_content: + if len(snap_content) > 500: + snap_content = snap_content[:497] + "..." + formatted_part += "\n".join([f"{line}" for line in snap_content.splitlines()]) + "\n" + + if getattr(snap, "embeds", None): + for embed in snap.embeds: + if hasattr(embed, "description") and embed.description: + embed_desc = embed.description + if len(embed_desc) > 300: + embed_desc = embed_desc[:297] + "..." + formatted_part += ( + "\n".join([f"> {line}" for line in embed_desc.splitlines()]) + "\n" + ) + break # One embed preview is usually enough + + if getattr(snap, "attachments", None): + attachment_info = ", ".join( + [getattr(a, "filename", "Unknown") for a in snap.attachments[:3]] + ) + if len(snap.attachments) > 3: + attachment_info += f" (+{len(snap.attachments) - 3} more)" + formatted_part += f"[Attachments: {attachment_info}]\n" + + # Add source link to the container message since snapshot doesn't have its own public link + formatted_part += f"\n**Source:** {message.jump_url}" + + forwarded_parts.append(formatted_part) + + if forwarded_parts: + return "\n".join(forwarded_parts) # Handle single-message forward elif getattr(message, "type", None) == getattr(discord.MessageType, "forward", None):