diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 6dd3eb300..8429c4339 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -25,11 +25,16 @@ import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/moda import definePlugin from "@utils/types"; import { findByCodeLazy, findStoreLazy } from "@webpack"; import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; +import { Channel } from "discord-types/general"; import { Promisable } from "type-fest"; const StickersStore = findStoreLazy("StickersStore"); const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START"); +const ChannelStatusStore: { + getChannelStatus(c: Channel): string; +} = findStoreLazy("ChannelStatusStore"); + interface Sticker { t: "Sticker"; description: string; @@ -272,12 +277,12 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) { ); } -function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable>) { +function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable>, label?: string) { return ( openModalLazy(async () => { const res = await fetchData(); @@ -360,13 +365,57 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t } }; +const emojiRegex = /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.([a-zA-Z]{3,4}).*/; +const imageContextPatch: NavContextMenuPatchCallback = (children, props: { + src: string; +}) => { + // this context menu is called on normal images, as well as stock emojis. + const matches = [...props.src.match(emojiRegex) ?? []]; + if (matches.length === 0) return; + children.push(buildMenuItem("Emoji", () => ({ + id: matches[1], + isAnimated: (matches[2] === "gif"), + name: "ProfileEmoji" + }))); +}; + +const emojiMatchRegex = /<(a?):(\w+):(\d{19})>/g; +const channelContextStatusPatch: NavContextMenuPatchCallback = (children, props: { + channel: Channel; +}) => { + const status = ChannelStatusStore.getChannelStatus(props.channel); + + if (!status) return; + + const emojis = [...status.matchAll(emojiMatchRegex)]; + if (emojis.length === 0) return; + console.log(emojis); + children.push(( + + { + emojis.map(([_, animated, name, id]) => ( + buildMenuItem("Emoji", () => ({ + id, + name, + isAnimated: !!animated, + }), + `Clone ${name}` + ) + )) + } + + )); +}; + export default definePlugin({ name: "EmoteCloner", description: "Allows you to clone Emotes & Stickers to your own server (right click them)", tags: ["StickerCloner"], - authors: [Devs.Ven, Devs.Nuckyz], + authors: [Devs.Ven, Devs.Nuckyz, Devs.sadan], contextMenus: { "message": messageContextMenuPatch, - "expression-picker": expressionPickerPatch - } + "expression-picker": expressionPickerPatch, + "image-context": imageContextPatch, + "channel-context": channelContextStatusPatch + }, });