aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/emoteCloner.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/emoteCloner.tsx')
-rw-r--r--src/plugins/emoteCloner.tsx130
1 files changed, 66 insertions, 64 deletions
diff --git a/src/plugins/emoteCloner.tsx b/src/plugins/emoteCloner.tsx
index e252fe5..7db5efd 100644
--- a/src/plugins/emoteCloner.tsx
+++ b/src/plugins/emoteCloner.tsx
@@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { migratePluginSettings, Settings } from "@api/settings";
+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";
import { Margins } from "@utils/margins";
-import { makeLazy } from "@utils/misc";
import { ModalContent, ModalHeader, ModalRoot, openModal } from "@utils/modal";
import definePlugin from "@utils/types";
import { findByCodeLazy, findByPropsLazy } from "@webpack";
@@ -176,72 +176,74 @@ function CloneModal({ id, name: emojiName, isAnimated }: { id: string; name: str
);
}
+const messageContextMenuPatch: NavContextMenuPatchCallback = (children, args) => {
+ if (!args?.[0]) return;
+ const { favoriteableId, emoteClonerDataAlt, itemHref, itemSrc, favoriteableType } = args[0];
+
+ if (!emoteClonerDataAlt || 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 group = findGroupChildrenByChildId("save-image", children);
+ if (group && !group.some(child => child?.props?.id === "emote-cloner")) {
+ group.push((
+ <Menu.MenuItem
+ id="emote-cloner"
+ key="emote-cloner"
+ label="Clone"
+ action={() =>
+ openModal(modalProps => (
+ <ModalRoot {...modalProps}>
+ <ModalHeader>
+ <img
+ role="presentation"
+ aria-hidden
+ src={`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/emojis/${favoriteableId}.${isAnimated ? "gif" : "png"}`}
+ alt=""
+ height={24}
+ width={24}
+ style={{ marginRight: "0.5em" }}
+ />
+ <Forms.FormText>Clone {name}</Forms.FormText>
+ </ModalHeader>
+ <ModalContent>
+ <CloneModal id={favoriteableId} name={name} isAnimated={isAnimated} />
+ </ModalContent>
+ </ModalRoot>
+ ))
+ }
+ >
+ </Menu.MenuItem>
+ ));
+ }
+};
+
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],
- dependencies: ["MenuItemDeobfuscatorAPI"],
-
- patches: [{
- // Literally copy pasted from ReverseImageSearch lol
- find: "open-native-link",
- replacement: {
- match: /id:"open-native-link".{0,200}\(\{href:(.{0,3}),.{0,200}\},"open-native-link"\)/,
- replace: "$&,$self.makeMenu(arguments[2])"
- },
-
- },
- // Also copy pasted from Reverse Image Search
- {
- // pass the target to the open link menu so we can grab its data
- find: "REMOVE_ALL_REACTIONS_CONFIRM_BODY,",
- predicate: makeLazy(() => !Settings.plugins.ReverseImageSearch.enabled),
- noWarn: true,
- replacement: {
- match: /(?<props>.).onHeightUpdate.{0,200}(.)=(.)=.\.url;.+?\(null!=\3\?\3:\2[^)]+/,
- replace: "$&,$<props>.target"
- }
- }],
-
- makeMenu(htmlElement: HTMLImageElement) {
- if (htmlElement?.dataset.type !== "emoji")
- return null;
-
- const { id } = htmlElement.dataset;
- const name = htmlElement.alt.match(/:(.*)(?:~\d+)?:/)?.[1];
-
- if (!name || !id)
- return null;
-
- const isAnimated = new URL(htmlElement.src).pathname.endsWith(".gif");
-
- return <Menu.MenuItem
- id="emote-cloner"
- key="emote-cloner"
- label="Clone"
- action={() =>
- openModal(modalProps => (
- <ModalRoot {...modalProps}>
- <ModalHeader>
- <img
- role="presentation"
- aria-hidden
- src={`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/emojis/${id}.${isAnimated ? "gif" : "png"}`}
- alt=""
- height={24}
- width={24}
- style={{ marginRight: "0.5em" }}
- />
- <Forms.FormText>Clone {name}</Forms.FormText>
- </ModalHeader>
- <ModalContent>
- <CloneModal id={id} name={name} isAnimated={isAnimated} />
- </ModalContent>
- </ModalRoot>
- ))
+ authors: [Devs.Ven, Devs.Nuckyz],
+ dependencies: ["MenuItemDeobfuscatorAPI", "ContextMenuAPI"],
+
+ patches: [
+ {
+ find: ".Messages.MESSAGE_ACTIONS_MENU_LABEL",
+ replacement: {
+ match: /(?<=favoriteableType:\i,)(?<=(\i)\.getAttribute\("data-type"\).+?)/,
+ replace: (_, target) => `emoteClonerDataAlt:${target}.alt,`
}
- >
- </Menu.MenuItem>;
+ }
+ ],
+
+ start() {
+ addContextMenuPatch("message", messageContextMenuPatch);
},
+
+ stop() {
+ removeContextMenuPatch("message", messageContextMenuPatch);
+ }
});