diff --git a/plugins/all-in-one/index.ts b/plugins/all-in-one/index.ts index c825f56..fb4e6ab 100644 --- a/plugins/all-in-one/index.ts +++ b/plugins/all-in-one/index.ts @@ -1,386 +1,15 @@ import { registerCommand } from "@vendetta/commands"; -import { findByStoreName, findByProps } from "@vendetta/metro"; import { storage } from "@vendetta/plugin"; -import { themes } from "@vendetta/themes"; -import { plugins } from "@vendetta/plugins"; -import { alerts } from "@vendetta/ui"; +import { + catFactCommand, + dogFactCommand, + uselessFactCommand, +} from "./src/commands/facts"; +import { pluginListCommand, themeListCommand } from "./src/commands/lists"; +import { petPetCommand } from "./src/commands/petpet"; import settings from "./settings"; -const UserStore = findByStoreName("UserStore"); -const MessageActions = findByProps("sendMessage"); -const Clyde = findByProps("sendBotMessage"); - -const maxMessageLength = - UserStore.getCurrentUser()?.premiumType === 2 ? 4000 : 2000; - -let commands: Array<() => void> = []; - -// Constants -const STATUS = { - ENABLED: "🟢", - DISABLED: "🔴", - SELECTED: "🔶", - NOT_SELECTED: "🔷", -} as const; - -const SPLIT_LARGE_MESSAGES_PLUGIN = - "https://vd-plugins.github.io/proxy/actuallythesun.github.io/vendetta-plugins/SplitLargeMessages/"; - -// API Functions -const uselessFact = async () => { - const response = await fetch( - "https://uselessfacts.jsph.pl/api/v2/facts/random", - ); - const resp = await response.json(); - return { - text: resp["text"], - source: resp["source"], - language: resp["language"], - }; -}; - -const dogFact = async () => { - const response = await fetch("https://dogapi.dog/api/v2/facts?limit=1"); - const resp = await response.json(); - return { - text: resp["data"]["0"]["attributes"]["body"], - }; -}; - -const catFact = async () => { - const response = await fetch("https://catfact.ninja/fact"); - const resp = await response.json(); - return { - text: resp["fact"], - length: resp["length"], - }; -}; - -async function getPetPetData(image: string) { - const data = await fetch( - `https://api.obamabot.me/v2/image/petpet?image=${image.replace("webp", "png")}`, - ); - const body = await data.json(); - return body; -} - -// Helper Functions -const formatFactResponse = (fact: { text: string; source?: string }) => { - let response = fact.text; - if (storage.factSettings?.includeCitation && fact.source) { - response += `\n\nSource: ${fact.source}`; - } - return response; -}; - -const sendMessage = ( - channelId: string, - content: string, - replyToId?: string, -) => { - const message = { - content, - ...(replyToId && storage.factSettings?.sendAsReply - ? { messageReference: { messageId: replyToId } } - : {}), - }; - - MessageActions.sendMessage(channelId, message, void 0, { - nonce: BigInt(Date.now()) << 22n, - }); - return { type: 4 }; // Acknowledge the command -}; - -const addonAuthors = (authors: Array<{ name: string }>) => - authors.map((author) => author.name).join(", "); - -const formatList = (list: string[]) => list.join("\n").trimEnd(); - -const getListLength = (list: string[]) => formatList(list).length; - -const sendList = async (channelID: string, list: string[]) => { - return sendMessage(channelID, formatList(list)); -}; - -const isSLMPluginInstalled = () => - Object.keys(plugins).includes(SPLIT_LARGE_MESSAGES_PLUGIN); - -const isSLMPluginEnabled = () => { - const plugin = Object.values(plugins).find( - (p) => p.id === SPLIT_LARGE_MESSAGES_PLUGIN, - ); - return plugin?.enabled ?? false; -}; - -// Command Handlers -async function handleThemeList(detailed: boolean, ctx: any) { - const alwaysDetailed = storage.themeListAlwaysDetailed ?? false; - const themeList = [ - `**My Theme List | ${Object.keys(themes).length} Themes**`, - "", - ]; - - const themeValues = Object.values(themes); - if (themeValues.length) { - for (const theme of themeValues) { - const { selected, data, id } = theme; - const { name, description, authors } = data; - - if (detailed || alwaysDetailed) { - themeList.push( - `> **Name**: ${name}`, - `> **Selected**: ${selected ? STATUS.SELECTED : STATUS.NOT_SELECTED}`, - `> **Description**: ${description}`, - `> **Authors**: ${addonAuthors(authors)}`, - `> **[Install!](${id})**`, - "", - ); - } else { - themeList.push( - `> ${selected ? STATUS.SELECTED : STATUS.NOT_SELECTED} **${name}** by ${addonAuthors(authors)}`, - ); - } - } - } else { - themeList.push("Nothing to see here, huh..."); - } - - const isListTooLong = getListLength(themeList) > maxMessageLength; - - if (isListTooLong && !isSLMPluginInstalled()) { - Clyde.sendBotMessage( - ctx.channel.id, - `Your list is too long to send it! Please install the [Split Large Messages](${SPLIT_LARGE_MESSAGES_PLUGIN}) plugin.`, - ); - return { type: 4 }; - } else if (isListTooLong && !isSLMPluginEnabled()) { - Clyde.sendBotMessage( - ctx.channel.id, - "Your list is too long to send it! You have the Split Large Messages plugin installed, but it's not enabled!\n> Please enable it in order to send the list.", - ); - return { type: 4 }; - } - - if (getListLength(themeList) > 2000) { - return alerts.showConfirmationAlert({ - content: "Your list is over than 2000 characters. Are you sure?", - confirmText: "Yes", - cancelText: "No", - onConfirm: async () => sendList(ctx.channel.id, themeList), - }); - } - - return sendList(ctx.channel.id, themeList); -} - -async function handlePluginList(detailed: boolean, ctx: any) { - const alwaysDetailed = storage.pluginListAlwaysDetailed ?? false; - const pluginList = [ - `**My Plugin List | ${Object.keys(plugins).length} Plugins**`, - "", - ]; - - for (const plugin of Object.values(plugins)) { - const { enabled, manifest, id } = plugin; - const { name, description, authors } = manifest; - - if (detailed || alwaysDetailed) { - pluginList.push( - `> **Name**: ${name}`, - `> **Status**: ${enabled ? STATUS.ENABLED : STATUS.DISABLED}`, - `> **Description**: ${description}`, - `> **Authors**: ${addonAuthors(authors)}`, - `> **[Install!](${id})**`, - "", - ); - } else { - pluginList.push( - `> ${enabled ? STATUS.ENABLED : STATUS.DISABLED} **${name}** by ${addonAuthors(authors)}`, - ); - } - } - - const isListTooLong = getListLength(pluginList) > maxMessageLength; - - if (isListTooLong && !isSLMPluginInstalled()) { - return sendMessage( - ctx.channel.id, - `Your list is too long to send it! Please install the [Split Large Messages](${SPLIT_LARGE_MESSAGES_PLUGIN}) plugin.`, - ); - } else if (isListTooLong && !isSLMPluginEnabled()) { - return sendMessage( - ctx.channel.id, - "Your list is too long to send it! You have the Split Large Messages plugin installed, but it's not enabled!\n> Please enable it in order to send the list.", - ); - } - - if (getListLength(pluginList) > 2000) { - return alerts.showConfirmationAlert({ - content: "Your list is over than 2000 characters. Are you sure?", - confirmText: "Yes", - cancelText: "No", - onConfirm: async () => - sendMessage(ctx.channel.id, formatList(pluginList)), - }); - } - - return sendMessage(ctx.channel.id, formatList(pluginList)); -} - -// Register Commands -const registerCommands = () => { - // Cat Facts Command - commands.push( - registerCommand({ - name: "catfact", - displayName: "catfact", - description: "Sends a random cat fact.", - displayDescription: "Sends a random cat fact.", - applicationId: "-1", - inputType: 1, - type: 1, - execute: async (args, ctx) => { - const fact = await catFact(); - return sendMessage( - ctx.channel.id, - formatFactResponse(fact), - ctx.message?.id, - ); - }, - }), - ); - - // Dog Facts Command - commands.push( - registerCommand({ - name: "dogfact", - displayName: "dogfact", - description: "Sends a dog fact.", - displayDescription: "Sends a dog fact.", - applicationId: "-1", - inputType: 1, - type: 1, - execute: async (args, ctx) => { - const fact = await dogFact(); - return sendMessage( - ctx.channel.id, - formatFactResponse(fact), - ctx.message?.id, - ); - }, - }), - ); - - // Useless Facts Command - commands.push( - registerCommand({ - name: "useless", - displayName: "useless", - description: "Sends a useless fact.", - displayDescription: "Sends a useless fact.", - applicationId: "-1", - inputType: 1, - type: 1, - execute: async (args, ctx) => { - const fact = await uselessFact(); - return sendMessage( - ctx.channel.id, - formatFactResponse(fact), - ctx.message?.id, - ); - }, - }), - ); - - // PetPet Command - commands.push( - registerCommand({ - name: "petpet", - displayName: "petpet", - description: "PetPet someone", - displayDescription: "PetPet someone", - options: [ - { - name: "user", - description: "The user(or their id) to be patted", - type: 6, - required: true, - displayName: "user", - displayDescription: "The user(or their id) to be patted", - }, - ], - execute: async (args, ctx) => { - const user = await UserStore.getUser(args[0].value); - const image = user.getAvatarURL(512); - const data = await getPetPetData(image); - return sendMessage(ctx.channel.id, data.url, ctx.message?.id); - }, - applicationId: "-1", - inputType: 1, - type: 1, - }), - ); - - // Plugin List Command - commands.push( - registerCommand({ - name: "plugin-list", - displayName: "plugin list", - description: "Send your plugin list to the current channel", - displayDescription: "Send your plugin list to the current channel", - options: [ - { - name: "detailed", - description: "Whether to send a list with detailed information.", - type: 5, - required: false, - displayName: "detailed", - displayDescription: - "Whether to send a list with detailed information.", - }, - ], - execute: async (args, ctx) => { - const detailed = - args.find((arg) => arg.name === "detailed")?.value ?? false; - return handlePluginList(detailed, ctx); - }, - applicationId: "-1", - inputType: 1, - type: 1, - }), - ); - - // Theme List Command - commands.push( - registerCommand({ - name: "theme-list", - displayName: "theme list", - description: "Send your theme list to the current channel", - displayDescription: "Send your theme list to the current channel", - options: [ - { - name: "detailed", - description: "Whether to send a list with detailed information.", - type: 5, - required: false, - displayName: "detailed", - displayDescription: - "Whether to send a list with detailed information.", - }, - ], - execute: async (args, ctx) => { - const detailed = - args.find((arg) => arg.name === "detailed")?.value ?? false; - return handleThemeList(detailed, ctx); - }, - applicationId: "-1", - inputType: 1, - type: 1, - }), - ); -}; - -// Initialize storage +// Initialize storage with default values if (!storage.factSettings) { storage.factSettings = { sendAsReply: true, @@ -395,15 +24,32 @@ if (!storage.listSettings) { }; } +// Store registered commands for cleanup +let commands: Array<() => void> = []; + export default { onLoad: () => { - console.log("[All-In-One Commands] Plugin loaded!"); - registerCommands(); + console.log("[All-In-One Commands] Loading plugin..."); + + // Register all commands + commands = [ + registerCommand(catFactCommand), + registerCommand(dogFactCommand), + registerCommand(uselessFactCommand), + registerCommand(petPetCommand), + registerCommand(pluginListCommand), + registerCommand(themeListCommand), + ]; + + console.log("[All-In-One Commands] Plugin loaded successfully!"); }, + onUnload: () => { - console.log("[All-In-One Commands] Plugin unloaded!"); + console.log("[All-In-One Commands] Unloading plugin..."); commands.forEach((unregister) => unregister()); commands = []; + console.log("[All-In-One Commands] Plugin unloaded successfully!"); }, + settings, }; diff --git a/plugins/all-in-one/src/commands/facts.ts b/plugins/all-in-one/src/commands/facts.ts new file mode 100644 index 0000000..1056331 --- /dev/null +++ b/plugins/all-in-one/src/commands/facts.ts @@ -0,0 +1,54 @@ +import { storage } from "@vendetta/plugin"; +import { sendMessage } from "../utils/messages"; +import { catFact, dogFact, uselessFact } from "../utils/api"; + +// Helper function to format fact response +const formatFactResponse = (fact: { text: string; source?: string }) => { + let response = fact.text; + if (storage.factSettings?.includeCitation && fact.source) { + response += `\n\nSource: ${fact.source}`; + } + return response; +}; + +export const catFactCommand = { + name: "catfact", + displayName: "catfact", + description: "Sends a random cat fact.", + displayDescription: "Sends a random cat fact.", + applicationId: "-1", + inputType: 1, + type: 1, + execute: async (args: any, ctx: any) => { + const fact = await catFact(); + return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage); + }, +}; + +export const dogFactCommand = { + name: "dogfact", + displayName: "dogfact", + description: "Sends a dog fact.", + displayDescription: "Sends a dog fact.", + applicationId: "-1", + inputType: 1, + type: 1, + execute: async (args: any, ctx: any) => { + const fact = await dogFact(); + return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage); + }, +}; + +export const uselessFactCommand = { + name: "useless", + displayName: "useless", + description: "Sends a useless fact.", + displayDescription: "Sends a useless fact.", + applicationId: "-1", + inputType: 1, + type: 1, + execute: async (args: any, ctx: any) => { + const fact = await uselessFact(); + return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage); + }, +}; diff --git a/plugins/all-in-one/src/commands/lists.ts b/plugins/all-in-one/src/commands/lists.ts new file mode 100644 index 0000000..09ff093 --- /dev/null +++ b/plugins/all-in-one/src/commands/lists.ts @@ -0,0 +1,188 @@ +import { findByProps } from "@vendetta/metro"; +import { themes } from "@vendetta/themes"; +import { plugins } from "@vendetta/plugins"; +import { storage } from "@vendetta/plugin"; +import { alerts } from "@vendetta/ui"; +import { sendMessage } from "../utils/messages"; + +const SPLIT_LARGE_MESSAGES_PLUGIN = "https://vd-plugins.github.io/proxy/actuallythesun.github.io/vendetta-plugins/SplitLargeMessages/"; + +const STATUS = { + ENABLED: "🟢", + DISABLED: "🔴", + SELECTED: "🔶", + NOT_SELECTED: "🔷", +} as const; + +// Helper Functions +const addonAuthors = (authors: Array<{ name: string }>) => + authors.map((author) => author.name).join(", "); + +const formatList = (list: string[]) => list.join("\n").trimEnd(); + +const getListLength = (list: string[]) => formatList(list).length; + +const isSLMPluginInstalled = () => + Object.keys(plugins).includes(SPLIT_LARGE_MESSAGES_PLUGIN); + +const isSLMPluginEnabled = () => + Object.values(plugins).find((p) => p.id === SPLIT_LARGE_MESSAGES_PLUGIN) + ?.enabled ?? false; + +// Command handlers +async function handlePluginList(detailed: boolean, ctx: any) { + const alwaysDetailed = storage.listSettings?.pluginListAlwaysDetailed ?? false; + const pluginList = [ + `**My Plugin List | ${Object.keys(plugins).length} Plugins**`, + "", + ]; + + for (const plugin of Object.values(plugins)) { + const { enabled, manifest, id } = plugin; + const { name, description, authors } = manifest; + + if (detailed || alwaysDetailed) { + pluginList.push( + `> **Name**: ${name}`, + `> **Status**: ${enabled ? STATUS.ENABLED : STATUS.DISABLED}`, + `> **Description**: ${description}`, + `> **Authors**: ${addonAuthors(authors)}`, + `> **[Install!](${id})**`, + "", + ); + } else { + pluginList.push( + `> ${enabled ? STATUS.ENABLED : STATUS.DISABLED} **${name}** by ${addonAuthors(authors)}`, + ); + } + } + + if (getListLength(pluginList) > 2000) { + if (!isSLMPluginInstalled()) { + return sendMessage( + ctx.channel.id, + `Your list is too long to send it! Please install the [Split Large Messages](${SPLIT_LARGE_MESSAGES_PLUGIN}) plugin.`, + ); + } + if (!isSLMPluginEnabled()) { + return sendMessage( + ctx.channel.id, + "Your list is too long to send it! You have the Split Large Messages plugin installed, but it's not enabled!\n> Please enable it in order to send the list.", + ); + } + + return alerts.showConfirmationAlert({ + content: "Your list is over than 2000 characters. Are you sure?", + confirmText: "Yes", + cancelText: "No", + onConfirm: () => sendMessage(ctx.channel.id, formatList(pluginList)), + }); + } + + return sendMessage(ctx.channel.id, formatList(pluginList)); +} + +async function handleThemeList(detailed: boolean, ctx: any) { + const alwaysDetailed = storage.themeListAlwaysDetailed ?? false; + const themeList = [ + `**My Theme List | ${Object.keys(themes).length} Themes**`, + "", + ]; + + const themeValues = Object.values(themes); + if (themeValues.length) { + for (const theme of themeValues) { + const { selected, data, id } = theme; + const { name, description, authors } = data; + + if (detailed || alwaysDetailed) { + themeList.push( + `> **Name**: ${name}`, + `> **Selected**: ${selected ? STATUS.SELECTED : STATUS.NOT_SELECTED}`, + `> **Description**: ${description}`, + `> **Authors**: ${addonAuthors(authors)}`, + `> **[Install!](${id})**`, + "", + ); + } else { + themeList.push( + `> ${selected ? STATUS.SELECTED : STATUS.NOT_SELECTED} **${name}** by ${addonAuthors(authors)}`, + ); + } + } + } else { + themeList.push("Nothing to see here, huh..."); + } + + if (getListLength(themeList) > 2000) { + if (!isSLMPluginInstalled()) { + return sendMessage( + ctx.channel.id, + `Your list is too long to send it! Please install the [Split Large Messages](${SPLIT_LARGE_MESSAGES_PLUGIN}) plugin.`, + ); + } + if (!isSLMPluginEnabled()) { + return sendMessage( + ctx.channel.id, + "Your list is too long to send it! You have the Split Large Messages plugin installed, but it's not enabled!\n> Please enable it in order to send the list.", + ); + } + + return alerts.showConfirmationAlert({ + content: "Your list is over than 2000 characters. Are you sure?", + confirmText: "Yes", + cancelText: "No", + onConfirm: () => sendMessage(ctx.channel.id, formatList(themeList)), + }); + } + + return sendMessage(ctx.channel.id, formatList(themeList)); +} + +export const pluginListCommand = { + name: "plugin-list", + displayName: "plugin list", + description: "Send your plugin list to the current channel", + displayDescription: "Send your plugin list to the current channel", + options: [ + { + name: "detailed", + description: "Whether to send a list with detailed information.", + type: 5, + required: false, + displayName: "detailed", + displayDescription: "Whether to send a list with detailed information.", + }, + ], + execute: async (args: any, ctx: any) => { + const detailed = args.find((arg: any) => arg.name === "detailed")?.value ?? false; + return handlePluginList(detailed, ctx); + }, + applicationId: "-1", + inputType: 1, + type: 1, +}; + +export const themeListCommand = { + name: "theme-list", + displayName: "theme list", + description: "Send your theme list to the current channel", + displayDescription: "Send your theme list to the current channel", + options: [ + { + name: "detailed", + description: "Whether to send a list with detailed information.", + type: 5, + required: false, + displayName: "detailed", + displayDescription: "Whether to send a list with detailed information.", + }, + ], + execute: async (args: any, ctx: any) => { + const detailed = args.find((arg: any) => arg.name === "detailed")?.value ?? false; + return handleThemeList(detailed, ctx); + }, + applicationId: "-1", + inputType: 1, + type: 1, +}; diff --git a/plugins/all-in-one/src/commands/petpet.ts b/plugins/all-in-one/src/commands/petpet.ts new file mode 100644 index 0000000..ff7b7e3 --- /dev/null +++ b/plugins/all-in-one/src/commands/petpet.ts @@ -0,0 +1,31 @@ +import { findByStoreName } from "@vendetta/metro"; +import { sendMessage } from "../utils/messages"; +import { getPetPetData } from "../utils/api"; + +const UserStore = findByStoreName("UserStore"); + +export const petPetCommand = { + name: "petpet", + displayName: "petpet", + description: "PetPet someone", + displayDescription: "PetPet someone", + options: [ + { + name: "user", + description: "The user(or their id) to be patted", + type: 6, + required: true, + displayName: "user", + displayDescription: "The user(or their id) to be patted", + }, + ], + execute: async (args: any, ctx: any) => { + const user = await UserStore.getUser(args[0].value); + const image = user.getAvatarURL(512); + const data = await getPetPetData(image); + return sendMessage(ctx.channel.id, data.url, ctx.message?.id); + }, + applicationId: "-1", + inputType: 1, + type: 1, +}; diff --git a/plugins/all-in-one/src/utils/api.ts b/plugins/all-in-one/src/utils/api.ts new file mode 100644 index 0000000..a0fc752 --- /dev/null +++ b/plugins/all-in-one/src/utils/api.ts @@ -0,0 +1,38 @@ +// API functions for facts and images + +// Facts APIs +export const uselessFact = async () => { + const response = await fetch("https://uselessfacts.jsph.pl/api/v2/facts/random"); + const resp = await response.json(); + return { + text: resp["text"], + source: resp["source"], + language: resp["language"], + }; +}; + +export const dogFact = async () => { + const response = await fetch("https://dogapi.dog/api/v2/facts?limit=1"); + const resp = await response.json(); + return { + text: resp["data"]["0"]["attributes"]["body"], + }; +}; + +export const catFact = async () => { + const response = await fetch("https://catfact.ninja/fact"); + const resp = await response.json(); + return { + text: resp["fact"], + length: resp["length"], + }; +}; + +// Image APIs +export const getPetPetData = async (image: string) => { + const data = await fetch( + `https://api.obamabot.me/v2/image/petpet?image=${image.replace("webp", "png")}` + ); + const body = await data.json(); + return body; +}; diff --git a/plugins/all-in-one/src/utils/messages.ts b/plugins/all-in-one/src/utils/messages.ts new file mode 100644 index 0000000..7cfb43a --- /dev/null +++ b/plugins/all-in-one/src/utils/messages.ts @@ -0,0 +1,22 @@ +import { findByProps } from "@vendetta/metro"; + +const MessageActions = findByProps("sendMessage"); + +export const sendMessage = ( + channelId: string, + content: string, + replyToId?: string, + storage?: any +) => { + const message = { + content, + ...(replyToId && storage?.factSettings?.sendAsReply + ? { messageReference: { messageId: replyToId } } + : {}), + }; + + MessageActions.sendMessage(channelId, message, void 0, { + nonce: BigInt(Date.now()) << 22n, + }); + return { type: 4 }; // Acknowledge the command +};