Add VoiceRejoin & Update VoiceButtons
* server mute / deafen feature yay :3 * Update settings.ts * Add VoiceRejoin plugin for automatic voice channel rejoin * preventReconnectIfCallEnded option to Select * change rejoindelay * t * Update utils.tsx * t * Update utils.tsx --------- Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
parent
9cbf3819cc
commit
25e568409d
4 changed files with 237 additions and 32 deletions
|
|
@ -38,6 +38,18 @@ export const settings = definePluginSettings({
|
|||
description: "Toggles their video upon clicking deafen button.",
|
||||
restartNeeded: false,
|
||||
},
|
||||
useServer: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Use server mute/deafen instead of local when you have permission.",
|
||||
default: false,
|
||||
restartNeeded: false,
|
||||
},
|
||||
serverSelf: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Deafen / Mute yourself on the server when using mute/deafen.",
|
||||
default: false,
|
||||
restartNeeded: false,
|
||||
},
|
||||
showButtonsSelf: {
|
||||
type: OptionType.SELECT,
|
||||
default: "display",
|
||||
|
|
@ -60,4 +72,15 @@ export const settings = definePluginSettings({
|
|||
{ label: "Both", value: "both" },
|
||||
],
|
||||
}
|
||||
}, {
|
||||
useServer: {
|
||||
disabled() {
|
||||
return !this.store.showMuteButton && !this.store.showDeafenButton;
|
||||
},
|
||||
},
|
||||
serverSelf: {
|
||||
disabled() {
|
||||
return !this.store.useServer && !this.store.showMuteButton && !this.store.showDeafenButton;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import "./styles.css";
|
|||
|
||||
import { Icon, User } from "@vencord/discord-types";
|
||||
import { findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { Button, ChannelStore, MediaEngineStore, NavigationRouter, Tooltip, UserStore, VoiceActions } from "@webpack/common";
|
||||
import { Button, ChannelStore, GuildActions, MediaEngineStore, NavigationRouter, PermissionsBits, PermissionStore, Tooltip, UserStore, VoiceActions, VoiceStateStore } from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
|
||||
import { settings } from "./settings";
|
||||
|
|
@ -61,6 +61,29 @@ function getUserName(user: User) {
|
|||
return username;
|
||||
}
|
||||
|
||||
function canServerMuteDeafen(userId: string) {
|
||||
if (!settings.store.useServer) return { canMute: false, canDeafen: false };
|
||||
|
||||
const voiceState = VoiceStateStore.getVoiceStateForUser(userId);
|
||||
const channel = voiceState?.channelId ? ChannelStore.getChannel(voiceState.channelId) : null;
|
||||
if (!channel?.guild_id) return { canMute: false, canDeafen: false };
|
||||
|
||||
const canMute = PermissionStore.can(PermissionsBits.MUTE_MEMBERS, channel);
|
||||
const canDeafen = PermissionStore.can(PermissionsBits.DEAFEN_MEMBERS, channel);
|
||||
|
||||
return { canMute, canDeafen };
|
||||
}
|
||||
|
||||
function getServerMuteDeafenState(userId: string) {
|
||||
const voiceState = VoiceStateStore.getVoiceStateForUser(userId);
|
||||
if (!voiceState) return { isServerMuted: false, isServerDeafened: false };
|
||||
|
||||
return {
|
||||
isServerMuted: voiceState.mute ?? false,
|
||||
isServerDeafened: voiceState.deaf ?? false
|
||||
};
|
||||
}
|
||||
|
||||
export function UserChatButton({ user }: { user: User; }) {
|
||||
const isCurrent = (user.id === UserStore.getCurrentUser().id);
|
||||
return (
|
||||
|
|
@ -82,19 +105,42 @@ export function UserChatButton({ user }: { user: User; }) {
|
|||
|
||||
export function UserMuteButton({ user }: { user: User; }) {
|
||||
const isCurrent = (user.id === UserStore.getCurrentUser().id);
|
||||
const isMuted = (isCurrent && MediaEngineStore.isSelfMute()) || MediaEngineStore.isLocalMute(user.id);
|
||||
const { canMute: canServerMute } = canServerMuteDeafen(user.id);
|
||||
const { isServerMuted } = getServerMuteDeafenState(user.id);
|
||||
|
||||
const useServerMuteForSelf = isCurrent && settings.store.serverSelf;
|
||||
|
||||
const isLocalMuted = (isCurrent && MediaEngineStore.isSelfMute()) || MediaEngineStore.isLocalMute(user.id);
|
||||
const isMuted = canServerMute ? isServerMuted : isLocalMuted;
|
||||
const color = isMuted ? "var(--status-danger)" : "var(--channels-default)";
|
||||
|
||||
const muteAction = canServerMute && (useServerMuteForSelf || !isCurrent) ? "Server Mute" : "Mute";
|
||||
const tooltipAction = isMuted ? (canServerMute && (useServerMuteForSelf || !isCurrent) ? "Unserver Mute" : "Unmute") : muteAction;
|
||||
|
||||
return (
|
||||
<VoiceUserButton
|
||||
user={user}
|
||||
tooltip={`${isMuted ? "Unmute" : "Mute"} ${isCurrent ? "yourself" : `${getUserName(user)}`}`}
|
||||
tooltip={`${tooltipAction} ${isCurrent ? "yourself" : `${getUserName(user)}`}`}
|
||||
icon={isCurrent ? <MuteIconSelf muted={isMuted} size="sm" color={color} /> : <MuteIconOther muted={isMuted} size="sm" color={color} />}
|
||||
onClick={() => {
|
||||
if (isCurrent) {
|
||||
VoiceActions.toggleSelfMute();
|
||||
return;
|
||||
if (canServerMute) {
|
||||
if (!useServerMuteForSelf) {
|
||||
VoiceActions.toggleSelfMute();
|
||||
return;
|
||||
}
|
||||
|
||||
const voiceState = VoiceStateStore.getVoiceStateForUser(user.id);
|
||||
const channel = voiceState?.channelId ? ChannelStore.getChannel(voiceState.channelId) : null;
|
||||
if (channel?.guild_id) {
|
||||
GuildActions.setServerMute(channel.guild_id, user.id, !isServerMuted);
|
||||
}
|
||||
} else {
|
||||
if (isCurrent) {
|
||||
VoiceActions.toggleSelfMute();
|
||||
} else {
|
||||
VoiceActions.toggleLocalMute(user.id);
|
||||
}
|
||||
}
|
||||
VoiceActions.toggleLocalMute(user.id);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
@ -102,44 +148,68 @@ export function UserMuteButton({ user }: { user: User; }) {
|
|||
|
||||
export function UserDeafenButton({ user }: { user: User; }) {
|
||||
const isCurrent = (user.id === UserStore.getCurrentUser().id);
|
||||
const { canDeafen: canServerDeafen } = canServerMuteDeafen(user.id);
|
||||
const { isServerDeafened } = getServerMuteDeafenState(user.id);
|
||||
|
||||
const useServerDeafenForSelf = isCurrent && settings.store.serverSelf;
|
||||
|
||||
const isMuted = MediaEngineStore.isLocalMute(user.id);
|
||||
const isSoundboardMuted = SoundboardStore.isLocalSoundboardMuted(user.id);
|
||||
const isVideoDisabled = MediaEngineStore.isLocalVideoDisabled(user.id);
|
||||
const isDeafened = isCurrent && MediaEngineStore.isSelfDeaf() || isMuted && isSoundboardMuted && isVideoDisabled;
|
||||
const isLocalDeafened = isCurrent && MediaEngineStore.isSelfDeaf() || isMuted && isSoundboardMuted && isVideoDisabled;
|
||||
|
||||
const isDeafened = canServerDeafen && (useServerDeafenForSelf || !isCurrent) ? isServerDeafened : isLocalDeafened;
|
||||
const color = isDeafened ? "var(--status-danger)" : "var(--channels-default)";
|
||||
|
||||
const deafenAction = canServerDeafen && (useServerDeafenForSelf || !isCurrent) ? "Server Deafen" : "Deafen";
|
||||
const tooltipAction = isDeafened ? (canServerDeafen && (useServerDeafenForSelf || !isCurrent) ? "Unserver Deafen" : "Undeafen") : deafenAction;
|
||||
|
||||
return (
|
||||
<VoiceUserButton
|
||||
user={user}
|
||||
tooltip={`${isDeafened ? "Undeafen" : "Deafen"} ${isCurrent ? "yourself" : `${getUserName(user)}`}`}
|
||||
tooltip={`${tooltipAction} ${isCurrent ? "yourself" : `${getUserName(user)}`}`}
|
||||
icon={isCurrent ? <DeafenIconSelf muted={isDeafened} size="sm" color={color} /> : <DeafenIconOther muted={isDeafened} size="sm" color={color} />}
|
||||
onClick={() => {
|
||||
if (isCurrent) {
|
||||
VoiceActions.toggleSelfDeaf();
|
||||
return;
|
||||
}
|
||||
if (isMuted) {
|
||||
VoiceActions.toggleLocalMute(user.id);
|
||||
if (settings.store.muteSoundboard && isSoundboardMuted) {
|
||||
VoiceActions.toggleLocalSoundboardMute(user.id);
|
||||
if (canServerDeafen) {
|
||||
if (!useServerDeafenForSelf) {
|
||||
VoiceActions.toggleSelfDeaf();
|
||||
return;
|
||||
}
|
||||
if (settings.store.disableVideo && isVideoDisabled) {
|
||||
VoiceActions.setDisableLocalVideo(
|
||||
user.id,
|
||||
"ENABLED",
|
||||
"default"
|
||||
);
|
||||
|
||||
const voiceState = VoiceStateStore.getVoiceStateForUser(user.id);
|
||||
const channel = voiceState?.channelId ? ChannelStore.getChannel(voiceState.channelId) : null;
|
||||
if (channel?.guild_id) {
|
||||
GuildActions.setServerDeaf(channel.guild_id, user.id, !isServerDeafened);
|
||||
}
|
||||
} else {
|
||||
VoiceActions.toggleLocalMute(user.id);
|
||||
if (settings.store.muteSoundboard && !isSoundboardMuted) {
|
||||
VoiceActions.toggleLocalSoundboardMute(user.id);
|
||||
if (isCurrent) {
|
||||
VoiceActions.toggleSelfDeaf();
|
||||
return;
|
||||
}
|
||||
if (settings.store.disableVideo && !isVideoDisabled) {
|
||||
VoiceActions.setDisableLocalVideo(
|
||||
user.id,
|
||||
"DISABLED",
|
||||
"default"
|
||||
);
|
||||
if (isMuted) {
|
||||
VoiceActions.toggleLocalMute(user.id);
|
||||
if (settings.store.muteSoundboard && isSoundboardMuted) {
|
||||
VoiceActions.toggleLocalSoundboardMute(user.id);
|
||||
}
|
||||
if (settings.store.disableVideo && isVideoDisabled) {
|
||||
VoiceActions.setDisableLocalVideo(
|
||||
user.id,
|
||||
"ENABLED",
|
||||
"default"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
VoiceActions.toggleLocalMute(user.id);
|
||||
if (settings.store.muteSoundboard && !isSoundboardMuted) {
|
||||
VoiceActions.toggleLocalSoundboardMute(user.id);
|
||||
}
|
||||
if (settings.store.disableVideo && !isVideoDisabled) {
|
||||
VoiceActions.setDisableLocalVideo(
|
||||
user.id,
|
||||
"DISABLED",
|
||||
"default"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
|
|
|||
111
src/equicordplugins/voiceRejoin/index.tsx
Normal file
111
src/equicordplugins/voiceRejoin/index.tsx
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin, { makeRange, OptionType } from "@utils/types";
|
||||
import { ChannelStore, FluxDispatcher, UserStore, VoiceStateStore } from "@webpack/common";
|
||||
|
||||
const DATASTORE_KEY = "VCLastVoiceChannel";
|
||||
const DATASTORE_SESSION_KEY = "VCLastVoiceChannelSession";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
rejoinDelay: {
|
||||
type: OptionType.SLIDER,
|
||||
description: "Set Delay before rejoining voice channel.",
|
||||
markers: makeRange(1, 10, 1),
|
||||
default: 2,
|
||||
stickToMarkers: true,
|
||||
},
|
||||
preventReconnectIfCallEnded: {
|
||||
type: OptionType.SELECT,
|
||||
description: "Do not reconnect if the call has ended or the voice channel is empty or does not exist.",
|
||||
options: [
|
||||
{ label: "None", value: "none", default: false },
|
||||
{ label: "DMs only", value: "dms", default: false },
|
||||
{ label: "Servers only", value: "servers", default: false },
|
||||
{ label: "DMs and Servers", value: "both", default: true },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "VoiceRejoin",
|
||||
description: "Rejoins DM/Server call automatically when restarting Discord.",
|
||||
authors: [EquicordDevs.omaw],
|
||||
settings,
|
||||
|
||||
flux: {
|
||||
VOICE_STATE_UPDATES({ voiceStates }: { voiceStates: any[]; }) {
|
||||
const myUserId = UserStore?.getCurrentUser?.()?.id;
|
||||
if (!myUserId) return;
|
||||
|
||||
const myState = voiceStates.find(s => s.userId === myUserId);
|
||||
if (!myState) return;
|
||||
|
||||
if (myState.channelId) {
|
||||
const saved = {
|
||||
guildId: myState.guildId ?? null,
|
||||
channelId: myState.channelId,
|
||||
};
|
||||
DataStore.set(DATASTORE_KEY, saved);
|
||||
DataStore.set(DATASTORE_SESSION_KEY, true);
|
||||
} else {
|
||||
DataStore.set(DATASTORE_SESSION_KEY, false);
|
||||
}
|
||||
},
|
||||
|
||||
async CONNECTION_OPEN() {
|
||||
const wasInVC = await DataStore.get(DATASTORE_SESSION_KEY);
|
||||
if (wasInVC === false) {
|
||||
DataStore.del(DATASTORE_KEY);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
const saved = await DataStore.get(DATASTORE_KEY);
|
||||
if (!saved?.channelId) return;
|
||||
|
||||
const preventionMode = settings.store.preventReconnectIfCallEnded;
|
||||
if (preventionMode !== "none") {
|
||||
const channel = ChannelStore.getChannel(saved.channelId);
|
||||
|
||||
if (!channel) {
|
||||
DataStore.set(DATASTORE_SESSION_KEY, false);
|
||||
return;
|
||||
}
|
||||
|
||||
const isDM = !saved.guildId;
|
||||
const shouldPrevent =
|
||||
preventionMode === "both" ||
|
||||
(preventionMode === "dms" && isDM) ||
|
||||
(preventionMode === "servers" && !isDM);
|
||||
|
||||
if (shouldPrevent) {
|
||||
const connectedUsers = VoiceStateStore.getVoiceStatesForChannel(saved.channelId);
|
||||
const othersInCall = Object.values(connectedUsers).filter(
|
||||
(vs: any) => vs.userId !== UserStore.getCurrentUser().id
|
||||
);
|
||||
|
||||
if (othersInCall.length === 0) {
|
||||
DataStore.set(DATASTORE_SESSION_KEY, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluxDispatcher.dispatch({
|
||||
type: "VOICE_CHANNEL_SELECT",
|
||||
guildId: saved.guildId,
|
||||
channelId: saved.channelId,
|
||||
});
|
||||
|
||||
DataStore.set(DATASTORE_SESSION_KEY, true);
|
||||
}, settings.store.rejoinDelay * 1000);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -180,6 +180,7 @@ export const InviteActions = findByPropsLazy("resolveInvite");
|
|||
export const ChannelActionCreators = findByPropsLazy("openPrivateChannel");
|
||||
|
||||
export const VoiceActions = findByPropsLazy("toggleSelfMute");
|
||||
export const GuildActions = findByPropsLazy("setServerMute", "setServerDeaf");
|
||||
|
||||
export const IconUtils: t.IconUtils = findByPropsLazy("getGuildBannerURL", "getUserAvatarURL");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue