DiscordJS - Need Help setting Buttons for erela.js like "Play, Resume, Queue, etc."

I’m Coding a Discord Music Bot for my Discord Server and i need Help setting up Buttons for Embeds like PlayButton, ResumeButton, etc. which will run a command from my CommandsDir.

I was trying to add ActionRowBuilder(), but it haven’t work. I don’t know what i can otherwise do. I was also trying to get a help from OpenAi, but with the same result.

My Directory look like this :

discord-bot/
├── commands
├─── play.js
├─── resume.js
├─── etc.
├── events
├─── buildCreate.js
├─── message.js
├─── raw.js
├─── ready.js
├─── voiceStateUpdate.js
├── node_modules
├── structures
├─── DiscordMusicBot.js (main js)
├─── EpicPlayer.js
├─── Logger.js
├── util
├─── pagination.js
├─── ProgressBar.js
├─── RegisterSlashCommands.js
├─── TimeString.js
├── botconfig.js
├── index.js
├── package-lock.json
└── package.json

DiscordMusicBot.js ├───

const { Collection, Client, MessageEmbed } = require("discord.js");
const { LavasfyClient } = require("lavasfy");
const { Manager } = require("erela.js");
const { Server } = require("socket.io");
const http = require("http");
const Jsoning = require("jsoning");
const fs = require("fs");
const path = require("path");
const Express = require("express");
const Logger = require("./Logger");
const prettyMilliseconds = require("pretty-ms");
const deezer = require("erela.js-deezer");
const apple = require("erela.js-apple");
const facebook = require("erela.js-facebook");
const colors = require("colors");
const resumeCommand = require("../commands/resume");
const message = require("../events/message");

//Class extending Stuff
require("discordjs-activity"); //Epic Package, For more details: https://www.npmjs.com/package/discordjs-activity
require("./EpicPlayer"); //idk why im doing but i wanna learn something new so...



class DiscordMusicBot extends Client {
  constructor(props) {
    super(props);

    this.commands = new Collection();
    this.connections = new Map();
    this.CommandsRan = 0;
    this.SongsPlayed = 0;

    this.database = {
      //Saved at jsoning node_modules directory, DOCS: https://jsoning.js.org/
      guild: new Jsoning("guild.json"), //Server Config
    };
    this.logger = new Logger(path.join(__dirname, "..", "Logs.log"));

    try {
      //Config for testing
      this.botconfig = require("../dev-config");
    } catch {
      //Config for production
      this.botconfig = require("../botconfig"); 
    }
    if (this.botconfig.Token === "")
      return new TypeError(
        "The botconfig.js is not filled out. Please make sure nothing is blank, otherwise the bot will not work properly."
      );

    this.LoadCommands();
    this.LoadEvents();

    //Web Stuff
    this.server = Express();
    this.http = http.createServer(this.server);
    this.server.use("/", require("../api"));
    this.io = new Server(this.http);
    require("../api/socket")(this.io);

    //Utils
    this.ProgressBar = require("../util/ProgressBar");
    this.Pagination = require("../util/pagination");
    this.ParseHumanTime = (str) => {
      let Parsed;
      try {
        Parsed = require("../util/TimeString")(str);
        return Parsed;
      } catch {
        Parsed = false;
        return Parsed;
      }
    };

    this.Ready = false;

    //idk where do i do it so i did it here ;-;
    this.ws.on("INTERACTION_CREATE", async (interaction) => {
      let GuildDB = await this.GetGuild(interaction.guild_id);

      //Initialize GuildDB
      if (!GuildDB) {
        await this.database.guild.set(interaction.guild_id, {
          prefix: this.botconfig.DefaultPrefix,
          DJ: null,
        });
        GuildDB = await this.GetGuild(interaction.guild_id);
      }

      const command = interaction.data.name.toLowerCase();
      const args = interaction.data.options;

      //Easy to send respnose so ;)
      interaction.guild = await this.guilds.fetch(interaction.guild_id);
      interaction.send = async (message) => {
        return await this.api
          .interactions(interaction.id, interaction.token)
          .callback.post({
            data: {
              type: 4,
              data:
                typeof message == "string"
                  ? { content: message }
                  : message.type && message.type === "rich"
                  ? { embeds: [message] }
                  : message,
            },
          });
      };

      let cmd = client.commands.get(command);
      if (cmd.SlashCommand && cmd.SlashCommand.run)
        cmd.SlashCommand.run(this, interaction, args, { GuildDB });
    });

    //because not worked lol ;-;
    const client = this;

    this.Lavasfy = new LavasfyClient(
      {
        clientID: this.botconfig.Spotify.ClientID,
        clientSecret: this.botconfig.Spotify.ClientSecret,
        playlistPageLoadLimit: 3,
        filterAudioOnlyResult: true,
        autoResolve: true,
        useSpotifyMetadata: true,
      },
      [
        {
          id: this.botconfig.Lavalink.id,
          host: this.botconfig.Lavalink.host,
          port: this.botconfig.Lavalink.port,
          password: this.botconfig.Lavalink.pass,
          secure: this.botconfig.Lavalink.secure,
        },
      ]
    );

    this.Manager = new Manager({
      plugins: [
        new deezer(),
        new apple(),
        new facebook(),
      ],
      nodes: [
        {
          identifier: this.botconfig.Lavalink.id,
          host: this.botconfig.Lavalink.host,
          port: this.botconfig.Lavalink.port,
          password: this.botconfig.Lavalink.pass,
          secure: this.botconfig.Lavalink.secure,
        },
      ],
      send(id, payload) {
        const guild = client.guilds.cache.get(id);
        if (guild) guild.shard.send(payload);
      },
    })
      .on("nodeConnect", (node) =>
        this.log(colors.yellow("[Connection] ") +
        colors.green(`Node successfully connected to lavalink => ${node.options.identifier}`)))
      .on("nodeError", (node, error) =>
      this.log(
        colors.red(`[Lavalink] Node with hostname => ${node.options.identifier} had an error: ${error.message}`))
    )
      .on("trackStart", async (player, track,) => {
        let TrackStartedEmbed = new MessageEmbed()
                .setAuthor(`Now playing ♪`, this.botconfig.IconURL)
                .setThumbnail(player.queue.current.displayThumbnail())
                .setDescription(`[${track.title}](${track.uri})`)
                .addField("Requested by", `${track.requester}`, true)
                .addField(
                  "Duration",
                  `\`${prettyMilliseconds(track.duration, {
                    colonNotation: true,
                  })}\``,
                  true
                )
                .setColor(this.botconfig.EmbedColor)
        //.setFooter("Started playing at");
        let NowPlaying = await client.channels.cache
          .get(player.textChannel)
          .send(TrackStartedEmbed);
        NowPlaying.react("▶️");
        player.setNowplayingMessage(NowPlaying);
        this.log(colors.blue("[Command Execute] ") + colors.green("Now Playing ") + colors.white(`[${track.title}] => (${track.uri})`) + " Requested by " + colors.cyan(`${track.requester}`));
      })
      .on("queueEnd", (player) => {
        let QueueEmbed = new MessageEmbed()
          .setAuthor("The queue has ended", this.botconfig.IconURL)
          .setColor(this.botconfig.EmbedColor)
          .setTimestamp();
        client.channels.cache.get(player.textChannel).send(QueueEmbed);
        this.log(colors.blue("[Command Execute]") + colors.white(" The Queue has ended!"));
        if (!this.botconfig["24/7"]) player.destroy();
      });
  }

  LoadCommands() {
    let CommandsDir = path.join(__dirname, "..", "commands");
    fs.readdir(CommandsDir, (err, files) => {
      if (err) this.log(err);
      else
        files.forEach((file) => {
          let cmd = require(CommandsDir + "/" + file);
          if (!cmd.name || !cmd.description || !cmd.run)
            return this.log(
              "Unable to load Command: " +
                file.split(".")[0] +
                ", Reason: File doesn't had run/name/desciption"
            );
          this.commands.set(file.split(".")[0].toLowerCase(), cmd);
          this.log(colors.yellow("[Info] ") +
          colors.green("🟢[Command] successfully Loaded: ") + colors.white(file.split(".")[0]));
        });
    });
  }

  LoadEvents() {
    let EventsDir = path.join(__dirname, "..", "events");
    fs.readdir(EventsDir, (err, files) => {
      if (err) this.log(err);
      else
        files.forEach((file) => {
          const event = require(EventsDir + "/" + file);
          this.on(file.split(".")[0], event.bind(null, this));
          this.logger.log(
            colors.yellow("[Info] ") +
            colors.green("🟢[Event] successfully Loaded: " + colors.white(file.split(".")[0]))); // Wyświetl informację o załadowaniu eventu
        });
    });
  }

  async GetGuild(GuildID) {
    return new Promise(async (res, rej) => {
      let guild = await this.database.guild
        .get(GuildID)
        .catch((err) => rej(err));
      res(guild);
    });
  }

  log(Text) {
    this.logger.log(Text);
  }

  sendError(Channel, Error) {
    let embed = new MessageEmbed()
      .setTitle("An error occured")
      .setColor("RED")
      .setDescription(Error)
      .setFooter(
        "If you think this as a bug, please report it in the support server!"
      );

    Channel.send(embed);
  }

  sendTime(Channel, Error) {
    let embed = new MessageEmbed()
      .setColor(this.botconfig.EmbedColor)
      .setDescription(Error);

    Channel.send(embed);
  }

  build() {
    this.login(this.botconfig.Token);
    if (this.botconfig.ExpressServer) {
      this.http.listen(process.env.PORT || this.botconfig.Port, () =>
        this.log("Web Server has been started")
      );
    }
  }

  RegisterSlashCommands() {
    this.guilds.cache.forEach((guild) => {
      require("../util/RegisterSlashCommands")(this, guild.id);
    });
  }
}

module.exports = DiscordMusicBot;

EpicPlayer.js ├───

const { Message } = require("discord.js");
const { Structure } = require("erela.js");

Structure.extend(
  "Player",
  (Player) =>
    class extends Player {
      /**
       * Sets now playing message for deleting next time
       * @param {Message} message
       */
      setNowplayingMessage(message) {
        if (this.nowPlayingMessage && !this.nowPlayingMessage.deleted)
          this.nowPlayingMessage.delete();
        return (this.nowPlayingMessage = message);
      }
    }
);

voiceStateUpdate.js ├───

const { DiscordMusicBot } = require("../structures/DiscordMusicBot");
const { VoiceState, MessageEmbed } = require("discord.js");
/**
 *
 * @param {DiscordMusicBot} client
 * @param {VoiceState} oldState
 * @param {VoiceState} newState
 * @returns {Promise<void>}
 */
module.exports = async (client, oldState, newState) => {
  // get guild and player
  let guildId = newState.guild.id;
  const player = client.Manager.get(guildId);

  // check if the bot is active (playing, paused or empty does not matter (return otherwise)
  if (!player || player.state !== "CONNECTED") return;

  // prepreoces the data
  const stateChange = {};
  // get the state change
  if (oldState.channel === null && newState.channel !== null)
    stateChange.type = "JOIN";
  if (oldState.channel !== null && newState.channel === null)
    stateChange.type = "LEAVE";
  if (oldState.channel !== null && newState.channel !== null)
    stateChange.type = "MOVE";
  if (oldState.channel === null && newState.channel === null) return; // you never know, right
  if (newState.serverMute == true && oldState.serverMute == false)
    return player.pause(true);
  if (newState.serverMute == false && oldState.serverMute == true)
    return player.pause(false);
  // move check first as it changes type
  if (stateChange.type === "MOVE") {
    if (oldState.channel.id === player.voiceChannel) stateChange.type = "LEAVE";
    if (newState.channel.id === player.voiceChannel) stateChange.type = "JOIN";
  }
  // double triggered on purpose for MOVE events
  if (stateChange.type === "JOIN") stateChange.channel = newState.channel;
  if (stateChange.type === "LEAVE") stateChange.channel = oldState.channel;

  // check if the bot's voice channel is involved (return otherwise)
  if (!stateChange.channel || stateChange.channel.id !== player.voiceChannel)
    return;

  // filter current users based on being a bot
  stateChange.members = stateChange.channel.members.filter(
    (member) => !member.user.bot
  );

  switch (stateChange.type) {
    case "JOIN":
      if (stateChange.members.size === 1 && player.paused) {
        let emb = new MessageEmbed()
          .setAuthor(`Resuming paused queue`, client.botconfig.IconURL)
          .setColor(client.botconfig.EmbedColor)
          .setDescription(
            `Resuming playback because all of you left me with music to play all alone`
          );
        await client.channels.cache.get(player.textChannel).send(emb);

        // update the now playing message and bring it to the front
        let msg2 = await client.channels.cache
          .get(player.textChannel)
          .send(player.nowPlayingMessage.embeds[0]);
        player.setNowplayingMessage(msg2);

        player.pause(false);
      }
      break;
    case "LEAVE":
      if (stateChange.members.size === 0 && !player.paused && player.playing) {
        player.pause(true);

        let emb = new MessageEmbed()
          .setAuthor(`Paused!`, client.botconfig.IconURL)
          .setColor(client.botconfig.EmbedColor)
          .setDescription(`The player has been paused because everybody left`);
        await client.channels.cache.get(player.textChannel).send(emb);
      }
      break;
  }
};

ready.js ├───

module.exports = async (client) => {
  (client.Ready = true),
    client.user.setPresence({
    status: client.botconfig.Presence.status, // You can show online, idle, and dnd
      activity: {
        name: client.botconfig.Presence.name,
        type: client.botconfig.Presence.type,
      },
});
  client.Manager.init(client.user.id);
  client.log("Successfully Logged in as " + client.user.tag); // You can change the text if you want, but DO NOT REMOVE "client.user.tag"
  client.RegisterSlashCommands();
};

raw.js ├───

module.exports = (client, data) => {
  //What is data? Discord Gateway Data, Please check discord api docs
  client.Manager.updateVoiceState(data);
};

message.js ├───

/**
 *
 * @param {require("../structures/DiscordMusicBot")} client
 * @param {require("discord.js").Message} message
 * @returns {void} aka: nothing ;-;
 */

module.exports = async (client, message) => {
  if (message.author.bot || message.channel.type === "dm") return;
  let prefix = client.botconfig.DefaultPrefix;

  let GuildDB = await client.GetGuild(message.guild.id);
  if (GuildDB && GuildDB.prefix) prefix = GuildDB.prefix;

  //Initialize GuildDB
  if (!GuildDB) {
    await client.database.guild.set(message.guild.id, {
      prefix: prefix,
      DJ: null,
    });
    GuildDB = await client.GetGuild(message.guild.id);
  }

  //Prefixes also have mention match
  const prefixMention = new RegExp(`^<@!?${client.user.id}> `);
  prefix = message.content.match(prefixMention)
    ? message.content.match(prefixMention)[0]
    : prefix;

  if (message.content.indexOf(prefix) !== 0) return;

  const args = message.content.slice(prefix.length).trim().split(/ +/g);
  //Making the command lowerCase because our file name will be in lowerCase
  const command = args.shift().toLowerCase();

  //Searching a command
  const cmd =
    client.commands.get(command) ||
    client.commands.find((x) => x.aliases && x.aliases.includes(command));

  //Executing the codes when we get the command or aliases
  if (cmd) {
    if (
      (cmd.permissions &&
        cmd.permissions.channel &&
        !message.channel
          .permissionsFor(client.user)
          .has(cmd.permissions.channel)) ||
      (cmd.permissions &&
        cmd.permissions.member &&
        !message.channel
          .permissionsFor(message.member)
          .has(cmd.permissions.member)) ||
      (cmd.permissions &&
        GuildDB.DJ &&
        !message.channel
          .permissionsFor(message.member)
          .has(["ADMINISTRATOR"]) &&
        !message.member.roles.cache.has(GuildDB.DJ))
    )
      return client.sendError(
        message.channel,
        "Missing Permissions!" + GuildDB.DJ
          ? " You need the `DJ` role to access this command."
          : ""
      );
    cmd.run(client, message, args, { GuildDB });
    client.CommandsRan++;
  } else return;
};


guildCreate.js ├───

module.exports = (client, guild) => {
  require("../util/RegisterSlashCommands")(client, guild.id);
};

commands/resume.js --

const { MessageEmbed } = require("discord.js");
const { TrackUtils } = require("erela.js");

module.exports = {
  name: "resume",
  description: "Resumes the music",
  usage: "",
  permissions: {
    channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"],
    member: [],
  },
  aliases: [],
  /**
   *
   * @param {import("../structures/DiscordMusicBot")} client
   * @param {import("discord.js").Message} message
   * @param {string[]} args
   * @param {*} param3
   */
  run: async (client, message, args, { GuildDB }) => {
    let player = await client.Manager.get(message.guild.id);
    if (!player)
      return client.sendTime(
        message.channel,
        "❌ | **Nothing is playing right now...**"
      );
    if (!message.member.voice.channel)
      return client.sendTime(
        message.channel,
        "❌ | **You must be in a voice channel to use this command!**"
      );
    if (
      message.guild.me.voice.channel &&
      message.member.voice.channel.id !== message.guild.me.voice.channel.id
    )
      return client.sendTime(
        message.channel,
        ":x: | **You must be in the same voice channel as me to use this command!**"
      );

    if (player.playing)
      return client.sendTime(
        message.channel,
        "❌ | **Music is already resumed!**"
      );
    player.pause(false);
    await message.react("✅");
  },

  SlashCommand: {
    /**
     *
     * @param {import("../structures/DiscordMusicBot")} client
     * @param {import("discord.js").Message} message
     * @param {string[]} args
     * @param {*} param3
     */
    run: async (client, interaction, args, { GuildDB }) => {
      const guild = client.guilds.cache.get(interaction.guild_id);
      const member = guild.members.cache.get(interaction.member.user.id);

      if (!member.voice.channel)
        return client.sendTime(
          interaction,
          "❌ | **You must be in a voice channel to use this command.**"
        );
      if (
        guild.me.voice.channel &&
        !guild.me.voice.channel.equals(member.voice.channel)
      )
        return client.sendTime(
          interaction,
          ":x: | **You must be in the same voice channel as me to use this command!**"
        );

      let player = await client.Manager.get(interaction.guild_id);
      if (!player)
        return client.sendTime(
          interaction,
          "❌ | **Nothing is playing right now...**"
        );
      if (player.playing)
        return client.sendTime(
          interaction,
          "❌ | **Music is already resumed!**"
        );
      player.pause(false);
      client.sendTime(interaction, "**⏯ Resumed!**");
    },
  },
};

Hi! I recommend you checking this:

You need to use new ButtonBuilder()

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.