1
votes

I'm trying to build a music discord bot with yt-search but it gives me undefined whenever I play the song and it joins the voice channel without playing the song. I'm trying to use yt-search to find the video I want or only the URL then pass it to ytdl to run it with the URL given from yt-search but I think I'm wrong in some points. I don't know where, could you please fix my code ?

Image to show the problem:

enter image description here

My code:

const Discord = require("discord.js");
const { prefix, token } = require("./config.json");
const ytdl = require("ytdl-core");
const yts = require("yt-search");

const client = new Discord.Client();

const queue = new Map();

client.once("ready", () => {
  console.log("Ready!");
});

client.once("reconnecting", () => {
  console.log("Reconnecting!");
});

client.once("disconnect", () => {
  console.log("Disconnect!");
});

client.on("message", async message => {
  if (message.author.bot) return;
  if (!message.content.startsWith(prefix)) return;

  const serverQueue = queue.get(message.guild.id);

  if (message.content.startsWith(`${prefix}play`)) {
    execute(message, serverQueue);
    return;
  } else if (message.content.startsWith(`${prefix}skip`)) {
    skip(message, serverQueue);
    return;
  } else if (message.content.startsWith(`${prefix}stop`)) {
    stop(message, serverQueue);
    return;
  } else {
    message.channel.send("You need to enter a valid command!");
  }
});

async function execute(message, serverQueue) {
  const args = message.content.split(" ");

  const voiceChannel = message.member.voice.channel;
  if (!voiceChannel)
    return message.channel.send(
      "You need to be in a voice channel to play music!"
    );
  const permissions = voiceChannel.permissionsFor(message.client.user);
  if (!permissions.has("CONNECT") || !permissions.has("SPEAK")) {
    return message.channel.send(
      "I need the permissions to join and speak in your voice channel!"
    );
  }
  const r = await yts(args[1,2]);
  const video = r.videos.slice( 0, 1 );
  console.log(video);
  const songInfo = await ytdl.getInfo(video.url);
  const song = {
        title: songInfo.videoDetails.title,
        url: songInfo.videoDetails.video_url,
   };

  if (!serverQueue) {
    const queueContruct = {
      textChannel: message.channel,
      voiceChannel: voiceChannel,
      connection: null,
      songs: [],
      volume: 5,
      playing: true
    };

    queue.set(message.guild.id, queueContruct);

    queueContruct.songs.push(song);

    try {
      var connection = await voiceChannel.join();
      queueContruct.connection = connection;
      play(message.guild, queueContruct.songs[0]);
    } catch (err) {
      console.log(err);
      queue.delete(message.guild.id);
      return message.channel.send(err);
    }
  } else {
    serverQueue.songs.push(song);
    return message.channel.send(`${song.title} has been added to the queue!`);
  }
}

function skip(message, serverQueue) {
  if (!message.member.voice.channel)
    return message.channel.send(
      "You have to be in a voice channel to stop the music!"
    );
  if (!serverQueue)
    return message.channel.send("There is no song that I could skip!");
  serverQueue.connection.dispatcher.end();
}

function stop(message, serverQueue) {
  if (!message.member.voice.channel)
    return message.channel.send(
      "You have to be in a voice channel to stop the music!"
    );
    
  if (!serverQueue)
    return message.channel.send("There is no song that I could stop!");
    
  serverQueue.songs = [];
  serverQueue.connection.dispatcher.end();
}

function play(guild, song) {
  const serverQueue = queue.get(guild.id);
  if (!song) {
    serverQueue.voiceChannel.leave();
    queue.delete(guild.id);
    return;
  }

  const dispatcher = serverQueue.connection
    .play(ytdl(song.url))
    .on("finish", () => {
      serverQueue.songs.shift();
      play(guild, serverQueue.songs[0]);
    })
    .on("error", error => console.error(error));
  dispatcher.setVolumeLogarithmic(serverQueue.volume / 5);
  serverQueue.textChannel.send(`Start playing: **${song.title}**`);
}

client.login(token);
1

1 Answers

0
votes

There are two errors. I'm not sure what you think args[1,2] is but it's the same as args[2] which is the third item of the args array. By reading your code, I think you want to use a string here, the search term. By removing the first item (the command) from the args array and joining the rest of them, you will receive a string you can use as keywords. Check out the example below:

const message = { content: '!play some music I want'}
const args = message.content.split(' ')

console.log({ args })
// => ["!play", "some", "music", "I", "want"]
console.log({ 'args[1, 2]': args[1, 2] })
// => "music"
console.log({ 'search': args.slice(1).join(' ') })
// => "some music I want"

The other error is that await yts(query) returns an array of results and when you define the video variable you use r.videos.slice(0, 1). The .slice() method returns a new array with the first item of r.videos.

As the video variable is an array, video.url is undefined. You could fix it by using the first item instead as it will have a url property. You should also check if there are any search results.

Check out the updated code below:

async function execute(message, serverQueue) {
  const args = message.content.split(' ');

  const voiceChannel = message.member.voice.channel;
  if (!voiceChannel)
    return message.channel.send(
      'You need to be in a voice channel to play music!',
    );
  const permissions = voiceChannel.permissionsFor(message.client.user);
  if (!permissions.has('CONNECT') || !permissions.has('SPEAK')) {
    return message.channel.send(
      'I need the permissions to join and speak in your voice channel!',
    );
  }
  const query = args.slice(1).join(' ');
  const results = await yts(query);

  if (!results.videos.length)
    return message.channel.send(`No results for \`${query}\``);

  const firstVideo = results.videos[0];
  const songInfo = await ytdl.getInfo(firstVideo.url);
  const song = {
    title: songInfo.videoDetails.title,
    url: songInfo.videoDetails.video_url,
  };
  console.log(song);

  if (!serverQueue) {
    // ...
    // ...