Snoweuph
Snoweuph

Reputation: 91

function returns undefined discord.js

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)

Upvotes: 1

Views: 1266

Answers (1)

Cannicide
Cannicide

Reputation: 4520

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).

Upvotes: 1

Related Questions