DiscordMusicBot.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. const { Collection, Client, MessageEmbed } = require("discord.js");
  2. const { LavasfyClient } = require("lavasfy");
  3. const { Manager } = require("erela.js");
  4. const { Server } = require("socket.io");
  5. const http = require("http");
  6. const Jsoning = require("jsoning");
  7. const fs = require("fs");
  8. const path = require("path");
  9. const Express = require("express");
  10. const Logger = require("./Logger");
  11. const prettyMilliseconds = require("pretty-ms");
  12. //Class extending Stuff
  13. require("./EpicPlayer"); //idk why im doing but i wanna learn something new so...
  14. class DiscordMusicBot extends Client {
  15. constructor(props) {
  16. super(props);
  17. this.commands = new Collection();
  18. this.connections = new Map();
  19. this.CommandsRan = 0;
  20. this.SongsPlayed = 0;
  21. this.database = {
  22. //Saved at jsoning node_modules directory, DOCS: https://jsoning.js.org/
  23. guild: new Jsoning("guild.json"), //Server Config
  24. };
  25. this.logger = new Logger(path.join(__dirname, "..", "Logs.log"));
  26. try {
  27. //Config for testing
  28. this.config = require("../dev-config");
  29. } catch {
  30. //Config for production
  31. this.config = require("../config");
  32. }
  33. if (this.config.Token === "")
  34. return new TypeError(
  35. "Please fill in the information in the config.js file."
  36. );
  37. this.LoadCommands();
  38. this.LoadEvents();
  39. //Web Stuff
  40. this.server = Express();
  41. this.http = http.createServer(this.server);
  42. this.server.use("/", require("../api"));
  43. this.io = new Server(this.http);
  44. require("../api/socket")(this.io);
  45. //Utils
  46. this.ProgressBar = require("../util/ProgressBar");
  47. this.Pagination = require("../util/pagination");
  48. this.ParseHumanTime = (str) => {
  49. let Parsed;
  50. try {
  51. Parsed = require("../util/TimeString")(str);
  52. return Parsed;
  53. } catch {
  54. Parsed = false;
  55. return Parsed;
  56. }
  57. };
  58. this.Ready = false;
  59. //idk where do i do it so i did it here ;-;
  60. this.ws.on("INTERACTION_CREATE", async (interaction) => {
  61. let GuildDB = await this.GetGuild(interaction.guild_id);
  62. //Initialize GuildDB
  63. if (!GuildDB) {
  64. await this.database.guild.set(message.guild.id, {
  65. prefix: prefix,
  66. DJ: null,
  67. });
  68. GuildDB = await this.GetGuild(message.guild.id);
  69. }
  70. const command = interaction.data.name.toLowerCase();
  71. const args = interaction.data.options;
  72. //Easy to send respnose so ;)
  73. interaction.guild = await this.guilds.fetch(interaction.guild_id);
  74. interaction.send = async (message) => {
  75. return await this.api
  76. .interactions(interaction.id, interaction.token)
  77. .callback.post({
  78. data: {
  79. type: 4,
  80. data:
  81. typeof message == "string"
  82. ? { content: message }
  83. : message.type && message.type === "rich"
  84. ? { embeds: [message] }
  85. : message,
  86. },
  87. });
  88. };
  89. let cmd = client.commands.get(command);
  90. if (cmd.SlashCommand && cmd.SlashCommand.run)
  91. cmd.SlashCommand.run(this, interaction, args, { GuildDB });
  92. });
  93. //because not worked lol ;-;
  94. const client = this;
  95. this.Lavasfy = new LavasfyClient(
  96. {
  97. clientID: this.config.Spotify.ClientID,
  98. clientSecret: this.config.Spotify.ClientSecret,
  99. },
  100. [
  101. {
  102. id: this.config.Lavalink.id,
  103. host: this.config.Lavalink.host,
  104. port: this.config.Lavalink.port,
  105. password: this.config.Lavalink.pass,
  106. },
  107. ]
  108. );
  109. this.Manager = new Manager({
  110. nodes: [
  111. {
  112. identifier: this.config.Lavalink.id,
  113. host: this.config.Lavalink.host,
  114. port: this.config.Lavalink.port,
  115. password: this.config.Lavalink.pass,
  116. },
  117. ],
  118. send(id, payload) {
  119. const guild = client.guilds.cache.get(id);
  120. if (guild) guild.shard.send(payload);
  121. },
  122. })
  123. .on("nodeConnect", (node) =>
  124. this.log(`Lavalink: Node ${node.options.identifier} connected`)
  125. )
  126. .on("nodeError", (node, error) =>
  127. this.log(
  128. `Lavalink: Node ${node.options.identifier} had an error: ${error.message}`
  129. )
  130. )
  131. .on("trackStart", async (player, track) => {
  132. this.SongsPlayed++;
  133. let TrackStartedEmbed = new MessageEmbed()
  134. .setAuthor(`Now playing ♪`, this.config.IconURL)
  135. .setThumbnail(player.queue.current.displayThumbnail())
  136. .setDescription(`[${track.title}](${track.uri})`)
  137. .addField("Requested by", `${track.requester}`, true)
  138. .addField(
  139. "Duration",
  140. `\`${prettyMilliseconds(track.duration, {
  141. colonNotation: true,
  142. })}\``,
  143. true
  144. )
  145. .setColor("RANDOM");
  146. //.setFooter("Started playing at");
  147. let NowPlaying = await client.channels.cache
  148. .get(player.textChannel)
  149. .send(TrackStartedEmbed);
  150. player.setNowplayingMessage(NowPlaying);
  151. })
  152. .on("queueEnd", (player) => {
  153. let QueueEmbed = new MessageEmbed()
  154. .setAuthor("The queue has ended", this.config.IconURL)
  155. .setColor("RANDOM")
  156. .setTimestamp();
  157. client.channels.cache.get(player.textChannel).send(QueueEmbed);
  158. if (!this.config["24/7"]) player.destroy();
  159. });
  160. }
  161. LoadCommands() {
  162. let CommandsDir = path.join(__dirname, "..", "commands");
  163. fs.readdir(CommandsDir, (err, files) => {
  164. if (err) this.log(err);
  165. else
  166. files.forEach((file) => {
  167. let cmd = require(CommandsDir + "/" + file);
  168. if (!cmd.name || !cmd.description || !cmd.run)
  169. return this.log(
  170. "Unable to load Command: " +
  171. file.split(".")[0] +
  172. ", Reason: File doesn't had run/name/desciption"
  173. );
  174. this.commands.set(file.split(".")[0], cmd);
  175. this.log("Command Loaded: " + file.split(".")[0]);
  176. });
  177. });
  178. }
  179. LoadEvents() {
  180. let EventsDir = path.join(__dirname, "..", "events");
  181. fs.readdir(EventsDir, (err, files) => {
  182. if (err) this.log(err);
  183. else
  184. files.forEach((file) => {
  185. const event = require(EventsDir + "/" + file);
  186. this.on(file.split(".")[0], event.bind(null, this));
  187. this.logger.log("Event Loaded: " + file.split(".")[0]);
  188. });
  189. });
  190. }
  191. async GetGuild(GuildID) {
  192. return new Promise(async (res, rej) => {
  193. let guild = await this.database.guild
  194. .get(GuildID)
  195. .catch((err) => rej(err));
  196. res(guild);
  197. });
  198. }
  199. log(Text) {
  200. this.logger.log(Text);
  201. }
  202. sendError(Channel, Error) {
  203. let embed = new MessageEmbed()
  204. .setTitle("An error occured")
  205. .setColor("RED")
  206. .setDescription(Error)
  207. .setFooter(
  208. "If you think this as a bug, please report it in the support server!"
  209. );
  210. Channel.send(embed);
  211. }
  212. sendTime(Channel, Error) {
  213. let embed = new MessageEmbed().setColor("RANDOM").setDescription(Error);
  214. Channel.send(embed);
  215. }
  216. build() {
  217. this.login(this.config.Token);
  218. this.http.listen(process.env.PORT || this.config.Port, () =>
  219. this.log("Web Server has been started")
  220. );
  221. }
  222. RegisterSlashCommands() {
  223. this.guilds.cache.forEach((guild) => {
  224. require("../util/RegisterSlashCommands")(this, guild.id);
  225. });
  226. }
  227. }
  228. module.exports = DiscordMusicBot;