discordjs / discord.js

A powerful JavaScript library for interacting with the Discord API
https://discord.js.org
Apache License 2.0
25.49k stars 3.97k forks source link

TypeError: Cannot read property 'has' of null at VoiceChannel.get joinable [as joinable] #3421

Closed sav3nwarrioR closed 5 years ago

sav3nwarrioR commented 5 years ago

Please describe the problem you are having in as much detail as possible: My bot can play music with url or video title. But everytime I try to search a video and connect to the channel it returns an error: UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'has' of null at VoiceChannel.get joinable [as joinable]

But at the same time my bot can play music with url and join the channel without any error.

Include a reproducible code sample here, if possible:

music.js [handleVideo function]

const handleVideo = async (video, msg, voiceChannel, playlist = false) => {
  const serverQueue = queue.get(msg.guild.id);

  const song = {
    duration: video.durationSeconds,
    id: video.id,
    title: htmlDecode(video.title),
    url: `https://www.youtube.com/watch?v=${video.id}`
  };

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

    queue.set(msg.guild.id, queueConstruct);

    queueConstruct.songs.push(song);

    try {
      let connection = await voiceChannel.join();
      queueConstruct.connection = connection;
      play(msg.guild, queueConstruct.songs[0]);
    } catch (error) {
      queue.delete(msg.guild.id);

      return msg.channel.send(
        `⚠ **Error** | Error while joining channel: ${error}`
      );
      }
  } else {
    serverQueue.songs.push(song);

    if (playlist) return undefined;
    else
      return msg.channel.send(
        `✅ **Success** | Added **${escapeRegExp(
          htmlDecode(song.title)
        )}** \`[${fancyTimeFormat(song.duration)}]\` to the queue!`
      );
  }

  return undefined;
}

music.js [play function]

const play = async (guild, song) => {
  const serverQueue = queue.get(guild.id);

  if (!song) {
    serverQueue.voiceChannel.leave();
    queue.delete(guild.id);
    return;
  }

  const dispatcher = serverQueue.connection
    .playStream(ytdl(song.url))
    .on("error", error => console.error("Error! " + error))
    .on("end", reason => {
      console.log("Stream ended: " + reason);
      serverQueue.songs.shift();
      setTimeout(() => {
        play(guild, serverQueue.songs[0]);
      }, 250);
    })

  dispatcher.setVolumeLogarithmic(serverQueue.volume / 5);

  serverQueue.textChannel.send(
    `🎶 Now playing: **${escapeRegExp(
      htmlDecode(song.title)
    )}** \`[${fancyTimeFormat(song.duration)}]\``
  );
}

play.js

if (url.match(/^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/)) {
      const playlist = await youtube.getPlaylist(url);

      const videos = await playlist.getVideos();
      for (const video of Object.values(videos)) {
        const video2 = await youtube.getVideoByID(video.id);

        await handleVideo(video2, message, voiceChannel, true);
      }

      return message.channel.send(
        `✅ **Success** | Playlist: **${escapeRegExp(
          htmlDecode(playlist.title)
        )}** was added to the queue!`
      );
    } else {
      let video = null  
      try {
        video = await youtube.getVideo(url);
      } catch (error) {
        try {
          if (searchString.length > 32)
            return message.channel.send(
              "⚠ **Error** | Too big video title!"
            );

          let videos = await youtube.searchVideos(searchString, 10);

          let index = 0;

          message.channel.send(`
                    🤔 **[Tried to search:"${escapeRegExp(
                      searchString
                    )}"]** | __**Search result:**__\n
                    ${videos
                      .map(
                        video2 =>
                          `:musical_note:   **${++index}.**  ${escapeRegExp(
                            htmlDecode(video2.title)
                          )}`
                      )
                      .join("\n                    ")}
                    \n Use \`--select [1-10]\` command to select one.
                    `);
          let response = null                  
          try {
            response = await message.channel.awaitMessages(
              message2 =>
                (message2.author.id =
                  message.author.id &&
                  message2.content.slice(9) > 0 &&
                  message2.content.slice(9) < 11 &&
                  message2.content.startsWith("--select")),
              {
                maxMatches: 1,
                time: 15000,
                errors: ["time"]
              }
            );
          } catch (err) {
            console.error(err);

            return message.channel.send(
              "⚠ **Error** | Cancelling video search."
            );
          }

          const videoIndex = parseInt(response.first().content.slice(9));

          video = await youtube.getVideoByID(videos[videoIndex - 1].id);
        } catch (err) {
          console.error(err);
          return message.channel.send(
            "⚠ **Error** | No videos found!"
          );
        }
      }
      return handleVideo(video, message, voiceChannel);
    }

Further details:

Fyko commented 5 years ago

Please join the Discord Server and ask in the corresponding channel.