all repos — simple-discord-music-bot @ d16335811e5121043b717ec4dc564800eaf8573f

A Discord bot making use of discord.js and play-yt.

commands/play.js (view raw)

  1const path = require("node:path");
  2const { SlashCommandBuilder } = require("discord.js");
  3const {
  4  createAudioResource,
  5  createAudioPlayer,
  6  joinVoiceChannel,
  7  NoSubscriberBehavior,
  8  AudioPlayerStatus,
  9} = require("@discordjs/voice");
 10
 11const ytdl = require("ytdl-core");
 12const ytsr = require("ytsr");
 13
 14async function reply_efemeral(interaction, reply) {
 15  return await interaction.reply({ content: reply, ephemeral: true });
 16}
 17
 18function get_player(resource) {
 19  const player = createAudioPlayer({
 20    behaviors: { noSubscriber: NoSubscriberBehavior.Pause },
 21  });
 22  player.on("error", (error) =>
 23    console.error(
 24      `Error: ${error.message} with resource ${error.resource.metadata.title}`
 25    )
 26  );
 27  player.on(AudioPlayerStatus.Idle, () => {
 28    player.stop();
 29    player.subscribers.forEach((element) => element.connection.disconnect());
 30  });
 31
 32  player.play(createAudioResource(resource));
 33  return player;
 34}
 35
 36module.exports = {
 37  data: new SlashCommandBuilder()
 38    .setName("play")
 39    .setDescription("Play something off YouTube.")
 40    .addStringOption((option) =>
 41      option
 42        .setName("query")
 43        .setDescription("YouTube URL or search query")
 44        .setRequired(true)
 45    ),
 46
 47  async execute(interaction) {
 48    const member = interaction.member;
 49    if (!member)
 50      return await reply_efemeral(
 51        interaction,
 52        "Please use this in your current server."
 53      );
 54
 55    const user_connection = member.voice;
 56    const channel = user_connection.channel;
 57    if (!channel)
 58      return await reply_efemeral(
 59        interaction,
 60        "You're not in a voice channel."
 61      );
 62
 63    const guild = channel.guild;
 64
 65    // Get the YouTube URL or search query
 66    const url = interaction.options.getString("query");
 67
 68    // If the URL is not a valid YouTube URL, treat it as a search query and try to get the first result
 69
 70    if (!ytdl.validateURL(url)) {
 71        return await reply_efemeral(interaction, "This bot only supports URLs (for now).");
 72      try {
 73        const searchResults = await ytsr(url);
 74        results = searchResults.items;
 75
 76        url = null
 77        for(result in results){
 78            if (result.type == "video"){
 79                url = result.url;
 80                console.log("Using", url)
 81                break;
 82            }
 83        }
 84        if(url == null) {
 85            console.log("No results found");
 86            throw new Error("No results found");
 87        }
 88      } catch (error) {
 89        return await reply_efemeral(
 90          interaction,
 91          `Invalid YouTube URL or search query! ${error}`
 92        );
 93      }
 94    }
 95
 96    const stream = ytdl(url, {
 97      filter: "audioonly",
 98      opusEncoded: true,
 99      encoderArgs: ["-af", "bass=g=10,dynaudnorm=f=200"],
100    });
101
102    // Connect to the user's voice channel
103    const connection = joinVoiceChannel({
104      channelId: channel.id,
105      guildId: guild.id,
106      adapterCreator: guild.voiceAdapterCreator,
107    });
108
109    connection.subscribe(get_player(stream));
110    return await reply_efemeral(interaction, `Playing.`);
111  },
112};