fix FakeNitro & ImageLink (#4620)
Co-authored-by: Vendicated <vendicated@riseup.net>
This commit is contained in:
parent
6c7e9cd9a9
commit
de964b6282
2 changed files with 51 additions and 110 deletions
|
|
@ -26,7 +26,7 @@ import definePlugin, { OptionType } from "@utils/types";
|
|||
import type { Emoji, Message, RenderModalProps, Sticker } from "@vencord/discord-types";
|
||||
import { StickerFormatType } from "@vencord/discord-types/enums";
|
||||
import { findByCodeLazy, findByPropsLazy, proxyLazyWebpack } from "@webpack";
|
||||
import { ChannelStore, ConfirmModal, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, IconUtils, lodash, openModal, Parser, PermissionsBits, PermissionStore, StickersStore, UploadHandler, UserSettingsActionCreators, UserSettingsProtoStore, UserStore } from "@webpack/common";
|
||||
import { ChannelStore, ConfirmModal, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, IconUtils, openModal, PermissionsBits, PermissionStore, StickersStore, UploadHandler, UserSettingsActionCreators, UserSettingsProtoStore, UserStore } from "@webpack/common";
|
||||
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
||||
import type { ReactElement, ReactNode } from "react";
|
||||
|
||||
|
|
@ -40,6 +40,8 @@ function searchProtoClassField(localName: string, protoClass: any) {
|
|||
return fieldGetter?.();
|
||||
}
|
||||
|
||||
const logger = new Logger("FakeNitro");
|
||||
|
||||
const PreloadedUserSettingsActionCreators = proxyLazyWebpack(() => UserSettingsActionCreators.PreloadedUserSettingsActionCreators);
|
||||
const AppearanceSettingsActionCreators = proxyLazyWebpack(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
|
||||
const ClientThemeSettingsActionsCreators = proxyLazyWebpack(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
|
||||
|
|
@ -328,20 +330,11 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
find: '["strong","em","u","text","inlineCode","s","spoiler"]',
|
||||
replacement: [
|
||||
{
|
||||
// Call our function to decide whether the emoji link should be kept or not
|
||||
predicate: () => settings.store.transformEmojis,
|
||||
match: /1!==(\i)\.length\|\|1!==\i\.length/,
|
||||
replace: (m, content) => `${m}||$self.shouldKeepEmojiLink(${content}[0])`
|
||||
},
|
||||
{
|
||||
// Patch the rendered message content to add fake nitro emojis or remove sticker links
|
||||
predicate: () => settings.store.transformEmojis || settings.store.transformStickers,
|
||||
match: /(?=return{hasSpoilerEmbeds:\i,hasBailedAst:\i,content:(\i))/,
|
||||
replace: (_, content) => `${content}=$self.patchFakeNitroEmojisOrRemoveStickersLinks(${content},arguments[2]?.formatInline);`
|
||||
}
|
||||
]
|
||||
predicate: () => settings.store.transformEmojis || settings.store.transformStickers,
|
||||
replacement: {
|
||||
match: /\(\{ast:(\i)(?=,inline:\i)/,
|
||||
replace: "({ast:$self.transformAst($1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "}renderStickersAccessories(",
|
||||
|
|
@ -520,107 +513,58 @@ export default definePlugin({
|
|||
if (!Array.isArray(child.props.children)) child.props.children = [child.props.children];
|
||||
},
|
||||
|
||||
patchFakeNitroEmojisOrRemoveStickersLinks(content: Array<any>, inline: boolean) {
|
||||
// If content has more than one child or it's a single ReactElement like a header, list or span
|
||||
if ((content.length > 1 || typeof content[0]?.type === "string") && !settings.store.transformCompoundSentence) return content;
|
||||
transformAst(ast: any[]) {
|
||||
try {
|
||||
if (!settings.store.transformCompoundSentence && ast.length > 1) {
|
||||
return ast;
|
||||
}
|
||||
// Filter out sticker links. These are transformed into actual stickers later, so we don't want duplicate links
|
||||
if (settings.store.transformStickers) {
|
||||
ast = ast.filter(node => {
|
||||
const { type, target } = node;
|
||||
|
||||
let nextIndex = content.length;
|
||||
if (type !== "link") return true;
|
||||
if (fakeNitroStickerRegex.test(target)) return false;
|
||||
|
||||
const gifStickerLinkMatch = target.match(fakeNitroGifStickerRegex);
|
||||
const isGifStickerLink = gifStickerLinkMatch && StickersStore.getStickerById(gifStickerLinkMatch[1]);
|
||||
|
||||
return !isGifStickerLink;
|
||||
});
|
||||
}
|
||||
|
||||
const transformLinkChild = (child: ReactElement<any>) => {
|
||||
if (settings.store.transformEmojis) {
|
||||
const fakeNitroMatch = child.props.href.match(fakeNitroEmojiRegex);
|
||||
if (fakeNitroMatch) {
|
||||
ast = ast.map(node => {
|
||||
const { type, target } = node;
|
||||
|
||||
if (type !== "link") return node;
|
||||
|
||||
const fakeNitroMatch = target.match(fakeNitroEmojiRegex);
|
||||
if (!fakeNitroMatch) return node;
|
||||
|
||||
let url: URL | null = null;
|
||||
try {
|
||||
url = new URL(child.props.href);
|
||||
url = new URL(target);
|
||||
} catch { }
|
||||
|
||||
const emojiName = EmojiStore.getCustomEmojiById(fakeNitroMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroEmoji";
|
||||
const isAnimated = fakeNitroMatch[2] === "gif" || url?.searchParams.get("animated") === "true";
|
||||
const emojiId = fakeNitroMatch[1];
|
||||
const emojiName = EmojiStore.getCustomEmojiById(emojiId)?.name ?? url?.searchParams.get("name") ?? "FakeNitroEmoji";
|
||||
const animated = fakeNitroMatch[2] === "gif" || url?.searchParams.get("animated") === "true";
|
||||
|
||||
return Parser.defaultRules.customEmoji.react({
|
||||
jumboable: !inline && content.length === 1 && typeof content[0].type !== "string",
|
||||
animated: isAnimated,
|
||||
emojiId: fakeNitroMatch[1],
|
||||
name: emojiName,
|
||||
return {
|
||||
animated,
|
||||
emojiId,
|
||||
name: `:${emojiName}:`,
|
||||
type: "customEmoji",
|
||||
fake: true
|
||||
}, void 0, { key: String(nextIndex++) });
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.store.transformStickers) {
|
||||
if (fakeNitroStickerRegex.test(child.props.href)) return null;
|
||||
|
||||
const gifMatch = child.props.href.match(fakeNitroGifStickerRegex);
|
||||
if (gifMatch) {
|
||||
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
|
||||
if (StickersStore.getStickerById(gifMatch[1])) return null;
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
};
|
||||
|
||||
const transformChild = (child: ReactElement<any>) => {
|
||||
if (child?.props?.trusted != null) return transformLinkChild(child);
|
||||
if (child?.props?.children != null) {
|
||||
if (!Array.isArray(child.props.children)) {
|
||||
child.props.children = modifyChild(child.props.children);
|
||||
return child;
|
||||
}
|
||||
|
||||
child.props.children = modifyChildren(child.props.children);
|
||||
if (child.props.children.length === 0) return null;
|
||||
return child;
|
||||
}
|
||||
|
||||
return child;
|
||||
};
|
||||
|
||||
const modifyChild = (child: ReactElement<any>) => {
|
||||
const newChild = transformChild(child);
|
||||
|
||||
if (newChild?.type === "ul" || newChild?.type === "ol") {
|
||||
this.ensureChildrenIsArray(newChild);
|
||||
if (newChild.props.children.length === 0) return null;
|
||||
|
||||
let listHasAnItem = false;
|
||||
for (const [index, child] of newChild.props.children.entries()) {
|
||||
if (child == null) {
|
||||
delete newChild.props.children[index];
|
||||
continue;
|
||||
}
|
||||
|
||||
this.ensureChildrenIsArray(child);
|
||||
if (child.props.children.length > 0) listHasAnItem = true;
|
||||
else delete newChild.props.children[index];
|
||||
}
|
||||
|
||||
if (!listHasAnItem) return null;
|
||||
|
||||
newChild.props.children = this.clearEmptyArrayItems(newChild.props.children);
|
||||
}
|
||||
|
||||
return newChild;
|
||||
};
|
||||
|
||||
const modifyChildren = (children: Array<ReactElement<any>>) => {
|
||||
for (const [index, child] of children.entries()) children[index] = modifyChild(child);
|
||||
|
||||
children = this.clearEmptyArrayItems(children);
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
try {
|
||||
const newContent = modifyChildren(lodash.cloneDeep(content));
|
||||
this.trimContent(newContent);
|
||||
|
||||
return newContent;
|
||||
} catch (err) {
|
||||
new Logger("FakeNitro").error(err);
|
||||
return content;
|
||||
} catch (e) {
|
||||
logger.error("Error transforming AST:", e);
|
||||
}
|
||||
|
||||
return ast;
|
||||
},
|
||||
|
||||
patchFakeNitroStickers(stickers: Array<any>, message: Message) {
|
||||
|
|
@ -722,10 +666,6 @@ export default definePlugin({
|
|||
});
|
||||
},
|
||||
|
||||
shouldKeepEmojiLink(link: any) {
|
||||
return link.target && fakeNitroEmojiRegex.test(link.target);
|
||||
},
|
||||
|
||||
addFakeNotice(type: FakeNoticeType, node: Array<ReactNode>, fake: boolean) {
|
||||
if (!fake) return node;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: "unknownUserMentionPlaceholder:",
|
||||
// small util file
|
||||
find: "={linkCount:0,onlyLinks:!1};function ",
|
||||
replacement: {
|
||||
// SimpleEmbedTypes.has(embed.type) && isEmbedInline(embed)
|
||||
match: /\i\.has\(\i\.type\)&&\(0,\i\.\i\)\(\i\)/,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue