From f058a2f7ba594896aed01b8ee292b532439a0ebe Mon Sep 17 00:00:00 2001 From: kmmiio99o <164557248+kmmiio99o@users.noreply.github.com> Date: Sat, 27 Sep 2025 23:19:06 +0200 Subject: [PATCH] Add /firstmessage command to fetch first message in channel --- plugins/Commands/settings.tsx | 11 ++ plugins/Commands/src/commands/firstmessage.ts | 146 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 plugins/Commands/src/commands/firstmessage.ts diff --git a/plugins/Commands/settings.tsx b/plugins/Commands/settings.tsx index 6dc8c15..c74e8d4 100644 --- a/plugins/Commands/settings.tsx +++ b/plugins/Commands/settings.tsx @@ -39,6 +39,7 @@ if (!storage.enabledCommands) { themeList: true, konoself: true, konosend: true, + firstmessage: true, }; } @@ -179,6 +180,16 @@ export default function Settings() { /> + {/* Message Commands */} + + handleCommandToggle("firstmessage", v)} + /> + + {/* Credits */} diff --git a/plugins/Commands/src/commands/firstmessage.ts b/plugins/Commands/src/commands/firstmessage.ts new file mode 100644 index 0000000..76b9351 --- /dev/null +++ b/plugins/Commands/src/commands/firstmessage.ts @@ -0,0 +1,146 @@ +import { registerCommand } from "@vendetta/commands"; +import { findByProps } from "@vendetta/metro"; +import { url } from "@vendetta/metro/common"; +import { storage } from "@vendetta/plugin"; + +const messageUtil = findByProps( + "sendBotMessage", + "sendMessage", + "receiveMessage", +); +const APIUtils = findByProps("getAPIBaseURL", "get"); +let commands = []; + +export const onLoad = () => { + if (!storage?.enabledCommands?.firstmessage) return; + + commands.push( + registerCommand({ + name: "firstmessage", + displayName: "firstmessage", + description: "Tired of scrolling to first message?", + displayDescription: "Tired of scrolling to first message?", + type: 1, + inputType: 1, + applicationId: "-1", + options: [ + { + name: "user", + displayName: "user", + description: + "Target user to get their first message in this server/dm", + displayDescription: + "Target user to get their first message in this server/dm", + type: 6, + required: false, + }, + { + name: "channel", + displayName: "channel", + description: "Target channel to get first message of", + displayDescription: "Target channel to get first message of", + type: 7, + required: false, + }, + { + name: "send", + displayName: "send", + description: "Whether to send the resulting url", + displayDescription: "Whether to send the resulting url", + type: 5, + required: false, + }, + ], + async execute(args, ctx) { + const user = args.find((o: any) => o.name === "user")?.value; + const channel = args.find((o: any) => o.name === "channel")?.value; + const send = args.find((o: any) => o.name === "send")?.value; + + const guildId = ctx.guild?.id; + const channelId = ctx.channel.id; + const isDM = ctx.channel.type === 1; + + let result = "https://discord.com/channels/"; + + try { + // Handle DM error cases first + if (isDM && (channel || (user && channel))) { + messageUtil.sendBotMessage( + channelId, + "This combination cannot be used in DMs!", + ); + return { type: 4 }; + } + + if (!user && !channel) { + if (isDM) { + const message = await getFirstDMMessage(channelId); + result += `@me/${channelId}/${message.id}`; + } else { + const message = await getFirstGuildMessage(guildId); + result += `${guildId}/${message.channel_id}/${message.id}`; + } + } else if (user) { + if (isDM) { + const message = await getFirstDMMessage(channelId, user); + result += `@me/${channelId}/${message.id}`; + } else { + const message = await getFirstGuildMessage(guildId, user); + result += `${guildId}/${message.channel_id}/${message.id}`; + } + } else if (channel) { + const message = await getFirstGuildMessage(guildId, null, channel); + result += `${guildId}/${channel}/${message.id}`; + } else { + const message = await getFirstGuildMessage(guildId, user, channel); + result += `${guildId}/${channel}/${message.id}`; + } + + if (send) { + messageUtil.sendBotMessage(channelId, result); + return { type: 4 }; + } else { + return url.openDeeplink(result); + } + } catch (error) { + messageUtil.sendBotMessage( + channelId, + "Failed to fetch the first message. Please try again.", + ); + return { type: 4 }; + } + }, + }), + ); +}; + +export const onUnload = () => { + for (const unregisterCommands of commands) unregisterCommands(); +}; + +const getFirstGuildMessage = async ( + guildId: number, + userId?: number, + channelId?: number, +) => { + const userParam = userId ? `&author_id=${userId}` : ""; + const channelParam = channelId ? `&channel_id=${channelId}` : ""; + const minIdParam = userId ? "" : `&min_id=0`; + return ( + await APIUtils.get({ + url: `/guilds/${guildId}/messages/search`, + query: `include_nsfw=true${userParam}${channelParam}${minIdParam}&sort_by=timestamp&sort_order=asc&offset=0`, + }) + ).body.messages[0][0]; +}; + +const getFirstDMMessage = async (dmId: number, userId?: number) => { + const userParam = userId ? `&author_id=${userId}` : ""; + const minIdParam = userId ? "" : `&min_id=0`; + return ( + await APIUtils.get({ + url: `/channels/${dmId}/messages/search`, + query: `&sort_by=timestamp&sort_order=asc&offset=0${userParam}${minIdParam}`, + }) + ).body.messages[0][0]; +};