mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-18 19:07:08 -04:00
Merge remote-tracking branch 'upstream/dev'
This commit is contained in:
commit
f2d2ca1fa8
31 changed files with 540 additions and 302 deletions
37
src/plugins/_api/messageUpdater.ts
Normal file
37
src/plugins/_api/messageUpdater.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "MessageUpdaterAPI",
|
||||
description: "API for updating and re-rendering messages.",
|
||||
authors: [Devs.Nuckyz],
|
||||
|
||||
patches: [
|
||||
{
|
||||
// Message accessories have a custom logic to decide if they should render again, so we need to make it not ignore changed message reference
|
||||
find: "}renderEmbeds(",
|
||||
replacement: {
|
||||
match: /(?<=this.props,\i,\[)"message",/,
|
||||
replace: ""
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
|
@ -19,7 +19,7 @@
|
|||
import { popNotice, showNotice } from "@api/Notices";
|
||||
import { Link } from "@components/Link";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import definePlugin, { ReporterTestable } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { ApplicationAssetUtils, FluxDispatcher, Forms, Toasts } from "@webpack/common";
|
||||
|
||||
|
@ -41,6 +41,7 @@ export default definePlugin({
|
|||
name: "WebRichPresence (arRPC)",
|
||||
description: "Client plugin for arRPC to enable RPC on Discord Web (experimental)",
|
||||
authors: [Devs.Ducko],
|
||||
reporterTestable: ReporterTestable.None,
|
||||
|
||||
settingsAboutComponent: () => (
|
||||
<>
|
||||
|
|
|
@ -17,138 +17,198 @@
|
|||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
||||
import { SYM_LAZY_CACHED, SYM_LAZY_GET } from "@utils/lazy";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { canonicalizeMatch, canonicalizeReplace, canonicalizeReplacement } from "@utils/patches";
|
||||
import definePlugin, { StartAt } from "@utils/types";
|
||||
import definePlugin, { PluginNative, StartAt } from "@utils/types";
|
||||
import * as Webpack from "@webpack";
|
||||
import { extract, filters, findAll, findModuleId, search } from "@webpack";
|
||||
import * as Common from "@webpack/common";
|
||||
import type { ComponentType } from "react";
|
||||
|
||||
const WEB_ONLY = (f: string) => () => {
|
||||
const DESKTOP_ONLY = (f: string) => () => {
|
||||
throw new Error(`'${f}' is Discord Desktop only.`);
|
||||
};
|
||||
|
||||
const define: typeof Object.defineProperty =
|
||||
(obj, prop, desc) => {
|
||||
if (Object.hasOwn(desc, "value"))
|
||||
desc.writable = true;
|
||||
|
||||
return Object.defineProperty(obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
...desc
|
||||
});
|
||||
};
|
||||
|
||||
function makeShortcuts() {
|
||||
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn) {
|
||||
const cache = new Map<string, unknown>();
|
||||
|
||||
return function (...filterProps: unknown[]) {
|
||||
const cacheKey = String(filterProps);
|
||||
if (cache.has(cacheKey)) return cache.get(cacheKey);
|
||||
|
||||
const matches = findAll(filterFactory(...filterProps));
|
||||
|
||||
const result = (() => {
|
||||
switch (matches.length) {
|
||||
case 0: return null;
|
||||
case 1: return matches[0];
|
||||
default:
|
||||
const uniqueMatches = [...new Set(matches)];
|
||||
if (uniqueMatches.length > 1)
|
||||
console.warn(`Warning: This filter matches ${matches.length} modules. Make it more specific!\n`, uniqueMatches);
|
||||
|
||||
return matches[0];
|
||||
}
|
||||
})();
|
||||
if (result && cacheKey) cache.set(cacheKey, result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
let fakeRenderWin: WeakRef<Window> | undefined;
|
||||
const find = newFindWrapper(f => f);
|
||||
const findByProps = newFindWrapper(filters.byProps);
|
||||
|
||||
return {
|
||||
...Object.fromEntries(Object.keys(Common).map(key => [key, { getter: () => Common[key] }])),
|
||||
wp: Webpack,
|
||||
wpc: { getter: () => Webpack.cache },
|
||||
wreq: { getter: () => Webpack.wreq },
|
||||
wpsearch: search,
|
||||
wpex: extract,
|
||||
wpexs: (code: string) => extract(findModuleId(code)!),
|
||||
find,
|
||||
findAll: findAll,
|
||||
findByProps,
|
||||
findAllByProps: (...props: string[]) => findAll(filters.byProps(...props)),
|
||||
findByCode: newFindWrapper(filters.byCode),
|
||||
findAllByCode: (code: string) => findAll(filters.byCode(code)),
|
||||
findComponentByCode: newFindWrapper(filters.componentByCode),
|
||||
findAllComponentsByCode: (...code: string[]) => findAll(filters.componentByCode(...code)),
|
||||
findExportedComponent: (...props: string[]) => findByProps(...props)[props[0]],
|
||||
findStore: newFindWrapper(filters.byStoreName),
|
||||
PluginsApi: { getter: () => Vencord.Plugins },
|
||||
plugins: { getter: () => Vencord.Plugins.plugins },
|
||||
Settings: { getter: () => Vencord.Settings },
|
||||
Api: { getter: () => Vencord.Api },
|
||||
Util: { getter: () => Vencord.Util },
|
||||
reload: () => location.reload(),
|
||||
restart: IS_WEB ? DESKTOP_ONLY("restart") : relaunch,
|
||||
canonicalizeMatch,
|
||||
canonicalizeReplace,
|
||||
canonicalizeReplacement,
|
||||
fakeRender: (component: ComponentType, props: any) => {
|
||||
const prevWin = fakeRenderWin?.deref();
|
||||
const win = prevWin?.closed === false
|
||||
? prevWin
|
||||
: window.open("about:blank", "Fake Render", "popup,width=500,height=500")!;
|
||||
fakeRenderWin = new WeakRef(win);
|
||||
win.focus();
|
||||
|
||||
const doc = win.document;
|
||||
doc.body.style.margin = "1em";
|
||||
|
||||
if (!win.prepared) {
|
||||
win.prepared = true;
|
||||
|
||||
[...document.querySelectorAll("style"), ...document.querySelectorAll("link[rel=stylesheet]")].forEach(s => {
|
||||
const n = s.cloneNode(true) as HTMLStyleElement | HTMLLinkElement;
|
||||
|
||||
if (s.parentElement?.tagName === "HEAD")
|
||||
doc.head.append(n);
|
||||
else if (n.id?.startsWith("vencord-") || n.id?.startsWith("vcd-"))
|
||||
doc.documentElement.append(n);
|
||||
else
|
||||
doc.body.append(n);
|
||||
});
|
||||
}
|
||||
|
||||
Common.ReactDOM.render(Common.React.createElement(component, props), doc.body.appendChild(document.createElement("div")));
|
||||
},
|
||||
|
||||
preEnable: (plugin: string) => (Vencord.Settings.plugins[plugin] ??= { enabled: true }).enabled = true,
|
||||
|
||||
channel: { getter: () => getCurrentChannel(), preload: false },
|
||||
channelId: { getter: () => Common.SelectedChannelStore.getChannelId(), preload: false },
|
||||
guild: { getter: () => getCurrentGuild(), preload: false },
|
||||
guildId: { getter: () => Common.SelectedGuildStore.getGuildId(), preload: false },
|
||||
me: { getter: () => Common.UserStore.getCurrentUser(), preload: false },
|
||||
meId: { getter: () => Common.UserStore.getCurrentUser().id, preload: false },
|
||||
messages: { getter: () => Common.MessageStore.getMessages(Common.SelectedChannelStore.getChannelId()), preload: false }
|
||||
};
|
||||
}
|
||||
|
||||
function loadAndCacheShortcut(key: string, val: any, forceLoad: boolean) {
|
||||
const currentVal = val.getter();
|
||||
if (!currentVal || val.preload === false) return currentVal;
|
||||
|
||||
const value = currentVal[SYM_LAZY_GET]
|
||||
? forceLoad ? currentVal[SYM_LAZY_GET]() : currentVal[SYM_LAZY_CACHED]
|
||||
: currentVal;
|
||||
|
||||
if (value) define(window.shortcutList, key, { value });
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "ConsoleShortcuts",
|
||||
description: "Adds shorter Aliases for many things on the window. Run `shortcutList` for a list.",
|
||||
authors: [Devs.Ven],
|
||||
|
||||
getShortcuts(): Record<PropertyKey, any> {
|
||||
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn) {
|
||||
const cache = new Map<string, unknown>();
|
||||
|
||||
return function (...filterProps: unknown[]) {
|
||||
const cacheKey = String(filterProps);
|
||||
if (cache.has(cacheKey)) return cache.get(cacheKey);
|
||||
|
||||
const matches = findAll(filterFactory(...filterProps));
|
||||
|
||||
const result = (() => {
|
||||
switch (matches.length) {
|
||||
case 0: return null;
|
||||
case 1: return matches[0];
|
||||
default:
|
||||
const uniqueMatches = [...new Set(matches)];
|
||||
if (uniqueMatches.length > 1)
|
||||
console.warn(`Warning: This filter matches ${matches.length} modules. Make it more specific!\n`, uniqueMatches);
|
||||
|
||||
return matches[0];
|
||||
}
|
||||
})();
|
||||
if (result && cacheKey) cache.set(cacheKey, result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
let fakeRenderWin: WeakRef<Window> | undefined;
|
||||
const find = newFindWrapper(f => f);
|
||||
const findByProps = newFindWrapper(filters.byProps);
|
||||
|
||||
return {
|
||||
...Object.fromEntries(Object.keys(Common).map(key => [key, { getter: () => Common[key] }])),
|
||||
wp: Webpack,
|
||||
wpc: { getter: () => Webpack.cache },
|
||||
wreq: { getter: () => Webpack.wreq },
|
||||
wpsearch: search,
|
||||
wpex: extract,
|
||||
wpexs: (code: string) => extract(findModuleId(code)!),
|
||||
find,
|
||||
findAll: findAll,
|
||||
findByProps,
|
||||
findAllByProps: (...props: string[]) => findAll(filters.byProps(...props)),
|
||||
findByCode: newFindWrapper(filters.byCode),
|
||||
findAllByCode: (code: string) => findAll(filters.byCode(code)),
|
||||
findComponentByCode: newFindWrapper(filters.componentByCode),
|
||||
findAllComponentsByCode: (...code: string[]) => findAll(filters.componentByCode(...code)),
|
||||
findExportedComponent: (...props: string[]) => findByProps(...props)[props[0]],
|
||||
findStore: newFindWrapper(filters.byStoreName),
|
||||
PluginsApi: { getter: () => Vencord.Plugins },
|
||||
plugins: { getter: () => Vencord.Plugins.plugins },
|
||||
Settings: { getter: () => Vencord.Settings },
|
||||
Api: { getter: () => Vencord.Api },
|
||||
reload: () => location.reload(),
|
||||
restart: IS_WEB ? WEB_ONLY("restart") : relaunch,
|
||||
canonicalizeMatch,
|
||||
canonicalizeReplace,
|
||||
canonicalizeReplacement,
|
||||
fakeRender: (component: ComponentType, props: any) => {
|
||||
const prevWin = fakeRenderWin?.deref();
|
||||
const win = prevWin?.closed === false ? prevWin : window.open("about:blank", "Fake Render", "popup,width=500,height=500")!;
|
||||
fakeRenderWin = new WeakRef(win);
|
||||
win.focus();
|
||||
|
||||
const doc = win.document;
|
||||
doc.body.style.margin = "1em";
|
||||
|
||||
if (!win.prepared) {
|
||||
win.prepared = true;
|
||||
|
||||
[...document.querySelectorAll("style"), ...document.querySelectorAll("link[rel=stylesheet]")].forEach(s => {
|
||||
const n = s.cloneNode(true) as HTMLStyleElement | HTMLLinkElement;
|
||||
|
||||
if (s.parentElement?.tagName === "HEAD")
|
||||
doc.head.append(n);
|
||||
else if (n.id?.startsWith("vencord-") || n.id?.startsWith("vcd-"))
|
||||
doc.documentElement.append(n);
|
||||
else
|
||||
doc.body.append(n);
|
||||
});
|
||||
}
|
||||
|
||||
Common.ReactDOM.render(Common.React.createElement(component, props), doc.body.appendChild(document.createElement("div")));
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
startAt: StartAt.Init,
|
||||
start() {
|
||||
const shortcuts = this.getShortcuts();
|
||||
const shortcuts = makeShortcuts();
|
||||
window.shortcutList = {};
|
||||
|
||||
for (const [key, val] of Object.entries(shortcuts)) {
|
||||
if (val.getter != null) {
|
||||
Object.defineProperty(window.shortcutList, key, {
|
||||
get: val.getter,
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
if ("getter" in val) {
|
||||
define(window.shortcutList, key, {
|
||||
get: () => loadAndCacheShortcut(key, val, true)
|
||||
});
|
||||
|
||||
Object.defineProperty(window, key, {
|
||||
get: () => window.shortcutList[key],
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
define(window, key, {
|
||||
get: () => window.shortcutList[key]
|
||||
});
|
||||
} else {
|
||||
window.shortcutList[key] = val;
|
||||
window[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
// unproxy loaded modules
|
||||
Webpack.onceReady.then(() => {
|
||||
setTimeout(() => this.eagerLoad(false), 1000);
|
||||
|
||||
if (!IS_WEB) {
|
||||
const Native = VencordNative.pluginHelpers.ConsoleShortcuts as PluginNative<typeof import("./native")>;
|
||||
Native.initDevtoolsOpenEagerLoad();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
async eagerLoad(forceLoad: boolean) {
|
||||
await Webpack.onceReady;
|
||||
|
||||
const shortcuts = makeShortcuts();
|
||||
|
||||
for (const [key, val] of Object.entries(shortcuts)) {
|
||||
if (!Object.hasOwn(val, "getter") || (val as any).preload === false) continue;
|
||||
|
||||
try {
|
||||
loadAndCacheShortcut(key, val, forceLoad);
|
||||
} catch { } // swallow not found errors in DEV
|
||||
}
|
||||
},
|
||||
|
||||
stop() {
|
||||
delete window.shortcutList;
|
||||
for (const key in this.getShortcuts()) {
|
||||
for (const key in makeShortcuts()) {
|
||||
delete window[key];
|
||||
}
|
||||
}
|
||||
|
|
16
src/plugins/consoleShortcuts/native.ts
Normal file
16
src/plugins/consoleShortcuts/native.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { IpcMainInvokeEvent } from "electron";
|
||||
|
||||
export function initDevtoolsOpenEagerLoad(e: IpcMainInvokeEvent) {
|
||||
const handleDevtoolsOpened = () => e.sender.executeJavaScript("Vencord.Plugins.plugins.ConsoleShortcuts.eagerLoad(true)");
|
||||
|
||||
if (e.sender.isDevToolsOpened())
|
||||
handleDevtoolsOpened();
|
||||
else
|
||||
e.sender.once("devtools-opened", () => handleDevtoolsOpened());
|
||||
}
|
|
@ -21,7 +21,7 @@ import { definePluginSettings } from "@api/Settings";
|
|||
import { Devs } from "@utils/constants";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
|
||||
import { filters, findAll, search } from "@webpack";
|
||||
|
||||
const PORT = 8485;
|
||||
|
@ -243,6 +243,7 @@ export default definePlugin({
|
|||
name: "DevCompanion",
|
||||
description: "Dev Companion Plugin",
|
||||
authors: [Devs.Ven],
|
||||
reporterTestable: ReporterTestable.None,
|
||||
settings,
|
||||
|
||||
toolboxActions: {
|
||||
|
|
|
@ -333,7 +333,7 @@ export default definePlugin({
|
|||
]
|
||||
},
|
||||
{
|
||||
find: "renderEmbeds(",
|
||||
find: "}renderEmbeds(",
|
||||
replacement: [
|
||||
{
|
||||
// Call our function to decide whether the embed should be ignored or not
|
||||
|
|
|
@ -21,7 +21,7 @@ import { addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu";
|
|||
import { Settings } from "@api/Settings";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { canonicalizeFind } from "@utils/patches";
|
||||
import { Patch, Plugin, StartAt } from "@utils/types";
|
||||
import { Patch, Plugin, ReporterTestable, StartAt } from "@utils/types";
|
||||
import { FluxDispatcher } from "@webpack/common";
|
||||
import { FluxEvents } from "@webpack/types";
|
||||
|
||||
|
@ -39,35 +39,68 @@ export const patches = [] as Patch[];
|
|||
let enabledPluginsSubscribedFlux = false;
|
||||
const subscribedFluxEventsPlugins = new Set<string>();
|
||||
|
||||
const pluginsValues = Object.values(Plugins);
|
||||
const settings = Settings.plugins;
|
||||
|
||||
export function isPluginEnabled(p: string) {
|
||||
return (
|
||||
IS_REPORTER ||
|
||||
Plugins[p]?.required ||
|
||||
Plugins[p]?.isDependency ||
|
||||
settings[p]?.enabled
|
||||
) ?? false;
|
||||
}
|
||||
|
||||
const pluginsValues = Object.values(Plugins);
|
||||
export function addPatch(newPatch: Omit<Patch, "plugin">, pluginName: string) {
|
||||
const patch = newPatch as Patch;
|
||||
patch.plugin = pluginName;
|
||||
|
||||
// First roundtrip to mark and force enable dependencies (only for enabled plugins)
|
||||
if (IS_REPORTER) {
|
||||
delete patch.predicate;
|
||||
delete patch.group;
|
||||
}
|
||||
|
||||
canonicalizeFind(patch);
|
||||
if (!Array.isArray(patch.replacement)) {
|
||||
patch.replacement = [patch.replacement];
|
||||
}
|
||||
|
||||
if (IS_REPORTER) {
|
||||
patch.replacement.forEach(r => {
|
||||
delete r.predicate;
|
||||
});
|
||||
}
|
||||
|
||||
patches.push(patch);
|
||||
}
|
||||
|
||||
function isReporterTestable(p: Plugin, part: ReporterTestable) {
|
||||
return p.reporterTestable == null
|
||||
? true
|
||||
: (p.reporterTestable & part) === part;
|
||||
}
|
||||
|
||||
// First round-trip to mark and force enable dependencies
|
||||
//
|
||||
// FIXME: might need to revisit this if there's ever nested (dependencies of dependencies) dependencies since this only
|
||||
// goes for the top level and their children, but for now this works okay with the current API plugins
|
||||
for (const p of pluginsValues) if (settings[p.name]?.enabled) {
|
||||
for (const p of pluginsValues) if (isPluginEnabled(p.name)) {
|
||||
p.dependencies?.forEach(d => {
|
||||
const dep = Plugins[d];
|
||||
if (dep) {
|
||||
settings[d].enabled = true;
|
||||
dep.isDependency = true;
|
||||
}
|
||||
else {
|
||||
|
||||
if (!dep) {
|
||||
const error = new Error(`Plugin ${p.name} has unresolved dependency ${d}`);
|
||||
if (IS_DEV)
|
||||
|
||||
if (IS_DEV) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.warn(error);
|
||||
return;
|
||||
}
|
||||
|
||||
settings[d].enabled = true;
|
||||
dep.isDependency = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -82,23 +115,18 @@ for (const p of pluginsValues) {
|
|||
}
|
||||
|
||||
if (p.patches && isPluginEnabled(p.name)) {
|
||||
for (const patch of p.patches) {
|
||||
patch.plugin = p.name;
|
||||
|
||||
canonicalizeFind(patch);
|
||||
if (!Array.isArray(patch.replacement)) {
|
||||
patch.replacement = [patch.replacement];
|
||||
if (!IS_REPORTER || isReporterTestable(p, ReporterTestable.Patches)) {
|
||||
for (const patch of p.patches) {
|
||||
addPatch(patch, p.name);
|
||||
}
|
||||
|
||||
patches.push(patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const startAllPlugins = traceFunction("startAllPlugins", function startAllPlugins(target: StartAt) {
|
||||
logger.info(`Starting plugins (stage ${target})`);
|
||||
for (const name in Plugins)
|
||||
if (isPluginEnabled(name)) {
|
||||
for (const name in Plugins) {
|
||||
if (isPluginEnabled(name) && (!IS_REPORTER || isReporterTestable(Plugins[name], ReporterTestable.Start))) {
|
||||
const p = Plugins[name];
|
||||
|
||||
const startAt = p.startAt ?? StartAt.WebpackReady;
|
||||
|
@ -106,30 +134,38 @@ export const startAllPlugins = traceFunction("startAllPlugins", function startAl
|
|||
|
||||
startPlugin(Plugins[name]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export function startDependenciesRecursive(p: Plugin) {
|
||||
let restartNeeded = false;
|
||||
const failures: string[] = [];
|
||||
p.dependencies?.forEach(dep => {
|
||||
if (!Settings.plugins[dep].enabled) {
|
||||
startDependenciesRecursive(Plugins[dep]);
|
||||
|
||||
p.dependencies?.forEach(d => {
|
||||
if (!settings[d].enabled) {
|
||||
const dep = Plugins[d];
|
||||
startDependenciesRecursive(dep);
|
||||
|
||||
// If the plugin has patches, don't start the plugin, just enable it.
|
||||
Settings.plugins[dep].enabled = true;
|
||||
if (Plugins[dep].patches) {
|
||||
logger.warn(`Enabling dependency ${dep} requires restart.`);
|
||||
settings[d].enabled = true;
|
||||
dep.isDependency = true;
|
||||
|
||||
if (dep.patches) {
|
||||
logger.warn(`Enabling dependency ${d} requires restart.`);
|
||||
restartNeeded = true;
|
||||
return;
|
||||
}
|
||||
const result = startPlugin(Plugins[dep]);
|
||||
if (!result) failures.push(dep);
|
||||
|
||||
const result = startPlugin(dep);
|
||||
if (!result) failures.push(d);
|
||||
}
|
||||
});
|
||||
|
||||
return { restartNeeded, failures };
|
||||
}
|
||||
|
||||
export function subscribePluginFluxEvents(p: Plugin, fluxDispatcher: typeof FluxDispatcher) {
|
||||
if (p.flux && !subscribedFluxEventsPlugins.has(p.name)) {
|
||||
if (p.flux && !subscribedFluxEventsPlugins.has(p.name) && (!IS_REPORTER || isReporterTestable(p, ReporterTestable.FluxEvents))) {
|
||||
subscribedFluxEventsPlugins.add(p.name);
|
||||
|
||||
logger.debug("Subscribing to flux events of plugin", p.name);
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { addButton, removeButton } from "@api/MessagePopover";
|
||||
import { updateMessage } from "@api/MessageUpdater";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getStegCloak } from "@utils/dependencies";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { ChannelStore, Constants, FluxDispatcher, RestAPI, Tooltip } from "@webpack/common";
|
||||
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
|
||||
import { ChannelStore, Constants, RestAPI, Tooltip } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
import { buildDecModal } from "./components/DecryptionModal";
|
||||
|
@ -100,7 +101,10 @@ export default definePlugin({
|
|||
name: "InvisibleChat",
|
||||
description: "Encrypt your Messages in a non-suspicious way!",
|
||||
authors: [Devs.SammCheese],
|
||||
dependencies: ["MessagePopoverAPI"],
|
||||
dependencies: ["MessagePopoverAPI", "ChatInputButtonAPI", "MessageUpdaterAPI"],
|
||||
reporterTestable: ReporterTestable.Patches,
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
// Indicator
|
||||
|
@ -117,7 +121,6 @@ export default definePlugin({
|
|||
URL_REGEX: new RegExp(
|
||||
/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
|
||||
),
|
||||
settings,
|
||||
async start() {
|
||||
const { default: StegCloak } = await getStegCloak();
|
||||
steggo = new StegCloak(true, false);
|
||||
|
@ -176,14 +179,7 @@ export default definePlugin({
|
|||
message.embeds.push(embed);
|
||||
}
|
||||
|
||||
this.updateMessage(message);
|
||||
},
|
||||
|
||||
updateMessage: (message: any) => {
|
||||
FluxDispatcher.dispatch({
|
||||
type: "MESSAGE_UPDATE",
|
||||
message,
|
||||
});
|
||||
updateMessage(message.channel_id, message.id, { embeds: message.embeds });
|
||||
},
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(generateChatButton, { noop: true }),
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
||||
import { updateMessage } from "@api/MessageUpdater";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants.js";
|
||||
|
@ -28,7 +29,6 @@ import {
|
|||
Button,
|
||||
ChannelStore,
|
||||
Constants,
|
||||
FluxDispatcher,
|
||||
GuildStore,
|
||||
IconUtils,
|
||||
MessageStore,
|
||||
|
@ -250,15 +250,9 @@ function MessageEmbedAccessory({ message }: { message: Message; }) {
|
|||
if (linkedMessage) {
|
||||
messageCache.set(messageID, { message: linkedMessage, fetched: true });
|
||||
} else {
|
||||
const msg = { ...message } as any;
|
||||
delete msg.embeds;
|
||||
delete msg.interaction;
|
||||
|
||||
messageFetchQueue.unshift(() => fetchMessage(channelID, messageID)
|
||||
.then(m => m && FluxDispatcher.dispatch({
|
||||
type: "MESSAGE_UPDATE",
|
||||
message: msg
|
||||
}))
|
||||
.then(m => m && updateMessage(message.channel_id, message.id))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
@ -367,7 +361,7 @@ export default definePlugin({
|
|||
name: "MessageLinkEmbeds",
|
||||
description: "Adds a preview to messages that link another message",
|
||||
authors: [Devs.TheSun, Devs.Ven, Devs.RyanCaoDev],
|
||||
dependencies: ["MessageAccessoriesAPI"],
|
||||
dependencies: ["MessageAccessoriesAPI", "MessageUpdaterAPI"],
|
||||
|
||||
settings,
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import "./shiki.css";
|
|||
|
||||
import { enableStyle } from "@api/Styles";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import definePlugin, { ReporterTestable } from "@utils/types";
|
||||
import previewExampleText from "file://previewExample.tsx";
|
||||
|
||||
import { shiki } from "./api/shiki";
|
||||
|
@ -34,6 +34,9 @@ export default definePlugin({
|
|||
name: "ShikiCodeblocks",
|
||||
description: "Brings vscode-style codeblocks into Discord, powered by Shiki",
|
||||
authors: [Devs.Vap],
|
||||
reporterTestable: ReporterTestable.Patches,
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "codeBlock:{react(",
|
||||
|
@ -66,7 +69,6 @@ export default definePlugin({
|
|||
isPreview: true,
|
||||
tempSettings,
|
||||
}),
|
||||
settings,
|
||||
|
||||
// exports
|
||||
shiki,
|
||||
|
|
|
@ -22,12 +22,21 @@ import { Devs } from "@utils/constants";
|
|||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { wordsToTitle } from "@utils/text";
|
||||
import definePlugin, { OptionType, PluginOptionsItem } from "@utils/types";
|
||||
import { findStoreLazy } from "@webpack";
|
||||
import definePlugin, { OptionType, PluginOptionsItem, ReporterTestable } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Button, ChannelStore, Forms, GuildMemberStore, SelectedChannelStore, SelectedGuildStore, useMemo, UserStore } from "@webpack/common";
|
||||
import { VoiceState } from "@webpack/types";
|
||||
|
||||
const VoiceStateStore = findStoreLazy("VoiceStateStore");
|
||||
interface VoiceState {
|
||||
userId: string;
|
||||
channelId?: string;
|
||||
oldChannelId?: string;
|
||||
deaf: boolean;
|
||||
mute: boolean;
|
||||
selfDeaf: boolean;
|
||||
selfMute: boolean;
|
||||
}
|
||||
|
||||
const VoiceStateStore = findByPropsLazy("getVoiceStatesForChannel", "getCurrentClientVoiceChannelId");
|
||||
|
||||
// Mute/Deaf for other people than you is commented out, because otherwise someone can spam it and it will be annoying
|
||||
// Filtering out events is not as simple as just dropping duplicates, as otherwise mute, unmute, mute would
|
||||
|
@ -146,6 +155,7 @@ export default definePlugin({
|
|||
name: "VcNarrator",
|
||||
description: "Announces when users join, leave, or move voice channels via narrator",
|
||||
authors: [Devs.Ven],
|
||||
reporterTestable: ReporterTestable.None,
|
||||
|
||||
flux: {
|
||||
VOICE_STATE_UPDATES({ voiceStates }: { voiceStates: VoiceState[]; }) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { definePluginSettings } from "@api/Settings";
|
|||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType, PluginNative } from "@utils/types";
|
||||
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { ChannelStore, GuildStore, UserStore } from "@webpack/common";
|
||||
import type { Channel, Embed, GuildMember, MessageAttachment, User } from "discord-types/general";
|
||||
|
@ -143,7 +143,9 @@ export default definePlugin({
|
|||
description: "Forwards discord notifications to XSOverlay, for easy viewing in VR",
|
||||
authors: [Devs.Nyako],
|
||||
tags: ["vr", "notify"],
|
||||
reporterTestable: ReporterTestable.None,
|
||||
settings,
|
||||
|
||||
flux: {
|
||||
CALL_UPDATE({ call }: { call: Call; }) {
|
||||
if (call?.ringing?.includes(UserStore.getCurrentUser().id) && settings.store.callNotifications) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue