diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts index b05a424e..d8cbb44a 100644 --- a/scripts/generateReport.ts +++ b/scripts/generateReport.ts @@ -46,7 +46,8 @@ await page.setBypassCSP(true); async function maybeGetError(handle: JSHandle): Promise { return await (handle as JSHandle)?.getProperty("message") - .then(m => m?.jsonValue()); + .then(m => m?.jsonValue()) + .catch(() => undefined); } const report = { diff --git a/src/api/Commands/commandHelpers.ts b/src/api/Commands/commandHelpers.ts index 2f703913..4ae022c5 100644 --- a/src/api/Commands/commandHelpers.ts +++ b/src/api/Commands/commandHelpers.ts @@ -17,14 +17,14 @@ */ import { mergeDefaults } from "@utils/mergeDefaults"; -import { findByPropsLazy } from "@webpack"; +import { findByCodeLazy } from "@webpack"; import { MessageActions, SnowflakeUtils } from "@webpack/common"; import { Message } from "discord-types/general"; import type { PartialDeep } from "type-fest"; import { Argument } from "./types"; -const MessageCreator = findByPropsLazy("createBotMessage"); +const createBotMessage = findByCodeLazy('username:"Clyde"'); export function generateId() { return `-${SnowflakeUtils.fromTimestamp(Date.now())}`; @@ -37,7 +37,7 @@ export function generateId() { * @returns {Message} */ export function sendBotMessage(channelId: string, message: PartialDeep): Message { - const botMessage = MessageCreator.createBotMessage({ channelId, content: "", embeds: [] }); + const botMessage = createBotMessage({ channelId, content: "", embeds: [] }); MessageActions.receiveMessage(channelId, mergeDefaults(message, botMessage)); diff --git a/src/api/SettingsStores.ts b/src/api/SettingsStores.ts new file mode 100644 index 00000000..18139e4e --- /dev/null +++ b/src/api/SettingsStores.ts @@ -0,0 +1,69 @@ +/* + * 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 { proxyLazy } from "@utils/lazy"; +import { Logger } from "@utils/Logger"; +import { findModuleId, proxyLazyWebpack, wreq } from "@webpack"; + +import { Settings } from "./Settings"; + +interface Setting { + /** + * Get the setting value + */ + getSetting(): T; + /** + * Update the setting value + * @param value The new value + */ + updateSetting(value: T | ((old: T) => T)): Promise; + /** + * React hook for automatically updating components when the setting is updated + */ + useSetting(): T; + settingsStoreApiGroup: string; + settingsStoreApiName: string; +} + +export const SettingsStores: Array> | undefined = proxyLazyWebpack(() => { + const modId = findModuleId('"textAndImages","renderSpoilers"') as any; + if (modId == null) return new Logger("SettingsStoreAPI").error("Didn't find stores module."); + + const mod = wreq(modId); + if (mod == null) return; + + return Object.values(mod).filter((s: any) => s?.settingsStoreApiGroup) as any; +}); + +/** + * Get the store for a setting + * @param group The setting group + * @param name The name of the setting + */ +export function getSettingStore(group: string, name: string): Setting | undefined { + if (!Settings.plugins.SettingsStoreAPI.enabled) throw new Error("Cannot use SettingsStoreAPI without setting as dependency."); + + return SettingsStores?.find(s => s?.settingsStoreApiGroup === group && s?.settingsStoreApiName === name); +} + +/** + * getSettingStore but lazy + */ +export function getSettingStoreLazy(group: string, name: string) { + return proxyLazy(() => getSettingStore(group, name)); +} diff --git a/src/api/index.ts b/src/api/index.ts index 02c70008..737e06d6 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -31,6 +31,7 @@ import * as $Notices from "./Notices"; import * as $Notifications from "./Notifications"; import * as $ServerList from "./ServerList"; import * as $Settings from "./Settings"; +import * as $SettingsStores from "./SettingsStores"; import * as $Styles from "./Styles"; /** @@ -116,3 +117,5 @@ export const ChatButtons = $ChatButtons; * An API allowing you to update and re-render messages */ export const MessageUpdater = $MessageUpdater; + +export const SettingsStores = $SettingsStores; diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index d8e391ae..cb153c6a 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -93,7 +93,7 @@ export default definePlugin({ { find: ".PANEL]:14", replacement: { - match: /(?<=(\i)=\(0,\i\.default\)\(\i\);)return 0===\i.length\?/, + match: /(?<=(\i)=\(0,\i\.\i\)\(\i\);)return 0===\i.length\?/, replace: "$1.unshift(...$self.getBadges(arguments[0].displayProfile));$&" } }, diff --git a/src/plugins/_api/settingsStores.ts b/src/plugins/_api/settingsStores.ts new file mode 100644 index 00000000..a888532e --- /dev/null +++ b/src/plugins/_api/settingsStores.ts @@ -0,0 +1,43 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 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 { Devs } from "@utils/constants"; +import definePlugin from "@utils/types"; + +export default definePlugin({ + name: "SettingsStoreAPI", + description: "Patches Discord's SettingsStores to expose their group and name", + authors: [Devs.Nuckyz], + + patches: [ + { + find: ",updateSetting:", + replacement: [ + { + match: /(?<=INFREQUENT_USER_ACTION.{0,20}),useSetting:/, + replace: ",settingsStoreApiGroup:arguments[0],settingsStoreApiName:arguments[1]$&" + }, + // some wrapper. just make it copy the group and name + { + match: /updateSetting:.{0,20}shouldSync/, + replace: "settingsStoreApiGroup:arguments[0].settingsStoreApiGroup,settingsStoreApiName:arguments[0].settingsStoreApiName,$&" + } + ] + } + ] +}); diff --git a/src/plugins/_core/settings.tsx b/src/plugins/_core/settings.tsx index e998b864..85300862 100644 --- a/src/plugins/_core/settings.tsx +++ b/src/plugins/_core/settings.tsx @@ -94,8 +94,8 @@ export default definePlugin({ { find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL", replacement: { - match: /(?<=function\((\i),\i\)\{)(?=let \i=Object.values\(\i.UserSettingsSections\).*?(\i)\.default\.open\()/, - replace: "$2.default.open($1);return;" + match: /(?<=function\((\i),\i\)\{)(?=let \i=Object.values\(\i.\i\).*?(\i\.\i)\.open\()/, + replace: "$2.open($1);return;" } } ], @@ -182,7 +182,7 @@ export default definePlugin({ patchedSettings: new WeakSet(), addSettings(elements: any[], element: { header?: string; settings: string[]; }, sectionTypes: SectionTypes) { - if (this.patchedSettings.has(elements)) return; + if (this.patchedSettings.has(elements) || !this.isRightSpot(element)) return; this.patchedSettings.add(elements); diff --git a/src/plugins/arRPC.web/index.tsx b/src/plugins/arRPC.web/index.tsx index e41e8675..df307e75 100644 --- a/src/plugins/arRPC.web/index.tsx +++ b/src/plugins/arRPC.web/index.tsx @@ -20,10 +20,10 @@ import { popNotice, showNotice } from "@api/Notices"; import { Link } from "@components/Link"; import { Devs } from "@utils/constants"; import definePlugin, { ReporterTestable } from "@utils/types"; -import { findByPropsLazy } from "@webpack"; +import { findByCodeLazy } from "@webpack"; import { ApplicationAssetUtils, FluxDispatcher, Forms, Toasts } from "@webpack/common"; -const RpcUtils = findByPropsLazy("fetchApplicationsRPC", "getRemoteIconURL"); +const fetchApplicationsRPC = findByCodeLazy("APPLICATION_RPC(", "Client ID"); async function lookupAsset(applicationId: string, key: string): Promise { return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0]; @@ -32,7 +32,7 @@ async function lookupAsset(applicationId: string, key: string): Promise const apps: any = {}; async function lookupApp(applicationId: string): Promise { const socket: any = {}; - await RpcUtils.fetchApplicationsRPC(socket, applicationId); + await fetchApplicationsRPC(socket, applicationId); return socket.application; } diff --git a/src/plugins/betterGifAltText/index.ts b/src/plugins/betterGifAltText/index.ts index f0090343..55fa2252 100644 --- a/src/plugins/betterGifAltText/index.ts +++ b/src/plugins/betterGifAltText/index.ts @@ -36,7 +36,7 @@ export default definePlugin({ { find: ".Messages.GIF,", replacement: { - match: /alt:(\i)=(\i\.default\.Messages\.GIF)(?=,[^}]*\}=(\i))/, + match: /alt:(\i)=(\i\.\i\.Messages\.GIF)(?=,[^}]*\}=(\i))/, replace: // rename prop so we can always use default value "alt_$$:$1=$self.altify($3)||$2", diff --git a/src/plugins/betterRoleContext/index.tsx b/src/plugins/betterRoleContext/index.tsx index ecb1ed40..d69e188c 100644 --- a/src/plugins/betterRoleContext/index.tsx +++ b/src/plugins/betterRoleContext/index.tsx @@ -5,15 +5,18 @@ */ import { definePluginSettings } from "@api/Settings"; +import { getSettingStoreLazy } from "@api/SettingsStores"; import { ImageIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { getCurrentGuild, openImageModal } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy } from "@webpack"; -import { Clipboard, GuildStore, Menu, PermissionStore, TextAndImagesSettingsStores } from "@webpack/common"; +import { Clipboard, GuildStore, Menu, PermissionStore } from "@webpack/common"; const GuildSettingsActions = findByPropsLazy("open", "selectRole", "updateGuild"); +const DeveloperMode = getSettingStoreLazy("appearance", "developerMode")!; + function PencilIcon() { return ( `${leftPart} 48 - ((this.props.lowerBadgeHeight ?? 16) + 8) + 4 ${rightPart} (this.props.lowerBadgeHeight ?? 16) + 8,` - } } ], @@ -153,14 +144,16 @@ export default definePlugin({ } - lowerBadgeWidth={20} - lowerBadgeHeight={20} + lowerBadgeSize={{ + width: 20, + height: 20 + }} >
- +
); diff --git a/src/plugins/betterSettings/index.tsx b/src/plugins/betterSettings/index.tsx index e0267e4b..6d8d9855 100644 --- a/src/plugins/betterSettings/index.tsx +++ b/src/plugins/betterSettings/index.tsx @@ -83,19 +83,19 @@ export default definePlugin({ find: "this.renderArtisanalHack()", replacement: [ { // Fade in on layer - match: /(?<=\((\i),"contextType",\i\.AccessibilityPreferencesContext\);)/, + match: /(?<=\((\i),"contextType",\i\.\i\);)/, replace: "$1=$self.Layer;", predicate: () => settings.store.disableFade }, { // Lazy-load contents - match: /createPromise:\(\)=>([^:}]*?),webpackId:"\d+",name:(?!="CollectiblesShop")"[^"]+"/g, + match: /createPromise:\(\)=>([^:}]*?),webpackId:\d+,name:(?!="CollectiblesShop")"[^"]+"/g, replace: "$&,_:$1", predicate: () => settings.store.eagerLoad } ] }, { // For some reason standardSidebarView also has a small fade-in - find: "DefaultCustomContentScroller:function()", + find: 'minimal:"contentColumnMinimal"', replacement: [ { match: /\(0,\i\.useTransition\)\((\i)/, @@ -111,7 +111,7 @@ export default definePlugin({ { // Load menu TOC eagerly find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format", replacement: { - match: /(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?openContextMenuLazy.{0,100}?(await Promise\.all[^};]*?\)\)).*?,(?=\1\(this)/, + match: /(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?\i\.\i\).{0,100}?(await Promise\.all[^};]*?\)\)).*?,(?=\1\(this)/, replace: "$&(async ()=>$2)()," }, predicate: () => settings.store.eagerLoad @@ -119,7 +119,7 @@ export default definePlugin({ { // Settings cog context menu find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL", replacement: { - match: /\(0,\i.useDefaultUserSettingsSections\)\(\)(?=\.filter\(\i=>\{let\{section:\i\}=)/, + match: /\(0,\i.\i\)\(\)(?=\.filter\(\i=>\{let\{section:\i\}=)/, replace: "$self.wrapMenu($&)" } } diff --git a/src/plugins/customRPC/index.tsx b/src/plugins/customRPC/index.tsx index ed354cba..7e4e9a93 100644 --- a/src/plugins/customRPC/index.tsx +++ b/src/plugins/customRPC/index.tsx @@ -17,6 +17,7 @@ */ import { definePluginSettings, Settings } from "@api/Settings"; +import { getSettingStoreLazy } from "@api/SettingsStores"; import { ErrorCard } from "@components/ErrorCard"; import { Link } from "@components/Link"; import { Devs } from "@utils/constants"; @@ -26,12 +27,15 @@ import { classes } from "@utils/misc"; import { useAwaiter } from "@utils/react"; import definePlugin, { OptionType } from "@utils/types"; import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack"; -import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, StatusSettingsStores, UserStore } from "@webpack/common"; +import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common"; const useProfileThemeStyle = findByCodeLazy("profileThemeStyle:", "--profile-gradient-primary-color"); const ActivityComponent = findComponentByCodeLazy("onOpenGameProfile"); const ActivityClassName = findByPropsLazy("activity", "buttonColor"); +const ShowCurrentGame = getSettingStoreLazy("status", "showCurrentGame")!; + + async function getApplicationAsset(key: string): Promise { if (/https?:\/\/(cdn|media)\.discordapp\.(com|net)\/attachments\//.test(key)) return "mp:" + key.replace(/https?:\/\/(cdn|media)\.discordapp\.(com|net)\//, ""); return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0]; @@ -390,13 +394,14 @@ export default definePlugin({ name: "CustomRPC", description: "Allows you to set a custom rich presence.", authors: [Devs.captain, Devs.AutumnVN, Devs.nin0dev], + dependencies: ["SettingsStoreAPI"], start: setRpc, stop: () => setRpc(true), settings, settingsAboutComponent: () => { const activity = useAwaiter(createActivity); - const gameActivityEnabled = StatusSettingsStores.ShowCurrentGame.useSetting(); + const gameActivityEnabled = ShowCurrentGame.useSetting(); const { profileThemeStyle } = useProfileThemeStyle({}); return ( @@ -412,7 +417,7 @@ export default definePlugin({ diff --git a/src/plugins/customidle/index.ts b/src/plugins/customidle/index.ts index a59bbcb0..87caea75 100644 --- a/src/plugins/customidle/index.ts +++ b/src/plugins/customidle/index.ts @@ -44,15 +44,15 @@ export default definePlugin({ find: 'type:"IDLE",idle:', replacement: [ { - match: /Math\.min\((\i\.AfkTimeout\.getSetting\(\)\*\i\.default\.Millis\.SECOND),\i\.IDLE_DURATION\)/, + match: /Math\.min\((\i\.\i\.getSetting\(\)\*\i\.\i\.\i\.SECOND),\i\.\i\)/, replace: "$1" // Decouple idle from afk (phone notifications will remain at user setting or 10 min maximum) }, { - match: /\i\.default\.dispatch\({type:"IDLE",idle:!1}\)/, + match: /\i\.\i\.dispatch\({type:"IDLE",idle:!1}\)/, replace: "$self.handleOnline()" }, { - match: /(setInterval\(\i,\.25\*)\i\.IDLE_DURATION/, + match: /(setInterval\(\i,\.25\*)\i\.\i/, replace: "$1$self.getIntervalDelay()" // For web installs } ] diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index a6c3540d..cdf74d15 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -399,7 +399,7 @@ export default definePlugin({ }, // Separate patch for allowing using custom app icons { - find: ".FreemiumAppIconIds.DEFAULT&&(", + find: /\.getCurrentDesktopIcon.{0,25}\.isPremium/, replacement: { match: /\i\.\i\.isPremium\(\i\.\i\.getCurrentUser\(\)\)/, replace: "true" diff --git a/src/plugins/friendsSince/index.tsx b/src/plugins/friendsSince/index.tsx index 58014f36..6c354278 100644 --- a/src/plugins/friendsSince/index.tsx +++ b/src/plugins/friendsSince/index.tsx @@ -26,17 +26,17 @@ export default definePlugin({ patches: [ // User popup { - find: ".AnalyticsSections.USER_PROFILE}", + find: ".USER_PROFILE}};return", replacement: { - match: /\i.default,\{userId:(\i.id).{0,30}}\)/, + match: /\i.\i,\{userId:(\i.id).{0,30}}\)/, replace: "$&,$self.friendsSince({ userId: $1 })" } }, // User DMs "User Profile" popup in the right { - find: ".UserPopoutUpsellSource.PROFILE_PANEL,", + find: ".PROFILE_PANEL,", replacement: { - match: /\i.default,\{userId:([^,]+?)}\)/, + match: /\i.\i,\{userId:([^,]+?)}\)/, replace: "$&,$self.friendsSince({ userId: $1 })" } }, diff --git a/src/plugins/gameActivityToggle/index.tsx b/src/plugins/gameActivityToggle/index.tsx index 51feb916..4e2a390d 100644 --- a/src/plugins/gameActivityToggle/index.tsx +++ b/src/plugins/gameActivityToggle/index.tsx @@ -17,17 +17,19 @@ */ import { definePluginSettings } from "@api/Settings"; +import { getSettingStoreLazy } from "@api/SettingsStores"; import { disableStyle, enableStyle } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { findComponentByCodeLazy } from "@webpack"; -import { StatusSettingsStores } from "@webpack/common"; import style from "./style.css?managed"; const Button = findComponentByCodeLazy("Button.Sizes.NONE,disabled:"); +const ShowCurrentGame = getSettingStoreLazy("status", "showCurrentGame")!; + function makeIcon(showCurrentGame?: boolean) { const { oldIcon } = settings.use(["oldIcon"]); @@ -60,7 +62,7 @@ function makeIcon(showCurrentGame?: boolean) { } function GameActivityToggleButton() { - const showCurrentGame = StatusSettingsStores.ShowCurrentGame.useSetting(); + const showCurrentGame = ShowCurrentGame.useSetting(); return (