import type { Message, TextChannel, ThreadChannel, } from "discord.js-selfbot-v13"; export interface MessageLocation { channelId: string; threadId: string | null; threadName: string | null; channelName: string | null; } export interface RichMessageMetadata { stickers: Array<{ id: string; name: string; url: string; format: string | null; }>; embeds: Array<{ title: string | null; description: string | null; url: string | null; color: number | null; image: string | null; thumbnail: string | null; author: { name: string | null; url: string | null; iconURL: string | null; } | null; footer: { text: string | null; iconURL: string | null } | null; fields: Array<{ name: string; value: string; inline: boolean }>; }>; attachments: Array<{ id: string; name: string; url: string; contentType: string | null; size: number; }>; author: { id: string; username: string; tag: string | null; avatarURL: string | null; bot: boolean; }; member: { displayName: string | null; roles: Array<{ id: string; name: string }>; joinedTimestamp: number | null; } | null; channel: MessageLocation; reference: { messageId: string | null; channelId: string | null; guildId: string | null; } | null; } export function getMessageLocation(message: Message): MessageLocation { const channel = message.channel as TextChannel | ThreadChannel; if (!channel.isThread?.()) { return { channelId: message.channelId, threadId: null, threadName: null, channelName: "name" in channel ? channel.name : null, }; } return { channelId: channel.parentId ?? message.channelId, threadId: channel.id, threadName: channel.name, channelName: channel.parent?.name ?? null, }; } export function getStickerMetadata( message: Message, ): RichMessageMetadata["stickers"] { return Array.from(message.stickers.values()).map((sticker) => ({ id: sticker.id, name: sticker.name, url: sticker.url, format: sticker.format ?? null, })); } export function getAttachmentMetadata( message: Message, ): RichMessageMetadata["attachments"] { return Array.from(message.attachments.values()).map((attachment) => ({ id: attachment.id, name: attachment.name || "unknown", url: attachment.url, contentType: attachment.contentType ?? null, size: attachment.size, })); } export function getEmbedMetadata( message: Message, ): RichMessageMetadata["embeds"] { return message.embeds.map((embed) => ({ title: embed.title ?? null, description: embed.description ?? null, url: embed.url ?? null, color: embed.color ?? null, image: embed.image?.url ?? null, thumbnail: embed.thumbnail?.url ?? null, author: embed.author ? { name: embed.author.name ?? null, url: embed.author.url ?? null, iconURL: embed.author.iconURL ?? null, } : null, footer: embed.footer ? { text: embed.footer.text ?? null, iconURL: embed.footer.iconURL ?? null, } : null, fields: embed.fields.map((field) => ({ name: field.name, value: field.value, inline: Boolean(field.inline), })), })); } export function getMessageMetadata(message: Message): RichMessageMetadata { const member = message.member; return { stickers: getStickerMetadata(message), embeds: getEmbedMetadata(message), attachments: getAttachmentMetadata(message), author: { id: message.author.id, username: message.author.username, tag: "tag" in message.author ? message.author.tag : null, avatarURL: message.author.avatarURL() ?? null, bot: Boolean(message.author.bot), }, member: member ? { displayName: member.displayName ?? null, roles: member.roles.cache.map((role) => ({ id: role.id, name: role.name, })), joinedTimestamp: member.joinedTimestamp ?? null, } : null, channel: getMessageLocation(message), reference: message.reference ? { messageId: message.reference.messageId ?? null, channelId: message.reference.channelId ?? null, guildId: message.reference.guildId ?? null, } : null, }; } export function getDisplayContent(message: Message): string { if (message.content.trim().length > 0) return message.content; const stickers = getStickerMetadata(message); if (stickers.length > 0) { return stickers.map((sticker) => `[Sticker: ${sticker.name}]`).join(" "); } const attachments = getAttachmentMetadata(message); if (attachments.length > 0) { return attachments .map((attachment) => `[Attachment: ${attachment.name}]`) .join(" "); } const embeds = getEmbedMetadata(message); if (embeds.length > 0) { return embeds .map((embed) => embed.title || embed.description || "[Embed]") .join(" "); } return ""; }