Hello I'm trying to make the bot play specific songs then I want the bot to leave the channel and I made it, but the problem is when someone else joins the channel while the bot is playing it restart playing the songs
client.on('voiceStateUpdate', async (oldState, newState) => {
const channel = client.channels.cache.get('921118985876017217')
if (oldState.channel == null && newState.channel == channel) {
await new Promise(function (resolve , reject) {
resolve(
joinVoiceChannel({
channelId: channel.id,
guildId: newState.guild.id,
adapterCreator: newState.guild.voiceAdapterCreator
}))
let stream = ytdl('https://www.youtube.com/watch?v=TU1i6I1ms6s', {
filter: "audioonly",
fmt: "mp3",
encoderArgs: ['-af', 'bass=g=10'],
})
let secStream = ytdl('https://www.youtube.com/watch?v=wHqKkiHlvJc&list=RDwHqKkiHlvJc&start_radio=1', {
filter: "audioonly",
fmt: "mp3",
encoderArgs: ['-af', 'bass=g=10'],
})
const resource = createAudioResource(stream, {
inputType: StreamType.Arbitrary,
inlineVolume: true,
});
// resource.volume.setVolume(0.5);
const secReasorce = createAudioResource(secStream, {
inputType: StreamType.Arbitrary, /* StreamType.Arbitrary type of the song like mpe */
inlineVolume: true,
});
const player = createAudioPlayer();
player.play(resource)
const connection = getVoiceConnection(oldState.guild.id)
connection.subscribe(player)
player.on(AudioPlayerStatus.Idle, () =>setTimeout(() => {
try{
{player.play(secReasorce)}
}catch{
connection.destroy()
}
}, 3000))
player.on( AudioPlayerStatus.Playing , ()=>{
//I think there will be the solution but I don't know any functions does what I want
} )
})
You have to keep track of whether it's already playing audio or not. Since you're getting the channel based off of an ID; I'm assuming you're only using it in one voice channel. So you could just have a boolean outside of the lambda expression's scope that keeps track of whether it's playing.
If you implement that you'd have something like this:
let isPlaying = false; // Create a variable to keep track of whether it's playing or not.
client.on('voiceStateUpdate', async (oldState, newState) => {
// If it's already playing, return and do nothing.
if (isPlaying) return;
const channel = client.channels.cache.get('921118985876017217')
if (oldState.channel == null && newState.channel == channel) {
await new Promise(function (resolve , reject) {
resolve(
joinVoiceChannel({
channelId: channel.id,
guildId: newState.guild.id,
adapterCreator: newState.guild.voiceAdapterCreator
}))
isPlaying = true; // Bot successfully joined vc, it now begins to play audio.
// Removed code unrelated to the answer so you can more easily see the changes.
player.on(AudioPlayerStatus.Idle, () =>setTimeout(() => {
try{
{player.play(secReasorce)}
}catch{
// I assume this is where you make it disconnect?
// If so, retain the integrity of `isPlaying` by setting it back to false.
isPlaying = false;
connection.destroy()
}
}, 3000))
})```
Related
I am using discordjs/voice in order to sum up for how long users have talked in the voice channel. So far it never logged an data and I noticed that it is because the client.on('speaking' event is not triggered. I have tried looking for solutions to why that happens but couldn`t find any.
Here is the related piece from my code:
if (msg.content === '!scw start') {
if (!msg.guild) {
msg.channel.send('You\'re currently not in a guild!');
return;
};
msg.channel.send('Please wait a moment while I connect to the VC.')
.catch(error => {
console.log(error);
});
const channel = msg.member.voice.channel
if (channel === undefined) {
msg.channel.send('It seems like you\'re not in a VC.');
return
};
const connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
selfDeaf: false
});
msg.channel.send('Success! I\'m now connected and ready to listen.');
var speakers = [];
connection.on('speaking', (user, speaking) => {
// when a user starts speaking:
if (speaking) {
console.log(`${user} started talking`)
// add them to the list of speakers
// start a timer recording how long they're speaking
speakers.push({ user: new Date().getTime() });
// when a user stops speaking:
} else {
console.log(`${user} stopped talking`)
// stop the timer and add it to their total time
var talkTime = (new Date().getTime()) - (stats[user]['timeSpeaking']);
var talkTime = talkTime / 1000;
var talkTime = Math.abs(talkTime);
if (user in stats) {
stats[user]['timeSpeaking'] = stats[user]['timeSpeaking'] + talkTime;
} else {
stats[user] = {
'timeSpeaking': talkTime,
};
};
// remove them from the list of speakers
if (speakers.includes(user)) {
arrayRemove(speakers, user)
};
};
});
connection.on('disconnect', () => {
msg.channel.send('I was disconnected ⁉️.')
.catch(error => {
console.log(error);
});
})
};
first issue: all the embeds in my code stopped working - no matter what command I try to run if it has an embed in it I get the error: DiscordAPIError: Cannot send an empty message
second issue: I'm currently programming a mute command with a mongoDB database, it puts everything I need it in the database however if I try to mute someone it ends up only muting them for 1s by default, basically completely ignoring the second argument. heres what I want the command to do: when you mute someone you need to provide the user id and a time (works in ms) + reason then it puts it in the data base.
here's the code: [P.S. Im not getting an error message, it just doesnt work properly like I want it to]
const mongo = require('../mongo.js')
const muteSchema = require('../schemas/mute-schema.js')
const Discord = require('discord.js')
const ms = require ("ms")
module.exports = {
commands: 'mute',
minArgs: 2,
expectedArgs: "<Target user's #> <time> <reason>",
requiredRoles: ['Staff'],
callback: async (message, arguments) => {
const target = message.mentions.users.first() || message.guild.members.cache.get(arguments[0])
if (!target) {
message.channel.send('Please specify someone to mute.')
return
}
const { guild, channel } = message
arguments.shift()
const mutedRole = message.guild.roles.cache.find(role => role.name === 'muted');
const guildId = message.guild.id
const userId = target.id
const reason = arguments.join(' ')
const user = target
const arg2=arguments[2]
const mute = {
author: message.member.user.tag,
timestamp: new Date().getTime(),
reason,
}
await mongo().then(async (mongoose) => {
try {
await muteSchema.findOneAndUpdate(
{
guildId,
userId,
},
{
guildId,
userId,
$push: {
mutes: mute,
},
},
{
upsert: true,
}
)
} finally {
mongoose.connection.close()
}
})
message.delete()
user.roles.add(mutedRole)
setTimeout(function() {
user.roles.remove(mutedRole)
}, ms(`${arg2}`));
try{
message.channel.send(`works`)
}
catch(error){
const embed3 = new Discord.MessageEmbed()
.setDescription(`✅ I Couldn't DM them but **${target} has been muted || ${reason}**`)
.setColor('#004d00')
message.channel.send({ embeds: [embed3] });
}
},
}
djs v13 has a new update where you need to send embeds like this:
const exampleEmbed = new Discord.MessageEmbed()
.setTitle('example')
.setDescription('example')
.setColor('RANDOM')
message.channel.send({embed: [exampleEmbed]});
module.exports = {
name: "mute",
description: "Use this to mute members",
execute: async function (msg, arg) {
const muterole = await msg.guild.roles.cache.find((r) => r.name == "Mute");
let promise = new Promise(async function (resolve, reject) {
if (muterole) {
resolve(commandmute(msg, arg));
} else {
reject(createrole(msg, arg));
}
});
async function createrole(msg, arg) {
msg.guild.roles.create({
data: {
name: "Mute",
},
reason: "This is a mute role created by the bot ",
});
const tole = msg.guild.roles.cache.find((r) => r.name == "Mute");
const ch1 = msg.guild.channels.cache.forEach((ch, msg) => {
if ((ch = msg.guild.channels.type("text"))) {
ch.updateOverwrite(tole, { VIEW_MESSAGES: true, SEND_MESSAGES: true });
}
msg.reply("It seems that the server doesnt have a Mute role so the bot has created one ");
msg.reply("Successfully created the role");
});
}
function commandmute(msg, arg) {}
},
};
So I am using a promise to check whether the server has a mute role or not, and if it doesn't it will pass over to a function that will create a role named 'Mute'.
Now the problem is that I am not able to figure out how to change the permissions of the role in a channel so that users with the aforementioned role cannot send messages.
Also, I am not able to get the id of the role by doing role.id.
It shows undefined.
If role.id shows undefined, it must be because your "tole" const is undefined too. I recommand you trying this :
async function createrole(msg, arg) {
msg.guild.roles.create({
data: {
name: "Mute",
},
reason: "This is a mute role created by the bot ",
}).then( role => {
msg.guild.channels.cache.forEach((ch, msg) => {
if (ch = msg.guild.channels.type("text")) {
ch.updateOverwrite(role, { VIEW_MESSAGES: true, SEND_MESSAGES: false });
}
}
});
msg.reply("It seems that the server doesnt have a Mute role so the bot has created one ");
msg.reply("Successfully created the role");
}
By using then(), you make sure the role is created, and you can directly get the role object and use it, instead of using msg.guild.roles.cache.find((r) => r.name == "Mute").
I followed some tutorials and mixed some of the codes around and it works but I'm having difficulty understanding async with message.guild.channels.forEach no matter how i play to change it.
I want the bot to join only the voice channel where the user typed 'test' without running on all voice channels.
thank you
exports.run = async (client, message, args, level) => {
async function play(channel) {
await channel.join().then(async (connection) => {
let dispatcher = await connection.playFile('./img/aniroze.mp3');
await dispatcher.on('end', function () {
message.channel.send("🎧 **x** 🎧").then(sentEmbed => {
sentEmbed.react("👍")
sentEmbed.react("👎")
channel.leave();});
});
});
}
let timer = 10000;
message.guild.channels.forEach(async (channel) => {
if (channel.type == 'voice' && channel.members.size > 1) {
const embed2 = new Discord.RichEmbed()
.setTitle('🎧 🎧')
.setColor("#3498DB")
.setThumbnail(`${message.author.displayAvatarURL}`)
.setTimestamp()
message.channel.send(embed2);
setTimeout(function () {
play(channel);
}, timer);
}});
setTimeout(function () {
}, timer);
};
exports.conf = {
enabled: true,
aliases: ['test'],
guildOnly: true,
permLevel: 'User'
}
If you want the bot to join the voice channel of the user that sent the command then use this:
const voiceChannel = message.member.voiceChannel
if (!voiceChannel) return message.reply('you are not in a voice channel')
voiceChannel.join()
Note: This is a discord.js v11 answer, for v12 replace member.voiceChannel with member.voice.channel
I made code such that if someone connects to a particular channel, the bot will create a channel with their name and then move them in it. I want the bot to auto-delete the channel when this user disconnects and no one else connects to this channel. I have this code but I don't know how to delete the channel.
bot.on('voiceStateUpdate', (oldMember, newMember) =>{
let mainCatagory = '604259561536225298';
let mainChannel = '614954752693764119';
if(newMember.voiceChannelID === mainChannel){
newMember.guild.createChannel(`${newMember.user.username}'s Channel`,'voice')
.then(temporary => {
temporary.setParent(mainCatagory)
.then(() => newMember.setVoiceChannel(temporary.id))
}).catch(err =>{
console.error(err);
})
}
});
I tried to do if(newMember.voiceChannel.members.size === 0){temporary.detele}; but temporary is not defined.
Create an array to write the ID of the temporary channel and the server on which this channel was created, in front of the body of the event.
var temporary = []
bot.on('voiceStateUpdate', (oldMember, newMember) =>{
const mainCatagory = '604259561536225298';
const mainChannel = '614954752693764119';
if(newMember.voiceChannelID == mainChannel){
// Create channel...
await newMember.guild.createChannel(`${newMember.user.username}'s channel`, {type: 'voice', parent: mainCatagory})
.then(async channel => {
temporary.push({ newID: channel.id, guild: channel.guild })
// A new element has been added to temporary array!
await newMember.setVoiceChannel(channel.id)
})
}
if(temporary.length >= 0) for(let i = 0; i < temporary.length; i++) {
// Finding...
let ch = temporary[i].guild.channels.find(x => x.id == temporary[i].newID)
// Channel Found!
if(ch.members.size <= 0){
await ch.delete()
// Channel has been deleted!
return temporary.splice(i, 1)
}
}
})
You could try defining an empty variable first, like temp and then assign it the temporary channel when returning the createChannel() promise, like so:
bot.on('voiceStateUpdate', (oldMember, newMember) =>{
let mainCatagory = '604259561536225298';
let mainChannel = '614954752693764119';
let temp;
if(newMember.voiceChannelID === mainChannel){
newMember.guild.createChannel(`${newMember.user.username}'s Channel`,'voice')
.then(temporary => {
temp = temporary
temporary.setParent(mainCatagory)
.then(() => newMember.setVoiceChannel(temporary.id))
}).catch(err =>{
console.error(err);
})
}
if(newMember.voiceChannel.members.size === 0){temp.delete()};
});
This is based on Raifyks' answer, but updated for Discord.js v12/v13 and has a few improvements.
const mainCategory = '604259561536225298';
const mainChannel = '614954752693764119';
// A set that will contain the IDs of the temporary channels created.
/** #type {Set<import('discord.js').Snowflake>} */
const temporaryChannels = new Set();
bot.on('voiceStateUpdate', async (oldVoiceState, newVoiceState) => {
try {
const {channelID: oldChannelId, channel: oldChannel} = oldVoiceState;
const {channelID: newChannelId, guild, member} = newVoiceState;
// Create the temporary channel
if (newChannelId === mainChannel) {
// Create the temporary voice channel.
// Note that you can set the parent of the channel in the
// createChannel call, without having to set the parent in a
// separate request to Discord's API.
const channel = await guild.channels.create(
`${member.user.username}'s channel`,
{type: 'voice', parent: mainCategory}
);
// Add the channel id to the array of temporary channel ids.
temporaryChannels.add(channel.id);
// Move the member to the new channel.
await newVoiceState.setChannel(channel);
}
// Remove empty temporary channels
if (
// Is the channel empty? (thanks to Rakshith B S for pointing this out)
!oldChannel.members.size &&
// Did the user come from a temporary channel?
temporaryChannels.has(oldChannelId) &&
// Did the user change channels or leave the temporary channel?
oldChannelId !== newChannelId
) {
// Delete the channel
await oldChannel.delete();
// Remove the channel id from the temporary channels set
temporaryChannels.delete(oldChannelId);
}
} catch (error) {
// Handle any errors
console.error(error);
}
});