diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index 953b714eb5..400232b6c5 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -73,6 +73,18 @@ const fakeNitroStickerRegex = /\/stickers\/(\d+?)\./; const fakeNitroGifStickerRegex = /\/attachments\/\d+?\/\d+?\/(\d+?)\.gif/; const hyperLinkRegex = /\[.+?\]\((https?:\/\/.+?)\)/; +interface EmojiAutocompleteState { + query?: { + type: string; + typeInfo?: { + sentinel?: string; + }; + results?: { + emojis: Emoji[] & { sliceTo?: number; }; + }; + }; +} + const settings = definePluginSettings({ enableEmojiBypass: { description: "Allows sending fake emojis (also bypasses missing permission to use custom emojis)", @@ -80,6 +92,12 @@ const settings = definePluginSettings({ default: true, restartNeeded: true }, + preferCurrentServerEmoji: { + description: "Prefer current server custom emojis in emoji autocomplete", + type: OptionType.BOOLEAN, + default: false, + restartNeeded: true + }, emojiSize: { description: "Size of the emojis when sending", type: OptionType.SLIDER, @@ -153,7 +171,7 @@ const hasAttachmentPerms = (channelId: string) => hasPermission(channelId, Permi export default definePlugin({ name: "FakeNitro", - authors: [Devs.Arjix, Devs.D3SOX, Devs.Ven, Devs.fawn, Devs.captain, Devs.Nuckyz, Devs.AutumnVN, Devs.sadan], + authors: [Devs.Arjix, Devs.D3SOX, Devs.Ven, Devs.fawn, Devs.captain, Devs.Nuckyz, Devs.AutumnVN, Devs.sadan, Devs.laz], description: "Allows you to send fake emojis/stickers, use nitro themes, and stream in nitro quality", tags: ["Emotes", "Appearance", "Customisation", "Chat"], dependencies: ["MessageEventsAPI"], @@ -198,6 +216,27 @@ export default definePlugin({ replace: ".STATUS" } }, + { + find: "renderResults({results:", + predicate: () => settings.store.preferCurrentServerEmoji, + replacement: { + // https://regex101.com/r/N7kpLM/1 + match: /let \i=.{1,100}renderResults\({results:(\i)\.query\.results,/, + replace: "$self.sortCurrentGuildEmojis($1);$&" + } + }, + { + find: "numEmojiResults:", + predicate: () => settings.store.preferCurrentServerEmoji, + replacement: { + // Adapted from FavoriteEmojiFirst: collect full emoji results, then re-apply slice after custom sorting. + // set maxCount to Infinity so we can sort the full emoji list first + // searchEmojis(...,maxCount: stuff) ... endEmojis = emojis.slice(0, maxCount - gifResults.length) + match: /,maxCount:(\i)(.{1,500}\i)=(\i)\.slice\(0,(Math\.max\(\i,\i(?:-\i\.length){2}\))\)/, + // ,maxCount:Infinity ... endEmojis = (emojis.sliceTo = n, emojis) + replace: ",maxCount:Infinity$2=($3.sliceTo = $4, $3)" + } + }, { find: ".GUILD_SUBSCRIPTION_UNAVAILABLE;", group: true, @@ -708,6 +747,30 @@ export default definePlugin({ } }, + sortCurrentGuildEmojis({ query }: EmojiAutocompleteState) { + if ( + query?.type !== "EMOJIS_AND_STICKERS" + || query.typeInfo?.sentinel !== ":" + || !query.results?.emojis?.length + ) return; + + const { guildId } = this; + const { emojis } = query.results; + if (guildId) { + emojis.sort((a, b) => { + const aIsCurrentGuildEmoji = a.type === 1 && a.guildId === guildId; + const bIsCurrentGuildEmoji = b.type === 1 && b.guildId === guildId; + + if (aIsCurrentGuildEmoji && !bIsCurrentGuildEmoji) return -1; + if (!aIsCurrentGuildEmoji && bIsCurrentGuildEmoji) return 1; + + return 0; + }); + } + + query.results.emojis = emojis.slice(0, emojis.sliceTo ?? Infinity); + }, + getStickerLink({ format_type, id }: Sticker) { const ext = format_type === StickerFormatType.GIF ? "gif" : "png"; return `https://media.discordapp.net/stickers/${id}.${ext}?size=${settings.store.stickerSize}`; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 61550c00a0..612d84b87f 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -638,6 +638,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "prism", id: 390884143749136386n, }, + laz: { + name: "laz", + id: 137670410677256192n, + }, } satisfies Record); // iife so #__PURE__ works correctly