Merge branch 'immediate-finds' into immediate-finds-modules-proxy
This commit is contained in:
commit
bb22355a57
|
@ -40,7 +40,7 @@ import { Alerts, Button, Card, Forms, lodash, Parser, React, Select, Text, TextI
|
||||||
import Plugins from "~plugins";
|
import Plugins from "~plugins";
|
||||||
|
|
||||||
// Avoid circular dependency
|
// Avoid circular dependency
|
||||||
const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => require("../../plugins"));
|
const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => require("../../plugins")) as typeof import("../../plugins");
|
||||||
|
|
||||||
const cl = classNameFactory("vc-plugins-");
|
const cl = classNameFactory("vc-plugins-");
|
||||||
const logger = new Logger("PluginSettings", "#a6d189");
|
const logger = new Logger("PluginSettings", "#a6d189");
|
||||||
|
|
|
@ -250,7 +250,7 @@ function ThemesTab() {
|
||||||
Edit QuickCSS
|
Edit QuickCSS
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{Vencord.Settings.plugins.ClientTheme.enabled && (
|
{Vencord.Plugins.isPluginEnabled("ClientTheme") && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => openModal(modalProps => (
|
onClick={() => openModal(modalProps => (
|
||||||
<PluginModal
|
<PluginModal
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import BackupAndRestoreTab from "@components/VencordSettings/BackupAndRestoreTab";
|
import BackupAndRestoreTab from "@components/VencordSettings/BackupAndRestoreTab";
|
||||||
import CloudTab from "@components/VencordSettings/CloudTab";
|
import CloudTab from "@components/VencordSettings/CloudTab";
|
||||||
import PatchHelperTab from "@components/VencordSettings/PatchHelperTab";
|
import PatchHelperTab from "@components/VencordSettings/PatchHelperTab";
|
||||||
|
@ -33,11 +33,27 @@ import gitHash from "~git-hash";
|
||||||
type SectionType = "HEADER" | "DIVIDER" | "CUSTOM";
|
type SectionType = "HEADER" | "DIVIDER" | "CUSTOM";
|
||||||
type SectionTypes = Record<SectionType, SectionType>;
|
type SectionTypes = Record<SectionType, SectionType>;
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
settingsLocation: {
|
||||||
|
type: OptionType.SELECT,
|
||||||
|
description: "Where to put the Vencord settings section",
|
||||||
|
options: [
|
||||||
|
{ label: "At the very top", value: "top" },
|
||||||
|
{ label: "Above the Nitro section", value: "aboveNitro", default: true },
|
||||||
|
{ label: "Below the Nitro section", value: "belowNitro" },
|
||||||
|
{ label: "Above Activity Settings", value: "aboveActivity" },
|
||||||
|
{ label: "Below Activity Settings", value: "belowActivity" },
|
||||||
|
{ label: "At the very bottom", value: "bottom" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "Settings",
|
name: "Settings",
|
||||||
description: "Adds Settings UI and debug info",
|
description: "Adds Settings UI and debug info",
|
||||||
authors: [Devs.Ven, Devs.Megu],
|
authors: [Devs.Ven, Devs.Megu],
|
||||||
required: true,
|
required: true,
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
@ -63,7 +79,7 @@ export default definePlugin({
|
||||||
noWarn: true,
|
noWarn: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
get match() {
|
get match() {
|
||||||
switch (Settings.plugins.Settings.settingsLocation) {
|
switch (settings.store.settingsLocation) {
|
||||||
case "top": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.USER_SETTINGS/;
|
case "top": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.USER_SETTINGS/;
|
||||||
case "aboveNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.BILLING_SETTINGS/;
|
case "aboveNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.BILLING_SETTINGS/;
|
||||||
case "belowNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS/;
|
case "belowNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS/;
|
||||||
|
@ -158,12 +174,12 @@ export default definePlugin({
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
},
|
},
|
||||||
|
|
||||||
isRightSpot({ header, settings }: { header?: string; settings?: string[]; }) {
|
isRightSpot({ header, settingsChilds }: { header?: string; settingsChilds?: string[]; }) {
|
||||||
const firstChild = settings?.[0];
|
const firstChild = settingsChilds?.[0];
|
||||||
// lowest two elements... sanity backup
|
// lowest two elements... sanity backup
|
||||||
if (firstChild === "LOGOUT" || firstChild === "SOCIAL_LINKS") return true;
|
if (firstChild === "LOGOUT" || firstChild === "SOCIAL_LINKS") return true;
|
||||||
|
|
||||||
const { settingsLocation } = Settings.plugins.Settings;
|
const { settingsLocation } = settings.store;
|
||||||
|
|
||||||
if (settingsLocation === "bottom") return firstChild === "LOGOUT";
|
if (settingsLocation === "bottom") return firstChild === "LOGOUT";
|
||||||
if (settingsLocation === "belowActivity") return firstChild === "CHANGELOG";
|
if (settingsLocation === "belowActivity") return firstChild === "CHANGELOG";
|
||||||
|
@ -203,21 +219,6 @@ export default definePlugin({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
options: {
|
|
||||||
settingsLocation: {
|
|
||||||
type: OptionType.SELECT,
|
|
||||||
description: "Where to put the Vencord settings section",
|
|
||||||
options: [
|
|
||||||
{ label: "At the very top", value: "top" },
|
|
||||||
{ label: "Above the Nitro section", value: "aboveNitro", default: true },
|
|
||||||
{ label: "Below the Nitro section", value: "belowNitro" },
|
|
||||||
{ label: "Above Activity Settings", value: "aboveActivity" },
|
|
||||||
{ label: "Below Activity Settings", value: "belowActivity" },
|
|
||||||
{ label: "At the very bottom", value: "bottom" },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
get electronVersion() {
|
get electronVersion() {
|
||||||
return VencordNative.native.getVersions().electron || window.armcord?.electron || null;
|
return VencordNative.native.getVersions().electron || window.armcord?.electron || null;
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
||||||
|
@ -28,16 +29,17 @@ export default definePlugin({
|
||||||
find: "BAN_CONFIRM_TITLE.",
|
find: "BAN_CONFIRM_TITLE.",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /src:\i\("\d+"\)/g,
|
match: /src:\i\("\d+"\)/g,
|
||||||
replace: "src: Vencord.Settings.plugins.BANger.source"
|
replace: "src: $self.settings.store.source"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
options: {
|
|
||||||
|
settings: definePluginSettings({
|
||||||
source: {
|
source: {
|
||||||
description: "Source to replace ban GIF with (Video or Gif)",
|
description: "Source to replace ban GIF with (Video or Gif)",
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
default: "https://i.imgur.com/wp5q52C.mp4",
|
default: "https://i.imgur.com/wp5q52C.mp4",
|
||||||
restartNeeded: true,
|
restartNeeded: true,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { canonicalizeMatch } from "@utils/patches";
|
import { canonicalizeMatch } from "@utils/patches";
|
||||||
|
@ -25,10 +25,26 @@ import { findByProps } from "@webpack";
|
||||||
|
|
||||||
const UserPopoutSectionCssClasses = findByProps("section", "lastSection");
|
const UserPopoutSectionCssClasses = findByProps("section", "lastSection");
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
hide: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Hide notes",
|
||||||
|
default: false,
|
||||||
|
restartNeeded: true
|
||||||
|
},
|
||||||
|
noSpellCheck: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Disable spellcheck in notes",
|
||||||
|
disabled: () => settings.store.hide,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "BetterNotesBox",
|
name: "BetterNotesBox",
|
||||||
description: "Hide notes or disable spellcheck (Configure in settings!!)",
|
description: "Hide notes or disable spellcheck (Configure in settings!!)",
|
||||||
authors: [Devs.Ven],
|
authors: [Devs.Ven],
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
@ -36,7 +52,7 @@ export default definePlugin({
|
||||||
all: true,
|
all: true,
|
||||||
// Some modules match the find but the replacement is returned untouched
|
// Some modules match the find but the replacement is returned untouched
|
||||||
noWarn: true,
|
noWarn: true,
|
||||||
predicate: () => Vencord.Settings.plugins.BetterNotesBox.hide,
|
predicate: () => settings.store.hide,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /hideNote:.+?(?=([,}].*?\)))/g,
|
match: /hideNote:.+?(?=([,}].*?\)))/g,
|
||||||
replace: (m, rest) => {
|
replace: (m, rest) => {
|
||||||
|
@ -54,7 +70,7 @@ export default definePlugin({
|
||||||
find: "Messages.NOTE_PLACEHOLDER",
|
find: "Messages.NOTE_PLACEHOLDER",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\.NOTE_PLACEHOLDER,/,
|
match: /\.NOTE_PLACEHOLDER,/,
|
||||||
replace: "$&spellCheck:!Vencord.Settings.plugins.BetterNotesBox.noSpellCheck,"
|
replace: "$&spellCheck:!$self.settings.store.noSpellCheck,"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -66,21 +82,6 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
options: {
|
|
||||||
hide: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Hide notes",
|
|
||||||
default: false,
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
noSpellCheck: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Disable spellcheck in notes",
|
|
||||||
disabled: () => Settings.plugins.BetterNotesBox.hide,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
patchPadding: ErrorBoundary.wrap(({ lastSection }) => {
|
patchPadding: ErrorBoundary.wrap(({ lastSection }) => {
|
||||||
if (!lastSection) return null;
|
if (!lastSection) return null;
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -16,16 +16,32 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { Clipboard, Toasts } from "@webpack/common";
|
import { Clipboard, Toasts } from "@webpack/common";
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
bothStyles: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Show both role dot and coloured names",
|
||||||
|
restartNeeded: true,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
copyRoleColorInProfilePopout: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Allow click on role dot in profile popout to copy role color",
|
||||||
|
restartNeeded: true,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "BetterRoleDot",
|
name: "BetterRoleDot",
|
||||||
authors: [Devs.Ven, Devs.AutumnVN],
|
authors: [Devs.Ven, Devs.AutumnVN],
|
||||||
description:
|
description:
|
||||||
"Copy role colour on RoleDot (accessibility setting) click. Also allows using both RoleDot and coloured names simultaneously",
|
"Copy role colour on RoleDot (accessibility setting) click. Also allows using both RoleDot and coloured names simultaneously",
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
@ -39,7 +55,7 @@ export default definePlugin({
|
||||||
find: '"dot"===',
|
find: '"dot"===',
|
||||||
all: true,
|
all: true,
|
||||||
noWarn: true,
|
noWarn: true,
|
||||||
predicate: () => Settings.plugins.BetterRoleDot.bothStyles,
|
predicate: () => settings.store.bothStyles,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /"(?:username|dot)"===\i(?!\.\i)/g,
|
match: /"(?:username|dot)"===\i(?!\.\i)/g,
|
||||||
replace: "true",
|
replace: "true",
|
||||||
|
@ -49,7 +65,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".ADD_ROLE_A11Y_LABEL",
|
find: ".ADD_ROLE_A11Y_LABEL",
|
||||||
all: true,
|
all: true,
|
||||||
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
|
predicate: () => settings.store.copyRoleColorInProfilePopout && !settings.store.bothStyles,
|
||||||
noWarn: true,
|
noWarn: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /"dot"===\i/,
|
match: /"dot"===\i/,
|
||||||
|
@ -59,7 +75,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".roleVerifiedIcon",
|
find: ".roleVerifiedIcon",
|
||||||
all: true,
|
all: true,
|
||||||
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
|
predicate: () => settings.store.copyRoleColorInProfilePopout && !settings.store.bothStyles,
|
||||||
noWarn: true,
|
noWarn: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /"dot"===\i/,
|
match: /"dot"===\i/,
|
||||||
|
@ -68,21 +84,6 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
options: {
|
|
||||||
bothStyles: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Show both role dot and coloured names",
|
|
||||||
restartNeeded: true,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
copyRoleColorInProfilePopout: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Allow click on role dot in profile popout to copy role color",
|
|
||||||
restartNeeded: true,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
copyToClipBoard(color: string) {
|
copyToClipBoard(color: string) {
|
||||||
Clipboard.copy(color);
|
Clipboard.copy(color);
|
||||||
Toasts.show({
|
Toasts.show({
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ function setCss() {
|
||||||
style.textContent = `
|
style.textContent = `
|
||||||
.vc-nsfw-img [class^=imageWrapper] img,
|
.vc-nsfw-img [class^=imageWrapper] img,
|
||||||
.vc-nsfw-img [class^=wrapperPaused] video {
|
.vc-nsfw-img [class^=wrapperPaused] video {
|
||||||
filter: blur(${Settings.plugins.BlurNSFW.blurAmount}px);
|
filter: blur(${settings.store.blurAmount}px);
|
||||||
transition: filter 0.2s;
|
transition: filter 0.2s;
|
||||||
}
|
}
|
||||||
.vc-nsfw-img [class^=imageWrapper]:hover img,
|
.vc-nsfw-img [class^=imageWrapper]:hover img,
|
||||||
|
@ -36,10 +36,20 @@ function setCss() {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
blurAmount: {
|
||||||
|
type: OptionType.NUMBER,
|
||||||
|
description: "Blur Amount",
|
||||||
|
default: 10,
|
||||||
|
onChange: setCss
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "BlurNSFW",
|
name: "BlurNSFW",
|
||||||
description: "Blur attachments in NSFW channels until hovered",
|
description: "Blur attachments in NSFW channels until hovered",
|
||||||
authors: [Devs.Ven],
|
authors: [Devs.Ven],
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
@ -51,15 +61,6 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
options: {
|
|
||||||
blurAmount: {
|
|
||||||
type: OptionType.NUMBER,
|
|
||||||
description: "Blur Amount",
|
|
||||||
default: 10,
|
|
||||||
onChange: setCss
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
style = document.createElement("style");
|
style = document.createElement("style");
|
||||||
style.id = "VcBlurNsfw";
|
style.id = "VcBlurNsfw";
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { useTimer } from "@utils/react";
|
import { useTimer } from "@utils/react";
|
||||||
|
@ -25,7 +25,7 @@ import { React } from "@webpack/common";
|
||||||
|
|
||||||
function formatDuration(ms: number) {
|
function formatDuration(ms: number) {
|
||||||
// here be dragons (moment fucking sucks)
|
// here be dragons (moment fucking sucks)
|
||||||
const human = Settings.plugins.CallTimer.format === "human";
|
const human = settings.store.format === "human";
|
||||||
|
|
||||||
const format = (n: number) => human ? n : n.toString().padStart(2, "0");
|
const format = (n: number) => human ? n : n.toString().padStart(2, "0");
|
||||||
const unit = (s: string) => human ? s : "";
|
const unit = (s: string) => human ? s : "";
|
||||||
|
@ -46,15 +46,7 @@ function formatDuration(ms: number) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
const settings = definePluginSettings({
|
||||||
name: "CallTimer",
|
|
||||||
description: "Adds a timer to vcs",
|
|
||||||
authors: [Devs.Ven],
|
|
||||||
|
|
||||||
startTime: 0,
|
|
||||||
interval: void 0 as NodeJS.Timeout | undefined,
|
|
||||||
|
|
||||||
options: {
|
|
||||||
format: {
|
format: {
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
description: "The timer format. This can be any valid moment.js format",
|
description: "The timer format. This can be any valid moment.js format",
|
||||||
|
@ -70,7 +62,16 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "CallTimer",
|
||||||
|
description: "Adds a timer to vcs",
|
||||||
|
authors: [Devs.Ven],
|
||||||
|
settings,
|
||||||
|
|
||||||
|
startTime: 0,
|
||||||
|
interval: void 0 as NodeJS.Timeout | undefined,
|
||||||
|
|
||||||
patches: [{
|
patches: [{
|
||||||
find: "renderConnectionStatus(){",
|
find: "renderConnectionStatus(){",
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { definePluginSettings, Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -258,7 +258,7 @@ const settings = definePluginSettings({
|
||||||
|
|
||||||
function onChange() {
|
function onChange() {
|
||||||
setRpc(true);
|
setRpc(true);
|
||||||
if (Settings.plugins.CustomRPC.enabled) setRpc();
|
if (Vencord.Plugins.isPluginEnabled("CustomRPC")) setRpc();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isStreamLinkDisabled() {
|
function isStreamLinkDisabled() {
|
||||||
|
|
|
@ -21,20 +21,25 @@ import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps, findStore } from "@webpack";
|
import { findByProps, findStore } from "@webpack";
|
||||||
import { ChannelStore, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common";
|
import { ChannelStore, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common";
|
||||||
import { Settings } from "Vencord";
|
|
||||||
|
|
||||||
const UserAffinitiesStore = findStore("UserAffinitiesStore");
|
const UserAffinitiesStore = findStore("UserAffinitiesStore");
|
||||||
const { FriendsSections } = findByProps("FriendsSections");
|
const { FriendsSections } = findByProps("FriendsSections");
|
||||||
|
|
||||||
interface UserAffinity {
|
const settings = definePluginSettings({
|
||||||
user_id: string;
|
sortByAffinity: {
|
||||||
affinity: number;
|
type: OptionType.BOOLEAN,
|
||||||
|
default: true,
|
||||||
|
description: "Whether to sort implicit relationships by their affinity to you.",
|
||||||
|
restartNeeded: true
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ImplicitRelationships",
|
name: "ImplicitRelationships",
|
||||||
description: "Shows your implicit relationships in the Friends tab.",
|
description: "Shows your implicit relationships in the Friends tab.",
|
||||||
authors: [Devs.Dolfies],
|
authors: [Devs.Dolfies],
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
// Counts header
|
// Counts header
|
||||||
{
|
{
|
||||||
|
@ -81,7 +86,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "getRelationshipCounts(){",
|
find: "getRelationshipCounts(){",
|
||||||
replacement: {
|
replacement: {
|
||||||
predicate: () => Settings.plugins.ImplicitRelationships.sortByAffinity,
|
predicate: () => settings.store.sortByAffinity,
|
||||||
match: /\}\)\.sortBy\((.+?)\)\.value\(\)/,
|
match: /\}\)\.sortBy\((.+?)\)\.value\(\)/,
|
||||||
replace: "}).sortBy(row => $self.wrapSort(($1), row)).value()"
|
replace: "}).sortBy(row => $self.wrapSort(($1), row)).value()"
|
||||||
}
|
}
|
||||||
|
@ -110,16 +115,6 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
settings: definePluginSettings(
|
|
||||||
{
|
|
||||||
sortByAffinity: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
default: true,
|
|
||||||
description: "Whether to sort implicit relationships by their affinity to you.",
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
wrapSort(comparator: Function, row: any) {
|
wrapSort(comparator: Function, row: any) {
|
||||||
return row.type === 5
|
return row.type === 5
|
||||||
|
|
|
@ -20,7 +20,7 @@ import "./messageLogger.css";
|
||||||
|
|
||||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { updateMessage } from "@api/MessageUpdater";
|
import { updateMessage } from "@api/MessageUpdater";
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -41,7 +41,7 @@ interface MLMessage extends Message {
|
||||||
const styles = findByProps("edited", "communicationDisabled", "isSystemMessage");
|
const styles = findByProps("edited", "communicationDisabled", "isSystemMessage");
|
||||||
|
|
||||||
function addDeleteStyle() {
|
function addDeleteStyle() {
|
||||||
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
|
if (settings.store.deleteStyle === "text") {
|
||||||
enableStyle(textStyle);
|
enableStyle(textStyle);
|
||||||
disableStyle(overlayStyle);
|
disableStyle(overlayStyle);
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,57 +125,7 @@ const patchChannelContextMenu: NavContextMenuPatchCallback = (children, { channe
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default definePlugin({
|
const settings = definePluginSettings({
|
||||||
name: "MessageLogger",
|
|
||||||
description: "Temporarily logs deleted and edited messages.",
|
|
||||||
authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN, Devs.Nickyux],
|
|
||||||
dependencies: ["MessageUpdaterAPI"],
|
|
||||||
|
|
||||||
contextMenus: {
|
|
||||||
"message": patchMessageContextMenu,
|
|
||||||
"channel-context": patchChannelContextMenu,
|
|
||||||
"user-context": patchChannelContextMenu,
|
|
||||||
"gdm-context": patchChannelContextMenu
|
|
||||||
},
|
|
||||||
|
|
||||||
start() {
|
|
||||||
addDeleteStyle();
|
|
||||||
},
|
|
||||||
|
|
||||||
renderEdits: ErrorBoundary.wrap(({ message: { id: messageId, channel_id: channelId } }: { message: Message; }) => {
|
|
||||||
const message = useStateFromStores(
|
|
||||||
[MessageStore],
|
|
||||||
() => MessageStore.getMessage(channelId, messageId) as MLMessage,
|
|
||||||
null,
|
|
||||||
(oldMsg, newMsg) => oldMsg?.editHistory === newMsg?.editHistory
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{message.editHistory?.map(edit => (
|
|
||||||
<div className="messagelogger-edited">
|
|
||||||
{Parser.parse(edit.content)}
|
|
||||||
<Timestamp
|
|
||||||
timestamp={edit.timestamp}
|
|
||||||
isEdited={true}
|
|
||||||
isInline={false}
|
|
||||||
>
|
|
||||||
<span className={styles.edited}>{" "}({i18n.Messages.MESSAGE_EDITED})</span>
|
|
||||||
</Timestamp>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}, { noop: true }),
|
|
||||||
|
|
||||||
makeEdit(newMessage: any, oldMessage: any): any {
|
|
||||||
return {
|
|
||||||
timestamp: new Date(newMessage.edited_timestamp),
|
|
||||||
content: oldMessage.content
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
options: {
|
|
||||||
deleteStyle: {
|
deleteStyle: {
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
description: "The style of deleted messages",
|
description: "The style of deleted messages",
|
||||||
|
@ -221,6 +171,57 @@ export default definePlugin({
|
||||||
description: "Comma-separated list of guild IDs to ignore",
|
description: "Comma-separated list of guild IDs to ignore",
|
||||||
default: ""
|
default: ""
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "MessageLogger",
|
||||||
|
description: "Temporarily logs deleted and edited messages.",
|
||||||
|
authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN, Devs.Nickyux],
|
||||||
|
dependencies: ["MessageUpdaterAPI"],
|
||||||
|
settings,
|
||||||
|
|
||||||
|
contextMenus: {
|
||||||
|
"message": patchMessageContextMenu,
|
||||||
|
"channel-context": patchChannelContextMenu,
|
||||||
|
"user-context": patchChannelContextMenu,
|
||||||
|
"gdm-context": patchChannelContextMenu
|
||||||
|
},
|
||||||
|
|
||||||
|
start() {
|
||||||
|
addDeleteStyle();
|
||||||
|
},
|
||||||
|
|
||||||
|
renderEdits: ErrorBoundary.wrap(({ message: { id: messageId, channel_id: channelId } }: { message: Message; }) => {
|
||||||
|
const message = useStateFromStores(
|
||||||
|
[MessageStore],
|
||||||
|
() => MessageStore.getMessage(channelId, messageId) as MLMessage,
|
||||||
|
null,
|
||||||
|
(oldMsg, newMsg) => oldMsg?.editHistory === newMsg?.editHistory
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{message.editHistory?.map(edit => (
|
||||||
|
<div className="messagelogger-edited">
|
||||||
|
{Parser.parse(edit.content)}
|
||||||
|
<Timestamp
|
||||||
|
timestamp={edit.timestamp}
|
||||||
|
isEdited={true}
|
||||||
|
isInline={false}
|
||||||
|
>
|
||||||
|
<span className={styles.edited}>{" "}({i18n.Messages.MESSAGE_EDITED})</span>
|
||||||
|
</Timestamp>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, { noop: true }),
|
||||||
|
|
||||||
|
makeEdit(newMessage: any, oldMessage: any): any {
|
||||||
|
return {
|
||||||
|
timestamp: new Date(newMessage.edited_timestamp),
|
||||||
|
content: oldMessage.content
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDelete(cache: any, data: { ids: string[], id: string; mlDeleted?: boolean; }, isBulk: boolean) {
|
handleDelete(cache: any, data: { ids: string[], id: string; mlDeleted?: boolean; }, isBulk: boolean) {
|
||||||
|
@ -257,7 +258,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldIgnore(message: any, isEdit = false) {
|
shouldIgnore(message: any, isEdit = false) {
|
||||||
const { ignoreBots, ignoreSelf, ignoreUsers, ignoreChannels, ignoreGuilds, logEdits, logDeletes } = Settings.plugins.MessageLogger;
|
const { ignoreBots, ignoreSelf, ignoreUsers, ignoreChannels, ignoreGuilds, logEdits, logDeletes } = settings.store;
|
||||||
const myId = UserStore.getCurrentUser().id;
|
const myId = UserStore.getCurrentUser().id;
|
||||||
|
|
||||||
return ignoreBots && message.author?.bot ||
|
return ignoreBots && message.author?.bot ||
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, registerCommand, sendBotMessage, unregisterCommand } from "@api/Commands";
|
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, registerCommand, sendBotMessage, unregisterCommand } from "@api/Commands";
|
||||||
import * as DataStore from "@api/DataStore";
|
import * as DataStore from "@api/DataStore";
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ function createTagCommand(tag: Tag) {
|
||||||
return { content: `/${tag.name}` };
|
return { content: `/${tag.name}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.plugins.MessageTags.clyde) sendBotMessage(ctx.channel.id, {
|
if (settings.store.clyde) sendBotMessage(ctx.channel.id, {
|
||||||
content: `${EMOTE} The tag **${tag.name}** has been sent!`
|
content: `${EMOTE} The tag **${tag.name}** has been sent!`
|
||||||
});
|
});
|
||||||
return { content: tag.message.replaceAll("\\n", "\n") };
|
return { content: tag.message.replaceAll("\\n", "\n") };
|
||||||
|
@ -69,19 +69,21 @@ function createTagCommand(tag: Tag) {
|
||||||
}, "CustomTags");
|
}, "CustomTags");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
export default definePlugin({
|
|
||||||
name: "MessageTags",
|
|
||||||
description: "Allows you to save messages and to use them with a simple command.",
|
|
||||||
authors: [Devs.Luna],
|
|
||||||
options: {
|
|
||||||
clyde: {
|
clyde: {
|
||||||
name: "Clyde message on send",
|
name: "Clyde message on send",
|
||||||
description: "If enabled, clyde will send you an ephemeral message when a tag was used.",
|
description: "If enabled, clyde will send you an ephemeral message when a tag was used.",
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "MessageTags",
|
||||||
|
description: "Allows you to save messages and to use them with a simple command.",
|
||||||
|
authors: [Devs.Luna],
|
||||||
|
settings,
|
||||||
|
|
||||||
dependencies: ["CommandsAPI"],
|
dependencies: ["CommandsAPI"],
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
|
|
@ -16,17 +16,28 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
|
|
||||||
const RelationshipStore = findByProps("getRelationships", "isBlocked");
|
const RelationshipStore = findByProps("getRelationships", "isBlocked");
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
ignoreBlockedMessages: {
|
||||||
|
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
default: false,
|
||||||
|
restartNeeded: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "NoBlockedMessages",
|
name: "NoBlockedMessages",
|
||||||
description: "Hides all blocked messages from chat completely.",
|
description: "Hides all blocked messages from chat completely.",
|
||||||
authors: [Devs.rushii, Devs.Samu],
|
authors: [Devs.rushii, Devs.Samu],
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "Messages.BLOCKED_MESSAGES_HIDE",
|
find: "Messages.BLOCKED_MESSAGES_HIDE",
|
||||||
|
@ -42,7 +53,7 @@ export default definePlugin({
|
||||||
'"displayName","ReadStateStore")'
|
'"displayName","ReadStateStore")'
|
||||||
].map(find => ({
|
].map(find => ({
|
||||||
find,
|
find,
|
||||||
predicate: () => Settings.plugins.NoBlockedMessages.ignoreBlockedMessages === true,
|
predicate: () => settings.store.ignoreBlockedMessages === true,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(?<=MESSAGE_CREATE:function\((\i)\){)/,
|
match: /(?<=MESSAGE_CREATE:function\((\i)\){)/,
|
||||||
|
@ -51,14 +62,6 @@ export default definePlugin({
|
||||||
]
|
]
|
||||||
}))
|
}))
|
||||||
],
|
],
|
||||||
options: {
|
|
||||||
ignoreBlockedMessages: {
|
|
||||||
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
default: false,
|
|
||||||
restartNeeded: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
isBlocked: message =>
|
isBlocked: message =>
|
||||||
RelationshipStore.isBlocked(message.author.id)
|
RelationshipStore.isBlocked(message.author.id)
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import { addBadge, BadgePosition, ProfileBadge, removeBadge } from "@api/Badges";
|
import { addBadge, BadgePosition, ProfileBadge, removeBadge } from "@api/Badges";
|
||||||
import { addDecorator, removeDecorator } from "@api/MemberListDecorators";
|
import { addDecorator, removeDecorator } from "@api/MemberListDecorators";
|
||||||
import { addDecoration, removeDecoration } from "@api/MessageDecorations";
|
import { addDecoration, removeDecoration } from "@api/MessageDecorations";
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
@ -162,27 +162,34 @@ const indicatorLocations = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
...Object.fromEntries(
|
||||||
|
Object.entries(indicatorLocations).map(([key, value]) => {
|
||||||
|
return [key, {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: `Show indicators ${value.description.toLowerCase()}`,
|
||||||
|
// onChange doesn't give any way to know which setting was changed, so restart required
|
||||||
|
restartNeeded: true,
|
||||||
|
default: true
|
||||||
|
}];
|
||||||
|
})
|
||||||
|
) as Record<"list" | "badges" | "messages", { type: OptionType.BOOLEAN; description: string; restartNeeded: boolean; default: boolean; }>,
|
||||||
|
colorMobileIndicator: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Whether to make the mobile indicator match the color of the user status.",
|
||||||
|
default: true,
|
||||||
|
restartNeeded: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "PlatformIndicators",
|
name: "PlatformIndicators",
|
||||||
description: "Adds platform indicators (Desktop, Mobile, Web...) to users",
|
description: "Adds platform indicators (Desktop, Mobile, Web...) to users",
|
||||||
authors: [Devs.kemo, Devs.TheSun, Devs.Nuckyz, Devs.Ven],
|
authors: [Devs.kemo, Devs.TheSun, Devs.Nuckyz, Devs.Ven],
|
||||||
dependencies: ["MessageDecorationsAPI", "MemberListDecoratorsAPI"],
|
dependencies: ["MessageDecorationsAPI", "MemberListDecoratorsAPI"],
|
||||||
|
settings,
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
const settings = Settings.plugins.PlatformIndicators;
|
|
||||||
const { displayMode } = settings;
|
|
||||||
|
|
||||||
// transfer settings from the old ones, which had a select menu instead of booleans
|
|
||||||
if (displayMode) {
|
|
||||||
if (displayMode !== "both") settings[displayMode] = true;
|
|
||||||
else {
|
|
||||||
settings.list = true;
|
|
||||||
settings.badges = true;
|
|
||||||
}
|
|
||||||
settings.messages = true;
|
|
||||||
delete settings.displayMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.entries(indicatorLocations).forEach(([key, value]) => {
|
Object.entries(indicatorLocations).forEach(([key, value]) => {
|
||||||
if (settings[key]) value.onEnable();
|
if (settings[key]) value.onEnable();
|
||||||
});
|
});
|
||||||
|
@ -197,7 +204,7 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: ".Masks.STATUS_ONLINE_MOBILE",
|
find: ".Masks.STATUS_ONLINE_MOBILE",
|
||||||
predicate: () => Settings.plugins.PlatformIndicators.colorMobileIndicator,
|
predicate: () => settings.store.colorMobileIndicator,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
// Return the STATUS_ONLINE_MOBILE mask if the user is on mobile, no matter the status
|
// Return the STATUS_ONLINE_MOBILE mask if the user is on mobile, no matter the status
|
||||||
|
@ -213,7 +220,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".AVATAR_STATUS_MOBILE_16;",
|
find: ".AVATAR_STATUS_MOBILE_16;",
|
||||||
predicate: () => Settings.plugins.PlatformIndicators.colorMobileIndicator,
|
predicate: () => settings.store.colorMobileIndicator,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
// Return the AVATAR_STATUS_MOBILE size mask if the user is on mobile, no matter the status
|
// Return the AVATAR_STATUS_MOBILE size mask if the user is on mobile, no matter the status
|
||||||
|
@ -234,32 +241,12 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "}isMobileOnline(",
|
find: "}isMobileOnline(",
|
||||||
predicate: () => Settings.plugins.PlatformIndicators.colorMobileIndicator,
|
predicate: () => settings.store.colorMobileIndicator,
|
||||||
replacement: {
|
replacement: {
|
||||||
// Make isMobileOnline return true no matter what is the user status
|
// Make isMobileOnline return true no matter what is the user status
|
||||||
match: /(?<=\i\[\i\.\i\.MOBILE\])===\i\.\i\.ONLINE/,
|
match: /(?<=\i\[\i\.\i\.MOBILE\])===\i\.\i\.ONLINE/,
|
||||||
replace: "!= null"
|
replace: "!= null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
|
|
||||||
options: {
|
|
||||||
...Object.fromEntries(
|
|
||||||
Object.entries(indicatorLocations).map(([key, value]) => {
|
|
||||||
return [key, {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: `Show indicators ${value.description.toLowerCase()}`,
|
|
||||||
// onChange doesn't give any way to know which setting was changed, so restart required
|
|
||||||
restartNeeded: true,
|
|
||||||
default: true
|
|
||||||
}];
|
|
||||||
})
|
|
||||||
),
|
|
||||||
colorMobileIndicator: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Whether to make the mobile indicator match the color of the user status.",
|
|
||||||
default: true,
|
|
||||||
restartNeeded: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
|
||||||
import { debounce } from "@shared/debounce";
|
import { debounce } from "@shared/debounce";
|
||||||
import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent";
|
import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent";
|
||||||
import { getCurrentChannel } from "@utils/discord";
|
import { getCurrentChannel } from "@utils/discord";
|
||||||
|
@ -147,11 +146,11 @@ async function bulkFetchPronouns(ids: string[]): Promise<PronounsResponse> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[] }): string {
|
export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[]; }): string {
|
||||||
if (!pronounSet || !pronounSet.en) return PronounMapping.unspecified;
|
if (!pronounSet || !pronounSet.en) return PronounMapping.unspecified;
|
||||||
// PronounDB returns an empty set instead of {sets: {en: ["unspecified"]}}.
|
// PronounDB returns an empty set instead of {sets: {en: ["unspecified"]}}.
|
||||||
const pronouns = pronounSet.en;
|
const pronouns = pronounSet.en;
|
||||||
const { pronounsFormat } = Settings.plugins.PronounDB as { pronounsFormat: PronounsFormat, enabled: boolean; };
|
const { pronounsFormat } = settings.store;
|
||||||
|
|
||||||
if (pronouns.length === 1) {
|
if (pronouns.length === 1) {
|
||||||
// For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string
|
// For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList";
|
import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList";
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { useForceUpdater } from "@utils/react";
|
import { useForceUpdater } from "@utils/react";
|
||||||
|
@ -89,13 +89,7 @@ function handleGuildUpdate() {
|
||||||
forceUpdateGuildCount?.();
|
forceUpdateGuildCount?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
const settings = definePluginSettings({
|
||||||
name: "ServerListIndicators",
|
|
||||||
description: "Add online friend count or server count in the server list",
|
|
||||||
authors: [Devs.dzshn],
|
|
||||||
dependencies: ["ServerListAPI"],
|
|
||||||
|
|
||||||
options: {
|
|
||||||
mode: {
|
mode: {
|
||||||
description: "mode",
|
description: "mode",
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
|
@ -105,10 +99,17 @@ export default definePlugin({
|
||||||
{ label: "Both server and online friend counts", value: IndicatorType.BOTH },
|
{ label: "Both server and online friend counts", value: IndicatorType.BOTH },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "ServerListIndicators",
|
||||||
|
description: "Add online friend count or server count in the server list",
|
||||||
|
authors: [Devs.dzshn],
|
||||||
|
dependencies: ["ServerListAPI"],
|
||||||
|
settings,
|
||||||
|
|
||||||
renderIndicator: () => {
|
renderIndicator: () => {
|
||||||
const { mode } = Settings.plugins.ServerListIndicators;
|
const { mode } = settings.store;
|
||||||
return <ErrorBoundary noop>
|
return <ErrorBoundary noop>
|
||||||
<div style={{ marginBottom: "4px" }}>
|
<div style={{ marginBottom: "4px" }}>
|
||||||
{!!(mode & IndicatorType.FRIEND) && <FriendsIndicator />}
|
{!!(mode & IndicatorType.FRIEND) && <FriendsIndicator />}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { formatDuration } from "@utils/text";
|
import { formatDuration } from "@utils/text";
|
||||||
import { findByProps, findComponentByCode } from "@webpack";
|
import { findByProps, findComponentByCode } from "@webpack";
|
||||||
|
@ -157,7 +156,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.plugins.PermissionsViewer.enabled) {
|
if (Vencord.Plugins.isPluginEnabled("PermissionsViewer")) {
|
||||||
setPermissions(sortPermissionOverwrites(Object.values(permissionOverwrites).map(overwrite => ({
|
setPermissions(sortPermissionOverwrites(Object.values(permissionOverwrites).map(overwrite => ({
|
||||||
type: overwrite.type as PermissionType,
|
type: overwrite.type as PermissionType,
|
||||||
id: overwrite.id,
|
id: overwrite.id,
|
||||||
|
@ -274,7 +273,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
|
||||||
}
|
}
|
||||||
<div className="shc-lock-screen-allowed-users-and-roles-container">
|
<div className="shc-lock-screen-allowed-users-and-roles-container">
|
||||||
<div className="shc-lock-screen-allowed-users-and-roles-container-title">
|
<div className="shc-lock-screen-allowed-users-and-roles-container-title">
|
||||||
{Settings.plugins.PermissionsViewer.enabled && (
|
{Vencord.Plugins.isPluginEnabled("PermissionsViewer") && (
|
||||||
<Tooltip text="Permission Details">
|
<Tooltip text="Permission Details">
|
||||||
{({ onMouseLeave, onMouseEnter }) => (
|
{({ onMouseLeave, onMouseEnter }) => (
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -16,10 +16,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { proxyLazy } from "@utils/lazy";
|
||||||
import { findByProps, webpackDependantLazy } from "@webpack";
|
import { findByProps, webpackDependantLazy } from "@webpack";
|
||||||
import { Flux, FluxDispatcher } from "@webpack/common";
|
import { Flux, FluxDispatcher } from "@webpack/common";
|
||||||
|
|
||||||
|
// Avoid circular dependency
|
||||||
|
const { settings } = proxyLazy(() => require(".")) as typeof import(".");
|
||||||
|
|
||||||
export interface Track {
|
export interface Track {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -88,7 +91,7 @@ export const SpotifyStore = webpackDependantLazy(() => {
|
||||||
public isSettingPosition = false;
|
public isSettingPosition = false;
|
||||||
|
|
||||||
public openExternal(path: string) {
|
public openExternal(path: string) {
|
||||||
const url = Settings.plugins.SpotifyControls.useSpotifyUris || Vencord.Plugins.isPluginEnabled("OpenInApp")
|
const url = settings.store.useSpotifyUris || Vencord.Plugins.isPluginEnabled("OpenInApp")
|
||||||
? "spotify:" + path.replaceAll("/", (_, idx) => idx === 0 ? "" : ":")
|
? "spotify:" + path.replaceAll("/", (_, idx) => idx === 0 ? "" : ":")
|
||||||
: "https://open.spotify.com" + path;
|
: "https://open.spotify.com" + path;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -29,11 +29,7 @@ function toggleHoverControls(value: boolean) {
|
||||||
(value ? enableStyle : disableStyle)(hoverOnlyStyle);
|
(value ? enableStyle : disableStyle)(hoverOnlyStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
export const settings = definePluginSettings({
|
||||||
name: "SpotifyControls",
|
|
||||||
description: "Adds a Spotify player above the account panel",
|
|
||||||
authors: [Devs.Ven, Devs.afn, Devs.KraXen72, Devs.Av32000],
|
|
||||||
options: {
|
|
||||||
hoverControls: {
|
hoverControls: {
|
||||||
description: "Show controls on hover",
|
description: "Show controls on hover",
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
|
@ -45,7 +41,14 @@ export default definePlugin({
|
||||||
description: "Open Spotify URIs instead of Spotify URLs. Will only work if you have Spotify installed and might not work on all platforms",
|
description: "Open Spotify URIs instead of Spotify URLs. Will only work if you have Spotify installed and might not work on all platforms",
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "SpotifyControls",
|
||||||
|
description: "Adds a Spotify player above the account panel",
|
||||||
|
authors: [Devs.Ven, Devs.afn, Devs.KraXen72, Devs.Av32000],
|
||||||
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "showTaglessAccountPanel:",
|
find: "showTaglessAccountPanel:",
|
||||||
|
@ -87,7 +90,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
start: () => toggleHoverControls(Settings.plugins.SpotifyControls.hoverControls),
|
start: () => toggleHoverControls(settings.store.hoverControls),
|
||||||
|
|
||||||
PanelWrapper({ VencordOriginal, ...props }) {
|
PanelWrapper({ VencordOriginal, ...props }) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { definePluginSettings, Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
@ -87,7 +87,7 @@ function TypingIndicator({ channelId }: { channelId: string; }) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
tooltipText = Settings.plugins.TypingTweaks.enabled
|
tooltipText = Vencord.Plugins.isPluginEnabled("TypingTweaks")
|
||||||
? buildSeveralUsers({ a: getDisplayName(guildId, typingUsersArray[0]), b: getDisplayName(guildId, typingUsersArray[1]), count: typingUsersArray.length - 2 })
|
? buildSeveralUsers({ a: getDisplayName(guildId, typingUsersArray[0]), b: getDisplayName(guildId, typingUsersArray[1]), count: typingUsersArray.length - 2 })
|
||||||
: i18n.Messages.SEVERAL_USERS_TYPING;
|
: i18n.Messages.SEVERAL_USERS_TYPING;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { proxyLazy } from "@utils/lazy";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { wordsToTitle } from "@utils/text";
|
import { wordsToTitle } from "@utils/text";
|
||||||
import definePlugin, { OptionType, PluginOptionsItem, ReporterTestable } from "@utils/types";
|
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
import { Button, ChannelStore, Forms, GuildMemberStore, SelectedChannelStore, SelectedGuildStore, useMemo, UserStore } from "@webpack/common";
|
import { Button, ChannelStore, Forms, GuildMemberStore, SelectedChannelStore, SelectedGuildStore, useMemo, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
|
@ -42,25 +43,25 @@ const VoiceStateStore = findByProps("getVoiceStatesForChannel", "getCurrentClien
|
||||||
// Filtering out events is not as simple as just dropping duplicates, as otherwise mute, unmute, mute would
|
// Filtering out events is not as simple as just dropping duplicates, as otherwise mute, unmute, mute would
|
||||||
// not say the second mute, which would lead you to believe they're unmuted
|
// not say the second mute, which would lead you to believe they're unmuted
|
||||||
|
|
||||||
function speak(text: string, settings: any = Settings.plugins.VcNarrator) {
|
function speak(text: string, mergedSettings: typeof settings.store = settings.store) {
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
|
|
||||||
const speech = new SpeechSynthesisUtterance(text);
|
const speech = new SpeechSynthesisUtterance(text);
|
||||||
let voice = speechSynthesis.getVoices().find(v => v.voiceURI === settings.voice);
|
let voice = speechSynthesis.getVoices().find(v => v.voiceURI === mergedSettings.voice);
|
||||||
if (!voice) {
|
if (!voice) {
|
||||||
new Logger("VcNarrator").error(`Voice "${settings.voice}" not found. Resetting to default.`);
|
new Logger("VcNarrator").error(`Voice "${mergedSettings.voice}" not found. Resetting to default.`);
|
||||||
voice = speechSynthesis.getVoices().find(v => v.default);
|
voice = speechSynthesis.getVoices().find(v => v.default);
|
||||||
settings.voice = voice?.voiceURI;
|
mergedSettings.voice = voice?.voiceURI as string;
|
||||||
if (!voice) return; // This should never happen
|
if (!voice) return; // This should never happen
|
||||||
}
|
}
|
||||||
speech.voice = voice!;
|
speech.voice = voice;
|
||||||
speech.volume = settings.volume;
|
speech.volume = mergedSettings.volume;
|
||||||
speech.rate = settings.rate;
|
speech.rate = mergedSettings.rate;
|
||||||
speechSynthesis.speak(speech);
|
speechSynthesis.speak(speech);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clean(str: string) {
|
function clean(str: string) {
|
||||||
const replacer = Settings.plugins.VcNarrator.latinOnly
|
const replacer = settings.store.latinOnly
|
||||||
? /[^\p{Script=Latin}\p{Number}\p{Punctuation}\s]/gu
|
? /[^\p{Script=Latin}\p{Number}\p{Punctuation}\s]/gu
|
||||||
: /[^\p{Letter}\p{Number}\p{Punctuation}\s]/gu;
|
: /[^\p{Letter}\p{Number}\p{Punctuation}\s]/gu;
|
||||||
|
|
||||||
|
@ -143,92 +144,23 @@ function updateStatuses(type: string, { deaf, mute, selfDeaf, selfMute, userId,
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function playSample(tempSettings: any, type: string) {
|
function playSample(tempSettings: typeof settings.store, type: string) {
|
||||||
const settings = Object.assign({}, Settings.plugins.VcNarrator, tempSettings);
|
const mergedSettings = Object.assign({}, settings.store, tempSettings);
|
||||||
const currentUser = UserStore.getCurrentUser();
|
const currentUser = UserStore.getCurrentUser();
|
||||||
const myGuildId = SelectedGuildStore.getGuildId();
|
const myGuildId = SelectedGuildStore.getGuildId();
|
||||||
|
|
||||||
speak(formatText(settings[type + "Message"], currentUser.username, "general", (currentUser as any).globalName ?? currentUser.username, GuildMemberStore.getNick(myGuildId, currentUser.id) ?? currentUser.username), settings);
|
speak(formatText(mergedSettings[type + "Message"], currentUser.username, "general", (currentUser as any).globalName ?? currentUser.username, GuildMemberStore.getNick(myGuildId, currentUser.id) ?? currentUser.username), mergedSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
const settings = definePluginSettings({
|
||||||
name: "VcNarrator",
|
|
||||||
description: "Announces when users join, leave, or move voice channels via narrator",
|
|
||||||
authors: [Devs.Ven],
|
|
||||||
reporterTestable: ReporterTestable.None,
|
|
||||||
|
|
||||||
flux: {
|
|
||||||
VOICE_STATE_UPDATES({ voiceStates }: { voiceStates: VoiceState[]; }) {
|
|
||||||
const myGuildId = SelectedGuildStore.getGuildId();
|
|
||||||
const myChanId = SelectedChannelStore.getVoiceChannelId();
|
|
||||||
const myId = UserStore.getCurrentUser().id;
|
|
||||||
|
|
||||||
if (ChannelStore.getChannel(myChanId!)?.type === 13 /* Stage Channel */) return;
|
|
||||||
|
|
||||||
for (const state of voiceStates) {
|
|
||||||
const { userId, channelId, oldChannelId } = state;
|
|
||||||
const isMe = userId === myId;
|
|
||||||
if (!isMe) {
|
|
||||||
if (!myChanId) continue;
|
|
||||||
if (channelId !== myChanId && oldChannelId !== myChanId) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [type, id] = getTypeAndChannelId(state, isMe);
|
|
||||||
if (!type) continue;
|
|
||||||
|
|
||||||
const template = Settings.plugins.VcNarrator[type + "Message"];
|
|
||||||
const user = isMe && !Settings.plugins.VcNarrator.sayOwnName ? "" : UserStore.getUser(userId).username;
|
|
||||||
const displayName = user && ((UserStore.getUser(userId) as any).globalName ?? user);
|
|
||||||
const nickname = user && (GuildMemberStore.getNick(myGuildId, userId) ?? user);
|
|
||||||
const channel = ChannelStore.getChannel(id).name;
|
|
||||||
|
|
||||||
speak(formatText(template, user, channel, displayName, nickname));
|
|
||||||
|
|
||||||
// updateStatuses(type, state, isMe);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
AUDIO_TOGGLE_SELF_MUTE() {
|
|
||||||
const chanId = SelectedChannelStore.getVoiceChannelId()!;
|
|
||||||
const s = VoiceStateStore.getVoiceStateForChannel(chanId) as VoiceState;
|
|
||||||
if (!s) return;
|
|
||||||
|
|
||||||
const event = s.mute || s.selfMute ? "unmute" : "mute";
|
|
||||||
speak(formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", ""));
|
|
||||||
},
|
|
||||||
|
|
||||||
AUDIO_TOGGLE_SELF_DEAF() {
|
|
||||||
const chanId = SelectedChannelStore.getVoiceChannelId()!;
|
|
||||||
const s = VoiceStateStore.getVoiceStateForChannel(chanId) as VoiceState;
|
|
||||||
if (!s) return;
|
|
||||||
|
|
||||||
const event = s.deaf || s.selfDeaf ? "undeafen" : "deafen";
|
|
||||||
speak(formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", ""));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
start() {
|
|
||||||
if (typeof speechSynthesis === "undefined" || speechSynthesis.getVoices().length === 0) {
|
|
||||||
new Logger("VcNarrator").warn(
|
|
||||||
"SpeechSynthesis not supported or no Narrator voices found. Thus, this plugin will not work. Check my Settings for more info"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
optionsCache: null as Record<string, PluginOptionsItem> | null,
|
|
||||||
|
|
||||||
get options() {
|
|
||||||
return this.optionsCache ??= {
|
|
||||||
voice: {
|
voice: {
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
description: "Narrator Voice",
|
description: "Narrator Voice",
|
||||||
options: window.speechSynthesis?.getVoices().map(v => ({
|
options: proxyLazy(() => window.speechSynthesis?.getVoices().map(v => ({
|
||||||
label: v.name,
|
label: v.name,
|
||||||
value: v.voiceURI,
|
value: v.voiceURI,
|
||||||
default: v.default
|
default: v.default
|
||||||
})) ?? []
|
})) ?? [])
|
||||||
},
|
},
|
||||||
volume: {
|
volume: {
|
||||||
type: OptionType.SLIDER,
|
type: OptionType.SLIDER,
|
||||||
|
@ -289,7 +221,73 @@ export default definePlugin({
|
||||||
description: "Undeafen Message (only self for now)",
|
description: "Undeafen Message (only self for now)",
|
||||||
default: "{{USER}} undeafened"
|
default: "{{USER}} undeafened"
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "VcNarrator",
|
||||||
|
description: "Announces when users join, leave, or move voice channels via narrator",
|
||||||
|
authors: [Devs.Ven],
|
||||||
|
reporterTestable: ReporterTestable.None,
|
||||||
|
settings,
|
||||||
|
|
||||||
|
flux: {
|
||||||
|
VOICE_STATE_UPDATES({ voiceStates }: { voiceStates: VoiceState[]; }) {
|
||||||
|
const myGuildId = SelectedGuildStore.getGuildId();
|
||||||
|
const myChanId = SelectedChannelStore.getVoiceChannelId();
|
||||||
|
const myId = UserStore.getCurrentUser().id;
|
||||||
|
|
||||||
|
if (ChannelStore.getChannel(myChanId!)?.type === 13 /* Stage Channel */) return;
|
||||||
|
|
||||||
|
for (const state of voiceStates) {
|
||||||
|
const { userId, channelId, oldChannelId } = state;
|
||||||
|
const isMe = userId === myId;
|
||||||
|
if (!isMe) {
|
||||||
|
if (!myChanId) continue;
|
||||||
|
if (channelId !== myChanId && oldChannelId !== myChanId) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [type, id] = getTypeAndChannelId(state, isMe);
|
||||||
|
if (!type) continue;
|
||||||
|
|
||||||
|
const template = settings.store[type + "Message"];
|
||||||
|
const user = isMe && !settings.store.sayOwnName ? "" : UserStore.getUser(userId).username;
|
||||||
|
const displayName = user && ((UserStore.getUser(userId) as any).globalName ?? user);
|
||||||
|
const nickname = user && (GuildMemberStore.getNick(myGuildId, userId) ?? user);
|
||||||
|
const channel = ChannelStore.getChannel(id).name;
|
||||||
|
|
||||||
|
speak(formatText(template, user, channel, displayName, nickname));
|
||||||
|
|
||||||
|
// updateStatuses(type, state, isMe);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
AUDIO_TOGGLE_SELF_MUTE() {
|
||||||
|
const chanId = SelectedChannelStore.getVoiceChannelId()!;
|
||||||
|
const s = VoiceStateStore.getVoiceStateForChannel(chanId) as VoiceState;
|
||||||
|
if (!s) return;
|
||||||
|
|
||||||
|
const event = s.mute || s.selfMute ? "unmute" : "mute";
|
||||||
|
speak(formatText(settings.store[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", ""));
|
||||||
|
},
|
||||||
|
|
||||||
|
AUDIO_TOGGLE_SELF_DEAF() {
|
||||||
|
const chanId = SelectedChannelStore.getVoiceChannelId()!;
|
||||||
|
const s = VoiceStateStore.getVoiceStateForChannel(chanId) as VoiceState;
|
||||||
|
if (!s) return;
|
||||||
|
|
||||||
|
const event = s.deaf || s.selfDeaf ? "undeafen" : "deafen";
|
||||||
|
speak(formatText(settings.store[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", ""));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (typeof speechSynthesis === "undefined" || speechSynthesis.getVoices().length === 0) {
|
||||||
|
new Logger("VcNarrator").warn(
|
||||||
|
"SpeechSynthesis not supported or no Narrator voices found. Thus, this plugin will not work. Check my Settings for more info"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
settingsAboutComponent({ tempSettings: s }) {
|
settingsAboutComponent({ tempSettings: s }) {
|
||||||
|
@ -299,7 +297,7 @@ export default definePlugin({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const types = useMemo(
|
const types = useMemo(
|
||||||
() => Object.keys(Vencord.Plugins.plugins.VcNarrator.options!).filter(k => k.endsWith("Message")).map(k => k.slice(0, -7)),
|
() => Object.keys(settings.def).filter(k => k.endsWith("Message")).map(k => k.slice(0, -7)),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -335,7 +333,7 @@ export default definePlugin({
|
||||||
className={"vc-narrator-buttons"}
|
className={"vc-narrator-buttons"}
|
||||||
>
|
>
|
||||||
{types.map(t => (
|
{types.map(t => (
|
||||||
<Button key={t} onClick={() => playSample(s, t)}>
|
<Button key={t} onClick={() => playSample(s as typeof settings.store, t)}>
|
||||||
{wordsToTitle([t])}
|
{wordsToTitle([t])}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|
1
src/webpack/common/types/utils.d.ts
vendored
1
src/webpack/common/types/utils.d.ts
vendored
|
@ -124,6 +124,7 @@ export type Permissions = "ADD_REACTIONS"
|
||||||
| "USE_APPLICATION_COMMANDS"
|
| "USE_APPLICATION_COMMANDS"
|
||||||
| "USE_CLYDE_AI"
|
| "USE_CLYDE_AI"
|
||||||
| "USE_EMBEDDED_ACTIVITIES"
|
| "USE_EMBEDDED_ACTIVITIES"
|
||||||
|
| "USE_EXTERNAL_APPS"
|
||||||
| "USE_EXTERNAL_EMOJIS"
|
| "USE_EXTERNAL_EMOJIS"
|
||||||
| "USE_EXTERNAL_SOUNDS"
|
| "USE_EXTERNAL_SOUNDS"
|
||||||
| "USE_EXTERNAL_STICKERS"
|
| "USE_EXTERNAL_STICKERS"
|
||||||
|
|
Loading…
Reference in a new issue