+
{!!getCurrentChannel()?.guild_id && (
Date: Sat, 20 Apr 2024 14:51:33 +0200
Subject: [PATCH 22/30] Make Updater slightly more future proof
- Removes the option to disable update notifications. Users really should not be outdated, so this option was never good. To disable notifications, turn on auto update
- Enables auto update by default. Users keep complaining about issues while being outdated, so this should help
- Update Notification now opens Updater in a modal to remove dependency on Settings patch. This makes it slightly more failsafe, it's unlikely that both modals and our settings patch break
---
src/Vencord.ts | 20 ++++-----
src/api/Settings.ts | 4 +-
src/components/VencordSettings/UpdaterTab.tsx | 41 ++++++++++++-------
.../VencordSettings/settingsStyles.css | 8 ++++
src/components/VencordSettings/shared.tsx | 6 +--
5 files changed, 48 insertions(+), 31 deletions(-)
diff --git a/src/Vencord.ts b/src/Vencord.ts
index 29e965fa0..655e76c3d 100644
--- a/src/Vencord.ts
+++ b/src/Vencord.ts
@@ -27,6 +27,7 @@ export { PlainSettings, Settings };
import "./utils/quickCss";
import "./webpack/patchWebpack";
+import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab";
import { StartAt } from "@utils/types";
import { get as dsGet } from "./api/DataStore";
@@ -85,7 +86,7 @@ async function init() {
syncSettings();
- if (!IS_WEB) {
+ if (!IS_WEB && !IS_UPDATER_DISABLED) {
try {
const isOutdated = await checkForUpdates();
if (!isOutdated) return;
@@ -103,16 +104,13 @@ async function init() {
return;
}
- if (Settings.notifyAboutUpdates)
- setTimeout(() => showNotification({
- title: "A Vencord update is available!",
- body: "Click here to view the update",
- permanent: true,
- noPersist: true,
- onClick() {
- SettingsRouter.open("VencordUpdater");
- }
- }), 10_000);
+ setTimeout(() => showNotification({
+ title: "A Vencord update is available!",
+ body: "Click here to view the update",
+ permanent: true,
+ noPersist: true,
+ onClick: openUpdaterModal!
+ }), 10_000);
} catch (err) {
UpdateLogger.error("Failed to check for updates", err);
}
diff --git a/src/api/Settings.ts b/src/api/Settings.ts
index 0b7975300..696c12c28 100644
--- a/src/api/Settings.ts
+++ b/src/api/Settings.ts
@@ -29,7 +29,6 @@ import plugins from "~plugins";
const logger = new Logger("Settings");
export interface Settings {
- notifyAboutUpdates: boolean;
autoUpdate: boolean;
autoUpdateNotification: boolean,
useQuickCss: boolean;
@@ -78,8 +77,7 @@ export interface Settings {
}
const DefaultSettings: Settings = {
- notifyAboutUpdates: true,
- autoUpdate: false,
+ autoUpdate: true,
autoUpdateNotification: true,
useQuickCss: true,
themeLinks: [],
diff --git a/src/components/VencordSettings/UpdaterTab.tsx b/src/components/VencordSettings/UpdaterTab.tsx
index 0a5d1f149..680e262d8 100644
--- a/src/components/VencordSettings/UpdaterTab.tsx
+++ b/src/components/VencordSettings/UpdaterTab.tsx
@@ -22,6 +22,7 @@ import { Flex } from "@components/Flex";
import { Link } from "@components/Link";
import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
+import { ModalCloseButton, ModalContent, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { relaunch } from "@utils/native";
import { useAwaiter } from "@utils/react";
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
@@ -29,7 +30,7 @@ import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@web
import gitHash from "~git-hash";
-import { SettingsTab, wrapTab } from "./shared";
+import { handleSettingsTabError, SettingsTab, wrapTab } from "./shared";
function withDispatcher(dispatcher: React.Dispatch>, action: () => any) {
return async () => {
@@ -38,21 +39,24 @@ function withDispatcher(dispatcher: React.Dispatch
await action();
} catch (e: any) {
UpdateLogger.error("Failed to update", e);
+
+ let err: string;
if (!e) {
- var err = "An unknown error occurred (error is undefined).\nPlease try again.";
+ err = "An unknown error occurred (error is undefined).\nPlease try again.";
} else if (e.code && e.cmd) {
const { code, path, cmd, stderr } = e;
if (code === "ENOENT")
- var err = `Command \`${path}\` not found.\nPlease install it and try again`;
+ err = `Command \`${path}\` not found.\nPlease install it and try again`;
else {
- var err = `An error occurred while running \`${cmd}\`:\n`;
+ err = `An error occurred while running \`${cmd}\`:\n`;
err += stderr || `Code \`${code}\`. See the console for more info`;
}
} else {
- var err = "An unknown error occurred. See the console for more info.";
+ err = "An unknown error occurred. See the console for more info.";
}
+
Alerts.show({
title: "Oops!",
body: (
@@ -186,7 +190,7 @@ function Newer(props: CommonProps) {
}
function Updater() {
- const settings = useSettings(["notifyAboutUpdates", "autoUpdate", "autoUpdateNotification"]);
+ const settings = useSettings(["autoUpdate", "autoUpdateNotification"]);
const [repo, err, repoPending] = useAwaiter(getRepo, { fallbackValue: "Loading..." });
@@ -203,14 +207,6 @@ function Updater() {
return (
Updater Settings
- settings.notifyAboutUpdates = v}
- note="Shows a notification on startup"
- disabled={settings.autoUpdate}
- >
- Get notified about new updates
-
settings.autoUpdate = v}
@@ -253,3 +249,20 @@ function Updater() {
}
export default IS_UPDATER_DISABLED ? null : wrapTab(Updater, "Updater");
+
+export const openUpdaterModal = IS_UPDATER_DISABLED ? null : function () {
+ const UpdaterTab = wrapTab(Updater, "Updater");
+
+ try {
+ openModal(wrapTab((modalProps: ModalProps) => (
+
+
+
+
+
+
+ ), "UpdaterModal"));
+ } catch {
+ handleSettingsTabError();
+ }
+};
diff --git a/src/components/VencordSettings/settingsStyles.css b/src/components/VencordSettings/settingsStyles.css
index 01cbcd557..310dba9af 100644
--- a/src/components/VencordSettings/settingsStyles.css
+++ b/src/components/VencordSettings/settingsStyles.css
@@ -65,3 +65,11 @@
/* discord also sets cursor: default which prevents the cursor from showing as text */
cursor: initial;
}
+
+.vc-updater-modal {
+ padding: 1.5em !important;
+}
+
+.vc-updater-modal-close-button {
+ float: right;
+}
diff --git a/src/components/VencordSettings/shared.tsx b/src/components/VencordSettings/shared.tsx
index 6dd34c46f..1c5f37d82 100644
--- a/src/components/VencordSettings/shared.tsx
+++ b/src/components/VencordSettings/shared.tsx
@@ -42,11 +42,11 @@ export function SettingsTab({ title, children }: PropsWithChildren<{ title: stri
);
}
-const onError = onlyOnce(handleComponentFailed);
+export const handleSettingsTabError = onlyOnce(handleComponentFailed);
-export function wrapTab(component: ComponentType, tab: string) {
+export function wrapTab(component: ComponentType, tab: string) {
return ErrorBoundary.wrap(component, {
message: `Failed to render the ${tab} tab. If this issue persists, try using the installer to reinstall!`,
- onError,
+ onError: handleSettingsTabError,
});
}
From af67ddefa14edb896d63afe026d4736ebf954169 Mon Sep 17 00:00:00 2001
From: dolfies
Date: Mon, 22 Apr 2024 19:46:11 -0400
Subject: [PATCH 23/30] ShowTimeouts->ShowHiddenThings ~show invite-disabled
tooltip too (#2375)
---
src/plugins/showHiddenThings/README.md | 11 +++++++
.../index.ts | 32 +++++++++++++++++--
2 files changed, 40 insertions(+), 3 deletions(-)
create mode 100644 src/plugins/showHiddenThings/README.md
rename src/plugins/{showTimeouts => showHiddenThings}/index.ts (51%)
diff --git a/src/plugins/showHiddenThings/README.md b/src/plugins/showHiddenThings/README.md
new file mode 100644
index 000000000..b41e2d94d
--- /dev/null
+++ b/src/plugins/showHiddenThings/README.md
@@ -0,0 +1,11 @@
+# ShowHiddenThings
+
+Displays various moderator-only elements regardless of permissions.
+
+## Features
+
+- Show member timeout icons in chat
+![](https://github.com/Vendicated/Vencord/assets/47677887/75e1f6ba-8921-4188-9c2d-c9c3f9d07101)
+
+- Show the invites paused tooltip in the server list
+![](https://github.com/Vendicated/Vencord/assets/47677887/b6a923d2-ac55-40d9-b4f8-fa6fc117148b)
diff --git a/src/plugins/showTimeouts/index.ts b/src/plugins/showHiddenThings/index.ts
similarity index 51%
rename from src/plugins/showTimeouts/index.ts
rename to src/plugins/showHiddenThings/index.ts
index b0774bed4..e7be929bf 100644
--- a/src/plugins/showTimeouts/index.ts
+++ b/src/plugins/showHiddenThings/index.ts
@@ -16,20 +16,46 @@
* along with this program. If not, see .
*/
+import { definePluginSettings, migratePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
-import definePlugin from "@utils/types";
+import definePlugin, { OptionType } from "@utils/types";
+const settings = definePluginSettings({
+ showTimeouts: {
+ type: OptionType.BOOLEAN,
+ description: "Show member timeout icons in chat.",
+ default: true,
+ },
+ showInvitesPaused: {
+ type: OptionType.BOOLEAN,
+ description: "Show the invites paused tooltip in the server list.",
+ default: true,
+ },
+});
+
+migratePluginSettings("ShowHiddenThings", "ShowTimeouts");
export default definePlugin({
- name: "ShowTimeouts",
- description: "Display member timeout icons in chat regardless of permissions.",
+ name: "ShowHiddenThings",
+ tags: ["ShowTimeouts", "ShowInvitesPaused"],
+ description: "Displays various moderator-only elements regardless of permissions.",
authors: [Devs.Dolfies],
patches: [
{
find: "showCommunicationDisabledStyles",
+ predicate: () => settings.store.showTimeouts,
replacement: {
match: /&&\i\.\i\.canManageUser\(\i\.\i\.MODERATE_MEMBERS,\i\.author,\i\)/,
replace: "",
},
},
+ {
+ find: "useShouldShowInvitesDisabledNotif:",
+ predicate: () => settings.store.showInvitesPaused,
+ replacement: {
+ match: /\i\.\i\.can\(\i\.Permissions.MANAGE_GUILD,\i\)/,
+ replace: "true",
+ },
+ }
],
+ settings,
});
From 5cf014cb06c759d2af643a00272a10e2816d5d4e Mon Sep 17 00:00:00 2001
From: Amia <9750071+aamiaa@users.noreply.github.com>
Date: Tue, 23 Apr 2024 23:06:19 +0200
Subject: [PATCH 24/30] New Plugin: BetterSessions (#1324)
Co-authored-by: V
---
src/plugins/betterSessions/README.md | 5 +
.../components/RenameButton.tsx | 37 +++
.../betterSessions/components/RenameModal.tsx | 94 ++++++++
.../betterSessions/components/icons.tsx | 106 ++++++++
src/plugins/betterSessions/index.tsx | 227 ++++++++++++++++++
src/plugins/betterSessions/types.ts | 32 +++
src/plugins/betterSessions/utils.ts | 90 +++++++
7 files changed, 591 insertions(+)
create mode 100644 src/plugins/betterSessions/README.md
create mode 100644 src/plugins/betterSessions/components/RenameButton.tsx
create mode 100644 src/plugins/betterSessions/components/RenameModal.tsx
create mode 100644 src/plugins/betterSessions/components/icons.tsx
create mode 100644 src/plugins/betterSessions/index.tsx
create mode 100644 src/plugins/betterSessions/types.ts
create mode 100644 src/plugins/betterSessions/utils.ts
diff --git a/src/plugins/betterSessions/README.md b/src/plugins/betterSessions/README.md
new file mode 100644
index 000000000..cf13e6c50
--- /dev/null
+++ b/src/plugins/betterSessions/README.md
@@ -0,0 +1,5 @@
+# BetterSessions
+
+Enhances the sessions (devices) menu. Allows you to view exact timestamps, give each session a custom name, and receive notifications about new sessions.
+
+![](https://github.com/Vendicated/Vencord/assets/9750071/4a44b617-bb8f-4dcb-93f1-b7d2575ed3d8)
diff --git a/src/plugins/betterSessions/components/RenameButton.tsx b/src/plugins/betterSessions/components/RenameButton.tsx
new file mode 100644
index 000000000..a0c95a6f4
--- /dev/null
+++ b/src/plugins/betterSessions/components/RenameButton.tsx
@@ -0,0 +1,37 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { openModal } from "@utils/modal";
+import { Button } from "@webpack/common";
+
+import { SessionInfo } from "../types";
+import { RenameModal } from "./RenameModal";
+
+export function RenameButton({ session, state }: { session: SessionInfo["session"], state: [string, React.Dispatch>]; }) {
+ return (
+
+ openModal(props => (
+
+ ))
+ }
+ >
+ Rename
+
+ );
+}
diff --git a/src/plugins/betterSessions/components/RenameModal.tsx b/src/plugins/betterSessions/components/RenameModal.tsx
new file mode 100644
index 000000000..1c5783c0e
--- /dev/null
+++ b/src/plugins/betterSessions/components/RenameModal.tsx
@@ -0,0 +1,94 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2023 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
+import { Button, Forms, React, TextInput } from "@webpack/common";
+import { KeyboardEvent } from "react";
+
+import { SessionInfo } from "../types";
+import { getDefaultName, savedSessionsCache, saveSessionsToDataStore } from "../utils";
+
+export function RenameModal({ props, session, state }: { props: ModalProps, session: SessionInfo["session"], state: [string, React.Dispatch>]; }) {
+ const [title, setTitle] = state;
+ const [value, setValue] = React.useState(savedSessionsCache.get(session.id_hash)?.name ?? "");
+
+ function onSaveClick() {
+ savedSessionsCache.set(session.id_hash, { name: value, isNew: false });
+ if (value !== "") {
+ setTitle(`${value}*`);
+ } else {
+ setTitle(getDefaultName(session.client_info));
+ }
+
+ saveSessionsToDataStore();
+ props.onClose();
+ }
+
+ return (
+
+
+ Rename
+
+
+
+ New device name
+ ) => {
+ if (e.key === "Enter") {
+ onSaveClick();
+ }
+ }}
+ />
+ setValue("")}
+ >
+ Reset Name
+
+
+
+
+
+ Save
+
+ props.onClose()}
+ >
+ Cancel
+
+
+
+ );
+}
diff --git a/src/plugins/betterSessions/components/icons.tsx b/src/plugins/betterSessions/components/icons.tsx
new file mode 100644
index 000000000..bd745e76c
--- /dev/null
+++ b/src/plugins/betterSessions/components/icons.tsx
@@ -0,0 +1,106 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2023 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { LazyComponent } from "@utils/react";
+import { findByCode } from "@webpack";
+import { SVGProps } from "react";
+
+export const DiscordIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const ChromeIcon = (props: React.PropsWithChildren>) => (
+
+
+
+
+
+
+);
+
+export const EdgeIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const FirefoxIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const IEIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const OperaIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const SafariIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const UnknownIcon = (props: React.PropsWithChildren>) => (
+
+
+
+);
+
+export const MobileIcon = LazyComponent(() => findByCode("M15.5 1h-8C6.12 1 5 2.12 5 3.5v17C5 21.88 6.12 23 7.5 23h8c1.38"));
diff --git a/src/plugins/betterSessions/index.tsx b/src/plugins/betterSessions/index.tsx
new file mode 100644
index 000000000..bb79870d2
--- /dev/null
+++ b/src/plugins/betterSessions/index.tsx
@@ -0,0 +1,227 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2023 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { showNotification } from "@api/Notifications";
+import { definePluginSettings } from "@api/Settings";
+import ErrorBoundary from "@components/ErrorBoundary";
+import { Devs } from "@utils/constants";
+import definePlugin, { OptionType } from "@utils/types";
+import { findByPropsLazy, findExportedComponentLazy } from "@webpack";
+import { React, RestAPI, Tooltip } from "@webpack/common";
+
+import { RenameButton } from "./components/RenameButton";
+import { Session, SessionInfo } from "./types";
+import { fetchNamesFromDataStore, getDefaultName, GetOsColor, GetPlatformIcon, savedSessionsCache, saveSessionsToDataStore } from "./utils";
+
+const AuthSessionsStore = findByPropsLazy("getSessions");
+const UserSettingsModal = findByPropsLazy("saveAccountChanges", "open");
+
+const TimestampClasses = findByPropsLazy("timestampTooltip", "blockquoteContainer");
+const SessionIconClasses = findByPropsLazy("sessionIcon");
+
+const BlobMask = findExportedComponentLazy("BlobMask");
+
+const settings = definePluginSettings({
+ backgroundCheck: {
+ type: OptionType.BOOLEAN,
+ description: "Check for new sessions in the background, and display notifications when they are detected",
+ default: false,
+ restartNeeded: true
+ },
+ checkInterval: {
+ description: "How often to check for new sessions in the background (if enabled), in minutes",
+ type: OptionType.NUMBER,
+ default: 20,
+ restartNeeded: true
+ }
+});
+
+export default definePlugin({
+ name: "BetterSessions",
+ description: "Enhances the sessions (devices) menu. Allows you to view exact timestamps, give each session a custom name, and receive notifications about new sessions.",
+ authors: [Devs.amia],
+
+ settings: settings,
+
+ patches: [
+ {
+ find: "Messages.AUTH_SESSIONS_SESSION_LOG_OUT",
+ replacement: [
+ // Replace children with a single label with state
+ {
+ match: /({variant:"eyebrow",className:\i\.sessionInfoRow,children:).{70,110}{children:"\\xb7"}\),\(0,\i\.\i\)\("span",{children:\i\[\d+\]}\)\]}\)\]/,
+ replace: "$1$self.renderName(arguments[0])"
+ },
+ {
+ match: /({variant:"text-sm\/medium",className:\i\.sessionInfoRow,children:.{70,110}{children:"\\xb7"}\),\(0,\i\.\i\)\("span",{children:)(\i\[\d+\])}/,
+ replace: "$1$self.renderTimestamp({ ...arguments[0], timeLabel: $2 })}"
+ },
+ // Replace the icon
+ {
+ match: /\.currentSession:null\),children:\[(?<=,icon:(\i)\}.+?)/,
+ replace: "$& $self.renderIcon({ ...arguments[0], DeviceIcon: $1 }), false &&"
+ }
+ ]
+ },
+ {
+ // Add the ability to change BlobMask's lower badge height
+ // (it allows changing width so we can mirror that logic)
+ find: "this.getBadgePositionInterpolation(",
+ replacement: {
+ match: /(\i\.animated\.rect,{id:\i,x:48-\(\i\+8\)\+4,y:)28(,width:\i\+8,height:)24,/,
+ replace: (_, leftPart, rightPart) => `${leftPart} 48 - ((this.props.lowerBadgeHeight ?? 16) + 8) + 4 ${rightPart} (this.props.lowerBadgeHeight ?? 16) + 8,`
+ }
+ }
+ ],
+
+ renderName: ErrorBoundary.wrap(({ session }: SessionInfo) => {
+ const savedSession = savedSessionsCache.get(session.id_hash);
+
+ const state = React.useState(savedSession?.name ? `${savedSession.name}*` : getDefaultName(session.client_info));
+ const [title, setTitle] = state;
+
+ // Show a "NEW" badge if the session is seen for the first time
+ return (
+ <>
+ {title}
+ {(savedSession == null || savedSession.isNew) && (
+
+ NEW
+
+ )}
+
+ >
+ );
+ }, { noop: true }),
+
+ renderTimestamp: ErrorBoundary.wrap(({ session, timeLabel }: { session: Session, timeLabel: string; }) => {
+ return (
+
+ {props => (
+
+ {timeLabel}
+
+ )}
+
+ );
+ }, { noop: true }),
+
+ renderIcon: ErrorBoundary.wrap(({ session, DeviceIcon }: { session: Session, DeviceIcon: React.ComponentType; }) => {
+ const PlatformIcon = GetPlatformIcon(session.client_info.platform);
+
+ return (
+
+
+
+ }
+ lowerBadgeWidth={20}
+ lowerBadgeHeight={20}
+ >
+
+
+
+
+ );
+ }, { noop: true }),
+
+ async checkNewSessions() {
+ const data = await RestAPI.get({
+ url: "/auth/sessions"
+ });
+
+ for (const session of data.body.user_sessions) {
+ if (savedSessionsCache.has(session.id_hash)) continue;
+
+ savedSessionsCache.set(session.id_hash, { name: "", isNew: true });
+ showNotification({
+ title: "BetterSessions",
+ body: `New session:\n${session.client_info.os} · ${session.client_info.platform} · ${session.client_info.location}`,
+ permanent: true,
+ onClick: () => UserSettingsModal.open("Sessions")
+ });
+ }
+
+ saveSessionsToDataStore();
+ },
+
+ flux: {
+ USER_SETTINGS_ACCOUNT_RESET_AND_CLOSE_FORM() {
+ const lastFetchedHashes: string[] = AuthSessionsStore.getSessions().map((session: SessionInfo["session"]) => session.id_hash);
+
+ // Add new sessions to cache
+ lastFetchedHashes.forEach(idHash => {
+ if (!savedSessionsCache.has(idHash)) savedSessionsCache.set(idHash, { name: "", isNew: false });
+ });
+
+ // Delete removed sessions from cache
+ if (lastFetchedHashes.length > 0) {
+ savedSessionsCache.forEach((_, idHash) => {
+ if (!lastFetchedHashes.includes(idHash)) savedSessionsCache.delete(idHash);
+ });
+ }
+
+ // Dismiss the "NEW" badge of all sessions.
+ // Since the only way for a session to be marked as "NEW" is going to the Devices tab,
+ // closing the settings means they've been viewed and are no longer considered new.
+ savedSessionsCache.forEach(data => {
+ data.isNew = false;
+ });
+ saveSessionsToDataStore();
+ }
+ },
+
+ async start() {
+ await fetchNamesFromDataStore();
+
+ this.checkNewSessions();
+ if (settings.store.backgroundCheck) {
+ this.checkInterval = setInterval(this.checkNewSessions, settings.store.checkInterval * 60 * 1000);
+ }
+ },
+
+ stop() {
+ clearInterval(this.checkInterval);
+ }
+});
diff --git a/src/plugins/betterSessions/types.ts b/src/plugins/betterSessions/types.ts
new file mode 100644
index 000000000..9026d5313
--- /dev/null
+++ b/src/plugins/betterSessions/types.ts
@@ -0,0 +1,32 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2023 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
.
+*/
+
+export interface SessionInfo {
+ session: {
+ id_hash: string;
+ approx_last_used_time: Date;
+ client_info: {
+ os: string;
+ platform: string;
+ location: string;
+ };
+ },
+ current?: boolean;
+}
+
+export type Session = SessionInfo["session"];
diff --git a/src/plugins/betterSessions/utils.ts b/src/plugins/betterSessions/utils.ts
new file mode 100644
index 000000000..3015dc47c
--- /dev/null
+++ b/src/plugins/betterSessions/utils.ts
@@ -0,0 +1,90 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2023 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
.
+*/
+
+import { DataStore } from "@api/index";
+import { UserStore } from "@webpack/common";
+
+import { ChromeIcon, DiscordIcon, EdgeIcon, FirefoxIcon, IEIcon, MobileIcon, OperaIcon, SafariIcon, UnknownIcon } from "./components/icons";
+import { SessionInfo } from "./types";
+
+const getDataKey = () => `BetterSessions_savedSessions_${UserStore.getCurrentUser().id}`;
+
+export const savedSessionsCache: Map
= new Map();
+
+export function getDefaultName(clientInfo: SessionInfo["session"]["client_info"]) {
+ return `${clientInfo.os} · ${clientInfo.platform}`;
+}
+
+export function saveSessionsToDataStore() {
+ return DataStore.set(getDataKey(), savedSessionsCache);
+}
+
+export async function fetchNamesFromDataStore() {
+ const savedSessions = await DataStore.get>(getDataKey()) || new Map();
+ savedSessions.forEach((data, idHash) => {
+ savedSessionsCache.set(idHash, data);
+ });
+}
+
+export function GetOsColor(os: string) {
+ switch (os) {
+ case "Windows Mobile":
+ case "Windows":
+ return "#55a6ef"; // Light blue
+ case "Linux":
+ return "#cdcd31"; // Yellow
+ case "Android":
+ return "#7bc958"; // Green
+ case "Mac OS X":
+ case "iOS":
+ return ""; // Default to white/black (theme-dependent)
+ default:
+ return "#f3799a"; // Pink
+ }
+}
+
+export function GetPlatformIcon(platform: string) {
+ switch (platform) {
+ case "Discord Android":
+ case "Discord iOS":
+ case "Discord Client":
+ return DiscordIcon;
+ case "Android Chrome":
+ case "Chrome iOS":
+ case "Chrome":
+ return ChromeIcon;
+ case "Edge":
+ return EdgeIcon;
+ case "Firefox":
+ return FirefoxIcon;
+ case "Internet Explorer":
+ return IEIcon;
+ case "Opera Mini":
+ case "Opera":
+ return OperaIcon;
+ case "Mobile Safari":
+ case "Safari":
+ return SafariIcon;
+ case "BlackBerry":
+ case "Facebook Mobile":
+ case "Android Mobile":
+ return MobileIcon;
+ default:
+ return UnknownIcon;
+ }
+}
From 7f0e7dd02bd241f9999da77642189868164b6e54 Mon Sep 17 00:00:00 2001
From: Vendicated
Date: Wed, 24 Apr 2024 05:23:50 +0200
Subject: [PATCH 25/30] fix FakeProfileThemes
---
src/plugins/fakeProfileThemes/index.tsx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx
index c61437269..a1b629d10 100644
--- a/src/plugins/fakeProfileThemes/index.tsx
+++ b/src/plugins/fakeProfileThemes/index.tsx
@@ -92,8 +92,9 @@ export default definePlugin({
match: /(?<=getUserProfile\(\i\){return )(\i\[\i\])/,
replace: "$self.colorDecodeHook($1)"
}
- }, {
- find: ".USER_SETTINGS_PROFILE_THEME_ACCENT",
+ },
+ {
+ find: ".USER_SETTINGS_RESET_PROFILE_THEME",
replacement: {
match: /RESET_PROFILE_THEME}\)(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/,
replace: "$&,$self.addCopy3y3Button({primary:$1,accent:$2})"
From d5f70070efed3a6c2f481ffe4abce3c5ad45e57b Mon Sep 17 00:00:00 2001
From: Vendicated
Date: Wed, 24 Apr 2024 05:27:14 +0200
Subject: [PATCH 26/30] fix badges
---
src/plugins/_api/badges.tsx | 2 +-
src/plugins/betterSessions/index.tsx | 4 ++--
src/utils/constants.ts | 8 ++++++++
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/plugins/_api/badges.tsx b/src/plugins/_api/badges.tsx
index 16b244a19..6b1a79cd5 100644
--- a/src/plugins/_api/badges.tsx
+++ b/src/plugins/_api/badges.tsx
@@ -65,7 +65,7 @@ export default definePlugin({
patches: [
/* Patch the badge list component on user profiles */
{
- find: "Messages.PROFILE_USER_BADGES,role:",
+ find: 'id:"premium",',
replacement: [
{
match: /&&(\i)\.push\(\{id:"premium".+?\}\);/,
diff --git a/src/plugins/betterSessions/index.tsx b/src/plugins/betterSessions/index.tsx
index bb79870d2..539508f80 100644
--- a/src/plugins/betterSessions/index.tsx
+++ b/src/plugins/betterSessions/index.tsx
@@ -21,14 +21,14 @@ import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
-import { findByPropsLazy, findExportedComponentLazy } from "@webpack";
+import { findByPropsLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
import { React, RestAPI, Tooltip } from "@webpack/common";
import { RenameButton } from "./components/RenameButton";
import { Session, SessionInfo } from "./types";
import { fetchNamesFromDataStore, getDefaultName, GetOsColor, GetPlatformIcon, savedSessionsCache, saveSessionsToDataStore } from "./utils";
-const AuthSessionsStore = findByPropsLazy("getSessions");
+const AuthSessionsStore = findStoreLazy("AuthSessionsStore");
const UserSettingsModal = findByPropsLazy("saveAccountChanges", "open");
const TimestampClasses = findByPropsLazy("timestampTooltip", "blockquoteContainer");
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 3098e29d0..917fabf43 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -437,6 +437,14 @@ export const Devs = /* #__PURE__*/ Object.freeze({
Byron: {
name: "byeoon",
id: 1167275288036655133n
+ },
+ Kaitlyn: {
+ name: "kaitlyn",
+ id: 306158896630988801n
+ },
+ PolisanTheEasyNick: {
+ name: "Oleh Polisan",
+ id: 242305263313485825n
}
} satisfies Record);
From 6a69701b54107cbb696615949ba0594a097bf010 Mon Sep 17 00:00:00 2001
From: My-Name-Is-Jeff <37018278+My-Name-Is-Jeff@users.noreply.github.com>
Date: Tue, 23 Apr 2024 23:30:23 -0400
Subject: [PATCH 27/30] fix ValidUser (#2381)
---
src/plugins/validUser/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx
index d3decd941..2fce693e8 100644
--- a/src/plugins/validUser/index.tsx
+++ b/src/plugins/validUser/index.tsx
@@ -120,7 +120,7 @@ export default definePlugin({
find: 'className:"mention"',
replacement: {
// mention = { react: function (data, parse, props) { if (data.userId == null) return RoleMention() else return UserMention()
- match: /react(?=\(\i,\i,\i\).{0,50}return null==.{0,70}\?\(0,\i\.jsx\)\((\i\.\i),.+?jsx\)\((\i\.\i),\{className:"mention")/,
+ match: /react(?=\(\i,\i,\i\).{0,100}return null==.{0,70}\?\(0,\i\.jsx\)\((\i\.\i),.+?jsx\)\((\i\.\i),\{className:"mention")/,
// react: (...args) => OurWrapper(RoleMention, UserMention, ...args), originalReact: theirFunc
replace: "react:(...args)=>$self.renderMention($1,$2,...args),originalReact"
}
From d55205c55ad9ffa82fa03837ebb4eae623d28705 Mon Sep 17 00:00:00 2001
From: dolfies
Date: Tue, 23 Apr 2024 23:41:53 -0400
Subject: [PATCH 28/30] feat(plugin): ImplicitRelationships (#947)
Co-authored-by: Angelos Bouklis <53124886+ArjixWasTaken@users.noreply.github.com>
Co-authored-by: V
---
src/plugins/implicitRelationships/README.md | 7 +
src/plugins/implicitRelationships/index.ts | 182 ++++++++++++++++++++
src/plugins/sortFriendRequests/index.tsx | 2 +-
3 files changed, 190 insertions(+), 1 deletion(-)
create mode 100644 src/plugins/implicitRelationships/README.md
create mode 100644 src/plugins/implicitRelationships/index.ts
diff --git a/src/plugins/implicitRelationships/README.md b/src/plugins/implicitRelationships/README.md
new file mode 100644
index 000000000..a76e298f7
--- /dev/null
+++ b/src/plugins/implicitRelationships/README.md
@@ -0,0 +1,7 @@
+# ImplicitRelationships
+
+Shows your implicit relationships in the Friends tab.
+
+Implicit relationships on Discord are people with whom you've frecently interacted and share a mutual server; even though Discord thinks you should be friends with them, you haven't added them as friends.
+
+![](https://camo.githubusercontent.com/6927161ee0c933f7ef6d61f243cca3e6ea4c8db9d1becd8cbf73c45e1bd0d127/68747470733a2f2f692e646f6c66692e65732f7055447859464662674d2e706e673f6b65793d736e3950343936416c32444c7072)
diff --git a/src/plugins/implicitRelationships/index.ts b/src/plugins/implicitRelationships/index.ts
new file mode 100644
index 000000000..9ae9fb512
--- /dev/null
+++ b/src/plugins/implicitRelationships/index.ts
@@ -0,0 +1,182 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2023 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { definePluginSettings } from "@api/Settings";
+import { Devs } from "@utils/constants";
+import definePlugin, { OptionType } from "@utils/types";
+import { findByProps, findStoreLazy } from "@webpack";
+import { ChannelStore, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common";
+import { Settings } from "Vencord";
+
+const UserAffinitiesStore = findStoreLazy("UserAffinitiesStore");
+
+interface UserAffinity {
+ user_id: string;
+ affinity: number;
+}
+
+export default definePlugin({
+ name: "ImplicitRelationships",
+ description: "Shows your implicit relationships in the Friends tab.",
+ authors: [Devs.Dolfies],
+ patches: [
+ // Counts header
+ {
+ find: ".FRIENDS_ALL_HEADER",
+ replacement: {
+ match: /toString\(\)\}\);case (\i\.\i)\.BLOCKED/,
+ replace: 'toString()});case $1.IMPLICIT:return "Implicit — "+arguments[1];case $1.BLOCKED'
+ },
+ },
+ // No friends page
+ {
+ find: "FriendsEmptyState: Invalid empty state",
+ replacement: {
+ match: /case (\i\.\i)\.ONLINE:(?=return (\i)\.SECTION_ONLINE)/,
+ replace: "case $1.ONLINE:case $1.IMPLICIT:"
+ },
+ },
+ // Sections header
+ {
+ find: ".FRIENDS_SECTION_ONLINE",
+ replacement: {
+ match: /(\(0,\i\.jsx\)\(\i\.TabBar\.Item,\{id:\i\.\i)\.BLOCKED,className:([^\s]+?)\.item,children:\i\.\i\.Messages\.BLOCKED\}\)/,
+ replace: "$1.IMPLICIT,className:$2.item,children:\"Implicit\"}),$&"
+ },
+ },
+ // Sections content
+ {
+ find: '"FriendsStore"',
+ replacement: {
+ match: /(?<=case (\i\.\i)\.BLOCKED:return (\i)\.type===\i\.\i\.BLOCKED)/,
+ replace: ";case $1.IMPLICIT:return $2.type===5"
+ },
+ },
+ // Piggyback relationship fetch
+ {
+ find: ".fetchRelationships()",
+ replacement: {
+ match: /(\i\.\i)\.fetchRelationships\(\)/,
+ // This relationship fetch is actually completely useless, but whatevs
+ replace: "$1.fetchRelationships(),$self.fetchImplicitRelationships()"
+ },
+ },
+ // Modify sort -- thanks megu for the patch (from sortFriendRequests)
+ {
+ find: "getRelationshipCounts(){",
+ replacement: {
+ predicate: () => Settings.plugins.ImplicitRelationships.sortByAffinity,
+ match: /\.sortBy\(\i=>\i\.comparator\)/,
+ replace: "$&.sortBy((row) => $self.sortList(row))"
+ }
+ },
+
+ // Add support for the nonce parameter to Discord's shitcode
+ {
+ find: ".REQUEST_GUILD_MEMBERS",
+ replacement: {
+ match: /\.send\(8,{/,
+ replace: "$&nonce:arguments[1].nonce,"
+ }
+ },
+ {
+ find: "GUILD_MEMBERS_REQUEST:",
+ replacement: {
+ match: /presences:!!(\i)\.presences/,
+ replace: "$&,nonce:$1.nonce"
+ },
+ },
+ {
+ find: ".not_found",
+ replacement: {
+ match: /notFound:(\i)\.not_found/,
+ replace: "$&,nonce:$1.nonce"
+ },
+ }
+ ],
+ settings: definePluginSettings(
+ {
+ sortByAffinity: {
+ type: OptionType.BOOLEAN,
+ default: true,
+ description: "Whether to sort implicit relationships by their affinity to you.",
+ restartNeeded: true
+ },
+ }
+ ),
+
+ sortList(row: any) {
+ return row.type === 5
+ ? -UserAffinitiesStore.getUserAffinity(row.user.id)?.affinity ?? 0
+ : row.comparator;
+ },
+
+ async fetchImplicitRelationships() {
+ // Implicit relationships are defined as users that you:
+ // 1. Have an affinity for
+ // 2. Do not have a relationship with // TODO: Check how this works with pending/blocked relationships
+ // 3. Have a mutual guild with
+ const userAffinities: Set = UserAffinitiesStore.getUserAffinitiesUserIds();
+ const nonFriendAffinities = Array.from(userAffinities).filter(
+ id => !RelationshipStore.getRelationshipType(id)
+ );
+
+ // I would love to just check user cache here (falling back to the gateway of course)
+ // However, users in user cache may just be there because they share a DM or group DM with you
+ // So there's no guarantee that a user being in user cache means they have a mutual with you
+ // To get around this, we request users we have DMs with, and ignore them below if we don't get them back
+ const dmUserIds = new Set(
+ Object.values(ChannelStore.getSortedPrivateChannels()).flatMap(c => c.recipients)
+ );
+ const toRequest = nonFriendAffinities.filter(id => !UserStore.getUser(id) || dmUserIds.has(id));
+ const allGuildIds = Object.keys(GuildStore.getGuilds());
+ const sentNonce = SnowflakeUtils.fromTimestamp(Date.now());
+ let count = allGuildIds.length * Math.ceil(toRequest.length / 100);
+
+ // OP 8 Request Guild Members allows 100 user IDs at a time
+ const ignore = new Set(toRequest);
+ const relationships = RelationshipStore.getRelationships();
+ const callback = ({ nonce, members }) => {
+ if (nonce !== sentNonce) return;
+ members.forEach(member => {
+ ignore.delete(member.user.id);
+ });
+
+ nonFriendAffinities.map(id => UserStore.getUser(id)).filter(user => user && !ignore.has(user.id)).forEach(user => relationships[user.id] = 5);
+ RelationshipStore.emitChange();
+ if (--count === 0) {
+ FluxDispatcher.unsubscribe("GUILD_MEMBERS_CHUNK", callback);
+ }
+ };
+
+ FluxDispatcher.subscribe("GUILD_MEMBERS_CHUNK", callback);
+ for (let i = 0; i < toRequest.length; i += 100) {
+ FluxDispatcher.dispatch({
+ type: "GUILD_MEMBERS_REQUEST",
+ guildIds: allGuildIds,
+ userIds: toRequest.slice(i, i + 100),
+ nonce: sentNonce,
+ });
+ }
+ },
+
+ start() {
+ const { FriendsSections } = findByProps("FriendsSections");
+ FriendsSections.IMPLICIT = "IMPLICIT";
+ }
+});
diff --git a/src/plugins/sortFriendRequests/index.tsx b/src/plugins/sortFriendRequests/index.tsx
index c40a18140..32579a803 100644
--- a/src/plugins/sortFriendRequests/index.tsx
+++ b/src/plugins/sortFriendRequests/index.tsx
@@ -42,7 +42,7 @@ export default definePlugin({
find: "getRelationshipCounts(){",
replacement: {
match: /\.sortBy\(\i=>\i\.comparator\)/,
- replace: ".sortBy((row) => $self.sortList(row))"
+ replace: "$&.sortBy((row) => $self.sortList(row))"
}
}, {
find: ".Messages.FRIEND_REQUEST_CANCEL",
From 9e0aa4b23ccaef9e030d20d3881135875a3364e2 Mon Sep 17 00:00:00 2001
From: Koda!! <162957404+Kodarru@users.noreply.github.com>
Date: Tue, 23 Apr 2024 20:51:49 -0700
Subject: [PATCH 29/30] feat(plugin): StreamerModeOnStream (#2320)
Co-authored-by: V
---
src/plugins/streamerModeOnStream/index.ts | 45 +++++++++++++++++++++++
src/utils/constants.ts | 4 ++
2 files changed, 49 insertions(+)
create mode 100644 src/plugins/streamerModeOnStream/index.ts
diff --git a/src/plugins/streamerModeOnStream/index.ts b/src/plugins/streamerModeOnStream/index.ts
new file mode 100644
index 000000000..03b83f577
--- /dev/null
+++ b/src/plugins/streamerModeOnStream/index.ts
@@ -0,0 +1,45 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2024 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { Devs } from "@utils/constants";
+import definePlugin from "@utils/types";
+import { FluxDispatcher, UserStore } from "@webpack/common";
+
+interface StreamEvent {
+ streamKey: string;
+}
+
+function toggleStreamerMode({ streamKey }: StreamEvent, value: boolean) {
+ if (!streamKey.endsWith(UserStore.getCurrentUser().id)) return;
+
+ FluxDispatcher.dispatch({
+ type: "STREAMER_MODE_UPDATE",
+ key: "enabled",
+ value
+ });
+}
+
+export default definePlugin({
+ name: "StreamerModeOnStream",
+ description: "Automatically enables streamer mode when you start streaming in Discord",
+ authors: [Devs.Kodarru],
+ flux: {
+ STREAM_CREATE: d => toggleStreamerMode(d, true),
+ STREAM_DELETE: d => toggleStreamerMode(d, false)
+ }
+});
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 917fabf43..8ab0bffb3 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -426,6 +426,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "newwares",
id: 421405303951851520n
},
+ Kodarru: {
+ name: "Kodarru",
+ id: 785227396218748949n
+ },
nakoyasha: {
name: "nakoyasha",
id: 222069018507345921n
From 4fce88fa8f048e648240a42e553c740a2927afda Mon Sep 17 00:00:00 2001
From: Elvyra <88881326+EdVraz@users.noreply.github.com>
Date: Wed, 24 Apr 2024 23:05:02 +0200
Subject: [PATCH 30/30] Fix OnePingPerDM and RoleColorEverywhere patches
(#2387)
---
src/plugins/onePingPerDM/index.ts | 2 +-
src/plugins/roleColorEverywhere/index.tsx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/plugins/onePingPerDM/index.ts b/src/plugins/onePingPerDM/index.ts
index ae38343db..e9cde6523 100644
--- a/src/plugins/onePingPerDM/index.ts
+++ b/src/plugins/onePingPerDM/index.ts
@@ -49,7 +49,7 @@ export default definePlugin({
replace: "$&if(!$self.isPrivateChannelRead(arguments[0]?.message))return;else "
},
{
- match: /sound:(\i\?\i:void 0,volume:\i,onClick)/,
+ match: /sound:(\i\?\i:void 0,soundpack:\i,volume:\i,onClick)/,
replace: "sound:!$self.isPrivateChannelRead(arguments[0]?.message)?undefined:$1"
}]
}],
diff --git a/src/plugins/roleColorEverywhere/index.tsx b/src/plugins/roleColorEverywhere/index.tsx
index 71c291fef..942697801 100644
--- a/src/plugins/roleColorEverywhere/index.tsx
+++ b/src/plugins/roleColorEverywhere/index.tsx
@@ -94,7 +94,7 @@ export default definePlugin({
find: "renderPrioritySpeaker",
replacement: [
{
- match: /renderName\(\).{0,100}speaking:.{50,150}"div",{/,
+ match: /renderName\(\).{0,100}speaking:.{50,200}"div",{/,
replace: "$&...$self.getVoiceProps(this.props),"
}
],