OAuth2 URL + Bot Permissions + Discord Intents
I don't fully understand the relationship between OAuth2 URL creation, bot permissions url creation and the intents required in the code.
I think there might be a permissions issue that's preventing my both from passing 'signalling' and 'connecting' status
Code for init and part of the 'listener' functionality below:
client.once('ready', async () => {
console.log('Bot is ready');
client.channels.fetch(voiceChannelId)
.then(channel => {
if (channel.type === 'GUILD_VOICE') {
try {
voiceConnection = joinVoiceChannel({
channelId: String(voiceChannelId),
guildId: String(guildId),
adapterCreator: channel.guild.voiceAdapterCreator,
debug: true,
});
console.log('Bot joined the voice channel');
} catch (error) {
console.error('Error with bot joining: ', error);
}
voiceConnection.on('stateChange', async (state) => {
if (state && state.userId) {
const user = await client.users.fetch(state.userId)
if (state.connectionStatus === 'ready' && state.type === 'join') {
console.log(
${user.username} joined the voice channel.
);
handleUserJoin(user)
} else {
(state.connectionStatus === 'destroyed' && state.type === 'leave')
console.log(${user.username} left the voice channel.
);
handleUserLeave(user)
}
} else {
console.error('Voice channel not found.');
}
});
}
});
});2 Replies
- What's your exact discord.js
npm list discord.js
and node node -v
version?
- Not a discord.js issue? Check out #other-js-ts.
- Consider reading #how-to-get-help to improve your question!
- Explain what exactly your issue is.
- Post the full error stack trace, not just the top part!
- Show your code!
- Issue solved? Press the button!Overall, my bot needs to have the following permissions:
- detect user join/leave a room
- mute/unmute user
- detect user start speaking/stop speaking
- send messages to channels (both all users and single user)
my client with intents are as follows:
const client = new Discord.Client({
intents: [
Discord.Intents.FLAGS.GUILDS,
Discord.Intents.FLAGS.GUILD_MEMBERS,
Discord.Intents.FLAGS.GUILD_PRESENCES,
Discord.Intents.FLAGS.GUILD_VOICE_STATES,
Discord.Intents.FLAGS.GUILD_MESSAGES
]
});
First real question is - Do I also have to follow the steps for OAuth2 URL permissions? (even though I have intents coded)
Have included screenshots to show what I'm thinking I should tick. Am I missing anything? What should I be putting into the field for Redirects?
Further, do I also need to follow steps for the Bot Permissions URL too? I'm not sure why I would be doing this, so any explanation would be great :)
If so, similarly, what should I tick to achieve the above permissions functionalities for the bot?
Great info, appreciated 🙂 @Qjuh
To provide more context, the start/stop listener is switched on and off for a specific user within this function:
async function startTimer() {
if (queueActive && queue.length > 0) {
try {
const currentUser = queue[0];
await unmuteUser(currentUser);
userActive = true;
unmuteTimestamp = Date.now();
const listener = speakingListener(currentUser);
voiceConnection.receiver.speaking.on('start', listener);
voiceConnection.receiver.speaking.on('end', listener);
while (userActive) {
elapsedTime = Date.now() - unmuteTimestamp;
if (!startedSpeakingTimestamp && elapsedTime >= startedSpeakingLimit) {
console.log(
${currentUser.user.tag} did not start speaking.
);
await muteUser(currentUser);
queue.push(queue.shift());
userActive = false;
} else if (elapsedTime >= speakTime) {
console.log(${currentUser.user.tag} reached maximum speak time.
);
await muteUser(currentUser);
queue.push(queue.shift());
userActive = false;
}
// Repeat after userSwitchInterval
await new Promise(resolve => setTimeout(resolve, userSwitchInterval));
}
voiceConnection.receiver.speaking.off('start', listener);
voiceConnection.receiver.speaking.off('end', listener);
startedSpeakingTimestamp = null;
stoppedSpeakingTimestamp = null;
unmuteTimestamp = null;
if (queueActive) {
await startTimer();
}
} catch (error) {
console.error('Error in user timer:', error);
}
}
}
Regarding the bot being the target that connects, am I correct regarding the following two points:
1. I can write some conditions to prevent the bot from joining
2. Regardless, the voiceConnection will continue to listen for join/leaves?
No, the while loop isn't involved where I've got the bot issue - I only showcased it to illustrate where the speaking start/stop listener was.
Oh I see! So would I actually need "two bots", one being the regular bot gateway and a totally separate one to for start/stop?
(The fact I'm running join/leave through a VoiceConnection is likely to be my current trouble huh?)
So if I have my speaking listeners loaded:
botConnection.receiver.speaking.on('start', (userId) => {
if (!startedSpeakingTimestamp) {
client.users.fetch(userId)
.then(user => {
startedSpeakingTimestamp = Date.now();
const startedDate = new Date(startedSpeakingTimestamp)
console.log(
${user.displayName} started speaking at ${startedDate});
})
}
});
botConnection.receiver.speaking.on('end', (userId) => {
if (!stoppedSpeakingTimestamp || Date.now() > stoppedSpeakingTimestamp) {
client.users.fetch(userId)
.then(user => {
stoppedSpeakingTimestamp = Date.now();
const stoppedDate = new Date(stoppedSpeakingTimestamp)
console.log(
${user.displayName} finished speaking at ${stoppedDate});
});
}
});
But they are triggering repeatedly, start and end, multiple times a second (which obviously isn't representing the fact that a user has finished and starts speaking again).
You mentioned the blocking while loop (see below for it in context) - is it likely to be 'cutting off' the speaking stream thus causing these multiple speaker triggers?
async function startTimer() {
if (queueActive && queue.length > 0) {
try {
const currentMember = queue[0];
await unmuteUser(currentMember);
userActive = true;
unmuteTimestamp = Date.now();
const unmuteDate = new Date(unmuteTimestamp)
console.log(unmuteDate)
while (userActive) {
elapsedTime = Date.now() - unmuteTimestamp;
if (!startedSpeakingTimestamp && elapsedTime >= startedSpeakingLimit) {
console.log(${currentMember.displayName} did not start speaking.
);
await muteUser(currentMember);
queue.push(queue.shift());
userActive = false;
} else if (elapsedTime >= speakTime) {
console.log(${currentMember.displayName} reached maximum speak time.
);
await muteUser(currentMember);
queue.push(queue.shift());
userActive = false;
}
await new Promise(resolve => setTimeout(resolve, userSwitchInterval));
}
startedSpeakingTimestamp = null;
stoppedSpeakingTimestamp = null;
unmuteTimestamp = null;
if (queueActive) {
await startTimer();
}
} catch (error) {
console.error('Error in user timer:', error);
}
}
}