diff --git a/src/commands/music/ClearQueue.ts b/src/commands/music/ClearQueue.ts new file mode 100644 index 000000000..8506c11d0 --- /dev/null +++ b/src/commands/music/ClearQueue.ts @@ -0,0 +1,41 @@ +import { Command, Lavamusic, Context } from "../../structures/index.js"; + + +export default class ClearQueue extends Command { + constructor(client: Lavamusic) { + super(client, { + name: "clearqueue", + description: { + content: "Clears the queue", + examples: ["clearqueue"], + usage: "clearqueue" + }, + category: "music", + aliases: ["cq"], + cooldown: 3, + args: false, + player: { + voice: true, + dj: false, + active: true, + djPerm: null + }, + permissions: { + dev: false, + client: ["SendMessages", "ViewChannel", "EmbedLinks"], + user: [] + }, + slashCommand: true, + options: [] + }); + }; + public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { + + const player = client.queue.get(ctx.guild.id); + const embed = this.client.embed(); + if (!player.queue.length) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("There are no songs in the queue.")] }); + player.queue = []; + + return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Cleared the queue`)] }); + } +} \ No newline at end of file diff --git a/src/commands/music/Join.ts b/src/commands/music/Join.ts new file mode 100644 index 000000000..b168d36e0 --- /dev/null +++ b/src/commands/music/Join.ts @@ -0,0 +1,43 @@ +import { Command, Lavamusic, Context } from "../../structures/index.js"; + + +export default class Join extends Command { + constructor(client: Lavamusic) { + super(client, { + name: "join", + description: { + content: "Joins the voice channel", + examples: ["join"], + usage: "join" + }, + category: "music", + aliases: ["j"], + cooldown: 3, + args: false, + player: { + voice: true, + dj: false, + active: true, + djPerm: null + }, + permissions: { + dev: false, + client: ["SendMessages", "ViewChannel", "EmbedLinks"], + user: [] + }, + slashCommand: true, + options: [] + }); + }; + public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { + + let player = client.queue.get(ctx.guild.id) as any; + const embed = this.client.embed(); + if (!player) { + player = this.client.queue.create(ctx.guild, ctx.member, ctx.channel); + return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Joined <#${player.player.connection.channelId}>`)] }); + } else { + return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`I'm already connected to <#${player.player.connection.channelId}>`)] }); + } + } +} \ No newline at end of file diff --git a/src/commands/music/Leave.ts b/src/commands/music/Leave.ts new file mode 100644 index 000000000..d9a2ab69f --- /dev/null +++ b/src/commands/music/Leave.ts @@ -0,0 +1,40 @@ +import { Command, Lavamusic, Context } from "../../structures/index.js"; + + +export default class Leave extends Command { + constructor(client: Lavamusic) { + super(client, { + name: "leave", + description: { + content: "Leaves the voice channel", + examples: ["leave"], + usage: "leave" + }, + category: "music", + aliases: ["l"], + cooldown: 3, + args: false, + player: { + voice: true, + dj: false, + active: true, + djPerm: null + }, + permissions: { + dev: false, + client: ["SendMessages", "ViewChannel", "EmbedLinks"], + user: [] + }, + slashCommand: true, + options: [] + }); + }; + public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { + + const player = client.queue.get(ctx.guild.id); + const embed = this.client.embed(); + + ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Left <#${player.player.connection.channelId}>`)] }); + player.destroy(); + } +} \ No newline at end of file diff --git a/src/commands/music/Nowplaying.ts b/src/commands/music/Nowplaying.ts new file mode 100644 index 000000000..a91ff9b8c --- /dev/null +++ b/src/commands/music/Nowplaying.ts @@ -0,0 +1,52 @@ +import { Command, Lavamusic, Context } from "../../structures/index.js"; + + +export default class Nowplaying extends Command { + constructor(client: Lavamusic) { + super(client, { + name: "nowplaying", + description: { + content: "Shows the currently playing song", + examples: ["nowplaying"], + usage: "nowplaying" + }, + category: "music", + aliases: ["np"], + cooldown: 3, + args: false, + player: { + voice: true, + dj: false, + active: true, + djPerm: null + }, + permissions: { + dev: false, + client: ["SendMessages", "ViewChannel", "EmbedLinks"], + user: [] + }, + slashCommand: true, + options: [] + }); + }; + public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { + + const player = client.queue.get(ctx.guild.id); + + const track = player.current; + const position = player.player.position + const duration = track.info.length; + const bar = client.utils.progressBar(position, duration, 20); + const embed1 = this.client.embed() + .setColor(this.client.color.main) + .setAuthor({ name: "Now Playing", iconURL: ctx.guild.iconURL({}) }) + .setThumbnail(track.info.thumbnail) + .setDescription(`[${track.info.title}](${track.info.uri}) - Request By: ${track.info.requester}\n\n\`${bar}\``) + .addFields({ + name: '\u200b', + value: `\`${client.utils.formatTime(position)} / ${client.utils.formatTime(duration)}\``, + }) + return ctx.sendMessage({ embeds: [embed1] }); + + } +} \ No newline at end of file diff --git a/src/commands/music/Shuffle.ts b/src/commands/music/Shuffle.ts new file mode 100644 index 000000000..b8b3342f6 --- /dev/null +++ b/src/commands/music/Shuffle.ts @@ -0,0 +1,41 @@ +import { Command, Lavamusic, Context } from "../../structures/index.js"; + + +export default class Shuffle extends Command { + constructor(client: Lavamusic) { + super(client, { + name: "shuffle", + description: { + content: "Shuffles the queue", + examples: ["shuffle"], + usage: "shuffle" + }, + category: "music", + aliases: ["sh"], + cooldown: 3, + args: false, + player: { + voice: true, + dj: false, + active: true, + djPerm: null + }, + permissions: { + dev: false, + client: ["SendMessages", "ViewChannel", "EmbedLinks"], + user: [] + }, + slashCommand: true, + options: [] + }); + }; + public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { + + const player = client.queue.get(ctx.guild.id); + const embed = this.client.embed(); + if (!player.queue.length) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("There are no songs in the queue.")] }); + player.setShuffle(true); + + return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Shuffled the queue`)] }); + } +} \ No newline at end of file diff --git a/src/commands/music/Skipto.ts b/src/commands/music/Skipto.ts new file mode 100644 index 000000000..41ccd1ee6 --- /dev/null +++ b/src/commands/music/Skipto.ts @@ -0,0 +1,44 @@ +import { Command, Lavamusic, Context } from "../../structures/index.js"; + + +export default class Skipto extends Command { + constructor(client: Lavamusic) { + super(client, { + name: "skipto", + description: { + content: "Skips to a specific song in the queue", + examples: ["skipto 3"], + usage: "skipto " + }, + category: "music", + aliases: ["st"], + cooldown: 3, + args: true, + player: { + voice: true, + dj: false, + active: true, + djPerm: null + }, + permissions: { + dev: false, + client: ["SendMessages", "ViewChannel", "EmbedLinks"], + user: [] + }, + slashCommand: true, + options: [] + }); + }; + public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { + + const player = client.queue.get(ctx.guild.id); + const embed = this.client.embed(); + if (!player.queue.length) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("There are no songs in the queue.")] }); + if (isNaN(Number(args[0]))) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("Please provide a valid number.")] }); + if (Number(args[0]) > player.queue.length) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("Please provide a valid number.")] }); + if (Number(args[0]) < 1) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("Please provide a valid number.")] }); + player.skip(Number(args[0]) - 1); + + return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Skipped to song number ${args[0]}`)] }); + } +} \ No newline at end of file diff --git a/src/commands/music/Volume.ts b/src/commands/music/Volume.ts index 5f967ee07..c4f33183a 100644 --- a/src/commands/music/Volume.ts +++ b/src/commands/music/Volume.ts @@ -45,6 +45,6 @@ export default class Volume extends Command { if (number > 200) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("The volume can't be higher than 200.")] }); if (number < 0) return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.red).setDescription("The volume can't be lower than 0.")] }); player.player.setVolume(number / 100); - return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Set the volume to ${player.volume.toFixed()}`)] }); + return ctx.sendMessage({ embeds: [embed.setColor(this.client.color.main).setDescription(`Set the volume to ${(player.volume * 100).toFixed()}`)] }); } } \ No newline at end of file diff --git a/src/events/player/TrackEnd.ts b/src/events/player/TrackEnd.ts index 9cccced95..1b4d226b1 100644 --- a/src/events/player/TrackEnd.ts +++ b/src/events/player/TrackEnd.ts @@ -16,7 +16,8 @@ export default class TrackEnd extends Event { if (dispatcher.loop === 'repeat') dispatcher.queue.unshift(track); if (dispatcher.loop === 'queue') dispatcher.queue.push(track); await dispatcher.play(); - await dispatcher.deleteNowPlayingMessage(); + const m = await dispatcher.nowPlayingMessage?.fetch(); + if (m && m.deletable) m.delete().catch(() => { }); } } diff --git a/src/structures/Context.ts b/src/structures/Context.ts index acb336b29..dcfa6df48 100644 --- a/src/structures/Context.ts +++ b/src/structures/Context.ts @@ -1,4 +1,4 @@ -import { CommandInteraction, Message, APIInteractionGuildMember, Guild, GuildMember, TextChannel, GuildChannel, User } from "discord.js"; +import { CommandInteraction, GuildMemberResolvable, Message, APIInteractionGuildMember, Guild, GuildMember, TextChannel, GuildChannel, User } from "discord.js"; import { Lavamusic } from './index.js'; export default class Context { @@ -14,7 +14,7 @@ export default class Context { public guild: Guild | null; public createdAt: Date; public createdTimestamp: number; - public member: GuildMember | APIInteractionGuildMember | null; + public member: GuildMemberResolvable | GuildMember | APIInteractionGuildMember | null; public args: any[]; public msg: any; constructor(ctx, args) { diff --git a/src/structures/Dispatcher.ts b/src/structures/Dispatcher.ts index 531bcde8a..7ff5e9053 100644 --- a/src/structures/Dispatcher.ts +++ b/src/structures/Dispatcher.ts @@ -65,14 +65,14 @@ export default class Dispatcher { this.nowPlayingMessage = null; this.player - .on('start', (data) => + .on('start', () => this.client.shoukaku.emit('trackStart', this.player, this.current, this), ) - .on('end', (data) => { + .on('end', () => { if (!this.queue.length) this.client.shoukaku.emit('queueEnd', this.player, this.current, this); this.client.shoukaku.emit('trackEnd', this.player, this.current, this); }) - .on('stuck', (data) => + .on('stuck', () => this.client.shoukaku.emit('trackStuck', this.player, this.current), ) .on('closed', (...arr) => { @@ -80,10 +80,6 @@ export default class Dispatcher { }); } - get manager() { - return this.client.shoukaku; - } - get exists() { return this.client.queue.has(this.guildId); } @@ -165,12 +161,7 @@ export default class Dispatcher { public setLoop(loop: any) { this.loop = loop; } - public async deleteNowPlayingMessage() { - if (this.nowPlayingMessage) { - await this.nowPlayingMessage.delete(); - this.nowPlayingMessage = null; - } - } + public buildTrack(track: Song, user: User) { return new Song(track, user); } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index bdeeb3962..3a23fa0f2 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -25,6 +25,17 @@ export class Utils { } return chunked_arr; } + + public static progressBar(current: number, total: number, size = 20, color = 0x00FF00): string { + const percent = Math.round((current / total) * 100); + const filledSize = Math.round((size * current) / total); + const emptySize = size - filledSize; + const filledBar = "▓".repeat(filledSize); + const emptyBar = "‎".repeat(emptySize); + const progressBar = `${filledBar}${emptyBar} ${percent}%`; + return progressBar; + } + public static async paginate(ctx, embed) { if (embed.length < 2) { if (ctx instanceof CommandInteraction) {