dellosmusic
Version:
Dellos Music Bot - Discord Music Bot
408 lines (365 loc) • 13.6 kB
JavaScript
const { GatewayIntentBits, 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");
let prettyMilliseconds;
(async () => {
const prettyMsModule = await import("pretty-ms");
prettyMilliseconds = prettyMsModule.default;
})();
const deezer = require("erela.js-deezer");
const apple = require("erela.js-apple");
const facebook = require("erela.js-facebook");
let d;
//Class extending Stuff
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: 1,
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,
retryAmount: this.botconfig.Lavalink.retryAmount,
retryDelay: this.botconfig.Lavalink.retryDelay,
},
],
send(id, payload) {
const guild = client.guilds.cache.get(id);
if (guild) guild.shard.send(payload);
},
})
.on("nodeConnect", (node) =>
this.log(`Lavalink: Node ${node.options.identifier} connected`)
)
.on("nodeError", (node, error) =>
this.log(
`Lavalink: Node ${node.options.identifier} had an error: ${error.message}`
)
)
.on("trackStart", async (player, track) => {
this.SongsPlayed++;
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)
.setColor(this.botconfig.EmbedColor);
// Check if the duration matches the duration of a livestream
if (track.duration == 9223372036854776000) {
d = "Live";
} else {
d = prettyMilliseconds(track.duration, { colonNotation: true });
}
TrackStartedEmbed.addField("Duration", `\`${d}\``, true);
//.setFooter("Started playing at");
let NowPlaying = await client.channels.cache
.get(player.textChannel)
.send(TrackStartedEmbed);
player.setNowplayingMessage(NowPlaying);
})
.on("queueEnd", (player) => {
let QueueEmbed = new MessageEmbed()
.setAuthor("The queue has ended", this.botconfig.IconURL)
.setColor(this.botconfig.EmbedColor);
client.channels.cache.get(player.textChannel).send(QueueEmbed);
player.destroy();
})
.on("playerMove", (player, currentChannel, newChannel) => {
if (!newChannel) {
//Channel deleted
let QueueEmbed = new MessageEmbed()
.setAuthor(
"The voice channel has been deleted, and I had to stop playing.",
this.botconfig.IconURL
)
.setColor(this.botconfig.EmbedColor);
client.channels.cache.get(player.textChannel).send(QueueEmbed);
player.destroy();
}
});
this.Lavasfy
.on("searchResults", async (msg, query, tracks) => {
let Pages = this.Pagination.createPages(tracks, msg.author);
let PaginationEmbed = new MessageEmbed()
.setAuthor(`Results for ${query}`, this.botconfig.IconURL)
.setColor(this.botconfig.EmbedColor)
.setFooter(
"Page 1 of " + Pages.length + ` | ` + tracks.length + " Songs"
);
Pages[0].forEach((track) => {
PaginationEmbed.addField(
`${Pages[0].indexOf(track) + 1}. ${track.title}`,
`[${track.uri}](${track.uri})`,
true
);
});
msg.channel.send(PaginationEmbed).then(async (msgg) => {
this.Pagination.createReactionEmbed(
Pages,
msgg,
msg.author,
PaginationEmbed,
tracks
);
});
})
.on("playlistResults", async (msg, query, playlists) => {
let Pages = this.Pagination.createPages(playlists, msg.author);
let PaginationEmbed = new MessageEmbed()
.setAuthor(`Results for ${query}`, this.botconfig.IconURL)
.setColor(this.botconfig.EmbedColor)
.setFooter(
"Page 1 of " + Pages.length + ` | ` + playlists.length + " Playlists"
);
Pages[0].forEach((playlist) => {
PaginationEmbed.addField(
`${Pages[0].indexOf(playlist) + 1}. ${playlist.name}`,
`[${playlist.uri}](${playlist.uri})`,
true
);
});
msg.channel.send(PaginationEmbed).then(async (msgg) => {
this.Pagination.createReactionEmbed(
Pages,
msgg,
msg.author,
PaginationEmbed,
playlists
);
});
})
.on("albumResults", async (msg, query, albums) => {
let Pages = this.Pagination.createPages(albums, msg.author);
let PaginationEmbed = new MessageEmbed()
.setAuthor(`Results for ${query}`, this.botconfig.IconURL)
.setColor(this.botconfig.EmbedColor)
.setFooter(
"Page 1 of " + Pages.length + ` | ` + albums.length + " Albums"
);
Pages[0].forEach((album) => {
PaginationEmbed.addField(
`${Pages[0].indexOf(album) + 1}. ${album.name}`,
`[${album.uri}](${album.uri})`,
true
);
});
msg.channel.send(PaginationEmbed).then(async (msgg) => {
this.Pagination.createReactionEmbed(
Pages,
msgg,
msg.author,
PaginationEmbed,
albums
);
});
})
.on("artistResults", async (msg, query, artists) => {
let Pages = this.Pagination.createPages(artists, msg.author);
let PaginationEmbed = new MessageEmbed()
.setAuthor(`Results for ${query}`, this.botconfig.IconURL)
.setColor(this.botconfig.EmbedColor)
.setFooter(
"Page 1 of " + Pages.length + ` | ` + artists.length + " Artists"
);
Pages[0].forEach((artist) => {
PaginationEmbed.addField(
`${Pages[0].indexOf(artist) + 1}. ${artist.name}`,
`[${artist.uri}](${artist.uri})`,
true
);
});
msg.channel.send(PaginationEmbed).then(async (msgg) => {
this.Pagination.createReactionEmbed(
Pages,
msgg,
msg.author,
PaginationEmbed,
artists
);
});
})
.on("noResults", async (msg, query) => {
let embed = new MessageEmbed()
.setColor(this.botconfig.EmbedColor)
.setAuthor("No results were found for " + query, this.botconfig.IconURL);
msg.channel.send(embed);
})
.on("loadTracks", async (player, tracks) => {
let embed = new MessageEmbed()
.setColor(this.botconfig.EmbedColor)
.setAuthor("Added to Queue", this.botconfig.IconURL)
.setThumbnail(player.queue.current.displayThumbnail())
.addField("Name", `[${tracks[0].title}](${tracks[0].uri})`, true)
.addField("Duration", `\`${tracks[0].isStream ? "LIVE" : prettyMilliseconds(tracks[0].duration, { colonNotation: true })}\``, true)
.addField("Position", player.queue.length, true)
.addField("Estimated time until playing", this.ProgressBar(player));
if (player.queue.current.isStream) embed.addField("Current time", "LIVE", true);
msg.channel.send(embed);
});
//Load the songs which has been started before the bot was restarted
this.database.guild.all().forEach(async (value) => {
if (!value.track) return;
let player = await this.Manager.join(
{
guild: value.guildID,
channel: value.voiceChannelID,
host: this.botconfig.Lavalink.host,
},
{
selfDeafen: this.botconfig.ServerDeafen,
selfMute: false,
}
);
if (player.state !== "CONNECTED") return;
player.set("autoplay", false);
player.set("djmode", false);
player.queue.add(value.track);
player.stop();
});
}
//Load Events
async LoadEvents() {
const eventFiles = fs
.readdirSync(path.join(__dirname, "..", "events"))
.filter((file) => file.endsWith(".js"));
for (const file of eventFiles) {
const event = require(path.join(__dirname, "..", "events", file));
const eventName = file.split(".")[0];
super.on(eventName, event.bind(null, this));
}
}
//Load Commands
async LoadCommands() {
const commandFolders = fs.readdirSync(
path.join(__dirname, "..", "commands")
);
for (const folder of commandFolders) {
const commandFiles = fs
.readdirSync(path.join(__dirname, "..", "commands", folder))
.filter((file) => file.endsWith(".js"));
for (const file of commandFiles) {
const command = require(path.join(
__dirname,
"..",
"commands",
folder,
file
));
this.commands.set(command.name, command);
}
}
}
log(text) {
return this.logger.log(text);
}
}
module.exports = DiscordMusicBot;