feat(gateway): auto server-undeafen + unmute the bot itself on voice join

A server-muted/server-deafened bot can't reliably receive/record members' audio
(and definitely can't receive video/screen share). After the voice connection
is Ready, force a REST guild-members PATCH (mute:false, deaf:false) on the self
member so the bot is auto-unmuted & undeafened on every join/reconnect.

Requires MUTE_MEMBERS + DEAFEN_MEMBERS permissions (user granted). Failure is
logged as a warning and never breaks the voice join.
This commit is contained in:
asepharyana
2026-08-30 21:15:04 +07:00
committed by asepharyana
parent 441b5282ef
commit 462f643d6f
@@ -7,7 +7,7 @@ import {
type VoiceConnection,
VoiceConnectionStatus,
} from "@discordjs/voice";
import type { Client, VoiceChannel } from "discord.js-selfbot-v13";
import type { Client, Guild, VoiceChannel } from "discord.js-selfbot-v13";
import { createChildLogger } from "@/shared/logger/index";
import { retryWithBackoff } from "@/shared/utils/index";
import { config } from "../../shared/config/config.js";
@@ -31,6 +31,39 @@ export function setEventBroadcaster(broadcaster: EventBroadcaster | undefined) {
_eventBroadcaster = broadcaster;
}
/**
* Force the bot (self member) to be unmuted + undeafened at the SERVER level.
*
* Why: a server-muted / server-deafened bot cannot receive/record other
* members' audio properly (and definitely cannot receive their video/screen
* share). The bot's own voice state may be server-muted/deafened by an admin
* or by a prior state. This issues a REST guild-members PATCH with
* `mute:false, deaf:false`.
*
* Requires the `MUTE_MEMBERS` + `DEAFEN_MEMBERS` permissions on the bot
* (user has granted them). Failures are logged, never fatal — an unmute
* failure must not break the voice join/recording.
*/
async function forceSelfServerUnmuteUndeafen(
client: Client,
guild: Guild,
): Promise<void> {
try {
const selfId = client.user?.id;
if (!selfId) return;
await guild.members.edit(selfId, { mute: false, deaf: false });
logger.info({ guildId: guild.id }, "Forced bot server unmute + undeafen");
} catch (err) {
logger.warn(
{
guildId: guild.id,
err: err instanceof Error ? err.message : String(err),
},
"Could not force server unmute/undeafen (permissions not granted?)",
);
}
}
let _pcmWsClient: VoicePcmWsClient | undefined;
export function setPcmWsClient(client: VoicePcmWsClient | undefined) {
@@ -115,6 +148,11 @@ export async function startRecording(
);
logger.info("Connected to voice channel. Recording started");
// Auto undeafen + unmute the bot itself at the server level (MUTE_MEMBERS /
// DEAFEN_MEMBERS permission granted). Server-muted/deafened bot can't
// receive others' audio/video. Fire-and-forget — never blocks recording.
void forceSelfServerUnmuteUndeafen(client, channel.guild);
// Create recording session after connection is ready
const sessionStartTime = Date.now();
const session = createRecordingSession({