diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index a30f41ce..8745584e 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -27,7 +27,7 @@ import { openContributorModal } from "@components/PluginSettings/ContributorModa import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import { Margins } from "@utils/margins"; -import { isPluginDev } from "@utils/misc"; +import { shouldShowContributorBadge } from "@utils/misc"; import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; import definePlugin from "@utils/types"; import { Forms, Toasts, UserStore } from "@webpack/common"; @@ -39,7 +39,7 @@ const ContributorBadge: ProfileBadge = { description: "Vencord Contributor", image: CONTRIBUTOR_BADGE, position: BadgePosition.START, - shouldShow: ({ userId }) => isPluginDev(userId), + shouldShow: ({ userId }) => shouldShowContributorBadge(userId), onClick: (_, { userId }) => openContributorModal(UserStore.getUser(userId)) }; diff --git a/src/plugins/anonymiseFileNames/index.tsx b/src/plugins/anonymiseFileNames/index.tsx index 34b5a5fa..d24de222 100644 --- a/src/plugins/anonymiseFileNames/index.tsx +++ b/src/plugins/anonymiseFileNames/index.tsx @@ -72,18 +72,17 @@ export default definePlugin({ patches: [ { - find: 'type:"UPLOAD_START"', - replacement: { - match: /await \i\.uploadFiles\((\i),/, - replace: "$1.forEach($self.anonymise),$&" - }, - }, - { - find: 'addFilesTo:"message.attachments"', - replacement: { - match: /\i.uploadFiles\((\i),/, - replace: "$1.forEach($self.anonymise),$&" - } + find: "async uploadFiles(", + replacement: [ + { + match: /async uploadFiles\((\i),\i\){/, + replace: "$&$1.forEach($self.anonymise);" + }, + { + match: /async uploadFilesSimple\((\i)\){/, + replace: "$&$1.forEach($self.anonymise);" + } + ], }, { find: "#{intl::ATTACHMENT_UTILITIES_SPOILER}", diff --git a/src/plugins/moreCommands/index.ts b/src/plugins/moreCommands/index.ts deleted file mode 100644 index 02f3c373..00000000 --- a/src/plugins/moreCommands/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated, Samu and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { ApplicationCommandInputType, findOption, OptionalMessageOption, RequiredMessageOption, sendBotMessage } from "@api/Commands"; -import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; - - -function mock(input: string): string { - let output = ""; - for (let i = 0; i < input.length; i++) { - output += i % 2 ? input[i].toUpperCase() : input[i].toLowerCase(); - } - return output; -} - -export default definePlugin({ - name: "MoreCommands", - description: "echo, lenny, mock", - authors: [Devs.Arjix, Devs.echo, Devs.Samu], - commands: [ - { - name: "echo", - description: "Sends a message as Clyde (locally)", - options: [OptionalMessageOption], - inputType: ApplicationCommandInputType.BOT, - execute: (opts, ctx) => { - const content = findOption(opts, "message", ""); - - sendBotMessage(ctx.channel.id, { content }); - }, - }, - { - name: "lenny", - description: "Sends a lenny face", - options: [OptionalMessageOption], - execute: opts => ({ - content: findOption(opts, "message", "") + " ( ͡° ͜ʖ ͡°)" - }), - }, - { - name: "mock", - description: "mOcK PeOpLe", - options: [RequiredMessageOption], - execute: opts => ({ - content: mock(findOption(opts, "message", "")) - }), - }, - ] -}); diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index e46824b4..1058410f 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -121,14 +121,9 @@ export default definePlugin({ }, // Make the gap between each item smaller so our tab can fit. { - match: /className:\i\.tabBar/, - replace: '$& + " vc-mutual-gdms-modal-v2-tab-bar"' + match: /type:"top",/, + replace: '$&className:"vc-mutual-gdms-modal-v2-tab-bar",' }, - // Make the tab bar item text smaller so our tab can fit. - { - match: /(\.tabBarItem.+?variant:)"heading-md\/normal"/, - replace: '$1"heading-sm/normal"' - } ] }, { diff --git a/src/plugins/mutualGroupDMs/style.css b/src/plugins/mutualGroupDMs/style.css index f0ad3c60..b6d992ad 100644 --- a/src/plugins/mutualGroupDMs/style.css +++ b/src/plugins/mutualGroupDMs/style.css @@ -3,5 +3,5 @@ } .vc-mutual-gdms-modal-v2-tab-bar { - gap: 12px; + --space-xl: 16px; } diff --git a/src/plugins/other-usrbg/index.tsx b/src/plugins/other-usrbg/index.tsx new file mode 100644 index 00000000..d77e8780 --- /dev/null +++ b/src/plugins/other-usrbg/index.tsx @@ -0,0 +1,120 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { definePluginSettings } from "@api/Settings"; +import { Link } from "@components/Link"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; + +const API_URL = "https://usrbg.dorkbutt.lol/users/users.json"; + +interface UsrbgApiReturn { + endpoint: string; + bucket: string; + prefix: string; + users: Record; +} + +const settings = definePluginSettings({ + nitroFirst: { + description: "Banner to use if both Nitro and USRBG banners are present", + type: OptionType.SELECT, + options: [ + { label: "Nitro banner", value: true, default: true }, + { label: "USRBG banner", value: false }, + ] + }, + voiceBackground: { + description: "Use USRBG banners as voice chat backgrounds", + type: OptionType.BOOLEAN, + default: true, + restartNeeded: true + } +}); + +export default definePlugin({ + name: "FORKED - USRBG", + description: "Displays user banners from dorkbutt's USRBG server, allowing anyone to get a banner without Nitro", + authors: [Devs.dorkbutt, Devs.AutumnVN, Devs.katlyn, Devs.pylix, Devs.TheKodeToad], + settings, + patches: [ + { + find: '.banner)==null?"COMPLETE"', + replacement: { + match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/, + replace: "$self.patchBannerUrl(arguments[0])||$&" + + } + }, + { + find: "\"data-selenium-video-tile\":", + predicate: () => settings.store.voiceBackground, + replacement: [ + { + match: /(?<=function\((\i),\i\)\{)(?=let.{20,40},style:)/, + replace: "$1.style=$self.getVoiceBackgroundStyles($1);" + } + ] + } + ], + + data: null as UsrbgApiReturn | null, + + settingsAboutComponent: () => { + return ( + "Message @dorkbutt about getting your personal banner added!" + ); + }, + + getVoiceBackgroundStyles({ className, participantUserId }: any) { + if (className.includes("tile_")) { + if (this.userHasBackground(participantUserId)) { + return { + backgroundImage: `url(${this.getImageUrl(participantUserId)})`, + backgroundSize: "cover", + backgroundPosition: "center", + backgroundRepeat: "no-repeat" + }; + } + } + }, + + patchBannerUrl({ displayProfile }: any) { + if (displayProfile?.banner && settings.store.nitroFirst) return; + if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId); + }, + + userHasBackground(userId: string) { + return !!this.data?.users[userId]; + }, + + getImageUrl(userId: string): string | null { + if (!this.userHasBackground(userId)) return null; + + // We can assert that data exists because userHasBackground returned true + const { endpoint, bucket, prefix, users: { [userId]: etag } } = this.data!; + return `${endpoint}/${bucket}/${prefix}${userId}?${etag}`; + }, + + async start() { + const res = await fetch(API_URL); + if (res.ok) { + this.data = await res.json(); + } + } +}); diff --git a/src/plugins/other-usrbg/users.json b/src/plugins/other-usrbg/users.json new file mode 100644 index 00000000..9ac83479 --- /dev/null +++ b/src/plugins/other-usrbg/users.json @@ -0,0 +1,6 @@ +{"endpoint":"https://usrbg.dorkbutt.lol","bucket":"usrbg","prefix":"v2/", + "users":{ + "862105885660676146":"db1d", + "578012873813524530":"315c" + } +} diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index cd1b19ba..149d422b 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -267,7 +267,7 @@ export default definePlugin({ { find: '"MessageManager"', replacement: { - match: /"Skipping fetch because channelId is a static route"\);return}(?=.+?getChannel\((\i)\))/, + match: /forceFetch:\i,isPreload:.+?}=\i;(?=.+?getChannel\((\i)\))/, replace: (m, channelId) => `${m}if($self.isHiddenChannel({channelId:${channelId}}))return;` } }, @@ -494,10 +494,11 @@ export default definePlugin({ isHiddenChannel(channel: Channel & { channelId?: string; }, checkConnect = false) { try { - if (!channel) return false; + if (channel == null || Object.hasOwn(channel, "channelId") && channel.channelId == null) return false; - if (channel.channelId) channel = ChannelStore.getChannel(channel.channelId); - if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false; + if (channel.channelId != null) channel = ChannelStore.getChannel(channel.channelId); + if (channel == null || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false; + if (["browse", "customize", "guide"].includes(channel.id)) return false; return !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || checkConnect && !PermissionStore.can(PermissionsBits.CONNECT, channel); } catch (e) { diff --git a/src/plugins/webContextMenus.web/index.ts b/src/plugins/webContextMenus.web/index.ts index 45e6fa00..666e51be 100644 --- a/src/plugins/webContextMenus.web/index.ts +++ b/src/plugins/webContextMenus.web/index.ts @@ -122,10 +122,16 @@ export default definePlugin({ { find: "Copy image not supported", - replacement: { - match: /(?<=(?:canSaveImage|canCopyImage)\(\i?\)\{.{0,50})!\i\.isPlatformEmbedded/g, - replace: "false" - } + replacement: [ + { + match: /(?<=(?:canSaveImage|canCopyImage)\(.{0,120}?)!\i\.isPlatformEmbedded/g, + replace: "false" + }, + { + match: /canCopyImage\(.+?(?=return"function"==typeof \i\.clipboard\.copyImage)/, + replace: "$&return true;" + } + ] }, // Add back Copy & Save Image { @@ -137,7 +143,7 @@ export default definePlugin({ replace: "false" }, { - match: /return\s*?\[.{0,50}?(?=\?.{0,100}?id:"copy-image")/, + match: /return\s*?\[.{0,50}?(?=\?\(0,\i\.jsxs?.{0,100}?id:"copy-image")/, replace: "return [true" }, { diff --git a/src/plugins/whoReacted/index.tsx b/src/plugins/whoReacted/index.tsx index aea57fef..f14de9f5 100644 --- a/src/plugins/whoReacted/index.tsx +++ b/src/plugins/whoReacted/index.tsx @@ -66,7 +66,7 @@ function fetchReactions(msg: Message, emoji: ReactionEmoji, type: number) { function getReactionsWithQueue(msg: Message, e: ReactionEmoji, type: number) { const key = `${msg.id}:${e.name}:${e.id ?? ""}:${type}`; - const cache = reactions[key] ??= { fetched: false, users: {} }; + const cache = reactions[key] ??= { fetched: false, users: new Map() }; if (!cache.fetched) { queue.unshift(() => fetchReactions(msg, e, type)); cache.fetched = true; @@ -159,7 +159,7 @@ export default definePlugin({ }, [message.id, forceUpdate]); const reactions = getReactionsWithQueue(message, emoji, type); - const users = Object.values(reactions).filter(Boolean) as User[]; + const users = [...reactions.values()].filter(Boolean); return (
; + users: Map; } interface RootObject { diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 65c73bd8..7bcadb42 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -589,6 +589,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "samsam", id: 836452332387565589n, }, + Cootshk: { + name: "Cootshk", + id: 921605971577548820n + }, } satisfies Record); // iife so #__PURE__ works correctly diff --git a/src/utils/misc.ts b/src/utils/misc.ts index 7f9f6e59..7028e00b 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -92,6 +92,7 @@ export function identity(value: T): T { export const isMobile = navigator.userAgent.includes("Mobi"); export const isPluginDev = (id: string) => Object.hasOwn(DevsById, id); +export const shouldShowContributorBadge = (id: string) => isPluginDev(id) && DevsById[id].badge !== false; export function pluralise(amount: number, singular: string, plural = singular + "s") { return amount === 1 ? `${amount} ${singular}` : `${amount} ${plural}`; diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 05eb5729..5c54c95a 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -138,7 +138,7 @@ export const UserUtils = { export const UploadManager = findByPropsLazy("clearAll", "addFile"); export const UploadHandler = { - promptToUpload: findByCodeLazy("#{intl::ATTACHMENT_TOO_MANY_ERROR_TITLE}") as (files: File[], channel: Channel, draftType: Number) => void + promptToUpload: findByCodeLazy("=!0,showLargeMessageDialog:") as (files: File[], channel: Channel, draftType: Number) => void }; export const ApplicationAssetUtils = mapMangledModuleLazy("getAssetImage: size must === [", {