Skip to content

Commit

Permalink
feat(plugin): Freemoji fixed for alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
Rico040 committed May 5, 2024
1 parent 3aad448 commit 4d31f05
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 0 deletions.
18 changes: 18 additions & 0 deletions plugins/freemoji/manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
45 changes: 45 additions & 0 deletions plugins/freemoji/src/Settings.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<RN.ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingBottom: 38 }}>
<FormSection title="Emoji Size" titleStyleType="no_border">
{Object.entries(sizeOptions).map(([name, size]) => <FormRadioRow
label={name}
subLabel={size}
selected={storage.emojiSize === size}
onPress={() => {
storage.emojiSize = size;
}}
/>)}
</FormSection>
<FormSection title="Preview">
<RN.Image
source={{
uri: `${previewUri}?size=${storage.emojiSize}`,
width: storage.emojiSize,
height: storage.emojiSize
}}
/>
</FormSection>
</RN.ScrollView>
)
}
5 changes: 5 additions & 0 deletions plugins/freemoji/src/def.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Message {
content: string;
// TODO: Get the proper type for this
invalidEmojis: any[];
}
17 changes: 17 additions & 0 deletions plugins/freemoji/src/index.ts
Original file line number Diff line number Diff line change
@@ -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";
48 changes: 48 additions & 0 deletions plugins/freemoji/src/msgProcessor.ts
Original file line number Diff line number Diff line change
@@ -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 = /<a?:(\w+):(\d+)>/i;

function extractUnusableEmojis(messageString: string, size: number) {
const emojiStrings = messageString.matchAll(/<a?:(\w+):(\d+)>/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 = [];
};
9 changes: 9 additions & 0 deletions plugins/freemoji/src/patches/nitroChecks.ts
Original file line number Diff line number Diff line change
@@ -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),
];
11 changes: 11 additions & 0 deletions plugins/freemoji/src/patches/sendMessage.ts
Original file line number Diff line number Diff line change
@@ -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)),
];
28 changes: 28 additions & 0 deletions plugins/freemoji/src/vpatcher.ts
Original file line number Diff line number Diff line change
@@ -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<F extends Function>(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<typeof vBefore>) => void = (name, obj, cb, once) => {
unpatches.push(vBefore(name, obj, wrapCb("before", name, cb), once));
};

export const after: (...args: Parameters<typeof vAfter>) => void = (name, obj, cb, once) => {
unpatches.push(vAfter(name, obj, wrapCb("after", name, cb), once));
};

export const instead: (...args: Parameters<typeof vInstead>) => void = (name, obj, cb, once) => {
unpatches.push(vInstead(name, obj, wrapCb("instead", name, cb), once));
};

export const unpatchAll = () => unpatches.forEach(u => u());

0 comments on commit 4d31f05

Please sign in to comment.