Option to transform emotes/stickers in compound messages (#876)

+ ContextMenu refactor to not call callbacks for same children multiple times

Co-authored-by: V <vendicated@riseup.net>
This commit is contained in:
Nuckyz 2023-04-12 23:22:38 -03:00 committed by GitHub
parent cfe41ef656
commit e34da54271
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 69 additions and 112 deletions

View file

@ -118,7 +118,12 @@ interface ContextMenuProps {
onClose: (callback: (...args: Array<any>) => any) => void; onClose: (callback: (...args: Array<any>) => any) => void;
} }
const patchedMenus = new WeakSet();
export function _patchContextMenu(props: ContextMenuProps) { export function _patchContextMenu(props: ContextMenuProps) {
if (patchedMenus.has(props)) return;
patchedMenus.add(props);
props.contextMenuApiArguments ??= []; props.contextMenuApiArguments ??= [];
const contextMenuPatches = navPatches.get(props.navId); const contextMenuPatches = navPatches.get(props.navId);

View file

@ -238,8 +238,6 @@ function initWs(isManual = false) {
} }
const contextMenuPatch: NavContextMenuPatchCallback = kids => { const contextMenuPatch: NavContextMenuPatchCallback = kids => {
if (kids.some(k => k?.props?.id === NAV_ID)) return;
kids.unshift( kids.unshift(
<Menu.MenuItem <Menu.MenuItem
id={NAV_ID} id={NAV_ID}

View file

@ -220,8 +220,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
const name = match[1] ?? "FakeNitroEmoji"; const name = match[1] ?? "FakeNitroEmoji";
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.push(buildMenuItem(favoriteableId, name, isGifUrl(itemHref ?? itemSrc)));
group.push(buildMenuItem(favoriteableId, name, isGifUrl(itemHref ?? itemSrc)));
}; };
const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => { const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
@ -230,8 +229,7 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t
const firstChild = props.target.firstChild as HTMLImageElement; 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)));
children.push(buildMenuItem(id, name, firstChild && isGifUrl(firstChild.src)));
}; };
export default definePlugin({ export default definePlugin({

View file

@ -136,6 +136,11 @@ const settings = definePluginSettings({
default: true, default: true,
restartNeeded: true restartNeeded: true
}, },
transformCompoundSentence: {
description: "Whether to transform fake stickers and emojis in compound sentences (sentences with more content than just the fake emoji or sticker link)",
type: OptionType.BOOLEAN,
default: false
},
enableStreamQualityBypass: { enableStreamQualityBypass: {
description: "Allow streaming in nitro quality", description: "Allow streaming in nitro quality",
type: OptionType.BOOLEAN, type: OptionType.BOOLEAN,
@ -305,45 +310,6 @@ export default definePlugin({
} }
], ],
options: {
enableEmojiBypass: {
description: "Allow sending fake emojis",
type: OptionType.BOOLEAN,
default: true,
restartNeeded: true,
},
emojiSize: {
description: "Size of the emojis when sending",
type: OptionType.SLIDER,
default: 48,
markers: [32, 48, 64, 128, 160, 256, 512],
},
transformEmojis: {
description: "Whether to transform fake emojis into real ones",
type: OptionType.BOOLEAN,
default: true,
restartNeeded: true,
},
enableStickerBypass: {
description: "Allow sending fake stickers",
type: OptionType.BOOLEAN,
default: true,
restartNeeded: true,
},
stickerSize: {
description: "Size of the stickers when sending",
type: OptionType.SLIDER,
default: 160,
markers: [32, 64, 128, 160, 256, 512],
},
enableStreamQualityBypass: {
description: "Allow streaming in nitro quality",
type: OptionType.BOOLEAN,
default: true,
restartNeeded: true,
}
},
get guildId() { get guildId() {
return getCurrentGuild()?.id; return getCurrentGuild()?.id;
}, },
@ -419,7 +385,7 @@ export default definePlugin({
}, },
patchFakeNitroEmojisOrRemoveStickersLinks(content: Array<any>, inline: boolean) { patchFakeNitroEmojisOrRemoveStickersLinks(content: Array<any>, inline: boolean) {
if (content.length > 1) return content; if (content.length > 1 && !settings.store.transformCompoundSentence) return content;
const newContent: Array<any> = []; const newContent: Array<any> = [];
@ -442,7 +408,7 @@ export default definePlugin({
const emojiName = EmojiStore.getCustomEmojiById(fakeNitroMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroEmoji"; const emojiName = EmojiStore.getCustomEmojiById(fakeNitroMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroEmoji";
newContent.push(Parser.defaultRules.customEmoji.react({ newContent.push(Parser.defaultRules.customEmoji.react({
jumboable: !inline, jumboable: !inline && content.length === 1,
animated: fakeNitroMatch[2] === "gif", animated: fakeNitroMatch[2] === "gif",
emojiId: fakeNitroMatch[1], emojiId: fakeNitroMatch[1],
name: emojiName, name: emojiName,
@ -466,8 +432,8 @@ export default definePlugin({
newContent.push(element); newContent.push(element);
} }
const firstTextElementIdx = newContent.findIndex(element => typeof element === "string"); const firstContent = newContent[0];
if (firstTextElementIdx !== -1) newContent[firstTextElementIdx] = newContent[firstTextElementIdx].trimStart(); if (typeof firstContent === "string") newContent[0] = firstContent.trimStart();
return newContent; return newContent;
}, },
@ -476,7 +442,8 @@ export default definePlugin({
const itemsToMaybePush: Array<string> = []; const itemsToMaybePush: Array<string> = [];
const contentItems = message.content.split(/\s/); const contentItems = message.content.split(/\s/);
if (contentItems.length === 1) itemsToMaybePush.push(contentItems[0]); if (contentItems.length === 1 && !settings.store.transformCompoundSentence) itemsToMaybePush.push(contentItems[0]);
else itemsToMaybePush.push(...contentItems);
itemsToMaybePush.push(...message.attachments.filter(attachment => attachment.content_type === "image/gif").map(attachment => attachment.url)); itemsToMaybePush.push(...message.attachments.filter(attachment => attachment.content_type === "image/gif").map(attachment => attachment.url));
@ -517,7 +484,7 @@ export default definePlugin({
}, },
shouldIgnoreEmbed(embed: Message["embeds"][number], message: Message) { shouldIgnoreEmbed(embed: Message["embeds"][number], message: Message) {
if (message.content.split(/\s/).length > 1) return false; if (message.content.split(/\s/).length > 1 && !settings.store.transformCompoundSentence) return false;
switch (embed.type) { switch (embed.type) {
case "image": { case "image": {

View file

@ -76,56 +76,54 @@ export const settings = definePluginSettings({
const imageContextMenuPatch: NavContextMenuPatchCallback = (children, _) => { const imageContextMenuPatch: NavContextMenuPatchCallback = (children, _) => {
if (!children.some(child => child?.props?.id === "image-zoom")) { children.push(
children.push( <Menu.MenuGroup id="image-zoom">
<Menu.MenuGroup id="image-zoom"> {/* thanks SpotifyControls */}
{/* thanks SpotifyControls */} <Menu.MenuControlItem
<Menu.MenuControlItem id="zoom"
id="zoom" label="Zoom"
label="Zoom" control={(props, ref) => (
control={(props, ref) => ( <Menu.MenuSliderControl
<Menu.MenuSliderControl ref={ref}
ref={ref} {...props}
{...props} minValue={1}
minValue={1} maxValue={50}
maxValue={50} value={settings.store.zoom}
value={settings.store.zoom} onChange={debounce((value: number) => settings.store.zoom = value, 100)}
onChange={debounce((value: number) => settings.store.zoom = value, 100)} />
/> )}
)} />
/> <Menu.MenuControlItem
<Menu.MenuControlItem id="size"
id="size" label="Lens Size"
label="Lens Size" control={(props, ref) => (
control={(props, ref) => ( <Menu.MenuSliderControl
<Menu.MenuSliderControl ref={ref}
ref={ref} {...props}
{...props} minValue={50}
minValue={50} maxValue={1000}
maxValue={1000} value={settings.store.size}
value={settings.store.size} onChange={debounce((value: number) => settings.store.size = value, 100)}
onChange={debounce((value: number) => settings.store.size = value, 100)} />
/> )}
)} />
/> <Menu.MenuControlItem
<Menu.MenuControlItem id="zoom-speed"
id="zoom-speed" label="Zoom Speed"
label="Zoom Speed" control={(props, ref) => (
control={(props, ref) => ( <Menu.MenuSliderControl
<Menu.MenuSliderControl ref={ref}
ref={ref} {...props}
{...props} minValue={0.1}
minValue={0.1} maxValue={5}
maxValue={5} value={settings.store.zoomSpeed}
value={settings.store.zoomSpeed} onChange={debounce((value: number) => settings.store.zoomSpeed = value, 100)}
onChange={debounce((value: number) => settings.store.zoomSpeed = value, 100)} renderValue={(value: number) => `${value.toFixed(3)}x`}
renderValue={(value: number) => `${value.toFixed(3)}x`} />
/> )}
)} />
/> </Menu.MenuGroup>
</Menu.MenuGroup> );
);
}
}; };
export default definePlugin({ export default definePlugin({

View file

@ -49,7 +49,6 @@ const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) =
const { deleted, editHistory, id, channel_id } = message; const { deleted, editHistory, id, channel_id } = message;
if (!deleted && !editHistory?.length) return; if (!deleted && !editHistory?.length) return;
if (children.some(c => c?.props?.id === MENU_ITEM_ID)) return;
children.push(( children.push((
<Menu.MenuItem <Menu.MenuItem

View file

@ -35,7 +35,7 @@ const bulkFetch = debounce(async () => {
const pronouns = await bulkFetchPronouns(ids); const pronouns = await bulkFetchPronouns(ids);
for (const id of ids) { for (const id of ids) {
// Call all callbacks for the id // Call all callbacks for the id
requestQueue[id].forEach(c => c(pronouns[id])); requestQueue[id]?.forEach(c => c(pronouns[id]));
delete requestQueue[id]; delete requestQueue[id];
} }
}); });

View file

@ -43,7 +43,7 @@ const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =>
const src = itemHref ?? itemSrc; const src = itemHref ?? itemSrc;
const group = findGroupChildrenByChildId("copy-link", children); const group = findGroupChildrenByChildId("copy-link", children);
if (group && !group.some(child => child?.props?.id === "search-image")) { if (group) {
group.push(( group.push((
<Menu.MenuItem <Menu.MenuItem
label="Search Image" label="Search Image"

View file

@ -80,12 +80,7 @@ function openImage(url: string) {
)); ));
} }
const seen = new WeakSet();
const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => { const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => {
if (seen.has(children)) return;
seen.add(children);
const memberAvatar = GuildMemberStore.getMember(guildId!, user.id)?.avatar || null; const memberAvatar = GuildMemberStore.getMember(guildId!, user.id)?.avatar || null;
children.splice(1, 0, ( children.splice(1, 0, (
@ -111,9 +106,6 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
}; };
const GuildContext: NavContextMenuPatchCallback = (children, { guild: { id, icon, banner } }: GuildContextProps) => { const GuildContext: NavContextMenuPatchCallback = (children, { guild: { id, icon, banner } }: GuildContextProps) => {
if (seen.has(children)) return;
seen.add(children);
if (!banner && !icon) return; if (!banner && !icon) return;
// before copy id (if it exists) // before copy id (if it exists)