[0]) {
+ const [state, setState] = React.useState(settings.store.icons ?? "");
+
+ function handleChange(newValue: string) {
+ setState(newValue);
+ props.setValue(newValue);
}
+ return
+ Icons
+ The icons you want to add.
+
+
+ ;
}
+function getCustomIcons(_match: string, original: string) {
+ var icons: Icon[] = [];
+ const settingsIcons = settings.store.icons?.split("\n") as string[];
+
+ let index = 0;
+ for (const icon of settingsIcons) {
+ const matched = /([^:]+):\s*(.+)/.exec(icon);
+ if (!matched || matched.length < 3) continue;
+
+ const name = matched[1].trim(),
+ iconSource = matched[2].trim();
+
+ const idName = name
+ .toLowerCase()
+ .replace(/\s/g, "_")
+ .replace(/\W/g, "#");
+
+ icons.push({
+ id: `CustomAppIcon-${index}:${idName}`,
+ iconSource,
+ isPremium: false,
+ name
+ });
+
+ index++;
+ }
+
+ const outIcons = icons.map(i => JSON.stringify(i)).join(",");
+
+ return `[${original}${icons.length > 0 ? "," : ""}${outIcons}]`;
+}
export default definePlugin({
name: "CustomAppIcons",
- description: "Add/upload custom (In-)App Icons.",
- authors: [Devs.HappyEnderman, EquicordDevs.SerStars],
+ description: "Allows you to add your own app icons to the list.",
+ authors: [Devs.nakoyasha, EquicordDevs.SimplyData],
+ settings,
patches: [
{
- find: /\i\.\i\.APP_ICON_UPSELL/,
- replacement: [
- {
- match: /\w+\.jsx\)\(\w+,{markAsDismissed:\w+,isCoachmark:\w+}\)/,
- replace(str) {
- return str + ",$self.addButtons()";
- }
- }
- ]
+ find: "APP_ICON_HOLO_WAVES}",
+ replacement: {
+ match: /\[({[^]*?})\]/,
+ replace: getCustomIcons,
+ }
}
],
-
-
- start() {
- const appIcons = JSON.parse(localStorage.getItem("vc_app_icons") ?? "[]");
- for (const icon of appIcons) {
- findByProps("M9", "UZ", "QA").UZ.push(icon);
- findByProps("M9", "UZ", "QA").QA[icon.id] = icon;
- }
- },
- stop() {
-
- },
- addButtons() {
-
- const { editorFooter } = findByProps("editorFooter");
- return (
- <>
-
-
- >
- );
- },
-
- settingsAboutComponent: () => {
- return (
- <>
- How to use?
-
-
- Go to { e.preventDefault(); closeAllModals(); FluxDispatcher.dispatch({ type: "USER_SETTINGS_MODAL_SET_SECTION", section: "Appearance" }); }}>Appearance Settings tab.
- Scroll down to "In-app Icons" and click on "Preview App Icon".
- And upload your own custom icon!
- You can only use links when you are uploading your Custom Icon.
- >
- );
- }
});
diff --git a/src/equicordplugins/emojiDumper/index.tsx b/src/equicordplugins/emojiDumper/index.tsx
index 2a80b64d..9569ad95 100644
--- a/src/equicordplugins/emojiDumper/index.tsx
+++ b/src/equicordplugins/emojiDumper/index.tsx
@@ -5,6 +5,7 @@
*/
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
+import { migratePluginSettings } from "@api/Settings";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
import { Menu } from "@webpack/common";
@@ -22,8 +23,9 @@ const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild;
}
};
+migratePluginSettings("EmojiDumper", "emojiDumper");
export default definePlugin({
- name: "emojiDumper",
+ name: "EmojiDumper",
description: "Context menu to dump and download a server's emojis.",
authors: [EquicordDevs.Cortex, Devs.Samwich, EquicordDevs.Woosh],
start() {
diff --git a/src/equicordplugins/loginWithQR/ui/modals/QrModal.tsx b/src/equicordplugins/loginWithQR/ui/modals/QrModal.tsx
index 2523d0fd..efa3ba64 100644
--- a/src/equicordplugins/loginWithQR/ui/modals/QrModal.tsx
+++ b/src/equicordplugins/loginWithQR/ui/modals/QrModal.tsx
@@ -344,6 +344,7 @@ function QrModal(props: ModalProps) {
stream = str;
video.srcObject = str;
video.addEventListener("loadedmetadata", () => {
+ if (stopped) return stop(str);
video.play();
modalProps.current.setPreview(video);
snapshot();
diff --git a/src/equicordplugins/newPluginsManager/index.tsx b/src/equicordplugins/newPluginsManager/index.tsx
index 8c693882..294036ab 100644
--- a/src/equicordplugins/newPluginsManager/index.tsx
+++ b/src/equicordplugins/newPluginsManager/index.tsx
@@ -12,7 +12,7 @@ import { openNewPluginsModal } from "./NewPluginsModal";
export default definePlugin({
name: "NewPluginsManager",
- description: "Utility that notifies you when new plugins are added to Vencord",
+ description: "Utility that notifies you when new plugins are added to Equicord",
authors: [Devs.Sqaaakoi],
flux: {
async POST_CONNECTION_OPEN() {
diff --git a/src/equicordplugins/noAppsAllowed/index.tsx b/src/equicordplugins/noAppsAllowed/index.tsx
index dbedeab8..00eb4729 100644
--- a/src/equicordplugins/noAppsAllowed/index.tsx
+++ b/src/equicordplugins/noAppsAllowed/index.tsx
@@ -4,11 +4,13 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
+import { migratePluginSettings } from "@api/Settings";
import { EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
+migratePluginSettings("NoAppsAllowed", "noAppsAllowed");
export default definePlugin({
- name: "noAppsAllowed",
+ name: "NoAppsAllowed",
description: "returns the bot's tag :skulk:",
authors: [EquicordDevs.kvba],
diff --git a/src/equicordplugins/stickerBlocker/index.tsx b/src/equicordplugins/stickerBlocker/index.tsx
new file mode 100644
index 00000000..d6bda559
--- /dev/null
+++ b/src/equicordplugins/stickerBlocker/index.tsx
@@ -0,0 +1,149 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
+import { DataStore } from "@api/index";
+import { definePluginSettings } from "@api/Settings";
+import ErrorBoundary from "@components/ErrorBoundary";
+import { Devs } from "@utils/constants";
+import definePlugin, { OptionType } from "@utils/types";
+import { Button, Menu } from "@webpack/common";
+import React, { ReactNode } from "react";
+
+const settings = definePluginSettings({
+ showGif: {
+ type: OptionType.BOOLEAN,
+ description: "Whether to show a snazzy cat gif",
+ default: true,
+ restartNeeded: true
+ },
+ showMessage: {
+ type: OptionType.BOOLEAN,
+ description: "Whether to show a message detailing which id was blocked",
+ default: false,
+ restartNeeded: true
+ },
+ showButton: {
+ type: OptionType.BOOLEAN,
+ description: "Whether to show a button to unblock the gif",
+ default: true,
+ restartNeeded: true
+ },
+ blockedStickers: {
+ type: OptionType.STRING,
+ description: "The list of blocked sticker IDs (don't edit unless you know what you're doing)",
+ default: ""
+ }
+});
+
+function blockedComponentRender(sticker) {
+ const { showGif, showMessage, showButton } = settings.store;
+ const elements = [] as ReactNode[];
+
+ if (showGif) {
+ elements.push(
+
+ );
+ }
+
+ if (showMessage) {
+ elements.push(
+ Blocked Sticker. ID: {sticker.id}, NAME: {sticker.name}
+ );
+ }
+
+ if (showButton) {
+ elements.push(
+
+ );
+ }
+
+ return <>{elements}>;
+}
+
+
+const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
+ const { favoriteableId, favoriteableType } = props ?? {};
+
+ if (!favoriteableId) return;
+
+ const menuItem = (() => {
+ switch (favoriteableType) {
+ case "sticker":
+ const sticker = props.message.stickerItems.find(s => s.id === favoriteableId);
+ if (sticker?.format_type === 3 /* LOTTIE */) return;
+
+ return buildMenuItem(favoriteableId);
+ }
+ })();
+
+ if (menuItem)
+ findGroupChildrenByChildId("copy-link", children)?.push(menuItem);
+};
+
+const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
+ const { id, type } = props?.target?.dataset ?? {};
+ if (!id) return;
+
+ if (type === "sticker" && !props.target.className?.includes("lottieCanvas")) {
+ children.push(buildMenuItem(id));
+ }
+};
+
+function buildMenuItem(name) {
+ return (
+ toggleBlock(name)}
+ />
+ );
+}
+
+function toggleBlock(name) {
+ if (settings.store.blockedStickers === undefined || settings.store.blockedStickers == null) {
+ return;
+ }
+ const excepted = isStickerBlocked(name);
+ if (excepted) {
+ settings.store.blockedStickers = settings.store.blockedStickers.split(", ").filter(item => item !== name).join(", ");
+ } else {
+ settings.store.blockedStickers = settings.store.blockedStickers.split(", ").concat(name).join(", ");
+ }
+}
+
+
+function isStickerBlocked(name) {
+ if (settings.store.blockedStickers === undefined || settings.store.blockedStickers == null) {
+ return;
+ }
+ return settings.store.blockedStickers.split(", ").includes(name);
+}
+
+export default definePlugin({
+ name: "StickerBlocker",
+ description: "Allows you to block stickers from being displayed.",
+ authors: [Devs.Samwich],
+ patches: [
+ {
+ find: /\i\.\i\.STICKER_MESSAGE/,
+ replacement: {
+ match: /}\),\(null!=\i\?\i:(\i)\)\.name]}\);/,
+ replace: "$& if(Vencord.Settings.plugins.StickerBlocker.blockedStickers.split(\", \").includes($1.id)) { return($self.blockedComponent($1)) }"
+ }
+ }
+ ],
+ contextMenus: {
+ "message": messageContextMenuPatch,
+ "expression-picker": expressionPickerPatch,
+ },
+ start() {
+ DataStore.createStore("StickerBlocker", "data");
+ },
+ blockedComponent: ErrorBoundary.wrap(blockedComponentRender, { fallback: () => Failed to render :(
}),
+ settings,
+});
diff --git a/src/equicordplugins/title/index.ts b/src/equicordplugins/title/index.ts
index 0314f815..9e67a72a 100644
--- a/src/equicordplugins/title/index.ts
+++ b/src/equicordplugins/title/index.ts
@@ -15,7 +15,7 @@ const rootTitle = { base: null as string | null };
export const settings = definePluginSettings({
title: {
type: OptionType.STRING,
- default: "Vencord",
+ default: "Equicord",
description: "Window title prefix",
onChange: setTitle,
},
diff --git a/src/equicordplugins/vencordRPC/index.ts b/src/equicordplugins/vencordRPC/index.ts
index 5a0cba47..e0e2f13f 100644
--- a/src/equicordplugins/vencordRPC/index.ts
+++ b/src/equicordplugins/vencordRPC/index.ts
@@ -241,7 +241,7 @@ async function createActivity(): Promise {
let { type } = settings.store;
- let appName = "Vencord";
+ let appName = "Equicord";
let details = "";
let state = "";
let imageBig = "";
diff --git a/src/main/index.ts b/src/main/index.ts
index cc2eb14e..8f6a677a 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -53,6 +53,31 @@ if (IS_VESKTOP || !IS_VANILLA) {
}
});
+ protocol.registerFileProtocol("equicord", ({ url: unsafeUrl }, cb) => {
+ let url = unsafeUrl.slice("equicord://".length);
+ if (url.endsWith("/")) url = url.slice(0, -1);
+ if (url.startsWith("/themes/")) {
+ const theme = url.slice("/themes/".length);
+ const safeUrl = ensureSafePath(THEMES_DIR, theme);
+ if (!safeUrl) {
+ cb({ statusCode: 403 });
+ return;
+ }
+ cb(safeUrl.replace(/\?v=\d+$/, ""));
+ return;
+ }
+ switch (url) {
+ case "renderer.js.map":
+ case "preload.js.map":
+ case "patcher.js.map":
+ case "main.js.map":
+ cb(join(__dirname, url));
+ break;
+ default:
+ cb({ statusCode: 403 });
+ }
+ });
+
try {
if (RendererSettings.store.enableReactDevtools)
installExt("fmkadmapgofadopljbjfkapdkoienihi")
diff --git a/src/plugins/_core/supportHelper.tsx b/src/plugins/_core/supportHelper.tsx
index c500c0a3..ad28a2cf 100644
--- a/src/plugins/_core/supportHelper.tsx
+++ b/src/plugins/_core/supportHelper.tsx
@@ -162,13 +162,13 @@ export default definePlugin({
{
name: "equicord-debug",
description: "Send Equicord debug info",
- predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
+ predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || isEquicordPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
execute: async () => ({ content: await generateDebugInfoMessage() })
},
{
name: "equicord-plugins",
description: "Send Equicord plugin list",
- predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
+ predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || isEquicordPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
execute: () => ({ content: generatePluginList() })
}
],
@@ -254,7 +254,7 @@ export default definePlugin({
ContributorDmWarningCard: ErrorBoundary.wrap(({ userId }) => {
if (!isPluginDev(userId) || !isEquicordPluginDev(userId)) return null;
- if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null;
+ if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id) || isEquicordPluginDev(UserStore.getCurrentUser()?.id)) return null;
return (
diff --git a/src/plugins/clientTheme/index.tsx b/src/plugins/clientTheme/index.tsx
index 1259dc8b..358bae01 100644
--- a/src/plugins/clientTheme/index.tsx
+++ b/src/plugins/clientTheme/index.tsx
@@ -30,7 +30,7 @@ function onPickColor(color: number) {
updateColorVars(hexColor);
}
-const saveClientTheme = findByCodeLazy('type:"UNSYNCED_USER_SETTINGS_UPDATE",settings:{useSystemTheme:null!=');
+const saveClientTheme = findByCodeLazy('type:"UNSYNCED_USER_SETTINGS_UPDATE', '"system"===');
function setTheme(theme: string) {
saveClientTheme({ theme });
diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx
index 0f8c6bb5..54585032 100644
--- a/src/plugins/fakeProfileThemes/index.tsx
+++ b/src/plugins/fakeProfileThemes/index.tsx
@@ -57,7 +57,7 @@ function decode(bio: string): Array | null {
if (bio == null) return null;
const colorString = bio.match(
- /\u{e005b}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{6})\u{e002c}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{6})\u{e005d}/u,
+ /\u{e005b}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{1,6})\u{e002c}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{1,6})\u{e005d}/u,
);
if (colorString != null) {
const parsed = [...colorString[0]]
diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx
index 710e30cf..59b2667c 100644
--- a/src/plugins/imageZoom/index.tsx
+++ b/src/plugins/imageZoom/index.tsx
@@ -171,7 +171,7 @@ export default definePlugin({
find: ".handleImageLoad)",
replacement: [
{
- match: /dataSafeSrc:\i,children:/,
+ match: /placeholderVersion:\i,(?=.{0,50}children:)/,
replace: "...$self.makeProps(this),$&"
},
diff --git a/src/plugins/oneko/index.ts b/src/plugins/oneko/index.ts
index ad35268f..32c7e917 100644
--- a/src/plugins/oneko/index.ts
+++ b/src/plugins/oneko/index.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import { definePluginSettings, Settings } from "@api/Settings";
+import { definePluginSettings, migratePluginSettings, Settings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
@@ -31,7 +31,7 @@ const settings = definePluginSettings({
},
onChange: () => {
// note: cant call the start() function from here. so i just copy pasted it (This was pointed out in the last commit i made. So this is to just clear stuff up for any future devs that work on this :D )
- if (Settings.plugins.oneko.enabled) {
+ if (Settings.plugins.Oneko.enabled) {
document.getElementById("oneko")?.remove();
fetch("https://raw.githubusercontent.com/adryd325/oneko.js/8fa8a1864aa71cd7a794d58bc139e755e96a236c/oneko.js")
.then(x => x.text())
@@ -45,8 +45,9 @@ const settings = definePluginSettings({
}
});
+migratePluginSettings("Oneko", "oneko");
export default definePlugin({
- name: "oneko",
+ name: "Oneko",
description: "cat follow mouse (real)",
// Listing adryd here because this literally just evals her script
authors: [Devs.Ven, Devs.adryd],
diff --git a/src/plugins/spotifyControls/index.tsx b/src/plugins/spotifyControls/index.tsx
index 73401ba7..3339cb33 100644
--- a/src/plugins/spotifyControls/index.tsx
+++ b/src/plugins/spotifyControls/index.tsx
@@ -48,7 +48,7 @@ export default definePlugin({
},
patches: [
{
- find: '"account";',
+ find: "this.isCopiedStreakGodlike",
replacement: {
// react.jsx)(AccountPanel, { ..., showTaglessAccountPanel: blah })
match: /(?<=\i\.jsxs?\)\()(\i),{(?=[^}]*?userTag:\i,hidePrivateData:)/,
diff --git a/src/plugins/viewIcons/index.tsx b/src/plugins/viewIcons/index.tsx
index 6bde04be..927a974f 100644
--- a/src/plugins/viewIcons/index.tsx
+++ b/src/plugins/viewIcons/index.tsx
@@ -189,7 +189,8 @@ export default definePlugin({
replacement: {
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/,
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openImage($1)},"
- }
+ },
+ all: true
},
// Old Profiles Modal pfp
{
diff --git a/src/plugins/xsOverlay.desktop/index.ts b/src/plugins/xsOverlay.desktop/index.ts
index 8b06475c..b48c4d7a 100644
--- a/src/plugins/xsOverlay.desktop/index.ts
+++ b/src/plugins/xsOverlay.desktop/index.ts
@@ -271,7 +271,7 @@ function sendMsgNotif(titleString: string, content: string, message: Message) {
content: content,
useBase64Icon: true,
icon: result,
- sourceApp: "Vencord"
+ sourceApp: "Equicord"
};
Native.sendToOverlay(msgData);
});
@@ -290,7 +290,7 @@ function sendOtherNotif(content: string, titleString: string) {
content: content,
useBase64Icon: false,
icon: null,
- sourceApp: "Vencord"
+ sourceApp: "Equicord"
};
Native.sendToOverlay(msgData);
}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 645e8dd2..7a19fe70 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -535,7 +535,11 @@ export const Devs = /* #__PURE__*/ Object.freeze({
Antti: {
name: "Antti",
id: 312974985876471810n
- }
+ },
+ Joona: {
+ name: "Joona",
+ id: 297410829589020673n
+ },
} satisfies Record);
export const EquicordDevs = Object.freeze({
@@ -707,6 +711,10 @@ export const EquicordDevs = Object.freeze({
name: "Joona",
id: 297410829589020673n
},
+ SimplyData: {
+ name: "SimplyData",
+ id: 301494563514613762n
+ },
} satisfies Record);
export const SuncordDevs = /* #__PURE__*/ Object.freeze({
diff --git a/src/utils/themes/usercss/compiler.ts b/src/utils/themes/usercss/compiler.ts
index 16e69677..d366ac13 100644
--- a/src/utils/themes/usercss/compiler.ts
+++ b/src/utils/themes/usercss/compiler.ts
@@ -68,7 +68,7 @@ export async function compileUsercss(fileName: string) {
const preprocessorFn = preprocessors[preprocessor];
if (!preprocessorFn) {
- UserCSSLogger.error("File", fileName, "requires preprocessor", preprocessor, "which isn't known to Vencord");
+ UserCSSLogger.error("File", fileName, "requires preprocessor", preprocessor, "which isn't known to Equicord");
return null;
}