Make Fake Nitro transformations support the new markdown (#911)

This commit is contained in:
Nuckyz 2023-05-23 00:25:48 -03:00 committed by GitHub
parent d888a0a291
commit 458c7ed4c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 32 deletions

@ -19,8 +19,7 @@
import { Dirent, readdirSync, readFileSync, writeFileSync } from "fs"; import { Dirent, readdirSync, readFileSync, writeFileSync } from "fs";
import { access, readFile } from "fs/promises"; import { access, readFile } from "fs/promises";
import { join } from "path"; import { join } from "path";
import { isSatisfiesExpression } from "typescript"; import { BigIntLiteral, createSourceFile, Identifier, isArrayLiteralExpression, isCallExpression, isExportAssignment, isIdentifier, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isStringLiteral, isVariableStatement, NamedDeclaration, NodeArray, ObjectLiteralExpression, ScriptTarget, StringLiteral, SyntaxKind } from "typescript";
import { BigIntLiteral, createSourceFile, Identifier, isArrayLiteralExpression, isCallExpression, isExportAssignment, isIdentifier, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isStringLiteral, isVariableStatement, NamedDeclaration, NodeArray, ObjectLiteralExpression, ScriptTarget, StringLiteral, SyntaxKind } from "typescript";
interface Dev { interface Dev {
name: string; name: string;
@ -131,7 +130,9 @@ async function parseFile(fileName: string) {
if (!isArrayLiteralExpression(value)) throw fail("authors is not an array literal"); if (!isArrayLiteralExpression(value)) throw fail("authors is not an array literal");
data.authors = value.elements.map(e => { data.authors = value.elements.map(e => {
if (!isPropertyAccessExpression(e)) throw fail("authors array contains non-property access expressions"); if (!isPropertyAccessExpression(e)) throw fail("authors array contains non-property access expressions");
return devs[getName(e)!]; const d = devs[getName(e)!];
if (!d) throw fail(`couldn't look up author ${getName(e)}`);
return d;
}); });
break; break;
case "tags": case "tags":

@ -22,11 +22,12 @@ import { Devs } from "@utils/constants";
import { ApngBlendOp, ApngDisposeOp, getGifEncoder, importApngJs } from "@utils/dependencies"; import { ApngBlendOp, ApngDisposeOp, getGifEncoder, importApngJs } from "@utils/dependencies";
import { getCurrentGuild } from "@utils/discord"; import { getCurrentGuild } from "@utils/discord";
import { proxyLazy } from "@utils/lazy"; import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findByPropsLazy, findLazy, findStoreLazy } from "@webpack"; import { findByCodeLazy, findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
import { ChannelStore, EmojiStore, FluxDispatcher, Parser, PermissionStore, UserStore } from "@webpack/common"; import { ChannelStore, EmojiStore, FluxDispatcher, Parser, PermissionStore, UserStore } from "@webpack/common";
import type { Message } from "discord-types/general"; import type { Message } from "discord-types/general";
import type { ReactNode } from "react"; import type { ReactElement, ReactNode } from "react";
const DRAFT_TYPE = 0; const DRAFT_TYPE = 0;
const promptToUpload = findByCodeLazy("UPLOAD_FILE_LIMIT_ERROR"); const promptToUpload = findByCodeLazy("UPLOAD_FILE_LIMIT_ERROR");
@ -392,70 +393,137 @@ export default definePlugin({
}); });
}, },
patchFakeNitroEmojisOrRemoveStickersLinks(content: Array<any>, inline: boolean) { trimContent(content: Array<any>) {
if (content.length > 1 && !settings.store.transformCompoundSentence) return content; const firstContent = content[0];
if (typeof firstContent === "string") content[0] = firstContent.trimStart();
if (content[0] === "") content.shift();
const newContent: Array<any> = []; const lastIndex = content.length - 1;
const lastContent = content[lastIndex];
if (typeof lastContent === "string") content[lastIndex] = lastContent.trimEnd();
if (content[lastIndex] === "") content.pop();
},
clearEmptyArrayItems(array: Array<any>) {
return array.filter(item => item != null);
},
ensureChildrenIsArray(child: ReactElement) {
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 or list
if ((content.length > 1 || typeof content[0]?.type === "string") && !settings.store.transformCompoundSentence) return content;
let nextIndex = content.length; let nextIndex = content.length;
for (const element of content) { const transformLinkChild = (child: ReactElement) => {
if (element.props?.trusted == null) {
newContent.push(element);
continue;
}
if (settings.store.transformEmojis) { if (settings.store.transformEmojis) {
const fakeNitroMatch = element.props.href.match(fakeNitroEmojiRegex); const fakeNitroMatch = child.props.href.match(fakeNitroEmojiRegex);
if (fakeNitroMatch) { if (fakeNitroMatch) {
let url: URL | null = null; let url: URL | null = null;
try { try {
url = new URL(element.props.href); url = new URL(child.props.href);
} catch { } } catch { }
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({ return Parser.defaultRules.customEmoji.react({
jumboable: !inline && content.length === 1, jumboable: !inline && content.length === 1 && typeof content[0].type !== "string",
animated: fakeNitroMatch[2] === "gif", animated: fakeNitroMatch[2] === "gif",
emojiId: fakeNitroMatch[1], emojiId: fakeNitroMatch[1],
name: emojiName, name: emojiName,
fake: true fake: true
}, void 0, { key: String(nextIndex++) })); }, void 0, { key: String(nextIndex++) });
continue;
} }
} }
if (settings.store.transformStickers) { if (settings.store.transformStickers) {
if (fakeNitroStickerRegex.test(element.props.href)) continue; if (fakeNitroStickerRegex.test(child.props.href)) return null;
const gifMatch = element.props.href.match(fakeNitroGifStickerRegex); const gifMatch = child.props.href.match(fakeNitroGifStickerRegex);
if (gifMatch) { if (gifMatch) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker // There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(gifMatch[1])) continue; if (StickerStore.getStickerById(gifMatch[1])) return null;
} }
} }
newContent.push(element); return child;
};
const transformChild = (child: ReactElement) => {
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) => {
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>) => {
for (const [index, child] of children.entries()) children[index] = modifyChild(child);
children = this.clearEmptyArrayItems(children);
this.trimContent(children);
return children;
};
try {
return modifyChildren(window._.cloneDeep(content));
} catch (err) {
new Logger("FakeNitro").error(err);
return content;
} }
const firstContent = newContent[0];
if (typeof firstContent === "string") newContent[0] = firstContent.trimStart();
return newContent;
}, },
patchFakeNitroStickers(stickers: Array<any>, message: Message) { patchFakeNitroStickers(stickers: Array<any>, message: Message) {
const itemsToMaybePush: Array<string> = []; const itemsToMaybePush: Array<string> = [];
const contentItems = message.content.split(/\s/); const contentItems = message.content.split(/\s/);
if (contentItems.length === 1 && !settings.store.transformCompoundSentence) itemsToMaybePush.push(contentItems[0]); if (settings.store.transformCompoundSentence) itemsToMaybePush.push(...contentItems);
else itemsToMaybePush.push(...contentItems); else if (contentItems.length === 1) itemsToMaybePush.push(contentItems[0]);
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));
for (const item of itemsToMaybePush) { for (const item of itemsToMaybePush) {
if (!settings.store.transformCompoundSentence && !item.startsWith("http")) continue;
const imgMatch = item.match(fakeNitroStickerRegex); const imgMatch = item.match(fakeNitroStickerRegex);
if (imgMatch) { if (imgMatch) {
let url: URL | null = null; let url: URL | null = null;
@ -492,10 +560,13 @@ export default definePlugin({
}, },
shouldIgnoreEmbed(embed: Message["embeds"][number], message: Message) { shouldIgnoreEmbed(embed: Message["embeds"][number], message: Message) {
if (message.content.split(/\s/).length > 1 && !settings.store.transformCompoundSentence) return false; const contentItems = message.content.split(/\s/);
if (contentItems.length > 1 && !settings.store.transformCompoundSentence) return false;
switch (embed.type) { switch (embed.type) {
case "image": { case "image": {
if (!settings.store.transformCompoundSentence && !contentItems.includes(embed.url!) && !contentItems.includes(embed.image!.proxyURL)) return false;
if (settings.store.transformEmojis) { if (settings.store.transformEmojis) {
if (fakeNitroEmojiRegex.test(embed.url!)) return true; if (fakeNitroEmojiRegex.test(embed.url!)) return true;
} }