From 4d31f05c630be313a0fd3bb8b38c76fef4cbc40a Mon Sep 17 00:00:00 2001 From: Rico040 <93081680+Rico040@users.noreply.github.com> Date: Sun, 5 May 2024 23:58:02 +1000 Subject: [PATCH] feat(plugin): `Freemoji` fixed for alpha --- plugins/freemoji/manifest.json | 18 ++++++++ plugins/freemoji/src/Settings.tsx | 45 +++++++++++++++++++ plugins/freemoji/src/def.d.ts | 5 +++ plugins/freemoji/src/index.ts | 17 ++++++++ plugins/freemoji/src/msgProcessor.ts | 48 +++++++++++++++++++++ plugins/freemoji/src/patches/nitroChecks.ts | 9 ++++ plugins/freemoji/src/patches/sendMessage.ts | 11 +++++ plugins/freemoji/src/vpatcher.ts | 28 ++++++++++++ 8 files changed, 181 insertions(+) create mode 100644 plugins/freemoji/manifest.json create mode 100644 plugins/freemoji/src/Settings.tsx create mode 100644 plugins/freemoji/src/def.d.ts create mode 100644 plugins/freemoji/src/index.ts create mode 100644 plugins/freemoji/src/msgProcessor.ts create mode 100644 plugins/freemoji/src/patches/nitroChecks.ts create mode 100644 plugins/freemoji/src/patches/sendMessage.ts create mode 100644 plugins/freemoji/src/vpatcher.ts diff --git a/plugins/freemoji/manifest.json b/plugins/freemoji/manifest.json new file mode 100644 index 0000000..ce411c2 --- /dev/null +++ b/plugins/freemoji/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Freemoji", + "description": "Allows you to use Nitro emoji without Nitro.", + "authors": [ + { + "name": "maisy", + "id": "257109471589957632" + }, + { + "name": "Rico040", + "id": "619474349845643275" + } + ], + "main": "src/index.ts", + "vendetta": { + "icon": "img_nitro_emojis" + } +} \ No newline at end of file diff --git a/plugins/freemoji/src/Settings.tsx b/plugins/freemoji/src/Settings.tsx new file mode 100644 index 0000000..600331b --- /dev/null +++ b/plugins/freemoji/src/Settings.tsx @@ -0,0 +1,45 @@ +import { ReactNative as RN } from "@vendetta/metro/common"; +import { Forms } from "@vendetta/ui/components"; +import { useProxy } from "@vendetta/storage"; +import { storage } from "@vendetta/plugin"; + +const { FormSection, FormRadioRow } = Forms; + +const sizeOptions = { + Tiny: 16, + Small: 32, + Medium: 48, + Large: 64, + Huge: 96, + Jumbo: 128, +} + +const previewUri = "https://cdn.discordapp.com/emojis/1105406110724268075.webp"; + +export default () => { + useProxy(storage); + + return ( + + + {Object.entries(sizeOptions).map(([name, size]) => { + storage.emojiSize = size; + }} + />)} + + + + + + ) +} \ No newline at end of file diff --git a/plugins/freemoji/src/def.d.ts b/plugins/freemoji/src/def.d.ts new file mode 100644 index 0000000..119c978 --- /dev/null +++ b/plugins/freemoji/src/def.d.ts @@ -0,0 +1,5 @@ +export interface Message { + content: string; + // TODO: Get the proper type for this + invalidEmojis: any[]; +} \ No newline at end of file diff --git a/plugins/freemoji/src/index.ts b/plugins/freemoji/src/index.ts new file mode 100644 index 0000000..d92977e --- /dev/null +++ b/plugins/freemoji/src/index.ts @@ -0,0 +1,17 @@ +import { storage } from "@vendetta/plugin"; +import nitroChecks from "./patches/nitroChecks"; +import sendMessage from "./patches/sendMessage"; + +// Default settings +storage.emojiSize ??= 48; + +// Migration code, used to be string containing a number but is now just a number +if (typeof storage.emojiSize === "string") storage.emojiSize = parseInt(storage.emojiSize); + +const patches = [ + ...nitroChecks, + ...sendMessage, +]; + +export const onUnload = () => patches.forEach(p => p()); +export { default as settings } from "./Settings"; \ No newline at end of file diff --git a/plugins/freemoji/src/msgProcessor.ts b/plugins/freemoji/src/msgProcessor.ts new file mode 100644 index 0000000..15366e5 --- /dev/null +++ b/plugins/freemoji/src/msgProcessor.ts @@ -0,0 +1,48 @@ +import { findByStoreName } from "@vendetta/metro"; +import { storage } from "@vendetta/plugin"; +import { Message } from "./def"; +const { getCustomEmojiById } = findByStoreName("EmojiStore"); +const { getGuildId } = findByStoreName("SelectedGuildStore"); + +// https://github.com/luimu64/nitro-spoof/blob/1bb75a2471c39669d590bfbabeb7b922672929f5/index.js#L25 +const hasEmotesRegex = //i; + +function extractUnusableEmojis(messageString: string, size: number) { + const emojiStrings = messageString.matchAll(//gi); + const emojiUrls = []; + + for (const emojiString of emojiStrings) { + // Fetch required info about the emoji + const emoji = getCustomEmojiById(emojiString[2]); + + // Check emoji usability + if ( + emoji.guildId != getGuildId() || + emoji.animated + ) { + // Remove emote from original msg + messageString = messageString.replace(emojiString[0], ""); + // Add to emotes to send + emojiUrls.push(`${emoji.url.split("?")[0]}?size=${size}`); + } + } + + return { + newContent: messageString.trim(), + extractedEmojis: emojiUrls, + }; +} + +export default function modifyIfNeeded(msg: Message) { + if (!msg.content.match(hasEmotesRegex)) return; + + // Find all emojis from the captured message string and return object with emojiURLS and content + const { newContent, extractedEmojis } = extractUnusableEmojis(msg.content, storage.emojiSize); + + msg.content = newContent; + + if (extractedEmojis.length > 0) msg.content += "\n" + extractedEmojis.join("\n"); + + // Set invalidEmojis to empty to prevent Discord yelling to you about you not having nitro + msg.invalidEmojis = []; +}; \ No newline at end of file diff --git a/plugins/freemoji/src/patches/nitroChecks.ts b/plugins/freemoji/src/patches/nitroChecks.ts new file mode 100644 index 0000000..09139cf --- /dev/null +++ b/plugins/freemoji/src/patches/nitroChecks.ts @@ -0,0 +1,9 @@ +import { findByProps } from "@vendetta/metro"; +import { instead } from "../vpatcher"; + +const nitroInfo = findByProps("canUseEmojisEverywhere"); + +export default [ + instead("canUseEmojisEverywhere", nitroInfo, () => true), + instead("canUseAnimatedEmojis", nitroInfo, () => true), +]; \ No newline at end of file diff --git a/plugins/freemoji/src/patches/sendMessage.ts b/plugins/freemoji/src/patches/sendMessage.ts new file mode 100644 index 0000000..add4cd2 --- /dev/null +++ b/plugins/freemoji/src/patches/sendMessage.ts @@ -0,0 +1,11 @@ +import { findByProps } from "@vendetta/metro"; +import { before } from "../vpatcher"; +import modifyIfNeeded from "../msgProcessor"; + +const messageModule = findByProps("sendMessage", "receiveMessage"); +const uploadModule = findByProps("uploadLocalFiles"); + +export default [ + before("sendMessage", messageModule, (args) => modifyIfNeeded(args[1])), + before("uploadLocalFiles", uploadModule, (args) => modifyIfNeeded(args[0].parsedMessage)), +]; \ No newline at end of file diff --git a/plugins/freemoji/src/vpatcher.ts b/plugins/freemoji/src/vpatcher.ts new file mode 100644 index 0000000..41e68d2 --- /dev/null +++ b/plugins/freemoji/src/vpatcher.ts @@ -0,0 +1,28 @@ +// https://github.com/Vendicated/its-called-vendetta-cause-its-owned-by-ven-plugins/blob/main/shared/vendetta-wrappers.ts +import { after as vAfter, before as vBefore, instead as vInstead } from "@vendetta/patcher"; + +export const unpatches = [] as Array<() => boolean>; + +function wrapCb(type: string, name: string, cb: F): F { + return function () { + try { + return cb.apply(this, arguments); + } catch (err) { + console.error(`Error while running ${type} callback for ${name}:`, err); + } + } as any as F; +} + +export const before: (...args: Parameters) => void = (name, obj, cb, once) => { + unpatches.push(vBefore(name, obj, wrapCb("before", name, cb), once)); +}; + +export const after: (...args: Parameters) => void = (name, obj, cb, once) => { + unpatches.push(vAfter(name, obj, wrapCb("after", name, cb), once)); +}; + +export const instead: (...args: Parameters) => void = (name, obj, cb, once) => { + unpatches.push(vInstead(name, obj, wrapCb("instead", name, cb), once)); +}; + +export const unpatchAll = () => unpatches.forEach(u => u()); \ No newline at end of file