diff options
Diffstat (limited to 'src/plugins/emoteCloner.tsx')
-rw-r--r-- | src/plugins/emoteCloner.tsx | 130 |
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); + } }); |