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

@ -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 {

@ -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,74 +175,78 @@ function CloneModal({ id, name: emojiName, isAnimated }: { id: string; name: str
); );
} }
function buildMenuItem(id: string, name: string, isAnimated: boolean) {
return (
<Menu.MenuItem
id="emote-cloner"
key="emote-cloner"
label="Clone Emote"
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>
))
}
/>
);
}
function isGifUrl(url: string) {
return new URL(url).pathname.endsWith(".gif");
}
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => { const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
if (!props) return; const { favoriteableId, itemHref, itemSrc, favoriteableType } = props ?? {};
const { favoriteableId, emoteClonerDataAlt, itemHref, itemSrc, favoriteableType } = props;
if (!emoteClonerDataAlt || favoriteableType !== "emoji") return; if (!favoriteableId || favoriteableType !== "emoji") return;
const name = emoteClonerDataAlt.match(/:(.*)(?:~\d+)?:/)?.[1]; const match = props.message.content.match(RegExp(`<a?:(\\w+)(?:~\\d+)?:${favoriteableId}>|https://cdn\\.discordapp\\.com/emojis/${favoriteableId}\\.`));
if (!name || !favoriteableId) return; if (!match) return;
const name = match[1] ?? "FakeNitroEmoji";
const src = itemHref ?? itemSrc;
const isAnimated = new URL(src).pathname.endsWith(".gif");
const group = findGroupChildrenByChildId("copy-link", children); const group = findGroupChildrenByChildId("copy-link", children);
if (group && !group.some(child => child?.props?.id === "emote-cloner")) { if (group && !group.some(child => child?.props?.id === "emote-cloner"))
group.push(( group.push(buildMenuItem(favoriteableId, name, isGifUrl(itemHref ?? itemSrc)));
<Menu.MenuItem };
id="emote-cloner"
key="emote-cloner" const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
label="Clone" const { id, name, type } = props?.target?.dataset ?? {};
action={() => if (!id || !name || type !== "emoji") return;
openModal(modalProps => (
<ModalRoot {...modalProps}> const firstChild = props.target.firstChild as HTMLImageElement;
<ModalHeader>
<img if (!children.some(c => c?.props?.id === "emote-cloner"))
role="presentation" children.push(buildMenuItem(id, name, firstChild && isGifUrl(firstChild.src)));
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({ 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);
} }
}); });