From 056851d4e8e16f1a8910f99a00e5aca7485551be Mon Sep 17 00:00:00 2001
From: Eazvy <57739965+Eazvy@users.noreply.github.com>
Date: Sat, 20 Sep 2025 17:49:50 -0400
Subject: [PATCH 1/8] Fix ImagePreview / Add voiceButtons (#409)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add AutoJump Back
Fixed not loading messages, properly & failing to jump in some instances.
* Add AutoJump back / Fixed!
Fixed Issue with not jumping to latest message in channel.
Fixed Issue with not loading message(s) properly when jumping.
* Update index.tsx
* Delete src/equicordplugins/autoJump directory
* Create UserChatButtons.tsx
* Create UserChatButtons.css
* Create index.tsx
* Delete index.tsx
* Add VoiceButtons
Allows you to easily deafen / mute people via voice-channel. With customizable settings that allows you to choose whether you want to toggle their video or soundboard in settings.
Source was taken from ClickToChat in vencord just added a few more things to make i way better
* fixes issue with YouTube embeds showing image and changing accounts image still staying
did what creations didnt ðŸ˜
* Create index.tsx
* Create styles.css
* Update index.tsx
* Some Fixes
* Update VoiceButtons
* Use MediaEngine Import
* Fix VSC
* Update index.tsx
* Delete src/equicordplugins/betterFormattingRedux directory
---------
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
---
.../src/stores/MediaEngineStore.d.ts | 2 +
src/equicordplugins/imagePreview/index.ts | 19 ++
src/equicordplugins/voiceButtons/index.tsx | 74 ++++++++
src/equicordplugins/voiceButtons/styles.css | 3 +
src/equicordplugins/voiceButtons/utils.tsx | 175 ++++++++++++++++++
src/utils/constants.ts | 4 +
6 files changed, 277 insertions(+)
create mode 100644 src/equicordplugins/voiceButtons/index.tsx
create mode 100644 src/equicordplugins/voiceButtons/styles.css
create mode 100644 src/equicordplugins/voiceButtons/utils.tsx
diff --git a/packages/discord-types/src/stores/MediaEngineStore.d.ts b/packages/discord-types/src/stores/MediaEngineStore.d.ts
index 2452a6056..d44f5aa58 100644
--- a/packages/discord-types/src/stores/MediaEngineStore.d.ts
+++ b/packages/discord-types/src/stores/MediaEngineStore.d.ts
@@ -3,6 +3,8 @@ import { FluxStore } from "..";
export class MediaEngineStore extends FluxStore {
isSelfMute(): boolean;
isSelfDeaf(): boolean;
+ isLocalMute(userId): boolean;
+ isLocalVideoDisabled(userId): boolean;
setAv1Enabled(AV1: boolean): void;
setH265Enabled(H265: boolean): void;
diff --git a/src/equicordplugins/imagePreview/index.ts b/src/equicordplugins/imagePreview/index.ts
index 065d8a392..948dd870d 100644
--- a/src/equicordplugins/imagePreview/index.ts
+++ b/src/equicordplugins/imagePreview/index.ts
@@ -376,6 +376,24 @@ function updatePreviewPosition(mouseEvent: MouseEvent, element: HTMLElement) {
}
}
+let previewCheckInterval;
+
+function watchSourceElement(el: Element) {
+ if (previewCheckInterval) {
+ clearInterval(previewCheckInterval);
+ previewCheckInterval = null;
+ }
+
+ previewCheckInterval = setInterval(() => {
+ const node = el as HTMLElement;
+ if (!document.body.contains(node) || !node.offsetParent) {
+ deleteCurrentPreview();
+ clearInterval(previewCheckInterval);
+ previewCheckInterval = null;
+ }
+ }, 300);
+}
+
function addHoverListener(element: Element, sticker: boolean = false) {
element.setAttribute("data-processed", "true");
@@ -406,6 +424,7 @@ function addHoverListener(element: Element, sticker: boolean = false) {
hoverDelayTimeout = setTimeout(() => {
loadImagePreview(strippedURL, sticker);
+ watchSourceElement(element);
if (lastMouseEvent) {
updatePreviewPosition(lastMouseEvent, element as HTMLElement);
}
diff --git a/src/equicordplugins/voiceButtons/index.tsx b/src/equicordplugins/voiceButtons/index.tsx
new file mode 100644
index 000000000..dfe0bfca7
--- /dev/null
+++ b/src/equicordplugins/voiceButtons/index.tsx
@@ -0,0 +1,74 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { definePluginSettings } from "@api/Settings";
+import { EquicordDevs } from "@utils/constants";
+import definePlugin, { OptionType } from "@utils/types";
+import { User } from "@vencord/discord-types";
+import { React } from "@webpack/common";
+
+import { UserChatButton, UserDeafenButton, UserMuteButton } from "./utils";
+
+export const settings = definePluginSettings({
+ showChatButton: {
+ type: OptionType.BOOLEAN,
+ default: true,
+ description: "Whether you want to display the chat button",
+ restartNeeded: true,
+ },
+ showMuteButton: {
+ type: OptionType.BOOLEAN,
+ default: true,
+ description: "Whether you want to display the mute button",
+ restartNeeded: true,
+ },
+ showDeafenButton: {
+ type: OptionType.BOOLEAN,
+ default: true,
+ description: "Whether you want to display the deafen button",
+ restartNeeded: true,
+ },
+ muteSoundboard: {
+ type: OptionType.BOOLEAN,
+ default: true,
+ description: "Toggles their soundboard upon clicking deafen button.",
+ restartNeeded: false,
+ },
+ disableVideo: {
+ type: OptionType.BOOLEAN,
+ default: true,
+ description: "Toggles their video upon clicking deafen button.",
+ restartNeeded: false,
+ },
+});
+
+export default definePlugin({
+ name: "VoiceButtons",
+ description: "Quickly DM, mute, or deafen any user right from the voice-call panel.",
+ authors: [EquicordDevs.nicola02nb, EquicordDevs.omaw],
+ settings,
+ patches: [
+ {
+ find: "\"avatarContainerClass\",\"userNameClassName\"",
+ replacement: [
+ {
+ match: /:(\i)\.username.*?flipped\]:\i\}\),children:\[/,
+ replace: "$&$self.renderButtons($1),"
+ }
+ ]
+ }
+ ],
+ renderPing(user?: User) {
+ if (!user) return null;
+ return (
+
+ {settings.store.showChatButton && }
+ {settings.store.showMuteButton && }
+ {settings.store.showDeafenButton && }
+
+ );
+ }
+});
diff --git a/src/equicordplugins/voiceButtons/styles.css b/src/equicordplugins/voiceButtons/styles.css
new file mode 100644
index 000000000..4dcda501c
--- /dev/null
+++ b/src/equicordplugins/voiceButtons/styles.css
@@ -0,0 +1,3 @@
+div[class^='list_'][class*='collapsed_'] .click-to-chat-btn {
+ display: none;
+}
\ No newline at end of file
diff --git a/src/equicordplugins/voiceButtons/utils.tsx b/src/equicordplugins/voiceButtons/utils.tsx
new file mode 100644
index 000000000..63f5e41bf
--- /dev/null
+++ b/src/equicordplugins/voiceButtons/utils.tsx
@@ -0,0 +1,175 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import "./styles.css";
+
+import { openPrivateChannel } from "@utils/discord";
+import { User } from "@vencord/discord-types";
+import { findStoreLazy } from "@webpack";
+import { Button, MediaEngineStore, Tooltip, UserStore, VoiceActions } from "@webpack/common";
+
+import { settings } from ".";
+
+const SoundboardStore = findStoreLazy("SoundboardStore");
+
+export function UserChatButton({ user }: { user: User; }) {
+ if (user.id === UserStore.getCurrentUser().id) return null;
+ return (
+
+
+ {({ onMouseEnter, onMouseLeave }) => (
+
+ )}
+
+
+ );
+}
+
+export function UserMuteButton({ user }: { user: User; }) {
+ if (user.id === UserStore.getCurrentUser().id) return null;
+ return (
+
+
+ {({ onMouseEnter, onMouseLeave }) => (
+
+ )}
+
+
+ );
+}
+
+function DeafenIcon({ user, ...props }) {
+ const isDeafened =
+ MediaEngineStore.isLocalMute(user.id) &&
+ SoundboardStore.isLocalSoundboardMuted(user.id) &&
+ MediaEngineStore.isLocalVideoDisabled(user.id);
+
+ return (
+
+ );
+}
+
+export function UserDeafenButton({ user }: { user: User; }) {
+ if (user.id === UserStore.getCurrentUser().id) return null;
+ const isDeafened =
+ MediaEngineStore.isLocalMute(user.id) &&
+ SoundboardStore.isLocalSoundboardMuted(user.id) &&
+ MediaEngineStore.isLocalVideoDisabled(user.id);
+ return (
+
+
+ {({ onMouseEnter, onMouseLeave }) => (
+
+ )}
+
+
+ );
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index bfb5a4bc3..cec3b5004 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -1148,6 +1148,10 @@ export const EquicordDevs = Object.freeze({
justjxke: {
name: "justjxke",
id: 852558183087472640n
+ },
+ nicola02nb: {
+ name: "nicola02nb",
+ id: 257900031351193600n
}
} satisfies Record);
From 22059c54783215d1f4e4caa95e7ab83500cc0299 Mon Sep 17 00:00:00 2001
From: thororen1234 <78185467+thororen1234@users.noreply.github.com>
Date: Sun, 21 Sep 2025 14:40:49 -0400
Subject: [PATCH 2/8] Update Requests Links
---
CONTRIBUTING.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1e945c0d0..013841274 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -20,8 +20,8 @@ Before starting your plugin:
- Be in our discord
- Check existing pull requests to see if someone is already working on a similar plugin
-- Check our [plugin requests tracker](https://discord.com/channels/1173279886065029291/1173334591302553631) to see if there is an existing request, or if the same idea has been rejected
-- If there isn't an existing request, [open one](https://discord.com/channels/1173279886065029291/1173334591302553631) yourself.
+- Check our [plugin requests tracker](https://discord.com/channels/1173279886065029291/1419347113745059961) to see if there is an existing request, or if the same idea has been rejected
+- If there isn't an existing request, [open one](https://discord.com/channels/1173279886065029291/1419347113745059961) yourself.
and include that you'd like to work on this yourself. Then wait for feedback to see if the idea even has any chance of being accepted. Or maybe others have some ideas to improve it!
- Familarise yourself with our plugin rules below to ensure your plugin is not banned
From 8c2dc84f3b3c18e20fc5c8c94ea1b837a1a3b093 Mon Sep 17 00:00:00 2001
From: thororen <78185467+thororen1234@users.noreply.github.com>
Date: Sun, 21 Sep 2025 22:38:57 -0400
Subject: [PATCH 3/8] Settings: fix debug info layout (#3673)
---
src/plugins/_core/settings.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/plugins/_core/settings.tsx b/src/plugins/_core/settings.tsx
index 4a0f297e4..4d12f37a1 100644
--- a/src/plugins/_core/settings.tsx
+++ b/src/plugins/_core/settings.tsx
@@ -39,7 +39,7 @@ export default definePlugin({
find: ".versionHash",
replacement: [
{
- match: /\[\(0,\i\.jsxs?\)\((.{1,10}),(\{[^{}}]+\{.{0,20}.versionHash,.+?\})\)," "/,
+ match: /\.info.+?\[\(0,\i\.jsxs?\)\((.{1,10}),(\{[^{}}]+\{.{0,20}.versionHash,.+?\})\)," "/,
replace: (m, component, props) => {
props = props.replace(/children:\[.+\]/, "");
return `${m},$self.makeInfoElements(${component}, ${props})`;
From 80872f4ab9a0184c05d1b34dfec4a052c1c0709b Mon Sep 17 00:00:00 2001
From: quarty <142720982+qwertyquarty@users.noreply.github.com>
Date: Mon, 22 Sep 2025 04:44:13 +0200
Subject: [PATCH 4/8] MessageLatency: add option to ignore own messages (#3677)
Co-authored-by: V
---
src/plugins/messageLatency/index.tsx | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/plugins/messageLatency/index.tsx b/src/plugins/messageLatency/index.tsx
index b81c55cf7..437ce6440 100644
--- a/src/plugins/messageLatency/index.tsx
+++ b/src/plugins/messageLatency/index.tsx
@@ -11,7 +11,7 @@ import { isNonNullish } from "@utils/guards";
import definePlugin, { OptionType } from "@utils/types";
import { Message } from "@vencord/discord-types";
import { findComponentByCodeLazy } from "@webpack";
-import { SnowflakeUtils, Tooltip } from "@webpack/common";
+import { AuthenticationStore, SnowflakeUtils, Tooltip } from "@webpack/common";
type FillValue = ("status-danger" | "status-warning" | "status-positive" | "text-muted");
type Fill = [FillValue, FillValue, FillValue];
@@ -48,6 +48,11 @@ export default definePlugin({
type: OptionType.BOOLEAN,
description: "Show milliseconds",
default: false
+ },
+ ignoreSelf: {
+ type: OptionType.BOOLEAN,
+ description: "Don't add indicator to your own messages",
+ default: false
}
}),
@@ -91,7 +96,7 @@ export default definePlugin({
},
latencyTooltipData(message: Message) {
- const { latency, detectDiscordKotlin, showMillis } = this.settings.store;
+ const { latency, detectDiscordKotlin, showMillis, ignoreSelf } = this.settings.store;
const { id, nonce } = message;
// Message wasn't received through gateway
@@ -100,6 +105,8 @@ export default definePlugin({
// Bots basically never send a nonce, and if someone does do it then it's usually not a snowflake
if (message.author.bot) return null;
+ if (ignoreSelf && message.author.id === AuthenticationStore.getId()) return null;
+
let isDiscordKotlin = false;
let delta = SnowflakeUtils.extractTimestamp(id) - SnowflakeUtils.extractTimestamp(nonce); // milliseconds
if (!showMillis) {
From edd68fe08e5f929e95e6635ec65ec9fdc54089f7 Mon Sep 17 00:00:00 2001
From: nin0
Date: Sun, 21 Sep 2025 23:08:08 -0400
Subject: [PATCH 5/8] AppleMusicRichPresence: add status display type (#3669)
Co-authored-by: V
---
packages/discord-types/enums/activity.ts | 30 +++++++++
packages/discord-types/enums/index.ts | 1 +
.../discord-types/src/common/Activity.d.ts | 36 ++++++++++
packages/discord-types/src/common/index.d.ts | 1 +
src/plugins/appleMusic.desktop/index.tsx | 67 ++++++++-----------
src/plugins/customRPC/index.tsx | 38 +----------
src/plugins/lastfmRichPresence/index.tsx | 51 ++------------
7 files changed, 104 insertions(+), 120 deletions(-)
create mode 100644 packages/discord-types/enums/activity.ts
create mode 100644 packages/discord-types/src/common/Activity.d.ts
diff --git a/packages/discord-types/enums/activity.ts b/packages/discord-types/enums/activity.ts
new file mode 100644
index 000000000..513a65dee
--- /dev/null
+++ b/packages/discord-types/enums/activity.ts
@@ -0,0 +1,30 @@
+export const enum ActivityType {
+ PLAYING = 0,
+ STREAMING = 1,
+ LISTENING = 2,
+ WATCHING = 3,
+ CUSTOM_STATUS = 4,
+ COMPETING = 5,
+ HANG_STATUS = 6
+}
+
+export const enum ActivityFlags {
+ INSTANCE = 1 << 0,
+ JOIN = 1 << 1,
+ /** @deprecated */
+ SPECTATE = 1 << 2,
+ /** @deprecated */
+ JOIN_REQUEST = 1 << 3,
+ SYNC = 1 << 4,
+ PLAY = 1 << 5,
+ PARTY_PRIVACY_FRIENDS = 1 << 6,
+ PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7,
+ EMBEDDED = 1 << 8,
+ CONTEXTLESS = 1 << 9
+}
+
+export const enum ActivityStatusDisplayType {
+ NAME = 0,
+ STATE = 1,
+ DETAILS = 2
+}
diff --git a/packages/discord-types/enums/index.ts b/packages/discord-types/enums/index.ts
index 3d80895cd..a25ff3b5d 100644
--- a/packages/discord-types/enums/index.ts
+++ b/packages/discord-types/enums/index.ts
@@ -1,3 +1,4 @@
+export * from "./activity";
export * from "./channel";
export * from "./commands";
export * from "./messages";
diff --git a/packages/discord-types/src/common/Activity.d.ts b/packages/discord-types/src/common/Activity.d.ts
new file mode 100644
index 000000000..d513780ac
--- /dev/null
+++ b/packages/discord-types/src/common/Activity.d.ts
@@ -0,0 +1,36 @@
+import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "../../enums";
+
+export interface ActivityAssets {
+ large_image?: string;
+ large_text?: string;
+ small_image?: string;
+ small_text?: string;
+}
+
+export interface ActivityButton {
+ label: string;
+ url: string;
+}
+
+export interface Activity {
+ name: string;
+ application_id: string;
+ type: ActivityType;
+ state?: string;
+ state_url?: string;
+ details?: string;
+ details_url?: string;
+ url?: string;
+ flags: ActivityFlags;
+ status_display_type?: ActivityStatusDisplayType;
+ timestamps?: {
+ start?: number;
+ end?: number;
+ };
+ assets?: ActivityAssets;
+ buttons?: string[];
+ metadata?: {
+ button_urls?: Array;
+ };
+}
+
diff --git a/packages/discord-types/src/common/index.d.ts b/packages/discord-types/src/common/index.d.ts
index 5e50e96e0..65ad88562 100644
--- a/packages/discord-types/src/common/index.d.ts
+++ b/packages/discord-types/src/common/index.d.ts
@@ -1,3 +1,4 @@
+export * from "./Activity";
export * from "./Application";
export * from "./Channel";
export * from "./Guild";
diff --git a/src/plugins/appleMusic.desktop/index.tsx b/src/plugins/appleMusic.desktop/index.tsx
index 57e5ae19e..f6fc9da93 100644
--- a/src/plugins/appleMusic.desktop/index.tsx
+++ b/src/plugins/appleMusic.desktop/index.tsx
@@ -7,49 +7,12 @@
import { definePluginSettings } from "@api/Settings";
import { Devs, IS_MAC } from "@utils/constants";
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
+import { Activity, ActivityAssets, ActivityButton } from "@vencord/discord-types";
+import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "@vencord/discord-types/enums";
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
const Native = VencordNative.pluginHelpers.AppleMusicRichPresence as PluginNative;
-interface ActivityAssets {
- large_image?: string;
- large_text?: string;
- small_image?: string;
- small_text?: string;
-}
-
-interface ActivityButton {
- label: string;
- url: string;
-}
-
-interface Activity {
- state?: string;
- details?: string;
- timestamps?: {
- start?: number;
- end?: number;
- };
- assets?: ActivityAssets;
- buttons?: Array;
- name: string;
- application_id: string;
- metadata?: {
- button_urls?: Array;
- };
- type: number;
- flags: number;
-}
-
-const enum ActivityType {
- PLAYING = 0,
- LISTENING = 2,
-}
-
-const enum ActivityFlag {
- INSTANCE = 1 << 0,
-}
-
export interface TrackData {
name: string;
album?: string;
@@ -90,6 +53,25 @@ const settings = definePluginSettings({
{ label: "Listening", value: ActivityType.LISTENING }
],
},
+ statusDisplayType: {
+ description: "Show the track / artist name in the member list",
+ type: OptionType.SELECT,
+ options: [
+ {
+ label: "Don't show (shows generic listening message)",
+ value: "off",
+ default: true
+ },
+ {
+ label: "Show artist name",
+ value: "artist"
+ },
+ {
+ label: "Show track name",
+ value: "track"
+ }
+ ]
+ },
refreshInterval: {
type: OptionType.SLIDER,
description: "The interval between activity refreshes (seconds)",
@@ -258,7 +240,12 @@ export default definePlugin({
metadata: !isRadio && buttons.length ? { button_urls: buttons.map(v => v.url) } : undefined,
type: settings.store.activityType,
- flags: ActivityFlag.INSTANCE,
+ status_display_type: {
+ "off": ActivityStatusDisplayType.NAME,
+ "artist": ActivityStatusDisplayType.STATE,
+ "track": ActivityStatusDisplayType.DETAILS
+ }[settings.store.statusDisplayType],
+ flags: ActivityFlags.INSTANCE,
};
}
});
diff --git a/src/plugins/customRPC/index.tsx b/src/plugins/customRPC/index.tsx
index d35dad135..9a5a1cd98 100644
--- a/src/plugins/customRPC/index.tsx
+++ b/src/plugins/customRPC/index.tsx
@@ -27,6 +27,8 @@ import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import { useAwaiter } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types";
+import { Activity } from "@vencord/discord-types";
+import { ActivityType } from "@vencord/discord-types/enums";
import { findByCodeLazy, findComponentByCodeLazy } from "@webpack";
import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, React, UserStore } from "@webpack/common";
@@ -39,41 +41,7 @@ async function getApplicationAsset(key: string): Promise {
return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0];
}
-interface ActivityAssets {
- large_image?: string;
- large_text?: string;
- small_image?: string;
- small_text?: string;
-}
-
-interface Activity {
- state?: string;
- details?: string;
- timestamps?: {
- start?: number;
- end?: number;
- };
- assets?: ActivityAssets;
- buttons?: Array;
- name: string;
- application_id: string;
- metadata?: {
- button_urls?: Array;
- };
- type: ActivityType;
- url?: string;
- flags: number;
-}
-
-const enum ActivityType {
- PLAYING = 0,
- STREAMING = 1,
- LISTENING = 2,
- WATCHING = 3,
- COMPETING = 5
-}
-
-const enum TimestampMode {
+export const enum TimestampMode {
NONE,
NOW,
TIME,
diff --git a/src/plugins/lastfmRichPresence/index.tsx b/src/plugins/lastfmRichPresence/index.tsx
index abf42d5ff..3c36e9dce 100644
--- a/src/plugins/lastfmRichPresence/index.tsx
+++ b/src/plugins/lastfmRichPresence/index.tsx
@@ -21,40 +21,11 @@ import { Link } from "@components/Link";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
+import { Activity, ActivityAssets, ActivityButton } from "@vencord/discord-types";
+import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "@vencord/discord-types/enums";
import { findByPropsLazy } from "@webpack";
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
-interface ActivityAssets {
- large_image?: string;
- large_text?: string;
- small_image?: string;
- small_text?: string;
-}
-
-
-interface ActivityButton {
- label: string;
- url: string;
-}
-
-interface Activity {
- state: string;
- details?: string;
- timestamps?: {
- start?: number;
- };
- assets?: ActivityAssets;
- buttons?: Array;
- name: string;
- application_id: string;
- status_display_type?: number;
- metadata?: {
- button_urls?: Array;
- };
- type: number;
- flags: number;
-}
-
interface TrackData {
name: string;
album: string;
@@ -63,16 +34,6 @@ interface TrackData {
imageUrl?: string;
}
-// only relevant enum values
-const enum ActivityType {
- PLAYING = 0,
- LISTENING = 2,
-}
-
-const enum ActivityFlag {
- INSTANCE = 1 << 0,
-}
-
const enum NameFormat {
StatusName = "status-name",
ArtistFirst = "artist-first",
@@ -367,9 +328,9 @@ export default definePlugin({
details: trackData.name,
state: trackData.artist,
status_display_type: {
- "off": 0,
- "artist": 1,
- "track": 2
+ "off": ActivityStatusDisplayType.NAME,
+ "artist": ActivityStatusDisplayType.STATE,
+ "track": ActivityStatusDisplayType.DETAILS
}[settings.store.statusDisplayType],
assets,
@@ -379,7 +340,7 @@ export default definePlugin({
},
type: settings.store.useListeningStatus ? ActivityType.LISTENING : ActivityType.PLAYING,
- flags: ActivityFlag.INSTANCE,
+ flags: ActivityFlags.INSTANCE,
};
}
});
From 2e9d67f0b4dbc59088b22e317c634d96c92a5985 Mon Sep 17 00:00:00 2001
From: thororen <78185467+thororen1234@users.noreply.github.com>
Date: Sun, 21 Sep 2025 23:15:14 -0400
Subject: [PATCH 6/8] add Vencord badges to user settings section (#3667)
Co-authored-by: V
---
src/plugins/_api/badges/index.tsx | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx
index 8742a4bd3..8c900038d 100644
--- a/src/plugins/_api/badges/index.tsx
+++ b/src/plugins/_api/badges/index.tsx
@@ -111,6 +111,13 @@ export default definePlugin({
replace: "...$self.getBadgeMouseEventHandlers($1),$&"
}
]
+ },
+ {
+ find: "profileCardUsernameRow,children:",
+ replacement: {
+ match: /badges:(\i)(?<=displayProfile:(\i).+?)/,
+ replace: "badges:[...$self.getBadges($2),...$1]"
+ }
}
],
From 228b85a0c8287e72f88b89a821919c51cb982468 Mon Sep 17 00:00:00 2001
From: Vendicated
Date: Mon, 22 Sep 2025 05:18:10 +0200
Subject: [PATCH 7/8] bump to v1.13.0
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 3f0e3371f..4f05e969d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "vencord",
"private": "true",
- "version": "1.12.13",
+ "version": "1.13.0",
"description": "The cutest Discord client mod",
"homepage": "https://github.com/Vendicated/Vencord#readme",
"bugs": {
@@ -105,4 +105,4 @@
"engines": {
"node": ">=18"
}
-}
\ No newline at end of file
+}
From f84aa0c92cc0e99966ea2f0af8a25933bed08514 Mon Sep 17 00:00:00 2001
From: thororen1234 <78185467+thororen1234@users.noreply.github.com>
Date: Mon, 22 Sep 2025 09:11:05 -0400
Subject: [PATCH 8/8] Move Activity Types
---
src/equicordplugins/betterActivities/types.ts | 8 ---
.../betterActivities/utils.tsx | 2 +-
.../gensokyoRadioRPC/index.tsx | 5 +-
src/equicordplugins/gensokyoRadioRPC/types.ts | 9 ----
.../rpcEditor/ReplaceSettings.tsx | 13 ++++-
src/equicordplugins/rpcEditor/index.tsx | 50 ++++---------------
src/equicordplugins/statsfmPresence/index.tsx | 15 +-----
src/equicordplugins/tosuRPC/index.ts | 6 ++-
src/equicordplugins/tosuRPC/type.ts | 34 -------------
src/equicordplugins/vencordRPC/index.ts | 37 +-------------
10 files changed, 34 insertions(+), 145 deletions(-)
diff --git a/src/equicordplugins/betterActivities/types.ts b/src/equicordplugins/betterActivities/types.ts
index e90524e62..de62b0ab3 100644
--- a/src/equicordplugins/betterActivities/types.ts
+++ b/src/equicordplugins/betterActivities/types.ts
@@ -78,11 +78,3 @@ export interface ActivityViewProps {
application?: Application;
currentUser: User;
}
-
-export const enum ActivityType {
- PLAYING = 0,
- STREAMING = 1,
- LISTENING = 2,
- WATCHING = 3,
- COMPETING = 5
-}
diff --git a/src/equicordplugins/betterActivities/utils.tsx b/src/equicordplugins/betterActivities/utils.tsx
index f1d0a9972..61de0479a 100644
--- a/src/equicordplugins/betterActivities/utils.tsx
+++ b/src/equicordplugins/betterActivities/utils.tsx
@@ -44,7 +44,7 @@ export function getApplicationIcons(activities: Activity[], preferSmall = false)
for (const activity of applications) {
const { assets, application_id, platform, id } = activity;
- if (!application_id && !platform && !id.startsWith("spotify:")) continue;
+ if (!application_id && !platform && !id?.startsWith("spotify:")) continue;
if (assets) {
const { small_image, small_text, large_image, large_text } = assets;
diff --git a/src/equicordplugins/gensokyoRadioRPC/index.tsx b/src/equicordplugins/gensokyoRadioRPC/index.tsx
index 4a166406d..5aa943e93 100644
--- a/src/equicordplugins/gensokyoRadioRPC/index.tsx
+++ b/src/equicordplugins/gensokyoRadioRPC/index.tsx
@@ -7,9 +7,10 @@
import { definePluginSettings } from "@api/Settings";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
+import { Activity } from "@vencord/discord-types";
+import { ActivityFlags, ActivityType } from "@vencord/discord-types/enums";
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
-import { Activity, ActivityFlag, ActivityType } from "./types";
const Native = VencordNative.pluginHelpers.GensokyoRadioRPC as PluginNative;
@@ -96,7 +97,7 @@ export default definePlugin({
metadata: { button_urls: undefined },
type: ActivityType.LISTENING,
- flags: ActivityFlag.INSTANCE,
+ flags: ActivityFlags.INSTANCE,
};
}
});
diff --git a/src/equicordplugins/gensokyoRadioRPC/types.ts b/src/equicordplugins/gensokyoRadioRPC/types.ts
index 3fa0464b3..21b44194e 100644
--- a/src/equicordplugins/gensokyoRadioRPC/types.ts
+++ b/src/equicordplugins/gensokyoRadioRPC/types.ts
@@ -36,15 +36,6 @@ export interface ActivityAssets {
small_text?: string;
}
-export const enum ActivityType {
- PLAYING = 0,
- LISTENING = 2,
-}
-
-export const enum ActivityFlag {
- INSTANCE = 1 << 0
-}
-
export interface TrackData {
title: string;
album: string;
diff --git a/src/equicordplugins/rpcEditor/ReplaceSettings.tsx b/src/equicordplugins/rpcEditor/ReplaceSettings.tsx
index 701ef21e8..ab393408c 100644
--- a/src/equicordplugins/rpcEditor/ReplaceSettings.tsx
+++ b/src/equicordplugins/rpcEditor/ReplaceSettings.tsx
@@ -7,9 +7,11 @@
import { CheckedTextInput } from "@components/CheckedTextInput";
import { Margins } from "@utils/margins";
import { identity } from "@utils/misc";
+import { Activity } from "@vencord/discord-types";
+import { ActivityFlags, ActivityType } from "@vencord/discord-types/enums";
import { Card, Forms, PresenceStore, React, Select, SnowflakeUtils, Switch, TextInput, UserStore } from "@webpack/common";
-import { Activity, ActivityType, AppIdSetting, makeEmptyAppId } from ".";
+import { AppIdSetting, makeEmptyAppId } from ".";
interface SettingsProps {
appIds: AppIdSetting[];
@@ -28,7 +30,14 @@ export function ReplaceTutorial() {
<>
IDs of currently running activities
{
- activities.length === 0 ? No running activities : activities.map(activity => { return activity.flags !== 48 ? {activity.name}: {activity.application_id} : null; /* hide spotify */ })
+ activities.length === 0
+ ? No running activities
+ : activities.map(activity => {
+ const isSpotify = (activity.flags & (ActivityFlags.SYNC | ActivityFlags.PLAY)) === (ActivityFlags.SYNC | ActivityFlags.PLAY);
+ return !isSpotify
+ ? {activity.name}: {activity.application_id}
+ : null;
+ })
}
Available variables
diff --git a/src/equicordplugins/rpcEditor/index.tsx b/src/equicordplugins/rpcEditor/index.tsx
index b623caacf..e60d6627f 100644
--- a/src/equicordplugins/rpcEditor/index.tsx
+++ b/src/equicordplugins/rpcEditor/index.tsx
@@ -9,11 +9,14 @@ import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { useForceUpdater } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types";
+import { Activity } from "@vencord/discord-types";
+import { ActivityType } from "@vencord/discord-types/enums";
import { React } from "@webpack/common";
import { ReplaceSettings, ReplaceTutorial } from "./ReplaceSettings";
const APP_IDS_KEY = "ReplaceActivityType_appids";
+
export type AppIdSetting = {
disableAssets: boolean;
disableTimestamps: boolean;
@@ -30,40 +33,6 @@ export type AppIdSetting = {
newStreamUrl: string;
};
-export interface Activity {
- state: string;
- details: string;
- timestamps?: {
- start?: number;
- end?: number;
- };
- url?: string;
- assets: ActivityAssets;
- buttons?: Array;
- name: string;
- application_id: string;
- metadata?: {
- button_urls?: Array;
- };
- type: number;
- flags: number;
-}
-
-interface ActivityAssets {
- large_image: string;
- large_text: string;
- small_image: string;
- small_text: string;
-}
-
-export const enum ActivityType {
- PLAYING = 0,
- STREAMING = 1,
- LISTENING = 2,
- WATCHING = 3,
- COMPETING = 5
-}
-
export const makeEmptyAppId: () => AppIdSetting = () => ({
appId: "",
enabled: true,
@@ -124,12 +93,12 @@ export default definePlugin({
if (text === "null") return "";
return text
.replaceAll(":name:", originalActivity.name)
- .replaceAll(":details:", originalActivity.details)
- .replaceAll(":state:", originalActivity.state)
- .replaceAll(":large_image:", originalActivity.assets.large_image)
- .replaceAll(":large_text:", originalActivity.assets.large_text)
- .replaceAll(":small_image:", originalActivity.assets.small_image)
- .replaceAll(":small_text:", originalActivity.assets.small_text);
+ .replaceAll(":details:", originalActivity.details ?? "")
+ .replaceAll(":state:", originalActivity.state ?? "")
+ .replaceAll(":large_image:", originalActivity.assets?.large_image ?? "")
+ .replaceAll(":large_text:", originalActivity.assets?.large_text ?? "")
+ .replaceAll(":small_image:", originalActivity.assets?.small_image ?? "")
+ .replaceAll(":small_text:", originalActivity.assets?.small_text ?? "");
},
patchActivity(activity: Activity) {
if (!activity) return;
@@ -141,6 +110,7 @@ export default definePlugin({
if (app.newActivityType === ActivityType.STREAMING && app.newStreamUrl) activity.url = app.newStreamUrl;
if (app.newDetails) activity.details = this.parseField(app.newDetails, oldActivity);
if (app.newState) activity.state = this.parseField(app.newState, oldActivity);
+ if (!activity.assets) activity.assets = {};
if (app.newLargeImageText) activity.assets.large_text = this.parseField(app.newLargeImageText, oldActivity);
if (app.newLargeImageUrl) activity.assets.large_image = this.parseField(app.newLargeImageUrl, oldActivity);
if (app.newSmallImageText) activity.assets.small_text = this.parseField(app.newSmallImageText, oldActivity);
diff --git a/src/equicordplugins/statsfmPresence/index.tsx b/src/equicordplugins/statsfmPresence/index.tsx
index fcb19ddc2..2d8b65782 100644
--- a/src/equicordplugins/statsfmPresence/index.tsx
+++ b/src/equicordplugins/statsfmPresence/index.tsx
@@ -9,6 +9,7 @@ import { getUserSettingLazy } from "@api/UserSettings";
import { EquicordDevs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
+import { ActivityFlags, ActivityType } from "@vencord/discord-types/enums";
import { findByPropsLazy } from "@webpack";
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
@@ -50,16 +51,6 @@ interface TrackData {
imageUrl?: string;
}
-// only relevant enum values
-const enum ActivityType {
- PLAYING = 0,
- LISTENING = 2,
-}
-
-const enum ActivityFlag {
- INSTANCE = 1 << 0,
-}
-
const enum NameFormat {
StatusName = "status-name",
ArtistFirst = "artist-first",
@@ -69,8 +60,6 @@ const enum NameFormat {
albumsName = "albums"
}
-
-
interface Albums {
id: number;
image: string;
@@ -373,7 +362,7 @@ export default definePlugin({
},
type: settings.store.useListeningStatus ? ActivityType.LISTENING : ActivityType.PLAYING,
- flags: ActivityFlag.INSTANCE,
+ flags: ActivityFlags.INSTANCE,
};
}
});
diff --git a/src/equicordplugins/tosuRPC/index.ts b/src/equicordplugins/tosuRPC/index.ts
index 05d908b37..9e2a9faef 100644
--- a/src/equicordplugins/tosuRPC/index.ts
+++ b/src/equicordplugins/tosuRPC/index.ts
@@ -6,9 +6,11 @@
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
+import { Activity } from "@vencord/discord-types";
+import { ActivityType } from "@vencord/discord-types/enums";
import { ApplicationAssetUtils, FluxDispatcher } from "@webpack/common";
-import { Activity, ActivityType, BanchoStatusEnum, GameState, Modes, TosuApi, UserLoginStatus } from "./type";
+import { BanchoStatusEnum, GameState, Modes, TosuApi, UserLoginStatus } from "./type";
const socketId = "tosu";
const OSU_APP_ID = "367827983903490050";
@@ -64,6 +66,8 @@ async function onMessage(data: string) {
flags: 1 << 0,
};
+ activity.assets = {};
+
switch (profile.mode.number) {
case Modes.Osu:
activity.assets.small_image = OSU_STARDARD_SMALL_IMAGE;
diff --git a/src/equicordplugins/tosuRPC/type.ts b/src/equicordplugins/tosuRPC/type.ts
index 67c3e4957..7ded0748f 100644
--- a/src/equicordplugins/tosuRPC/type.ts
+++ b/src/equicordplugins/tosuRPC/type.ts
@@ -4,40 +4,6 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-export interface ActivityAssets {
- large_image?: string;
- large_text?: string;
- small_image?: string;
- small_text?: string;
-}
-
-export interface Activity {
- state?: string;
- details?: string;
- timestamps?: {
- start?: number;
- end?: number;
- };
- assets: ActivityAssets;
- buttons?: Array;
- name: string;
- application_id: string;
- metadata?: {
- button_urls?: Array;
- };
- type: ActivityType;
- url?: string;
- flags: number;
-}
-
-export enum ActivityType {
- PLAYING = 0,
- STREAMING = 1,
- LISTENING = 2,
- WATCHING = 3,
- COMPETING = 5
-}
-
export enum BeatmapStatuses {
Unknown,
NotSubmitted = 1,
diff --git a/src/equicordplugins/vencordRPC/index.ts b/src/equicordplugins/vencordRPC/index.ts
index ec8fb81c3..ba985418a 100644
--- a/src/equicordplugins/vencordRPC/index.ts
+++ b/src/equicordplugins/vencordRPC/index.ts
@@ -8,7 +8,8 @@ import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { isTruthy } from "@utils/guards";
import definePlugin, { OptionType } from "@utils/types";
-import { Channel, FluxStore } from "@vencord/discord-types";
+import { Activity, Channel, FluxStore } from "@vencord/discord-types";
+import { ActivityType } from "@vencord/discord-types/enums";
import { findByPropsLazy, findStoreLazy } from "@webpack";
import { ApplicationAssetUtils, ChannelStore, FluxDispatcher, GuildStore, IconUtils, PresenceStore, RelationshipStore, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common";
@@ -26,40 +27,6 @@ async function getApplicationAsset(key: string): Promise {
return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0];
}
-interface ActivityAssets {
- large_image?: string;
- large_text?: string;
- small_image?: string;
- small_text?: string;
-}
-
-interface Activity {
- state?: string;
- details?: string;
- timestamps?: {
- start?: number;
- end?: number;
- };
- assets?: ActivityAssets;
- buttons?: Array;
- name: string;
- application_id: string;
- metadata?: {
- button_urls?: Array;
- };
- type: ActivityType;
- url?: string;
- flags: number;
-}
-
-const enum ActivityType {
- PLAYING = 0,
- STREAMING = 1,
- LISTENING = 2,
- WATCHING = 3,
- COMPETING = 5
-}
-
const enum TimestampMode {
NONE,
NOW,