Also add Emote Cloner to Emote picker rightclick menu (#664)

This commit is contained in:
Ven 2023-03-24 03:42:38 +01:00 committed by GitHub
parent 082ac62eda
commit 8d8cedd72c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 51 deletions

View file

@ -122,6 +122,8 @@ export function _patchContextMenu(props: ContextMenuProps) {
props.contextMenuApiArguments ??= []; props.contextMenuApiArguments ??= [];
const contextMenuPatches = navPatches.get(props.navId); const contextMenuPatches = navPatches.get(props.navId);
if (!Array.isArray(props.children)) props.children = [props.children];
if (contextMenuPatches) { if (contextMenuPatches) {
for (const patch of contextMenuPatches) { for (const patch of contextMenuPatches) {
try { try {

View file

@ -17,7 +17,6 @@
*/ */
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu"; import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
import { migratePluginSettings } from "@api/settings";
import { CheckedTextInput } from "@components/CheckedTextInput"; import { CheckedTextInput } from "@components/CheckedTextInput";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import Logger from "@utils/Logger"; import Logger from "@utils/Logger";
@ -176,25 +175,12 @@ function CloneModal({ id, name: emojiName, isAnimated }: { id: string; name: str
); );
} }
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => { function buildMenuItem(id: string, name: string, isAnimated: boolean) {
if (!props) return; return (
const { favoriteableId, emoteClonerDataAlt, itemHref, itemSrc, favoriteableType } = props;
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("copy-link", children);
if (group && !group.some(child => child?.props?.id === "emote-cloner")) {
group.push((
<Menu.MenuItem <Menu.MenuItem
id="emote-cloner" id="emote-cloner"
key="emote-cloner" key="emote-cloner"
label="Clone" label="Clone Emote"
action={() => action={() =>
openModal(modalProps => ( openModal(modalProps => (
<ModalRoot {...modalProps}> <ModalRoot {...modalProps}>
@ -202,7 +188,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
<img <img
role="presentation" role="presentation"
aria-hidden aria-hidden
src={`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/emojis/${favoriteableId}.${isAnimated ? "gif" : "png"}`} src={`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/emojis/${id}.${isAnimated ? "gif" : "png"}`}
alt="" alt=""
height={24} height={24}
width={24} width={24}
@ -211,39 +197,56 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
<Forms.FormText>Clone {name}</Forms.FormText> <Forms.FormText>Clone {name}</Forms.FormText>
</ModalHeader> </ModalHeader>
<ModalContent> <ModalContent>
<CloneModal id={favoriteableId} name={name} isAnimated={isAnimated} /> <CloneModal id={id} name={name} isAnimated={isAnimated} />
</ModalContent> </ModalContent>
</ModalRoot> </ModalRoot>
)) ))
} }
> />
</Menu.MenuItem> );
));
} }
function isGifUrl(url: string) {
return new URL(url).pathname.endsWith(".gif");
}
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
const { favoriteableId, itemHref, itemSrc, favoriteableType } = props ?? {};
if (!favoriteableId || favoriteableType !== "emoji") return;
const match = props.message.content.match(RegExp(`<a?:(\\w+)(?:~\\d+)?:${favoriteableId}>|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(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({ export default definePlugin({
name: "EmoteCloner", name: "EmoteCloner",
description: "Adds a Clone context menu item to emotes to clone them your own server", description: "Adds a Clone context menu item to emotes to clone them your own server",
authors: [Devs.Ven, Devs.Nuckyz], authors: [Devs.Ven, Devs.Nuckyz],
dependencies: ["MenuItemDeobfuscatorAPI", "ContextMenuAPI"], 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() { start() {
addContextMenuPatch("message", messageContextMenuPatch); addContextMenuPatch("message", messageContextMenuPatch);
addContextMenuPatch("expression-picker", expressionPickerPatch);
}, },
stop() { stop() {
removeContextMenuPatch("message", messageContextMenuPatch); removeContextMenuPatch("message", messageContextMenuPatch);
removeContextMenuPatch("expression-picker", expressionPickerPatch);
} }
}); });