diff --git a/src/api/ContextMenu.ts b/src/api/ContextMenu.ts
index 3f73a41e..16f9f32b 100644
--- a/src/api/ContextMenu.ts
+++ b/src/api/ContextMenu.ts
@@ -122,6 +122,8 @@ export function _patchContextMenu(props: ContextMenuProps) {
props.contextMenuApiArguments ??= [];
const contextMenuPatches = navPatches.get(props.navId);
+ if (!Array.isArray(props.children)) props.children = [props.children];
+
if (contextMenuPatches) {
for (const patch of contextMenuPatches) {
try {
diff --git a/src/plugins/emoteCloner.tsx b/src/plugins/emoteCloner.tsx
index afbb3987..3bcc6944 100644
--- a/src/plugins/emoteCloner.tsx
+++ b/src/plugins/emoteCloner.tsx
@@ -17,7 +17,6 @@
*/
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
-import { migratePluginSettings } from "@api/settings";
import { CheckedTextInput } from "@components/CheckedTextInput";
import { Devs } from "@utils/constants";
import Logger from "@utils/Logger";
@@ -176,74 +175,78 @@ function CloneModal({ id, name: emojiName, isAnimated }: { id: string; name: str
);
}
+function buildMenuItem(id: string, name: string, isAnimated: boolean) {
+ return (
+
+ openModal(modalProps => (
+
+
+
+ Clone {name}
+
+
+
+
+
+ ))
+ }
+ />
+ );
+}
+
+function isGifUrl(url: string) {
+ return new URL(url).pathname.endsWith(".gif");
+}
+
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
- if (!props) return;
- const { favoriteableId, emoteClonerDataAlt, itemHref, itemSrc, favoriteableType } = props;
+ const { favoriteableId, itemHref, itemSrc, favoriteableType } = props ?? {};
- if (!emoteClonerDataAlt || favoriteableType !== "emoji") return;
+ if (!favoriteableId || favoriteableType !== "emoji") return;
- const name = emoteClonerDataAlt.match(/:(.*)(?:~\d+)?:/)?.[1];
- if (!name || !favoriteableId) return;
-
- const src = itemHref ?? itemSrc;
- const isAnimated = new URL(src).pathname.endsWith(".gif");
+ const match = props.message.content.match(RegExp(`|https://cdn\\.discordapp\\.com/emojis/${favoriteableId}\\.`));
+ if (!match) return;
+ const name = match[1] ?? "FakeNitroEmoji";
const group = findGroupChildrenByChildId("copy-link", children);
- if (group && !group.some(child => child?.props?.id === "emote-cloner")) {
- group.push((
-
- openModal(modalProps => (
-
-
-
- Clone {name}
-
-
-
-
-
- ))
- }
- >
-
- ));
- }
+ if (group && !group.some(child => child?.props?.id === "emote-cloner"))
+ group.push(buildMenuItem(favoriteableId, name, isGifUrl(itemHref ?? itemSrc)));
+};
+
+const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
+ const { id, name, type } = props?.target?.dataset ?? {};
+ if (!id || !name || type !== "emoji") return;
+
+ const firstChild = props.target.firstChild as HTMLImageElement;
+
+ if (!children.some(c => c?.props?.id === "emote-cloner"))
+ children.push(buildMenuItem(id, name, firstChild && isGifUrl(firstChild.src)));
};
-migratePluginSettings("EmoteCloner", "EmoteYoink");
export default definePlugin({
name: "EmoteCloner",
description: "Adds a Clone context menu item to emotes to clone them your own server",
authors: [Devs.Ven, Devs.Nuckyz],
dependencies: ["MenuItemDeobfuscatorAPI", "ContextMenuAPI"],
- patches: [
- {
- find: ".Messages.MESSAGE_ACTIONS_MENU_LABEL",
- replacement: {
- match: /favoriteableType:\i,(?<=(\i)\.getAttribute\("data-type"\).+?)/,
- replace: (m, target) => `${m}emoteClonerDataAlt:${target}.alt,`
- }
- }
- ],
-
start() {
addContextMenuPatch("message", messageContextMenuPatch);
+ addContextMenuPatch("expression-picker", expressionPickerPatch);
},
stop() {
removeContextMenuPatch("message", messageContextMenuPatch);
+ removeContextMenuPatch("expression-picker", expressionPickerPatch);
}
});