From d7366ae1714a34176a053f95fc9bbcc4aae71910 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Wed, 10 Jul 2024 02:28:18 -0400 Subject: [PATCH 01/11] read desc add emote cloner to - emojis in user statuses - hang statuses (vc statuses) add name finding for fake nitro emojis that have &name=emoji_name --- src/plugins/emoteCloner/index.tsx | 61 +++++++++++++++++++++++++++++-- src/utils/constants.ts | 4 ++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 6dd3eb300..4f26ebe48 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -324,7 +324,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) = const match = props.message.content.match(RegExp(`|https://cdn\\.discordapp\\.com/emojis/${favoriteableId}\\.`)); const reaction = props.message.reactions.find(reaction => reaction.emoji.id === favoriteableId); if (!match && !reaction) return; - const name = (match && match[1]) ?? reaction?.emoji.name ?? "FakeNitroEmoji"; + const name = (match && match[1]) ?? reaction?.emoji.name ?? props?.message?.content.match(/(?<=name=)\w[a-zA-Z_0-9]*/gm) ?? "FakeNitroEmoji"; return buildMenuItem("Emoji", () => ({ id: favoriteableId, @@ -360,13 +360,66 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t } }; +function imageContextPatch(c, p: { + src: string +}){ + console.log("passed", p); + if ("src" in p + && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.(gif|png).*/gm.test(p.src) + ){ + const matches = [...p.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.(gif|png).*/gm)]; + if (!matches) return; + c.push(buildMenuItem("Emoji", () => ({ + id: matches[0][1], + isAnimated: (matches[0][2] === "gif"), + name: "ProfileEmoji" + }))); + } +} +interface HangStatus { + emoji?: { + // used for unicode emojis and custom emojis + name: string + // used for custom emojis + id?: string, + animated?: boolean + } +} +function vcHangStatusContextPatch(c, p: { + user: { + HangStatus?: HangStatus + } +}){ + if(p.user.HangStatus?.emoji?.id){ + const e = p.user.HangStatus.emoji as Emoji; + e.isAnimated = p.user.HangStatus.emoji.animated ?? false; + c.push(buildMenuItem("Emoji", () => { + return e; + })); + } +} 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, + "user-context": vcHangStatusContextPatch, + "image-context": imageContextPatch, + }, + patches: [ + // needed to pass the HangStatus to the context menu + { + find: "renderPrioritySpeaker", + replacement: { + match: /(handleContextMenu".*?)(let)/, + replace: "$1$self.patchVcListProps(this.props);$2" + } + }, + ], + patchVcListProps(props){ + props.user.HangStatus = props.hangStatusActivity; + }, }); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index c399baafe..37495d4f7 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -533,6 +533,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ Antti: { name: "Antti", id: 312974985876471810n + }, + sadan: { + name: "sadan", + id: 521819891141967883n, } } satisfies Record); From add443e67beff55da5386ad5afd50a133c4442b4 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:33:36 -0400 Subject: [PATCH 02/11] inline patch --- src/plugins/emoteCloner/index.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 4f26ebe48..75b4e8014 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -415,11 +415,9 @@ export default definePlugin({ find: "renderPrioritySpeaker", replacement: { match: /(handleContextMenu".*?)(let)/, - replace: "$1$self.patchVcListProps(this.props);$2" + replace: "$1this.props.user.HangStatus=this.props.hangStatusActivity;$2" + } }, ], - patchVcListProps(props){ - props.user.HangStatus = props.hangStatusActivity; - }, }); From 850b940306830c338c5d80befc7180a6e40d7347 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:35:27 -0400 Subject: [PATCH 03/11] fix regex and remove log --- src/plugins/emoteCloner/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 75b4e8014..b2ea9c46b 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -363,9 +363,8 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t function imageContextPatch(c, p: { src: string }){ - console.log("passed", p); if ("src" in p - && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.(gif|png).*/gm.test(p.src) + && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm.test(p.src) ){ const matches = [...p.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.(gif|png).*/gm)]; if (!matches) return; From 9c819e83b35334c81a3b67c7d94c8da04c0c6224 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Wed, 10 Jul 2024 23:35:19 -0400 Subject: [PATCH 04/11] fix regex remove fake nitro name part --- src/plugins/emoteCloner/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index b2ea9c46b..c49325a00 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -324,7 +324,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) = const match = props.message.content.match(RegExp(`|https://cdn\\.discordapp\\.com/emojis/${favoriteableId}\\.`)); const reaction = props.message.reactions.find(reaction => reaction.emoji.id === favoriteableId); if (!match && !reaction) return; - const name = (match && match[1]) ?? reaction?.emoji.name ?? props?.message?.content.match(/(?<=name=)\w[a-zA-Z_0-9]*/gm) ?? "FakeNitroEmoji"; + const name = (match && match[1]) ?? reaction?.emoji.name ?? "FakeNitroEmoji"; return buildMenuItem("Emoji", () => ({ id: favoriteableId, @@ -366,7 +366,7 @@ function imageContextPatch(c, p: { if ("src" in p && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm.test(p.src) ){ - const matches = [...p.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.(gif|png).*/gm)]; + const matches = [...p.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm)]; if (!matches) return; c.push(buildMenuItem("Emoji", () => ({ id: matches[0][1], From 8e649cfcc4fe811fed0b7024b58bd96e817fa932 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Thu, 11 Jul 2024 02:09:21 -0400 Subject: [PATCH 05/11] Update src/plugins/emoteCloner/index.tsx Co-authored-by: Drew <84212701+MrDiamondDog@users.noreply.github.com> --- src/plugins/emoteCloner/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index c49325a00..e1b964f22 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -363,9 +363,7 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t function imageContextPatch(c, p: { src: string }){ - if ("src" in p - && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm.test(p.src) - ){ + if ("src" in p && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm.test(p.src)) { const matches = [...p.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm)]; if (!matches) return; c.push(buildMenuItem("Emoji", () => ({ From bdae37ff23d75b2d696f7ebcd179aa5b9cd0e4d0 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Thu, 11 Jul 2024 02:20:07 -0400 Subject: [PATCH 06/11] fix var names, regex, and types --- src/plugins/emoteCloner/index.tsx | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index e1b964f22..a488d7eb9 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -360,19 +360,19 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t } }; -function imageContextPatch(c, p: { +const imageContextPatch: NavContextMenuPatchCallback = (children, props: { src: string -}){ - if ("src" in p && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm.test(p.src)) { - const matches = [...p.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.[a-zA-Z]{3,4}.*/gm)]; +}) => { + if ("src" in props && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.([a-zA-Z]{3,4}).*/gm.test(props.src)) { + const matches = [...props.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.([a-zA-Z]{3,4}).*/gm)]; if (!matches) return; - c.push(buildMenuItem("Emoji", () => ({ + children.push(buildMenuItem("Emoji", () => ({ id: matches[0][1], isAnimated: (matches[0][2] === "gif"), name: "ProfileEmoji" }))); } -} +}; interface HangStatus { emoji?: { // used for unicode emojis and custom emojis @@ -382,19 +382,19 @@ interface HangStatus { animated?: boolean } } -function vcHangStatusContextPatch(c, p: { +const vcHangStatusContextPatch: NavContextMenuPatchCallback =(children, props: { user: { HangStatus?: HangStatus } -}){ - if(p.user.HangStatus?.emoji?.id){ - const e = p.user.HangStatus.emoji as Emoji; - e.isAnimated = p.user.HangStatus.emoji.animated ?? false; - c.push(buildMenuItem("Emoji", () => { +}) => { + if(props.user.HangStatus?.emoji?.id){ + const e = props.user.HangStatus.emoji as Emoji; + e.isAnimated = props.user.HangStatus.emoji.animated ?? false; + children.push(buildMenuItem("Emoji", () => { return e; })); } -} +}; export default definePlugin({ name: "EmoteCloner", description: "Allows you to clone Emotes & Stickers to your own server (right click them)", From 359d7564a5cddb2ed6f46155571b48ae1fd0d4af Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Sun, 14 Jul 2024 23:16:58 -0400 Subject: [PATCH 07/11] fix wacky logic --- src/plugins/emoteCloner/index.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index a488d7eb9..130dd537f 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -360,18 +360,18 @@ 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 }) => { - if ("src" in props && /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.([a-zA-Z]{3,4}).*/gm.test(props.src)) { - const matches = [...props.src.matchAll(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.([a-zA-Z]{3,4}).*/gm)]; - if (!matches) return; - children.push(buildMenuItem("Emoji", () => ({ - id: matches[0][1], - isAnimated: (matches[0][2] === "gif"), - name: "ProfileEmoji" - }))); - } + // 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" + }))); }; interface HangStatus { emoji?: { From b4e4085382870bf062fe3f306b7b5b54ceb36cb1 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:18:26 -0400 Subject: [PATCH 08/11] fix patch modifying the user object --- src/plugins/emoteCloner/index.tsx | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 130dd537f..539d34f7c 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -383,13 +383,11 @@ interface HangStatus { } } const vcHangStatusContextPatch: NavContextMenuPatchCallback =(children, props: { - user: { - HangStatus?: HangStatus - } + hangStatusActivity?: HangStatus }) => { - if(props.user.HangStatus?.emoji?.id){ - const e = props.user.HangStatus.emoji as Emoji; - e.isAnimated = props.user.HangStatus.emoji.animated ?? false; + if(props.hangStatusActivity?.emoji?.id){ + const e = props.hangStatusActivity.emoji as Emoji; + e.isAnimated = props.hangStatusActivity.emoji.animated ?? false; children.push(buildMenuItem("Emoji", () => { return e; })); @@ -409,12 +407,11 @@ export default definePlugin({ patches: [ // needed to pass the HangStatus to the context menu { - find: "renderPrioritySpeaker", + find: "canWatchStream", replacement: { - match: /(handleContextMenu".*?)(let)/, - replace: "$1this.props.user.HangStatus=this.props.hangStatusActivity;$2" - + match: /Menu".*?\.\.\.\i,/, + replace: "$&hangStatusActivity:this.props.hangStatusActivity," } - }, + } ], }); From f8bf23db1f26c219ed9781b69d9bc3d035720a75 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Mon, 2 Sep 2024 01:16:32 -0400 Subject: [PATCH 09/11] fix contsatns --- src/utils/constants.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 209935d29..73aa3e2b0 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -538,10 +538,6 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "Joona", id: 297410829589020673n }, - sadan: { - name: "sadan", - id: 521819891141967883n, - }, Kylie: { name: "Cookie", id: 721853658941227088n From 7d70d530831da1eca176808c38ddb22037b0b9f0 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:42:52 -0400 Subject: [PATCH 10/11] remove hang status and add channel statuses --- src/plugins/emoteCloner/index.tsx | 72 ++++++++++++++++--------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 539d34f7c..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(); @@ -362,37 +367,46 @@ 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 + 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; + if (matches.length === 0) return; children.push(buildMenuItem("Emoji", () => ({ id: matches[1], isAnimated: (matches[2] === "gif"), name: "ProfileEmoji" }))); }; -interface HangStatus { - emoji?: { - // used for unicode emojis and custom emojis - name: string - // used for custom emojis - id?: string, - animated?: boolean - } -} -const vcHangStatusContextPatch: NavContextMenuPatchCallback =(children, props: { - hangStatusActivity?: HangStatus + +const emojiMatchRegex = /<(a?):(\w+):(\d{19})>/g; +const channelContextStatusPatch: NavContextMenuPatchCallback = (children, props: { + channel: Channel; }) => { - if(props.hangStatusActivity?.emoji?.id){ - const e = props.hangStatusActivity.emoji as Emoji; - e.isAnimated = props.hangStatusActivity.emoji.animated ?? false; - children.push(buildMenuItem("Emoji", () => { - return e; - })); - } + 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)", @@ -401,17 +415,7 @@ export default definePlugin({ contextMenus: { "message": messageContextMenuPatch, "expression-picker": expressionPickerPatch, - "user-context": vcHangStatusContextPatch, "image-context": imageContextPatch, + "channel-context": channelContextStatusPatch }, - patches: [ - // needed to pass the HangStatus to the context menu - { - find: "canWatchStream", - replacement: { - match: /Menu".*?\.\.\.\i,/, - replace: "$&hangStatusActivity:this.props.hangStatusActivity," - } - } - ], }); From 74b03c0962d67fe0b705b293f7c2976f44dde125 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:43:14 -0400 Subject: [PATCH 11/11] Discard changes to src/utils/constants.ts --- src/utils/constants.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index f8989e153..b0ad77fb1 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -530,14 +530,14 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "Antti", id: 312974985876471810n }, - sadan: { - name: "sadan", - id: 521819891141967883n, - }, Joona: { name: "Joona", id: 297410829589020673n }, + sadan: { + name: "sadan", + id: 521819891141967883n, + }, Kylie: { name: "Cookie", id: 721853658941227088n