diff --git a/bot.py b/bot.py index a884bcf..87f6343 100644 --- a/bot.py +++ b/bot.py @@ -6253,7 +6253,7 @@ async def viewmute(ctx, identifier: str): unmute_info += "\nšŸ¤– Automatic unmute" embed.add_field(name="šŸ”“ Unmuted At", value=unmute_info, inline=True) - # ── Referenced message + locally archived attachments ────────── + # ── Referenced message + locally archived attachments ────────────────────── local_files = [] raw_message_data = mute_data.get('message_data') @@ -6261,12 +6261,13 @@ async def viewmute(ctx, identifier: str): try: msg_data = json.loads(raw_message_data) if isinstance(raw_message_data, str) else raw_message_data - # Determine which format the stored message_data uses - if isinstance(msg_data, dict) and "main_message" in msg_data: - main_msg = msg_data.get("main_message") or {} - attachments_json = main_msg.get("attachments") + attachments_json = None + + if isinstance(msg_data, dict) and "main_message" in msg_data: + # Format: get_message_data() with context + main_msg = msg_data.get("main_message") or {} + attachments_raw = main_msg.get("attachments") - # Build referenced message field msg_info = f"**Message ID:** `{main_msg.get('id', 'N/A')}`\n" msg_info += f"**Channel:** <#{main_msg.get('channel_id', 'N/A')}>\n" msg_info += f"**Author:** {main_msg.get('author_name', 'Unknown')}\n" @@ -6276,8 +6277,8 @@ async def viewmute(ctx, identifier: str): embed.add_field(name="šŸ“„ Referenced Message", value=msg_info, inline=False) else: - # Flat format (honeypot / direct archive) - attachments_json = msg_data.get("attachments") + # Format: archive_message_with_attachments() (honeypot / flat) + attachments_raw = msg_data.get("attachments") msg_info = f"**Message ID:** `{msg_data.get('id', 'N/A')}`\n" msg_info += f"**Channel:** <#{msg_data.get('channel_id', 'N/A')}>\n" @@ -6289,36 +6290,67 @@ async def viewmute(ctx, identifier: str): msg_info += f"**Content:** {preview}" embed.add_field(name="šŸ“„ Referenced Message", value=msg_info, inline=False) - # Load local attachment files - if attachments_json: - att_field_text, local_files = build_attachment_field(attachments_json) - if att_field_text: - embed.add_field( - name=f"šŸ“Ž Archived Attachments ({len(local_files)} file(s) attached)" if local_files else "šŸ“Ž Archived Attachments", - value=att_field_text, - inline=False - ) + # Parse attachments — handle both string and already-parsed list + if attachments_raw: + if isinstance(attachments_raw, str): + try: + attachments_list = json.loads(attachments_raw) + except json.JSONDecodeError: + attachments_list = [] + elif isinstance(attachments_raw, list): + attachments_list = attachments_raw + else: + attachments_list = [] + + if attachments_list: + field_lines = [] + for i, att in enumerate(attachments_list): + local_path = att.get("local_path") + filename = att.get("filename", "unknown_file") + size = att.get("size", 0) + size_str = f"{size / 1024:.1f} KB" if size else "?" + + # Give each file a unique name to avoid discord.File conflicts + # when multiple files share the same filename (e.g. multiple "image.jpg") + unique_filename = f"{i+1}_{filename}" if len(attachments_list) > 1 else filename + + if local_path and os.path.exists(local_path): + try: + local_files.append(discord.File(local_path, filename=unique_filename)) + field_lines.append(f"āœ… `{filename}` ({size_str})") + except Exception as e: + logger.error(f"Could not open local file {local_path}: {e}") + field_lines.append(f"āš ļø `{filename}` ({size_str}) — *file unreadable*") + else: + original_url = att.get("original_url", "") + stored = att.get("stored", False) + if not stored: + field_lines.append(f"āŒ `{filename}` ({size_str}) — *download failed at archive time*") + else: + field_lines.append(f"āŒ `{filename}` ({size_str}) — *local file missing from disk*") + + att_header = f"šŸ“Ž Archived Attachments ({len(local_files)}/{len(attachments_list)} available)" + embed.add_field(name=att_header, value="\n".join(field_lines), inline=False) except Exception as e: logger.error(f"Error parsing message_data for viewmute {identifier}: {e}") embed.add_field(name="šŸ“„ Referenced Message", value="āš ļø Could not parse archived message data.", inline=False) elif mute_data.get('message_id') and mute_data.get('message_content'): - # Legacy fallback: separate columns (no attachment support) + # Legacy fallback: separate columns content_preview = mute_data['message_content'][:100] + "..." if len(mute_data['message_content']) > 100 else mute_data['message_content'] embed.add_field( name="šŸ“„ Referenced Message", value=f"ID: `{mute_data['message_id']}`\nContent: {content_preview}", inline=False ) - # ──────────────────────────────────────────────────────────────── + # ──────────────────────────────────────────────────────────────────────────── embed.add_field(name="šŸ†” Process UUID", value=f"`{mute_data['process_uuid']}`", inline=False) embed.add_field(name="šŸ†” Mute Record ID", value=f"`{mute_data['id']}`", inline=True) embed.set_thumbnail(url=muted_user.display_avatar.url) embed.set_footer(text=f"Mute Record from Database | Server: {ctx.guild.name}") - # Send embed + local files (if any) if local_files: await send_response(embed=embed, files=local_files[:10]) else: