1
votes

I'm writing my own discord bot and i have a function that should return a youtubelink, but everytime i get undefined. here is the code of the bot, it is written in discord.js/node.js

for example i'm in my discord talk and i write "!play allan becker faded" i only get an undefined in the embed message, i also tried to console.log the returned string, but its laso undefinedEmbed message

const Discord = require('discord.js')
const fs = require('fs')
const ytdl = require('ytdl-core')
const ffmpeg = require('ffmpeg')
const { debug, Console } = require('console')
const config = JSON.parse(fs.readFileSync('config.json', 'utf8'))
const ytapi3 = config.GoogleApiYT3
const search = require('youtube-search')

var client = new Discord.Client()

//setting status
client.on('ready', () => {
    console.log("Logged in as", client.user.username, "...")
    client.user.setPresence({
        status: config.status,
        activity: {
            name: config.activity,
            type: 'STREAMING',
            url: config.streamingURL
        }
    })
})

//musicbot
client.on('message', async message => {
    if(message.author.bot) return // test if bot has written this message
    if(!message.channel.id == config.botcommandsChannelID) return //test if message is in botcommands channel
    if(!message.content.startsWith(config.prefix)) return // test if prefix is used

    const args = message.content.substring(config.prefix.length).split(" ") // split arguments into args[]-list and cut the prefix out
    const voiceChannel = message.member.voice.channel

    //test if user has permissions to use command
    if(config.UseDJRole == "true") {
        if(message.member.roles.cache.has(config.DJroleID) || message.member.roles.cache.has(config.ModeratorRoleID) || message.member.user.id == config.owner){
        }else{
            return sendEmbed(message.channel, config.ErrorColor, "Error", config.NoPermissionsToUseThisCommand)
        }
    }

    if(!voiceChannel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_404) //testing if user is in voiceChannel

    if(message.content.startsWith(config.prefix + config.PlayCommand)){ //Play-case
        const permission = voiceChannel.permissionsFor(message.client.user)
        if(!permission.has('CONNECT')) sendEmbed(message.channel, config.ErrorColor, "Error", config.NoPermissionsToJoinVC)
        if(!permission.has('SPEAK')) sendEmbed(message.channel, config.ErrorColor, "Error", config.NoPermissionsToSpeakInVC)
        var vidURL = new String("nothing");

        //get link "vidURL"
        if(args.length >= 2){
            if(ytdl.validateURL(args[1])){
                vidURL = args[1]
            } else{
                args.shift()
                const vidSearchLink = args.join(' ')
                try{
                    vidURL = searchOnYT(vidSearchLink, message.channel, args)
                }catch(error){
                    return console.log(error)
                }
            }
        }else {
            return sendEmbed(message.channel, config.ErrorColor, "Error", config.NoArgs)
        }

        if(client.connection == null){
            voiceChannel.join()
            
            //play
            sendEmbed(message.channel, config.MusicEmbedColorHEX, "Playing", vidURL)
            
        } else{
            if(voiceChannel.id != client.connection.voice.channel.id){
                sendEmbed(message.channel, config.ErrorColor, "Error", config.AllreadyUsed + client.connection.voice.channel.name)
            } else{
                //play
                sendEmbed(message.channel, config.MusicEmbedColorHEX, "Playing", vidURL)
            }
        }

    }else if(message.content.startsWith(config.prefix + config.StopCommand) || message.content.startsWith(config.prefix + config.LeaveCommand)){
        if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
        voiceChannel.leave()
        if(message.member.voice.connection) message.guild.voice.disconnect()
    }else if(message.content.startsWith(config.prefix + config.PauseCommand)){
        if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
        //pause music
    }else if(message.content.startsWith(config.prefix + config.ResumeCommand)){
        if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
        //resume music
    }else if(message.content.startsWith(config.prefix + config.SkipCommand)){
        if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
        //skip
    }else if(message.content.startsWith(config.prefix + config.QueueCommand)){
        if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400)//test if you are in one voice channel with the bot
        //show queue
    }
})

function sendEmbed(_channel, _Color, _Title, _Description, _URL){
    const embedMessage = new Discord.MessageEmbed()
        .setColor(_Color)
        .setTitle(_Title)
        .setDescription(_Description)
        .setURL(_URL);
    _channel.send(embedMessage)

}

function searchOnYT(searchstring, _channel){
    var opts = {
        maxResults: 1,
        key: config.GoogleApiYT3,
        type: 'video'
    }
    search(searchstring, opts, function(err, results) {
        if(err) return console.log(err);
        if(results){
            const r = results[0]
            return new String(r.link)
        }else{
            return sendEmbed(_channel, config.ErrorColor, "Error", NoResultsFound, searchstring)
        }
      })
}

client.login(config.token)
1
Well if an error occurs when searching for the youtube video, you are returning the console.log and not a string value (on the line: if (err) return console.log(err)). So I think what's happening is, an error is occurring and your searchOnYT() function is trying to return a console.log (which has no output, and you therefore receive the response undefined). Instead of sending a "no results found" embed when results is undefined, you might instead want to do so when err is defined (so replace your console.log(err) with the content of your else statement in searchOnYT()).Cannicide
If I put an console.log with the result in the case that some result is found it gives me the right thing, I testet Something more, and I noticed that it doesn't wait for the function to return, and goes on, so that before the function returns the result is undefined, I need the searchOnYT() function to wait for the search(), so that it gets an result before returningSnoweuph
I have added an answer to solve that issue.Cannicide

1 Answers

1
votes

As you mentioned in your comment, your searchOnYT() function should only return a value once it gets a result. Otherwise, vidURL will always be undefined. You can use a Promise in combination with async/await to achieve this. Here's an example, in just the parts of the code that need to be changed to do this.

In your message handler:

try{
    vidURL = await searchOnYT(vidSearchLink, message.channel, args);
} catch(error){
    return console.log(error)
}

In your searchOnYT() function:

function searchOnYT(searchstring, _channel){
    var opts = {
        maxResults: 1,
        key: config.GoogleApiYT3,
        type: 'video'
    }

    return new Promise((resolve, reject) => {
        search(searchstring, opts, function(err, results) {
            if(err) reject(err);

            if(results) {
                const r = results[0]
                resolve(new String(r.link))
            }
            else {
                sendEmbed(_channel, config.ErrorColor, "Error", NoResultsFound, searchstring);
                reject("No results found");
            }
          })
    });

}

Now that searchOnYT() returns a Promise, this ensures that the function will only return a value once search() finishes executing. Using a callback would also have worked to achieve this, but promises are a much neater way of waiting before returning a value (and promises work very nicely with async/await, and your message handler luckily already uses async).