From dc7b50a0f52dc9772791020589f015c15e245a1b Mon Sep 17 00:00:00 2001 From: hsiF <90235641+zrodevkaan@users.noreply.github.com> Date: Thu, 8 Feb 2024 13:56:09 -0600 Subject: [PATCH 01/22] Fixed Replugged Crash --- src/renderer/coremods/settings/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/coremods/settings/index.tsx b/src/renderer/coremods/settings/index.tsx index a3ced2d22..a789799cc 100644 --- a/src/renderer/coremods/settings/index.tsx +++ b/src/renderer/coremods/settings/index.tsx @@ -17,7 +17,7 @@ async function injectVersionInfo(): Promise { const mod = await waitForModule(filters.bySource(".versionHash"), { raw: true }); injector.after(mod.exports, "default", (_, res) => { - res.props.children.push( + res.props.children.props.children.push( Date: Tue, 2 Apr 2024 19:25:33 -0500 Subject: [PATCH 02/22] ExperimentsFix --- src/renderer/coremods/experiments/plaintextPatches.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/coremods/experiments/plaintextPatches.ts b/src/renderer/coremods/experiments/plaintextPatches.ts index 6d18e8c6e..1a263bed9 100644 --- a/src/renderer/coremods/experiments/plaintextPatches.ts +++ b/src/renderer/coremods/experiments/plaintextPatches.ts @@ -9,7 +9,7 @@ const generalSettings = await init Date: Wed, 3 Apr 2024 19:57:31 -0500 Subject: [PATCH 03/22] uhhhh. something something uhhh yeah something something lint fix and recovery. --- src/globals.d.ts | 1 - src/renderer/coremods/recovery/index.tsx | 103 ++++++++++++++++++++++ src/renderer/coremods/recovery/styles.css | 21 +++++ src/renderer/managers/coremods.ts | 2 + src/renderer/modules/common/lodash.ts | 1 - src/renderer/modules/injector.ts | 27 +++--- src/types/settings.ts | 2 + 7 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 src/renderer/coremods/recovery/index.tsx create mode 100644 src/renderer/coremods/recovery/styles.css diff --git a/src/globals.d.ts b/src/globals.d.ts index 300593293..f40d51cf5 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -6,7 +6,6 @@ import type { WebpackChunkGlobal } from "./types/discord"; import * as replugged from "./renderer/replugged"; import type { RepluggedNativeType } from "./preload"; -// eslint-disable-next-line node/no-extraneous-import import type Lodash from "lodash"; declare global { export var appSettings: { diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx new file mode 100644 index 000000000..0b6925768 --- /dev/null +++ b/src/renderer/coremods/recovery/index.tsx @@ -0,0 +1,103 @@ +import { fluxDispatcher, parser } from "@common"; +import { Button } from "@components"; +import { Injector, Logger } from "@replugged"; +import { filters, getByProps, waitForModule } from "@webpack"; +import "./styles.css"; +import { AnyFunction } from "../../../types"; + +import { generalSettings } from "../settings/pages"; +const injector = new Injector(); + +// const URL_REGEX_FIND = /https:\/\/\S+/g; +const logger = Logger.coremod("recovery"); +interface ErrorComponentState { + error: { + message: string; + stack: string; + } | null; +} + +interface ErrorScreenInstance { + state?: ErrorComponentState; + setState: (state: ErrorComponentState) => void; +} + +interface Modals { + closeAllModals: AnyFunction; +} + +interface RouteInstance { + transitionTo: (location: string) => void; +} + +const ModalModule: Modals | undefined = getByProps("openModalLazy"); +const RouteModule: RouteInstance | undefined = getByProps("transitionTo"); + +function startMainRecovery(): void { + const log = (reason: string): void => logger.log(reason), + err = (reason: string): void => logger.error(reason); + log("Starting main recovery methods."); + if (!ModalModule) { + err("Could not find `openModalLazy` Module."); + return; + } + + try { + fluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" }); + } catch { + err("ContextMenu's could not be closed."); + } + + try { + ModalModule.closeAllModals(); + } catch { + err("Could not close (most) modals."); + } + + try { + RouteModule?.transitionTo("/channels/@me"); + } catch { + err("Failed to transition to '/channels/@me'."); + } + + log("Ended main recovery."); +} + +export async function start(): Promise { + const ErrorScreen = await waitForModule( + filters.bySource(".AnalyticEvents.APP_CRASHED"), + ); + + injector.after( + ErrorScreen.prototype, + "render", + (_args, res: React.ReactElement, instance: ErrorScreenInstance): void => { + if (generalSettings.get("automaticRecover")) { + instance.setState({ error: null }); + } + const children = res.props?.action?.props?.children; + if (!children || !instance.state?.error) return; + // const Link = instance.state.error.stack.match(URL_REGEX_FIND); + // this'll be used once I make a react decoder for errors. >:( + children.push( + <> + +
+ {parser.parse(`\`\`\`${instance.state.error.stack}\`\`\``)} +
+ , + ); + }, + ); +} + +export function stop(): void { + injector.uninjectAll(); +} diff --git a/src/renderer/coremods/recovery/styles.css b/src/renderer/coremods/recovery/styles.css new file mode 100644 index 000000000..bee0b3bfa --- /dev/null +++ b/src/renderer/coremods/recovery/styles.css @@ -0,0 +1,21 @@ +.buttons_faceef { + flex-direction: column; + align-items: center; +} +.buttons_faceef .button__581d0 { + width: 400px; + margin: 5px; +} +.recovery-button { + width: var(--custom-button-button-lg-width); + height: var(--custom-button-button-lg-height); + min-width: var(--custom-button-button-lg-width); + min-height: var(--custom-button-button-lg-height); + + background-color: var(--button-danger-background) !important; +} +.errorPage_a41002 [class^="scrollbarGhostHairline"] { + white-space: break-spaces; + width: 80vw; + text-align: center; +} diff --git a/src/renderer/managers/coremods.ts b/src/renderer/managers/coremods.ts index cafd75fb7..b748e7da3 100644 --- a/src/renderer/managers/coremods.ts +++ b/src/renderer/managers/coremods.ts @@ -34,6 +34,7 @@ export namespace coremods { export let watcher: Coremod; export let commands: Coremod; export let welcome: Coremod; + export let recovery: Coremod; } export async function start(name: keyof typeof coremods): Promise { @@ -59,6 +60,7 @@ export async function startAll(): Promise { coremods.watcher = await import("../coremods/watcher"); coremods.commands = await import("../coremods/commands"); coremods.welcome = await import("../coremods/welcome"); + coremods.recovery = await import("../coremods/recovery"); await Promise.all( Object.entries(coremods).map(async ([name, mod]) => { diff --git a/src/renderer/modules/common/lodash.ts b/src/renderer/modules/common/lodash.ts index f73360de7..c12897111 100644 --- a/src/renderer/modules/common/lodash.ts +++ b/src/renderer/modules/common/lodash.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line node/no-extraneous-import import type Lodash from "lodash"; import { waitForProps } from "../webpack"; diff --git a/src/renderer/modules/injector.ts b/src/renderer/modules/injector.ts index 8be38446b..e7aaa53d0 100644 --- a/src/renderer/modules/injector.ts +++ b/src/renderer/modules/injector.ts @@ -20,9 +20,9 @@ enum InjectionTypes { * @param self The module the injected function is on * @returns New arguments to pass to the original function, or undefined to leave them unchanged */ -export type BeforeCallback = ( +export type BeforeCallback = ( args: A, - self: ObjectExports, + self: I, ) => A | undefined | void; /** @@ -32,10 +32,10 @@ export type BeforeCallback = ( * @param self The module the injected function is on * @returns New result to return */ -export type InsteadCallback = ( +export type InsteadCallback = ( args: A, orig: (...args: A) => R, - self: ObjectExports, + self: I, ) => R | void; /** @@ -45,10 +45,10 @@ export type InsteadCallback = ( * @param self The module the injected function is on * @returns New result to return, or undefined to leave it unchanged */ -export type AfterCallback = ( +export type AfterCallback = ( args: A, res: R, - self: ObjectExports, + self: I, ) => R | undefined | void; interface ObjectInjections { @@ -167,7 +167,8 @@ function before< T extends Record, U extends keyof T & string, A extends unknown[] = Parameters, ->(obj: T, funcName: U, cb: BeforeCallback): () => void { + I = T[U], +>(obj: T, funcName: U, cb: BeforeCallback): () => void { // @ts-expect-error 'unknown[]' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint 'unknown[]'. return inject(obj, funcName, cb as BeforeCallback, InjectionTypes.Before); } @@ -177,7 +178,8 @@ function instead< U extends keyof T & string, A extends unknown[] = Parameters, R = ReturnType, ->(obj: T, funcName: U, cb: InsteadCallback): () => void { + I = T[U], +>(obj: T, funcName: U, cb: InsteadCallback): () => void { // @ts-expect-error 'unknown[]' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint 'unknown[]'. return inject(obj, funcName, cb, InjectionTypes.Instead); } @@ -187,7 +189,8 @@ function after< U extends keyof T & string, A extends unknown[] = Parameters, R = ReturnType, ->(obj: T, funcName: U, cb: AfterCallback): () => void { + I = T[U], +>(obj: T, funcName: U, cb: AfterCallback): () => void { // @ts-expect-error 'unknown[]' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint 'unknown[]'. return inject(obj, funcName, cb, InjectionTypes.After); } @@ -250,7 +253,8 @@ export class Injector { U extends keyof T & string, A extends unknown[] = Parameters, R = ReturnType, - >(obj: T, funcName: U, cb: InsteadCallback): () => void { + I = T[U], + >(obj: T, funcName: U, cb: InsteadCallback): () => void { const uninjector = instead(obj, funcName, cb); this.#uninjectors.add(uninjector); return uninjector; @@ -268,7 +272,8 @@ export class Injector { U extends keyof T & string, A extends unknown[] = Parameters, R = ReturnType, - >(obj: T, funcName: U, cb: AfterCallback): () => void { + I = T[U], + >(obj: T, funcName: U, cb: AfterCallback): () => void { const uninjector = after(obj, funcName, cb); this.#uninjectors.add(uninjector); return uninjector; diff --git a/src/types/settings.ts b/src/types/settings.ts index f9709bcb0..441dd80bf 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -13,6 +13,7 @@ export type GeneralSettings = { showWelcomeNoticeOnOpen?: boolean; addonEmbeds?: boolean; reactDevTools?: boolean; + automaticRecover?: boolean; }; export const defaultSettings = { @@ -23,4 +24,5 @@ export const defaultSettings = { showWelcomeNoticeOnOpen: true, reactDevTools: false, addonEmbeds: true, + automaticRecover: false, } satisfies Partial; From 8c1b8ef91f5361f725c159abdfd53df58d3196da Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Wed, 3 Apr 2024 20:09:51 -0500 Subject: [PATCH 04/22] Update cspell.json --- cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.json b/cspell.json index 2e4895344..bbf349004 100644 --- a/cspell.json +++ b/cspell.json @@ -6,6 +6,7 @@ "words": [ "alertdialog", "APPDATA", + "faceef", "asar", "Automod", "autosize", From 1b093b9aa20928fc6222d9bd541c939527ec7a2e Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Wed, 3 Apr 2024 20:48:48 -0500 Subject: [PATCH 05/22] more things like i18n and another setting switch item ;3 --- i18n/en-US.json | 4 +++- src/renderer/coremods/settings/pages/General.tsx | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/i18n/en-US.json b/i18n/en-US.json index 7b1df86be..e2865008a 100644 --- a/i18n/en-US.json +++ b/i18n/en-US.json @@ -242,5 +242,7 @@ "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_WINDOWS": "****WARNING:**** This will break **window snapping**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_LINUX": "****WARNING:**** **Hardware acceleration** may need to be turned **off**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", "REPLUGGED_SETTINGS_ERROR_PLUGIN_NAME": "Plugin: {name}", - "REPLUGGED_STORE": "Store" + "REPLUGGED_STORE": "Store", + "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY": "Automatic Recovery", + "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY_DESC": "Allows Discord to try to automatically recover from a crash." } diff --git a/src/renderer/coremods/settings/pages/General.tsx b/src/renderer/coremods/settings/pages/General.tsx index daf6165f8..80278b81d 100644 --- a/src/renderer/coremods/settings/pages/General.tsx +++ b/src/renderer/coremods/settings/pages/General.tsx @@ -102,6 +102,12 @@ export const General = (): React.ReactElement => { {Messages.REPLUGGED_SETTINGS_BADGES} + + {Messages.REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY} + + From 1963a02ab6fcfbd9d0259b60514877b942abf8c6 Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Wed, 3 Apr 2024 21:16:35 -0500 Subject: [PATCH 06/22] info null uwu changed state type --- src/renderer/coremods/recovery/index.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index 0b6925768..9ab9be72e 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -15,6 +15,7 @@ interface ErrorComponentState { message: string; stack: string; } | null; + info: null; } interface ErrorScreenInstance { @@ -42,6 +43,14 @@ function startMainRecovery(): void { return; } + try { + // I think trying to transition first is a better move. + // Considering most errors come from patching. + RouteModule?.transitionTo("/channels/@me"); + } catch { + err("Failed to transition to '/channels/@me'."); + } + try { fluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" }); } catch { @@ -54,12 +63,6 @@ function startMainRecovery(): void { err("Could not close (most) modals."); } - try { - RouteModule?.transitionTo("/channels/@me"); - } catch { - err("Failed to transition to '/channels/@me'."); - } - log("Ended main recovery."); } @@ -73,7 +76,7 @@ export async function start(): Promise { "render", (_args, res: React.ReactElement, instance: ErrorScreenInstance): void => { if (generalSettings.get("automaticRecover")) { - instance.setState({ error: null }); + instance.setState({ error: null, info: null }); } const children = res.props?.action?.props?.children; if (!children || !instance.state?.error) return; @@ -85,7 +88,7 @@ export async function start(): Promise { className={`recovery-button`} onClick={() => { startMainRecovery(); - instance.setState({ error: null }); + instance.setState({ error: null, info: null }); }}> Recover Discord From bdecea1e5a1d637d2461cae59fae599ab94bbd7d Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Wed, 3 Apr 2024 21:18:38 -0500 Subject: [PATCH 07/22] bruh a whitespace made it mad --- src/renderer/coremods/recovery/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index 9ab9be72e..d83da6b18 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -50,7 +50,7 @@ function startMainRecovery(): void { } catch { err("Failed to transition to '/channels/@me'."); } - + try { fluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" }); } catch { From b2a4a9d1e0deae1fd4c05a1c9e822605b250b071 Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:39:28 -0500 Subject: [PATCH 08/22] fishy keyboard man. be happy --- i18n/en-US.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/en-US.json b/i18n/en-US.json index e2865008a..83a837338 100644 --- a/i18n/en-US.json +++ b/i18n/en-US.json @@ -229,6 +229,8 @@ "REPLUGGED_SETTINGS_DEV_COMPANION_DESC": "Reconnects the Dev Companion coremod to the VSCode extension.", "REPLUGGED_SETTINGS_DEV_COMPANION_RECONNECT": "Reconnect", "REPLUGGED_SETTINGS_ADVANCED": "Advanced Settings", + "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY": "Automatic Recovery", + "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY_DESC": "Allows Discord to try to automatically recover from a crash.", "REPLUGGED_SETTINGS_REACT_DEVTOOLS": "Enable React DevTools", "REPLUGGED_SETTINGS_REACT_DEVTOOLS_DESC": "Loads the React DevTools extension, allowing you to inspect the React tree and debug more easily. **Requires restart**.", "REPLUGGED_SETTINGS_REACT_DEVTOOLS_FAILED": "Failed to download React DevTools.", @@ -242,7 +244,5 @@ "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_WINDOWS": "****WARNING:**** This will break **window snapping**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_LINUX": "****WARNING:**** **Hardware acceleration** may need to be turned **off**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", "REPLUGGED_SETTINGS_ERROR_PLUGIN_NAME": "Plugin: {name}", - "REPLUGGED_STORE": "Store", - "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY": "Automatic Recovery", - "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY_DESC": "Allows Discord to try to automatically recover from a crash." + "REPLUGGED_STORE": "Store" } From f7ce46b53372e85dd3c1e74d38b9fb8802ddc4ba Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Thu, 4 Apr 2024 19:01:20 -0500 Subject: [PATCH 09/22] could be better, --- src/renderer/coremods/recovery/index.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index d83da6b18..469865173 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -6,9 +6,11 @@ import "./styles.css"; import { AnyFunction } from "../../../types"; import { generalSettings } from "../settings/pages"; +import {disable} from "../../managers/plugins"; const injector = new Injector(); // const URL_REGEX_FIND = /https:\/\/\S+/g; +const PLUGIN_ID_FIND_REGEX = /plugin\/(.*?)\.asar/; const logger = Logger.coremod("recovery"); interface ErrorComponentState { error: { @@ -75,11 +77,18 @@ export async function start(): Promise { ErrorScreen.prototype, "render", (_args, res: React.ReactElement, instance: ErrorScreenInstance): void => { + startMainRecovery(); if (generalSettings.get("automaticRecover")) { instance.setState({ error: null, info: null }); } const children = res.props?.action?.props?.children; if (!children || !instance.state?.error) return; + + // I don't think this would fail..? + const pluginId = instance.state?.error?.stack.match(PLUGIN_ID_FIND_REGEX) + if (pluginId) { + disable(pluginId[1]); + } // const Link = instance.state.error.stack.match(URL_REGEX_FIND); // this'll be used once I make a react decoder for errors. >:( children.push( @@ -87,7 +96,6 @@ export async function start(): Promise {
- {parser.parse(`\`\`\`${instance.state.error.stack}\`\`\``)} + {parser.parse( + `\`\`\`${invar ? `${ReactErrors[invar[1] as any] }\n\n${ stackError}` : stackError}\`\`\``, + )}
, ); @@ -113,3 +124,13 @@ export async function start(): Promise { export function stop(): void { injector.uninjectAll(); } + +export async function startErrors() { + return await fetch(ReactErrorList) + .then((json) => json.json()) + .then((data) => { + for (const key in data) { + ReactErrors.push(data[key]); + } + }); +} From 8311921732803319722b89c96043e06a9542980a Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:56:29 -0500 Subject: [PATCH 13/22] types fixed thanks to uwu pookie bear --- src/renderer/coremods/recovery/index.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index 62dbe8f37..79946eb91 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -15,7 +15,7 @@ const FIND_ERROR_NUMBER = /invariant=(\d+)&/; const ReactErrorList = "https://raw.githubusercontent.com/facebook/react/17.0.2/scripts/error-codes/codes.json"; const logger = Logger.coremod("recovery"); -const ReactErrors: Array = []; +let ReactErrors: Record | undefined; interface ErrorComponentState { error: { @@ -97,9 +97,10 @@ export async function start(): Promise { } // const Link = instance.state.error.stack.match(URL_REGEX_FIND); // this'll be used once I make a react decoder for errors. >:( - // nevermind this idea is better. + // never mind this idea is better. const invar = stackError.match(FIND_ERROR_NUMBER); + children.push( <>
- {parser.parse( - `\`\`\`${invar ? `${ReactErrors[invar[1] as any] }\n\n${ stackError}` : stackError}\`\`\``, - )} + {parser.parse(`\`\`\`${invar ? ReactErrors?.[invar[1]] : ""}\n\n${stackError}\`\`\``)}
, ); @@ -125,12 +124,6 @@ export function stop(): void { injector.uninjectAll(); } -export async function startErrors() { - return await fetch(ReactErrorList) - .then((json) => json.json()) - .then((data) => { - for (const key in data) { - ReactErrors.push(data[key]); - } - }); +export async function startErrors(): Promise { + ReactErrors = await fetch(ReactErrorList).then((response) => response.json()); } From f14ea5990c657302611c88a420f2a0067bc3e339 Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:13:18 -0500 Subject: [PATCH 14/22] Upgrades people Upgrades used wildcards so I dont have to update classNames every reroll --- src/renderer/coremods/recovery/styles.css | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/renderer/coremods/recovery/styles.css b/src/renderer/coremods/recovery/styles.css index bee0b3bfa..1a62ec6a5 100644 --- a/src/renderer/coremods/recovery/styles.css +++ b/src/renderer/coremods/recovery/styles.css @@ -1,20 +1,18 @@ -.buttons_faceef { +[class^="wrapper"] [class^="buttons_"] { flex-direction: column; align-items: center; } -.buttons_faceef .button__581d0 { +[class^="wrapper"] [class^="button"] { width: 400px; margin: 5px; } -.recovery-button { - width: var(--custom-button-button-lg-width); - height: var(--custom-button-button-lg-height); - min-width: var(--custom-button-button-lg-width); - min-height: var(--custom-button-button-lg-height); +.recovery-button { + width: 400px; + margin: 5px; background-color: var(--button-danger-background) !important; } -.errorPage_a41002 [class^="scrollbarGhostHairline"] { +[class^="wrapper"] [class^="scrollbarGhostHairline"] { white-space: break-spaces; width: 80vw; text-align: center; From 0ab9015d8903a97bcece4c0494760548845fdcb5 Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:38:43 -0500 Subject: [PATCH 15/22] yes it would --- src/renderer/coremods/recovery/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index 79946eb91..75c050c34 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -13,7 +13,7 @@ const injector = new Injector(); const PLUGIN_ID_FIND_REGEX = /plugin\/(.*?)\.asar/; const FIND_ERROR_NUMBER = /invariant=(\d+)&/; const ReactErrorList = - "https://raw.githubusercontent.com/facebook/react/17.0.2/scripts/error-codes/codes.json"; + "https://raw.githubusercontent.com/facebook/react/v18.2.0/scripts/error-codes/codes.json"; const logger = Logger.coremod("recovery"); let ReactErrors: Record | undefined; @@ -89,7 +89,6 @@ export async function start(): Promise { const children = res.props?.action?.props?.children; if (!children || !instance.state?.error) return; const stackError = instance.state.error.stack; - // I don't think this would fail..? const pluginId = stackError.match(PLUGIN_ID_FIND_REGEX); if (pluginId) { void disable(pluginId[1]); From 29f1e747067e7d6ef51e5cf48609950d9ef8f721 Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:46:57 -0500 Subject: [PATCH 16/22] findInTree for children and comment removed. --- src/renderer/coremods/recovery/index.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index 75c050c34..6935b5ef0 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -7,6 +7,7 @@ import { AnyFunction } from "../../../types"; import { generalSettings } from "../settings/pages"; import { disable } from "../../managers/plugins"; +import {findInTree, Tree} from "../../util"; const injector = new Injector(); // const URL_REGEX_FIND = /https:\/\/\S+/g; @@ -72,7 +73,9 @@ function startMainRecovery(): void { log("Ended main recovery."); } - +interface TreeNode { + children: Array; +} export async function start(): Promise { const ErrorScreen = await waitForModule( filters.bySource(".AnalyticEvents.APP_CRASHED"), @@ -86,7 +89,8 @@ export async function start(): Promise { startMainRecovery(); instance.setState({ error: null, info: null }); } - const children = res.props?.action?.props?.children; + + const { props: {children} }: { props: TreeNode } = findInTree(res as unknown as Tree, x => Boolean(x?.action)) as { props: TreeNode }; if (!children || !instance.state?.error) return; const stackError = instance.state.error.stack; const pluginId = stackError.match(PLUGIN_ID_FIND_REGEX); @@ -94,9 +98,6 @@ export async function start(): Promise { void disable(pluginId[1]); toast.toast(`Plugin: ${pluginId[1]} was disabled!`, toast.Kind.SUCCESS); } - // const Link = instance.state.error.stack.match(URL_REGEX_FIND); - // this'll be used once I make a react decoder for errors. >:( - // never mind this idea is better. const invar = stackError.match(FIND_ERROR_NUMBER); From 0001200246fea637be072ca279fb9e716b793bdd Mon Sep 17 00:00:00 2001 From: zrodevkaan <90235641+zrodevkaan@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:48:28 -0500 Subject: [PATCH 17/22] removed Falsy Check --- src/renderer/coremods/recovery/index.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index 6935b5ef0..fa0a7db38 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -7,7 +7,7 @@ import { AnyFunction } from "../../../types"; import { generalSettings } from "../settings/pages"; import { disable } from "../../managers/plugins"; -import {findInTree, Tree} from "../../util"; +import { Tree, findInTree } from "../../util"; const injector = new Injector(); // const URL_REGEX_FIND = /https:\/\/\S+/g; @@ -74,7 +74,7 @@ function startMainRecovery(): void { log("Ended main recovery."); } interface TreeNode { - children: Array; + children: React.ReactElement[]; } export async function start(): Promise { const ErrorScreen = await waitForModule( @@ -89,9 +89,13 @@ export async function start(): Promise { startMainRecovery(); instance.setState({ error: null, info: null }); } - - const { props: {children} }: { props: TreeNode } = findInTree(res as unknown as Tree, x => Boolean(x?.action)) as { props: TreeNode }; - if (!children || !instance.state?.error) return; + + const { + props: { children }, + }: { props: TreeNode } = findInTree(res as unknown as Tree, (x) => Boolean(x?.action)) as { + props: TreeNode; + }; + if (!instance.state?.error) return; const stackError = instance.state.error.stack; const pluginId = stackError.match(PLUGIN_ID_FIND_REGEX); if (pluginId) { From c7921c380b2f3caebe04883f08a4927147cbc5dd Mon Sep 17 00:00:00 2001 From: hsiF <90235641+zrodevkaan@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:52:02 -0500 Subject: [PATCH 18/22] Main Resolves --- cspell.json | 1 - i18n/en-US.json | 490 +++++++++--------- src/renderer/coremods/recovery/index.tsx | 25 +- src/renderer/coremods/recovery/styles.css | 2 +- .../coremods/settings/pages/General.tsx | 4 +- 5 files changed, 267 insertions(+), 255 deletions(-) diff --git a/cspell.json b/cspell.json index 3273043a2..a4cfadff1 100644 --- a/cspell.json +++ b/cspell.json @@ -6,7 +6,6 @@ "words": [ "alertdialog", "APPDATA", - "faceef", "asar", "Automod", "autosize", diff --git a/i18n/en-US.json b/i18n/en-US.json index 83a837338..981332993 100644 --- a/i18n/en-US.json +++ b/i18n/en-US.json @@ -1,248 +1,246 @@ { - "REPLUGGED_ACCOUNT": "Replugged Account", - "REPLUGGED_BADGES_CONTRIBUTOR": "Replugged Contributor", - "REPLUGGED_BADGES_DEVELOPER": "Replugged Developer", - "REPLUGGED_BADGES_EARLY": "Replugged Early User", - "REPLUGGED_BADGES_HUNTER": "Replugged Bug Hunter", - "REPLUGGED_BADGES_STAFF": "Replugged Staff", - "REPLUGGED_BADGES_SUPPORT": "Replugged Support", - "REPLUGGED_BADGES_TRANSLATOR": "Replugged Translator", - "REPLUGGED_BADGES_BOOSTER": "Replugged Server Booster", - "REPLUGGED_BUTTON_GOT_IT": "Got It", - "REPLUGGED_BUTTON_INSTALLER_INSTALLED": "{type} Installed", - "REPLUGGED_BUTTON_INSTALLER_DOWNLOAD": "Download {type}", - "REPLUGGED_CANCEL": "Cancel", - "REPLUGGED_CONFIRM": "Confirm", - "REPLUGGED_OK": "OK", - "REPLUGGED_COMMAND_ERROR_GENERIC": "Something went wrong, please try again later. If this issue persists, please contact the Replugged team.", - "REPLUGGED_COMMAND_SUCCESS_GENERIC": "Success", - "REPLUGGED_COMMAND_ENABLE_NAME": "enable", - "REPLUGGED_COMMAND_ENABLE_DESC": "Enable a plugin or theme", - "REPLUGGED_COMMAND_ENABLE_OPTION_ADDON_NAME": "addon", - "REPLUGGED_COMMAND_ADDONS_OPTION_ADDON_DESC": "Choose which addon to enable", - "REPLUGGED_COMMAND_ENABLE_MESSAGE_ENABLED": "{type} {name} has been enabled!", - "REPLUGGED_COMMAND_DISABLE_NAME": "disable", - "REPLUGGED_COMMAND_DISABLE_DESC": "Disable a plugin or theme", - "REPLUGGED_COMMAND_DISABLE_OPTION_ADDON_NAME": "addon", - "REPLUGGED_COMMAND_DISABLE_OPTION_ADDON_DESC": "Choose which addon to disable", - "REPLUGGED_COMMAND_DISABLE_MESSAGE_ENABLED": "{type} {name} has been disabled!", - "REPLUGGED_COMMAND_RELOAD_NAME": "reload", - "REPLUGGED_COMMAND_RELOAD_DESC": "Reload a plugin or theme", - "REPLUGGED_COMMAND_RELOAD_OPTION_ADDON_NAME": "addon", - "REPLUGGED_COMMAND_RELOAD_OPTION_ADDON_DESC": "Choose which addon to reload", - "REPLUGGED_COMMAND_RELOAD_MESSAGE_ENABLED": "{type} {name} has been reloaded!", - "REPLUGGED_COMMAND_LIST_NAME": "list", - "REPLUGGED_COMMAND_LIST_DESC": "List all plugins or themes", - "REPLUGGED_COMMAND_LIST_OPTION_SEND_NAME": "send", - "REPLUGGED_COMMAND_LIST_OPTION_SEND_DESC": "Share the list publicly in chat", - "REPLUGGED_COMMAND_LIST_OPTION_TYPE_NAME": "type", - "REPLUGGED_COMMAND_LIST_OPTION_TYPE_DESC": "What type of addons to show", - "REPLUGGED_COMMAND_LIST_OPTION_TYPE_CHOICE_PLUGIN": "List Plugins", - "REPLUGGED_COMMAND_LIST_OPTION_TYPE_CHOICE_THEME": "List Themes", - "REPLUGGED_COMMAND_LIST_OPTION_VERSION_NAME": "version", - "REPLUGGED_COMMAND_LIST_OPTION_VERSION_DESC": "Include version numbers in the list", - "REPLUGGED_COMMAND_LIST_OPTION_STATUS_NAME": "status", - "REPLUGGED_COMMAND_LIST_OPTION_STATUS_DESC": "Whether to show addons that are enabled, disabled or both", - "REPLUGGED_COMMAND_LIST_OPTION_STATUS_CHOICE_ENABLED": "Enabled", - "REPLUGGED_COMMAND_LIST_OPTION_STATUS_CHOICE_DISABLED": "Disabled", - "REPLUGGED_COMMAND_LIST_OPTION_STATUS_CHOICE_BOTH": "Both", - "REPLUGGED_COMMAND_LIST_HEADER_ENABLED": "Enabled {type}", - "REPLUGGED_COMMAND_LIST_HEADER_DISABLED": "Disabled {type}", - "REPLUGGED_COMMAND_LIST_ERROR_SPECIFY": "You need to specify whether to send a plugin or theme list", - "REPLUGGED_COMMAND_INSTALL_NAME": "install", - "REPLUGGED_COMMAND_INSTALL_DESC": "Install a plugin or theme", - "REPLUGGED_COMMAND_INSTALL_OPTION_ADDON_NAME": "addon", - "REPLUGGED_COMMAND_INSTALL_OPTION_ADDON_DESC": "Identifier of the addon to install from the source", - "REPLUGGED_COMMAND_INSTALL_OPTION_SOURCE_NAME": "source", - "REPLUGGED_COMMAND_INSTALL_OPTION_SOURCE_DESC": "Source to install the addon from", - "REPLUGGED_COMMAND_INSTALL_OPTION_ID_NAME": "id", - "REPLUGGED_COMMAND_INSTALL_OPTION_ID_DESC": "If the source has multiple addons, specify which one to install", - "REPLUGGED_ERROR_ALREADY_INSTALLED": "{name} is already installed.", - "REPLUGGED_ERROR_AN_ERROR_OCCURRED_COMMAND": "An error occurred while executing the command:", - "REPLUGGED_ERROR_CHECK_CONSOLE": "Check the console for more details.", - "REPLUGGED_GENERAL_SETTINGS": "General Settings", - "REPLUGGED_I18N_CONTRIBUTE": "Want to help translate Replugged? Go to our [Weblate]({weblateUrl})!", - "REPLUGGED_I18N_TRANSLATED_PERCENTAGE": "Replugged: {translated,number}% translated", - "REPLUGGED_INSTALL_MODAL_HEADER": "Install {type}", - "REPLUGGED_LINK_NOW": "Link it now", - "REPLUGGED_NOTICES_WELCOME_NEW_USER": "Welcome! Replugged has been successfully injected into your Discord client. Feel free to join our Discord server for announcements, support and more!", - "REPLUGGED_NOTICES_JOIN_SERVER_BUTTON": "Join Server", - "REPLUGGED_PLUGIN": "Plugin", - "REPLUGGED_PLUGINS": "Plugins", - "REPLUGGED_QUICKCSS": "Quick CSS", - "REPLUGGED_SETTINGS_ADVANCED_DESC": "Don't touch stuff in here if you don't know what you're doing. Unexpected things can happen to your cat.", - "REPLUGGED_SETTINGS_BACKEND": "Backend URL", - "REPLUGGED_SETTINGS_BACKEND_DESC": "URL used to fetch some assets and to query Replugged's REST API.", - "REPLUGGED_SETTINGS_DISCORD_EXPERIMENTS": "Enable Discord Experiments", - "REPLUGGED_SETTINGS_DISCORD_EXPERIMENTS_DESC": "****WARNING:**** Enabling this gives you access to features that can be detected by Discord and may result in an ****account termination****. Replugged is **not responsible** for what you do with this feature. Leave it disabled if you are unsure. The Replugged Team will **not** provide any support regarding any experiment. **Requires restart**.", - "REPLUGGED_SETTINGS_ERROR_HEADER": "Something went wrong rendering this element!", - "REPLUGGED_SETTINGS_ERROR_RENDER_PANEL": "An error occurred while rendering settings panel.", - "REPLUGGED_SETTINGS_ERROR_COMPONENT_STACK": "Component stack:", - "REPLUGGED_SETTINGS_KEEP_TOKEN": "Keep token stored", - "REPLUGGED_SETTINGS_KEEP_TOKEN_DESC": "Prevents Discord from removing your token from localStorage, reducing the numbers of unwanted logouts.", - "REPLUGGED_SETTINGS_NO_CLYDE": "Eradicate Clyde", - "REPLUGGED_SETTINGS_NO_CLYDE_DESC": "Replaces [Clyde]({clydeUrl}) in Replugged commands with a mixed range of avatars and usernames selected by plug-in developers - fallbacks to \"Replugged\" by default.", - "REPLUGGED_SETTINGS_OVERLAY": "Overlay DevTools", - "REPLUGGED_SETTINGS_OVERLAY_DESC": "Opens a DevTools window that lets you inspect what's happening within Discord's in-game overlay.", - "REPLUGGED_SETTINGS_RESTART": "This setting requires you to restart Discord to take effect. Do you want to restart Discord now?", - "REPLUGGED_SNIPPET_APPLIED": "Snippet Applied", - "REPLUGGED_SNIPPET_APPLY": "Apply Snippet", - "REPLUGGED_SNIPPET_LINE1": "Snippet from #css-snippets applied the {date, date, medium} at {date, time, medium}", - "REPLUGGED_SNIPPET_LINE2": "Created by {authorTag} ({authorId})", - "REPLUGGED_THEME": "Theme", - "REPLUGGED_THEMES": "Themes", - "REPLUGGED_UPDATES_AVAILABLE": "{count, plural, =1 {# update is} other {# updates are}} available.", - "REPLUGGED_UPDATES_AWAITING_RELOAD_TITLE": "Reload Required", - "REPLUGGED_UPDATES_CHECK": "Check for Updates", - "REPLUGGED_UPDATES_ENABLE": "Enable Updates", - "REPLUGGED_UPDATES_FAILED": "Some updates failed!", - "REPLUGGED_UPDATES_FORCE": "Force Update", - "REPLUGGED_UPDATES_LAST_CHECKED": "Last checked: {date}", - "REPLUGGED_UPDATES_OPEN_UPDATER": "Open Updater", - "REPLUGGED_UPDATES_OPTS_AUTO": "Check for updates automatically", - "REPLUGGED_UPDATES_OPTS_AUTO_DESC": "Replugged will automatically check for updates and show you an alert when one is available. Updates will not be installed until you choose to update it. Only official addons will be checked automatically.", - "REPLUGGED_UPDATES_OPTS_CHANGE_LOGS": "Open Change Log", - "REPLUGGED_UPDATES_OPTS_CHANGE_LOGS_DESC": "Missed the change log, or want to see it again?", - "REPLUGGED_UPDATES_OPTS_CONCURRENCY": "Update Concurrency Limit", - "REPLUGGED_UPDATES_OPTS_CONCURRENCY_DESC": "How many concurrent tasks Replugged will run in background to check for updates. Minimum 1. If unsure, leave 2.", - "REPLUGGED_UPDATES_OPTS_DEBUG": "Debugging Information", - "REPLUGGED_UPDATES_OPTS_DEBUG_DESC": "Things that you may find useful for troubleshooting or flexing on some stats.", - "REPLUGGED_UPDATES_OPTS_DEBUG_CATEGORY_SYSTEM_DISCORD": "System / Discord", - "REPLUGGED_UPDATES_OPTS_DEBUG_CATEGORY_PROCESS_VERSIONS": "Process Versions", - "REPLUGGED_UPDATES_OPTS_DEBUG_LOCALE": "Locale:", - "REPLUGGED_UPDATES_OPTS_DEBUG_OS": "OS:", - "REPLUGGED_UPDATES_OPTS_DEBUG_OS_64BIT": "64-bit", - "REPLUGGED_UPDATES_OPTS_DEBUG_ARCH": "Architecture:", - "REPLUGGED_UPDATES_OPTS_DEBUG_DISTRO": "Distro:", - "REPLUGGED_UPDATES_OPTS_DEBUG_RELEASE_CHANNEL": "Release Channel:", - "REPLUGGED_UPDATES_OPTS_DEBUG_APP_VERSION": "App Version:", - "REPLUGGED_UPDATES_OPTS_DEBUG_BUILD_NUMBER": "Build Number:", - "REPLUGGED_UPDATES_OPTS_DEBUG_BUILD_ID": "Build ID:", - "REPLUGGED_UPDATES_OPTS_DEBUG_EXPERIMENTS": "Experiments:", - "REPLUGGED_UPDATES_OPTS_DEBUG_COMMANDS": "Commands:", - "REPLUGGED_UPDATES_OPTS_DEBUG_COPIED": "Copied!", - "REPLUGGED_UPDATES_OPTS_DEBUG_COPY": "Copy", - "REPLUGGED_UPDATES_OPTS_DEBUG_SETTINGS": "Settings:", - "REPLUGGED_UPDATES_OPTS_DEBUG_PLUGINS": "Plugins:", - "REPLUGGED_UPDATES_OPTS_DEBUG_PLUGINS_SHOW_LESS": "Show less", - "REPLUGGED_UPDATES_OPTS_DEBUG_PLUGINS_SHOW_MORE": "Show more", - "REPLUGGED_UPDATES_OPTS_DEBUG_UNAUTHORIZED_PLUGINS": "Unauthorized plugins:", - "REPLUGGED_UPDATES_OPTS_DEBUG_BETTERDISCORD_PLUGINS": "BetterDiscord Plugins:", - "REPLUGGED_UPDATES_OPTS_DEBUG_THEMES": "Themes:", - "REPLUGGED_UPDATES_OPTS_DEBUG_LABS": "Labs:", - "REPLUGGED_UPDATES_OPTS_DEBUG_SETTINGS_SYNC": "Settings Sync:", - "REPLUGGED_UPDATES_OPTS_DEBUG_CACHED_FILES": "Cached Files:", - "REPLUGGED_UPDATES_OPTS_DEBUG_ACCOUNT": "Account:", - "REPLUGGED_UPDATES_OPTS_DEBUG_APIS": "APIs:", - "REPLUGGED_UPDATES_OPTS_DEBUG_CONNECTIONS": "Connections:", - "REPLUGGED_UPDATES_OPTS_DEBUG_UPSTREAM": "Upstream:", - "REPLUGGED_UPDATES_OPTS_DEBUG_REVISION": "Revision:", - "REPLUGGED_UPDATES_OPTS_DEBUG_BRANCH": "Branch:", - "REPLUGGED_UPDATES_OPTS_DEBUG_LATEST": "Latest:", - "REPLUGGED_UPDATES_OPTS_DEBUG_REPLUGGED_PATH": "Replugged Path", - "REPLUGGED_UPDATES_OPTS_DEBUG_DISCORD_PATH": "Discord Path", - "REPLUGGED_UPDATES_OPTS_INTERVAL": "Update Check Interval", - "REPLUGGED_UPDATES_OPTS_INTERVAL_DESC": "How frequently Replugged will check for updates. Minimum 10 minutes.", - "REPLUGGED_UPDATES_OPTS_RELEASE": "Change Release Channel", - "REPLUGGED_UPDATES_OPTS_RELEASE_DESC": "You can choose between the stable branch, or the development branch. Stable branch will only get major updates, security and critical updates. If unsure, stay on stable.", - "REPLUGGED_UPDATES_OPTS_RELEASE_DEVELOP_BTN": "Switch to development branch", - "REPLUGGED_UPDATES_OPTS_RELEASE_MODAL": "Are you sure you want to change your release channel? Replugged will reload your Discord client.", - "REPLUGGED_UPDATES_OPTS_RELEASE_MODAL_HEADER": "Change release channel", - "REPLUGGED_UPDATES_OPTS_RELEASE_STABLE_BTN": "Switch to stable", - "REPLUGGED_UPDATES_OPTS_RELEASE_SWITCH": "Switch", - "REPLUGGED_UPDATES_OPTS_TOAST_ENABLED": "Show update checker toast", - "REPLUGGED_UPDATES_OPTS_TOAST_ENABLED_DESC": "Show an overlay over the client which says updates are being checked for, and if updates are found, prompt you to update. Only applies if update in background is disabled.", - "REPLUGGED_UPDATES_UPDATER": "Updater", - "REPLUGGED_UPDATES_UPDATE": "Update", - "REPLUGGED_UPDATES_UPDATING": "Updating Replugged…", - "REPLUGGED_UPDATES_UPDATING_ITEM": "Updating…", - "REPLUGGED_UPDATES_UP_TO_DATE": "Everything is up to date.", - "REPLUGGED_PLUGIN_EMBED_COPY": "Copy Link", - "REPLUGGED_PLUGIN_EMBED_VIEW_REPO": "View Repo", - "REPLUGGED_PLUGIN_EMBED_COPIED": "Copied!", - "REPLUGGED_PLUGIN_EMBED_WHATISTHIS": "What is this?", - "REPLUGGED_PLUGIN_EMBED_WHATISTHIS_CONTENT": "This is a Replugged feature. It allows you to install plugins or themes straight from chat.\nSimply hit the install button on the embed.", - "REPLUGGED_ADDON_DELETE": "Delete {type}", - "REPLUGGED_ADDON_PAGE_OPEN": "Open {type} Page", - "REPLUGGED_ADDON_PROFILE_OPEN": "Open {type} Profile", - "REPLUGGED_ADDON_RELOAD": "Reload {type}", - "REPLUGGED_ADDON_SETTINGS": "Open {type} Settings", - "REPLUGGED_ADDON_UNINSTALL_PROMPT_BODY": "Are you sure you want to uninstall this {type}? This cannot be undone.", - "REPLUGGED_ADDON_UNINSTALL": "Uninstall {name}", - "REPLUGGED_ADDONS_FOLDER_OPEN": "Open {type} Folder", - "REPLUGGED_ADDONS_LOAD_MISSING": "Load Missing {type}", - "REPLUGGED_ADDONS_TITLE_COUNT": "{type} ({count, number})", - "REPLUGGED_LIST_RESULTS": "{count, plural, =1 {# match} other {# matches}}", - "REPLUGGED_NO_ADDON_RESULTS": "No {type} matched your search.", - "REPLUGGED_NO_ADDONS_INSTALLED": "No {type} installed.", - "REPLUGGED_QUICKCSS_CHANGES_APPLY": "Apply Changes", - "REPLUGGED_SEARCH_FOR_ADDON": "Search for a {type}", - "REPLUGGED_TOAST_ADDON_DISABLE_SUCCESS": "Disabled {name}", - "REPLUGGED_TOAST_ADDON_ENABLE_SUCCESS": "Enabled {name}", - "REPLUGGED_TOAST_ADDON_RELOAD_FAILED": "Failed to reload {name}", - "REPLUGGED_TOAST_ADDON_RELOAD_SUCCESS": "Reloaded {name}", - "REPLUGGED_TOAST_ADDON_TOGGLE_FAILED": "Failed to toggle {name}", - "REPLUGGED_TOAST_ADDON_UNINSTALL_FAILED": "Failed to uninstall {name}", - "REPLUGGED_TOAST_ADDON_UNINSTALL_SUCCESS": "Uninstalled {name}", - "REPLUGGED_TOAST_ADDONS_LOAD_MISSING_FAILED": "Failed to load missing {type}", - "REPLUGGED_TOAST_ADDONS_LOAD_MISSING_SUCCESS": "Loaded missing {type}", - "REPLUGGED_TOAST_PROFILE_FETCH_FAILED": "Failed to fetch user profile", - "REPLUGGED_TOAST_QUICKCSS_CODE_FORMAT_FAILED": "Failed to format code", - "REPLUGGED_TOAST_QUICKCSS_CODE_FORMAT_SUCCESS": "Code formatted", - "REPLUGGED_TOAST_QUICKCSS_RELOAD": "Quick CSS reloaded", - "REPLUGGED_SETTINGS_ERROR_SUB_HEADER": "Check console for details.", - "REPLUGGED_INSTALLER_INSTALL_PROMPT_BODY": "Do you want to install {name} {authors}?", - "REPLUGGED_TOAST_INSTALLER_ADDON_INSTALL_FAILED": "Failed to install {name}.", - "REPLUGGED_TOAST_INSTALLER_ADDON_LOAD_FAILED": "{name} was installed but could not be loaded.", - "REPLUGGED_TOAST_INSTALLER_ADDON_INSTALL_SUCCESS": "{name} installed successfully.", - "REPLUGGED_TOAST_INSTALLER_ADDON_FETCH_INFO_FAILED": "Failed to get info for addon.", - "REPLUGGED_TOAST_INSTALLER_ADDON_CANCELED_INSTALL": "Install canceled.", - "REPLUGGED_QUICKCSS_FOLDER_OPEN": "Open Quick CSS Folder", - "REPLUGGED_ADDON_AUTHORS_ONE": "by {author1}", - "REPLUGGED_ADDON_AUTHORS_TWO": "by {author1} and {author2}", - "REPLUGGED_ADDON_AUTHORS_THREE": "by {author1}, {author2}, and {author3}", - "REPLUGGED_ADDON_AUTHORS_MANY": "by {author1}, {author2}, {author3}, and {count, plural, =1 {# other} other {# others}}", - "REPLUGGED_CONFIRM_INSTALL": "Install", - "REPLUGGED_UPDATES_UPDATE_ALL": "Update All", - "REPLUGGED_UPDATES_UPDATE_TO": "Update to {version}", - "REPLUGGED_UPDATES_TOAST_NO_NEW": "No new updates available.", - "REPLUGGED_UPDATES_TOAST_NEW": "{count, plural, =1 {# new update} other {# new updates}} available!", - "REPLUGGED_UPDATES_TOAST_FAILED_ONE": "Update failed!", - "REPLUGGED_UPDATES_TOAST_FAILED_ALL": "Some updates failed!", - "REPLUGGED_UPDATES_TOAST_SUCCESS_ONE": "Update completed successfully.", - "REPLUGGED_UPDATES_TOAST_SUCCESS_ALL": "All updates completed successfully.", - "REPLUGGED_PLUGIN_INSTALL_RELOAD_PROMPT_BODY": "{name} requires a reload to work properly. Reload now?", - "REPLUGGED_RELOAD": "Reload", - "REPLUGGED_UPDATES_UPDATE_NOUN": "Update", - "REPLUGGED_VERSION": "Replugged {version, select, dev {[DEV MODE]} other {v{version}}}", - "REPLUGGED_SETTINGS_BADGES": "Enable Replugged Badges", - "REPLUGGED_SETTINGS_BADGES_DESC": "Show custom Replugged badges on user profiles.", - "REPLUGGED_I18N": "Replugged Translations", - "REPLUGGED_VIEW_UPDATES": "View {count, plural, =1 {# Update} other {# Updates}}", - "REPLUGGED_DEVELOPER_MODE_WARNING": "You are currently running Replugged in developer mode and Replugged will not be able to update itself. [Switch to production mode]({url}).", - "REPLUGGED_ADDON_BROWSE": "Browse {type}", - "REPLUGGED_ADDON_NOT_REVIEWED": "Unreviewed {type}", - "REPLUGGED_ADDON_NOT_REVIEWED_DESC": "This {type} has not been reviewed by the Replugged team and could harm your computer. Use at your own risk.", - "REPLUGGED_SETTINGS_QUICKCSS_AUTO_APPLY": "Automatically Apply Quick CSS", - "REPLUGGED_SETTINGS_QUICKCSS_AUTO_APPLY_DESC": "Automatically apply changes to Quick CSS as you type.", - "REPLUGGED_SETTINGS_DEV_COMPANION": "Reconnect Dev Companion", - "REPLUGGED_SETTINGS_DEV_COMPANION_DESC": "Reconnects the Dev Companion coremod to the VSCode extension.", - "REPLUGGED_SETTINGS_DEV_COMPANION_RECONNECT": "Reconnect", - "REPLUGGED_SETTINGS_ADVANCED": "Advanced Settings", - "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY": "Automatic Recovery", - "REPLUGGED_SETTINGS_AUTOMATIC_RECOVERY_DESC": "Allows Discord to try to automatically recover from a crash.", - "REPLUGGED_SETTINGS_REACT_DEVTOOLS": "Enable React DevTools", - "REPLUGGED_SETTINGS_REACT_DEVTOOLS_DESC": "Loads the React DevTools extension, allowing you to inspect the React tree and debug more easily. **Requires restart**.", - "REPLUGGED_SETTINGS_REACT_DEVTOOLS_FAILED": "Failed to download React DevTools.", - "REPLUGGED_INSTALLER_OPEN_STORE": "View in Store", - "REPLUGGED_SETTINGS_ADDON_EMBEDS": "Show Addon Embeds", - "REPLUGGED_SETTINGS_ADDON_EMBEDS_DESC": "Show a card with information on an addon when a store/install link is shared in chat.", - "REPLUGGED_RESTART": "Restart", - "REPLUGGED_SETTINGS_RESTART_TITLE": "Restart Required", - "REPLUGGED_SETTINGS_TRANSPARENT": "Transparent Window", - "REPLUGGED_SETTINGS_TRANSPARENT_DESC": "Makes the Discord window transparent, primarily useful for theming. **Requires restart**.", - "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_WINDOWS": "****WARNING:**** This will break **window snapping**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", - "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_LINUX": "****WARNING:**** **Hardware acceleration** may need to be turned **off**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", - "REPLUGGED_SETTINGS_ERROR_PLUGIN_NAME": "Plugin: {name}", - "REPLUGGED_STORE": "Store" + "REPLUGGED_ACCOUNT": "Replugged Account", + "REPLUGGED_BADGES_CONTRIBUTOR": "Replugged Contributor", + "REPLUGGED_BADGES_DEVELOPER": "Replugged Developer", + "REPLUGGED_BADGES_EARLY": "Replugged Early User", + "REPLUGGED_BADGES_HUNTER": "Replugged Bug Hunter", + "REPLUGGED_BADGES_STAFF": "Replugged Staff", + "REPLUGGED_BADGES_SUPPORT": "Replugged Support", + "REPLUGGED_BADGES_TRANSLATOR": "Replugged Translator", + "REPLUGGED_BADGES_BOOSTER": "Replugged Server Booster", + "REPLUGGED_BUTTON_GOT_IT": "Got It", + "REPLUGGED_BUTTON_INSTALLER_INSTALLED": "{type} Installed", + "REPLUGGED_BUTTON_INSTALLER_DOWNLOAD": "Download {type}", + "REPLUGGED_CANCEL": "Cancel", + "REPLUGGED_CONFIRM": "Confirm", + "REPLUGGED_OK": "OK", + "REPLUGGED_COMMAND_ERROR_GENERIC": "Something went wrong, please try again later. If this issue persists, please contact the Replugged team.", + "REPLUGGED_COMMAND_SUCCESS_GENERIC": "Success", + "REPLUGGED_COMMAND_ENABLE_NAME": "enable", + "REPLUGGED_COMMAND_ENABLE_DESC": "Enable a plugin or theme", + "REPLUGGED_COMMAND_ENABLE_OPTION_ADDON_NAME": "addon", + "REPLUGGED_COMMAND_ADDONS_OPTION_ADDON_DESC": "Choose which addon to enable", + "REPLUGGED_COMMAND_ENABLE_MESSAGE_ENABLED": "{type} {name} has been enabled!", + "REPLUGGED_COMMAND_DISABLE_NAME": "disable", + "REPLUGGED_COMMAND_DISABLE_DESC": "Disable a plugin or theme", + "REPLUGGED_COMMAND_DISABLE_OPTION_ADDON_NAME": "addon", + "REPLUGGED_COMMAND_DISABLE_OPTION_ADDON_DESC": "Choose which addon to disable", + "REPLUGGED_COMMAND_DISABLE_MESSAGE_ENABLED": "{type} {name} has been disabled!", + "REPLUGGED_COMMAND_RELOAD_NAME": "reload", + "REPLUGGED_COMMAND_RELOAD_DESC": "Reload a plugin or theme", + "REPLUGGED_COMMAND_RELOAD_OPTION_ADDON_NAME": "addon", + "REPLUGGED_COMMAND_RELOAD_OPTION_ADDON_DESC": "Choose which addon to reload", + "REPLUGGED_COMMAND_RELOAD_MESSAGE_ENABLED": "{type} {name} has been reloaded!", + "REPLUGGED_COMMAND_LIST_NAME": "list", + "REPLUGGED_COMMAND_LIST_DESC": "List all plugins or themes", + "REPLUGGED_COMMAND_LIST_OPTION_SEND_NAME": "send", + "REPLUGGED_COMMAND_LIST_OPTION_SEND_DESC": "Share the list publicly in chat", + "REPLUGGED_COMMAND_LIST_OPTION_TYPE_NAME": "type", + "REPLUGGED_COMMAND_LIST_OPTION_TYPE_DESC": "What type of addons to show", + "REPLUGGED_COMMAND_LIST_OPTION_TYPE_CHOICE_PLUGIN": "List Plugins", + "REPLUGGED_COMMAND_LIST_OPTION_TYPE_CHOICE_THEME": "List Themes", + "REPLUGGED_COMMAND_LIST_OPTION_VERSION_NAME": "version", + "REPLUGGED_COMMAND_LIST_OPTION_VERSION_DESC": "Include version numbers in the list", + "REPLUGGED_COMMAND_LIST_OPTION_STATUS_NAME": "status", + "REPLUGGED_COMMAND_LIST_OPTION_STATUS_DESC": "Whether to show addons that are enabled, disabled or both", + "REPLUGGED_COMMAND_LIST_OPTION_STATUS_CHOICE_ENABLED": "Enabled", + "REPLUGGED_COMMAND_LIST_OPTION_STATUS_CHOICE_DISABLED": "Disabled", + "REPLUGGED_COMMAND_LIST_OPTION_STATUS_CHOICE_BOTH": "Both", + "REPLUGGED_COMMAND_LIST_HEADER_ENABLED": "Enabled {type}", + "REPLUGGED_COMMAND_LIST_HEADER_DISABLED": "Disabled {type}", + "REPLUGGED_COMMAND_LIST_ERROR_SPECIFY": "You need to specify whether to send a plugin or theme list", + "REPLUGGED_COMMAND_INSTALL_NAME": "install", + "REPLUGGED_COMMAND_INSTALL_DESC": "Install a plugin or theme", + "REPLUGGED_COMMAND_INSTALL_OPTION_ADDON_NAME": "addon", + "REPLUGGED_COMMAND_INSTALL_OPTION_ADDON_DESC": "Identifier of the addon to install from the source", + "REPLUGGED_COMMAND_INSTALL_OPTION_SOURCE_NAME": "source", + "REPLUGGED_COMMAND_INSTALL_OPTION_SOURCE_DESC": "Source to install the addon from", + "REPLUGGED_COMMAND_INSTALL_OPTION_ID_NAME": "id", + "REPLUGGED_COMMAND_INSTALL_OPTION_ID_DESC": "If the source has multiple addons, specify which one to install", + "REPLUGGED_ERROR_ALREADY_INSTALLED": "{name} is already installed.", + "REPLUGGED_ERROR_AN_ERROR_OCCURRED_COMMAND": "An error occurred while executing the command:", + "REPLUGGED_ERROR_CHECK_CONSOLE": "Check the console for more details.", + "REPLUGGED_GENERAL_SETTINGS": "General Settings", + "REPLUGGED_I18N_CONTRIBUTE": "Want to help translate Replugged? Go to our [Weblate]({weblateUrl})!", + "REPLUGGED_I18N_TRANSLATED_PERCENTAGE": "Replugged: {translated,number}% translated", + "REPLUGGED_INSTALL_MODAL_HEADER": "Install {type}", + "REPLUGGED_LINK_NOW": "Link it now", + "REPLUGGED_NOTICES_WELCOME_NEW_USER": "Welcome! Replugged has been successfully injected into your Discord client. Feel free to join our Discord server for announcements, support and more!", + "REPLUGGED_NOTICES_JOIN_SERVER_BUTTON": "Join Server", + "REPLUGGED_PLUGIN": "Plugin", + "REPLUGGED_PLUGINS": "Plugins", + "REPLUGGED_QUICKCSS": "Quick CSS", + "REPLUGGED_SETTINGS_ADVANCED_DESC": "Don't touch stuff in here if you don't know what you're doing. Unexpected things can happen to your cat.", + "REPLUGGED_SETTINGS_BACKEND": "Backend URL", + "REPLUGGED_SETTINGS_BACKEND_DESC": "URL used to fetch some assets and to query Replugged's REST API.", + "REPLUGGED_SETTINGS_DISCORD_EXPERIMENTS": "Enable Discord Experiments", + "REPLUGGED_SETTINGS_DISCORD_EXPERIMENTS_DESC": "****WARNING:**** Enabling this gives you access to features that can be detected by Discord and may result in an ****account termination****. Replugged is **not responsible** for what you do with this feature. Leave it disabled if you are unsure. The Replugged Team will **not** provide any support regarding any experiment. **Requires restart**.", + "REPLUGGED_SETTINGS_ERROR_HEADER": "Something went wrong rendering this element!", + "REPLUGGED_SETTINGS_ERROR_RENDER_PANEL": "An error occurred while rendering settings panel.", + "REPLUGGED_SETTINGS_ERROR_COMPONENT_STACK": "Component stack:", + "REPLUGGED_SETTINGS_KEEP_TOKEN": "Keep token stored", + "REPLUGGED_SETTINGS_KEEP_TOKEN_DESC": "Prevents Discord from removing your token from localStorage, reducing the numbers of unwanted logouts.", + "REPLUGGED_SETTINGS_NO_CLYDE": "Eradicate Clyde", + "REPLUGGED_SETTINGS_NO_CLYDE_DESC": "Replaces [Clyde]({clydeUrl}) in Replugged commands with a mixed range of avatars and usernames selected by plug-in developers - fallbacks to \"Replugged\" by default.", + "REPLUGGED_SETTINGS_OVERLAY": "Overlay DevTools", + "REPLUGGED_SETTINGS_OVERLAY_DESC": "Opens a DevTools window that lets you inspect what's happening within Discord's in-game overlay.", + "REPLUGGED_SETTINGS_RESTART": "This setting requires you to restart Discord to take effect. Do you want to restart Discord now?", + "REPLUGGED_SNIPPET_APPLIED": "Snippet Applied", + "REPLUGGED_SNIPPET_APPLY": "Apply Snippet", + "REPLUGGED_SNIPPET_LINE1": "Snippet from #css-snippets applied the {date, date, medium} at {date, time, medium}", + "REPLUGGED_SNIPPET_LINE2": "Created by {authorTag} ({authorId})", + "REPLUGGED_THEME": "Theme", + "REPLUGGED_THEMES": "Themes", + "REPLUGGED_UPDATES_AVAILABLE": "{count, plural, =1 {# update is} other {# updates are}} available.", + "REPLUGGED_UPDATES_AWAITING_RELOAD_TITLE": "Reload Required", + "REPLUGGED_UPDATES_CHECK": "Check for Updates", + "REPLUGGED_UPDATES_ENABLE": "Enable Updates", + "REPLUGGED_UPDATES_FAILED": "Some updates failed!", + "REPLUGGED_UPDATES_FORCE": "Force Update", + "REPLUGGED_UPDATES_LAST_CHECKED": "Last checked: {date}", + "REPLUGGED_UPDATES_OPEN_UPDATER": "Open Updater", + "REPLUGGED_UPDATES_OPTS_AUTO": "Check for updates automatically", + "REPLUGGED_UPDATES_OPTS_AUTO_DESC": "Replugged will automatically check for updates and show you an alert when one is available. Updates will not be installed until you choose to update it. Only official addons will be checked automatically.", + "REPLUGGED_UPDATES_OPTS_CHANGE_LOGS": "Open Change Log", + "REPLUGGED_UPDATES_OPTS_CHANGE_LOGS_DESC": "Missed the change log, or want to see it again?", + "REPLUGGED_UPDATES_OPTS_CONCURRENCY": "Update Concurrency Limit", + "REPLUGGED_UPDATES_OPTS_CONCURRENCY_DESC": "How many concurrent tasks Replugged will run in background to check for updates. Minimum 1. If unsure, leave 2.", + "REPLUGGED_UPDATES_OPTS_DEBUG": "Debugging Information", + "REPLUGGED_UPDATES_OPTS_DEBUG_DESC": "Things that you may find useful for troubleshooting or flexing on some stats.", + "REPLUGGED_UPDATES_OPTS_DEBUG_CATEGORY_SYSTEM_DISCORD": "System / Discord", + "REPLUGGED_UPDATES_OPTS_DEBUG_CATEGORY_PROCESS_VERSIONS": "Process Versions", + "REPLUGGED_UPDATES_OPTS_DEBUG_LOCALE": "Locale:", + "REPLUGGED_UPDATES_OPTS_DEBUG_OS": "OS:", + "REPLUGGED_UPDATES_OPTS_DEBUG_OS_64BIT": "64-bit", + "REPLUGGED_UPDATES_OPTS_DEBUG_ARCH": "Architecture:", + "REPLUGGED_UPDATES_OPTS_DEBUG_DISTRO": "Distro:", + "REPLUGGED_UPDATES_OPTS_DEBUG_RELEASE_CHANNEL": "Release Channel:", + "REPLUGGED_UPDATES_OPTS_DEBUG_APP_VERSION": "App Version:", + "REPLUGGED_UPDATES_OPTS_DEBUG_BUILD_NUMBER": "Build Number:", + "REPLUGGED_UPDATES_OPTS_DEBUG_BUILD_ID": "Build ID:", + "REPLUGGED_UPDATES_OPTS_DEBUG_EXPERIMENTS": "Experiments:", + "REPLUGGED_UPDATES_OPTS_DEBUG_COMMANDS": "Commands:", + "REPLUGGED_UPDATES_OPTS_DEBUG_COPIED": "Copied!", + "REPLUGGED_UPDATES_OPTS_DEBUG_COPY": "Copy", + "REPLUGGED_UPDATES_OPTS_DEBUG_SETTINGS": "Settings:", + "REPLUGGED_UPDATES_OPTS_DEBUG_PLUGINS": "Plugins:", + "REPLUGGED_UPDATES_OPTS_DEBUG_PLUGINS_SHOW_LESS": "Show less", + "REPLUGGED_UPDATES_OPTS_DEBUG_PLUGINS_SHOW_MORE": "Show more", + "REPLUGGED_UPDATES_OPTS_DEBUG_UNAUTHORIZED_PLUGINS": "Unauthorized plugins:", + "REPLUGGED_UPDATES_OPTS_DEBUG_BETTERDISCORD_PLUGINS": "BetterDiscord Plugins:", + "REPLUGGED_UPDATES_OPTS_DEBUG_THEMES": "Themes:", + "REPLUGGED_UPDATES_OPTS_DEBUG_LABS": "Labs:", + "REPLUGGED_UPDATES_OPTS_DEBUG_SETTINGS_SYNC": "Settings Sync:", + "REPLUGGED_UPDATES_OPTS_DEBUG_CACHED_FILES": "Cached Files:", + "REPLUGGED_UPDATES_OPTS_DEBUG_ACCOUNT": "Account:", + "REPLUGGED_UPDATES_OPTS_DEBUG_APIS": "APIs:", + "REPLUGGED_UPDATES_OPTS_DEBUG_CONNECTIONS": "Connections:", + "REPLUGGED_UPDATES_OPTS_DEBUG_UPSTREAM": "Upstream:", + "REPLUGGED_UPDATES_OPTS_DEBUG_REVISION": "Revision:", + "REPLUGGED_UPDATES_OPTS_DEBUG_BRANCH": "Branch:", + "REPLUGGED_UPDATES_OPTS_DEBUG_LATEST": "Latest:", + "REPLUGGED_UPDATES_OPTS_DEBUG_REPLUGGED_PATH": "Replugged Path", + "REPLUGGED_UPDATES_OPTS_DEBUG_DISCORD_PATH": "Discord Path", + "REPLUGGED_UPDATES_OPTS_INTERVAL": "Update Check Interval", + "REPLUGGED_UPDATES_OPTS_INTERVAL_DESC": "How frequently Replugged will check for updates. Minimum 10 minutes.", + "REPLUGGED_UPDATES_OPTS_RELEASE": "Change Release Channel", + "REPLUGGED_UPDATES_OPTS_RELEASE_DESC": "You can choose between the stable branch, or the development branch. Stable branch will only get major updates, security and critical updates. If unsure, stay on stable.", + "REPLUGGED_UPDATES_OPTS_RELEASE_DEVELOP_BTN": "Switch to development branch", + "REPLUGGED_UPDATES_OPTS_RELEASE_MODAL": "Are you sure you want to change your release channel? Replugged will reload your Discord client.", + "REPLUGGED_UPDATES_OPTS_RELEASE_MODAL_HEADER": "Change release channel", + "REPLUGGED_UPDATES_OPTS_RELEASE_STABLE_BTN": "Switch to stable", + "REPLUGGED_UPDATES_OPTS_RELEASE_SWITCH": "Switch", + "REPLUGGED_UPDATES_OPTS_TOAST_ENABLED": "Show update checker toast", + "REPLUGGED_UPDATES_OPTS_TOAST_ENABLED_DESC": "Show an overlay over the client which says updates are being checked for, and if updates are found, prompt you to update. Only applies if update in background is disabled.", + "REPLUGGED_UPDATES_UPDATER": "Updater", + "REPLUGGED_UPDATES_UPDATE": "Update", + "REPLUGGED_UPDATES_UPDATING": "Updating Replugged…", + "REPLUGGED_UPDATES_UPDATING_ITEM": "Updating…", + "REPLUGGED_UPDATES_UP_TO_DATE": "Everything is up to date.", + "REPLUGGED_PLUGIN_EMBED_COPY": "Copy Link", + "REPLUGGED_PLUGIN_EMBED_VIEW_REPO": "View Repo", + "REPLUGGED_PLUGIN_EMBED_COPIED": "Copied!", + "REPLUGGED_PLUGIN_EMBED_WHATISTHIS": "What is this?", + "REPLUGGED_PLUGIN_EMBED_WHATISTHIS_CONTENT": "This is a Replugged feature. It allows you to install plugins or themes straight from chat.\nSimply hit the install button on the embed.", + "REPLUGGED_ADDON_DELETE": "Delete {type}", + "REPLUGGED_ADDON_PAGE_OPEN": "Open {type} Page", + "REPLUGGED_ADDON_PROFILE_OPEN": "Open {type} Profile", + "REPLUGGED_ADDON_RELOAD": "Reload {type}", + "REPLUGGED_ADDON_SETTINGS": "Open {type} Settings", + "REPLUGGED_ADDON_UNINSTALL_PROMPT_BODY": "Are you sure you want to uninstall this {type}? This cannot be undone.", + "REPLUGGED_ADDON_UNINSTALL": "Uninstall {name}", + "REPLUGGED_ADDONS_FOLDER_OPEN": "Open {type} Folder", + "REPLUGGED_ADDONS_LOAD_MISSING": "Load Missing {type}", + "REPLUGGED_ADDONS_TITLE_COUNT": "{type} ({count, number})", + "REPLUGGED_LIST_RESULTS": "{count, plural, =1 {# match} other {# matches}}", + "REPLUGGED_NO_ADDON_RESULTS": "No {type} matched your search.", + "REPLUGGED_NO_ADDONS_INSTALLED": "No {type} installed.", + "REPLUGGED_QUICKCSS_CHANGES_APPLY": "Apply Changes", + "REPLUGGED_SEARCH_FOR_ADDON": "Search for a {type}", + "REPLUGGED_TOAST_ADDON_DISABLE_SUCCESS": "Disabled {name}", + "REPLUGGED_TOAST_ADDON_ENABLE_SUCCESS": "Enabled {name}", + "REPLUGGED_TOAST_ADDON_RELOAD_FAILED": "Failed to reload {name}", + "REPLUGGED_TOAST_ADDON_RELOAD_SUCCESS": "Reloaded {name}", + "REPLUGGED_TOAST_ADDON_TOGGLE_FAILED": "Failed to toggle {name}", + "REPLUGGED_TOAST_ADDON_UNINSTALL_FAILED": "Failed to uninstall {name}", + "REPLUGGED_TOAST_ADDON_UNINSTALL_SUCCESS": "Uninstalled {name}", + "REPLUGGED_TOAST_ADDONS_LOAD_MISSING_FAILED": "Failed to load missing {type}", + "REPLUGGED_TOAST_ADDONS_LOAD_MISSING_SUCCESS": "Loaded missing {type}", + "REPLUGGED_TOAST_PROFILE_FETCH_FAILED": "Failed to fetch user profile", + "REPLUGGED_TOAST_QUICKCSS_CODE_FORMAT_FAILED": "Failed to format code", + "REPLUGGED_TOAST_QUICKCSS_CODE_FORMAT_SUCCESS": "Code formatted", + "REPLUGGED_TOAST_QUICKCSS_RELOAD": "Quick CSS reloaded", + "REPLUGGED_SETTINGS_ERROR_SUB_HEADER": "Check console for details.", + "REPLUGGED_INSTALLER_INSTALL_PROMPT_BODY": "Do you want to install {name} {authors}?", + "REPLUGGED_TOAST_INSTALLER_ADDON_INSTALL_FAILED": "Failed to install {name}.", + "REPLUGGED_TOAST_INSTALLER_ADDON_LOAD_FAILED": "{name} was installed but could not be loaded.", + "REPLUGGED_TOAST_INSTALLER_ADDON_INSTALL_SUCCESS": "{name} installed successfully.", + "REPLUGGED_TOAST_INSTALLER_ADDON_FETCH_INFO_FAILED": "Failed to get info for addon.", + "REPLUGGED_TOAST_INSTALLER_ADDON_CANCELED_INSTALL": "Install canceled.", + "REPLUGGED_QUICKCSS_FOLDER_OPEN": "Open Quick CSS Folder", + "REPLUGGED_ADDON_AUTHORS_ONE": "by {author1}", + "REPLUGGED_ADDON_AUTHORS_TWO": "by {author1} and {author2}", + "REPLUGGED_ADDON_AUTHORS_THREE": "by {author1}, {author2}, and {author3}", + "REPLUGGED_ADDON_AUTHORS_MANY": "by {author1}, {author2}, {author3}, and {count, plural, =1 {# other} other {# others}}", + "REPLUGGED_CONFIRM_INSTALL": "Install", + "REPLUGGED_UPDATES_UPDATE_ALL": "Update All", + "REPLUGGED_UPDATES_UPDATE_TO": "Update to {version}", + "REPLUGGED_UPDATES_TOAST_NO_NEW": "No new updates available.", + "REPLUGGED_UPDATES_TOAST_NEW": "{count, plural, =1 {# new update} other {# new updates}} available!", + "REPLUGGED_UPDATES_TOAST_FAILED_ONE": "Update failed!", + "REPLUGGED_UPDATES_TOAST_FAILED_ALL": "Some updates failed!", + "REPLUGGED_UPDATES_TOAST_SUCCESS_ONE": "Update completed successfully.", + "REPLUGGED_UPDATES_TOAST_SUCCESS_ALL": "All updates completed successfully.", + "REPLUGGED_PLUGIN_INSTALL_RELOAD_PROMPT_BODY": "{name} requires a reload to work properly. Reload now?", + "REPLUGGED_RELOAD": "Reload", + "REPLUGGED_UPDATES_UPDATE_NOUN": "Update", + "REPLUGGED_VERSION": "Replugged {version, select, dev {[DEV MODE]} other {v{version}}}", + "REPLUGGED_SETTINGS_BADGES": "Enable Replugged Badges", + "REPLUGGED_SETTINGS_BADGES_DESC": "Show custom Replugged badges on user profiles.", + "REPLUGGED_I18N": "Replugged Translations", + "REPLUGGED_VIEW_UPDATES": "View {count, plural, =1 {# Update} other {# Updates}}", + "REPLUGGED_DEVELOPER_MODE_WARNING": "You are currently running Replugged in developer mode and Replugged will not be able to update itself. [Switch to production mode]({url}).", + "REPLUGGED_ADDON_BROWSE": "Browse {type}", + "REPLUGGED_ADDON_NOT_REVIEWED": "Unreviewed {type}", + "REPLUGGED_ADDON_NOT_REVIEWED_DESC": "This {type} has not been reviewed by the Replugged team and could harm your computer. Use at your own risk.", + "REPLUGGED_SETTINGS_QUICKCSS_AUTO_APPLY": "Automatically Apply Quick CSS", + "REPLUGGED_SETTINGS_QUICKCSS_AUTO_APPLY_DESC": "Automatically apply changes to Quick CSS as you type.", + "REPLUGGED_SETTINGS_DEV_COMPANION": "Reconnect Dev Companion", + "REPLUGGED_SETTINGS_DEV_COMPANION_DESC": "Reconnects the Dev Companion coremod to the VSCode extension.", + "REPLUGGED_SETTINGS_DEV_COMPANION_RECONNECT": "Reconnect", + "REPLUGGED_SETTINGS_ADVANCED": "Advanced Settings", + "REPLUGGED_SETTINGS_REACT_DEVTOOLS": "Enable React DevTools", + "REPLUGGED_SETTINGS_REACT_DEVTOOLS_DESC": "Loads the React DevTools extension, allowing you to inspect the React tree and debug more easily. **Requires restart**.", + "REPLUGGED_SETTINGS_REACT_DEVTOOLS_FAILED": "Failed to download React DevTools.", + "REPLUGGED_INSTALLER_OPEN_STORE": "View in Store", + "REPLUGGED_SETTINGS_ADDON_EMBEDS": "Show Addon Embeds", + "REPLUGGED_SETTINGS_ADDON_EMBEDS_DESC": "Show a card with information on an addon when a store/install link is shared in chat.", + "REPLUGGED_RESTART": "Restart", + "REPLUGGED_SETTINGS_RESTART_TITLE": "Restart Required", + "REPLUGGED_SETTINGS_TRANSPARENT": "Transparent Window", + "REPLUGGED_SETTINGS_TRANSPARENT_DESC": "Makes the Discord window transparent, primarily useful for theming. **Requires restart**.", + "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_WINDOWS": "****WARNING:**** This will break **window snapping**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", + "REPLUGGED_SETTINGS_TRANSPARENT_ISSUES_LINUX": "****WARNING:**** **Hardware acceleration** may need to be turned **off**. In some cases, you may experience a black background, such as when the window is cut off at the top or bottom due to the monitor resolution, or when the development tools are open and docked.", + "REPLUGGED_SETTINGS_ERROR_PLUGIN_NAME": "Plugin: {name}", + "REPLUGGED_STORE": "Store" } diff --git a/src/renderer/coremods/recovery/index.tsx b/src/renderer/coremods/recovery/index.tsx index fa0a7db38..d72c96ede 100644 --- a/src/renderer/coremods/recovery/index.tsx +++ b/src/renderer/coremods/recovery/index.tsx @@ -4,6 +4,7 @@ import { Injector, Logger } from "@replugged"; import { filters, getByProps, waitForModule } from "@webpack"; import "./styles.css"; import { AnyFunction } from "../../../types"; +import { Messages } from "@common/i18n"; import { generalSettings } from "../settings/pages"; import { disable } from "../../managers/plugins"; @@ -15,6 +16,8 @@ const PLUGIN_ID_FIND_REGEX = /plugin\/(.*?)\.asar/; const FIND_ERROR_NUMBER = /invariant=(\d+)&/; const ReactErrorList = "https://raw.githubusercontent.com/facebook/react/v18.2.0/scripts/error-codes/codes.json"; +const ReactErrorListFallback = + "https://raw.githubusercontent.com/facebook/react/v17.0.0/scripts/error-codes/codes.json"; const logger = Logger.coremod("recovery"); let ReactErrors: Record | undefined; @@ -25,7 +28,11 @@ interface ErrorComponentState { } | null; info: null; } - +interface ErrorScreenClass { + prototype: { + render: AnyFunction; + }; +} interface ErrorScreenInstance { state?: ErrorComponentState; setState: (state: ErrorComponentState) => void; @@ -77,7 +84,7 @@ interface TreeNode { children: React.ReactElement[]; } export async function start(): Promise { - const ErrorScreen = await waitForModule( + const ErrorScreen = await waitForModule( filters.bySource(".AnalyticEvents.APP_CRASHED"), ); void startErrors(); @@ -100,7 +107,12 @@ export async function start(): Promise { const pluginId = stackError.match(PLUGIN_ID_FIND_REGEX); if (pluginId) { void disable(pluginId[1]); - toast.toast(`Plugin: ${pluginId[1]} was disabled!`, toast.Kind.SUCCESS); + toast.toast( + Messages.REPLUGGED_TOAST_ADDON_DISABLE_SUCCESS.format({ + name: pluginId[1], + }), + toast.Kind.SUCCESS, + ); } const invar = stackError.match(FIND_ERROR_NUMBER); @@ -108,7 +120,7 @@ export async function start(): Promise { children.push( <>