diff --git a/.gcloudignore b/.gcloudignore
deleted file mode 100644
index a3f0c76..0000000
--- a/.gcloudignore
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file specifies files that are *not* uploaded to Google Cloud Platform
-# using gcloud. It follows the same syntax as .gitignore, with the addition of
-# "#!include" directives (which insert the entries of the given .gitignore-style
-# file at that point).
-#
-# For more information, run:
-# $ gcloud topic gcloudignore
-#
-.gcloudignore
-# If you would like to upload your .git directory, .gitignore file or files
-# from your .gitignore file, remove the corresponding line
-# below:
-.git
-.gitignore
-
-# Node.js dependencies:
-node_modules/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0c7ac32..af48262 100644
--- a/.gitignore
+++ b/.gitignore
@@ -363,7 +363,4 @@ MigrationBackup/
FodyWeavers.xsd
# typescript restrictions
-dist/
-
-# safety
-env.yaml
\ No newline at end of file
+dist/
\ No newline at end of file
diff --git a/5a0b-bot.njsproj b/5a0b-bot.njsproj
index 7f750d8..6b711e4 100644
--- a/5a0b-bot.njsproj
+++ b/5a0b-bot.njsproj
@@ -4,6 +4,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
5a0b-bot
NodejsConsoleApp1
+ True
@@ -17,11 +18,11 @@
.
- .
+ ./dist
v4.0
{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}
true
- false
+ False
true
@@ -38,24 +39,38 @@
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ Code
+
+
+
+
+
+
+
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
-
+
diff --git a/package-lock.json b/package-lock.json
index 2e4ed92..5e1da0c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,28 +19,39 @@
"ytdl-core": "4.9.1"
},
"devDependencies": {
+ "@discordjs/builders": "0.8.2",
"@types/yt-search": "^2.3.2"
},
"engines": {
- "node": "16.9.1"
+ "node": "16.x.x"
}
},
"node_modules/@discordjs/builders": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz",
- "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==",
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.8.2.tgz",
+ "integrity": "sha512-/YRd11SrcluqXkKppq/FAVzLIPRVlIVmc6X8ZklspzMIHDtJ+A4W37D43SHvLdH//+NnK+SHW/WeOF4Ts54PeQ==",
+ "dev": true,
"dependencies": {
- "@sindresorhus/is": "^4.0.1",
- "discord-api-types": "^0.22.0",
+ "@sindresorhus/is": "^4.2.0",
+ "discord-api-types": "^0.24.0",
"ow": "^0.27.0",
"ts-mixer": "^6.0.0",
"tslib": "^2.3.1"
},
"engines": {
- "node": ">=14.0.0",
+ "node": ">=16.0.0",
"npm": ">=7.0.0"
}
},
+ "node_modules/@discordjs/builders/node_modules/discord-api-types": {
+ "version": "0.24.0",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.24.0.tgz",
+ "integrity": "sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@discordjs/collection": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz",
@@ -515,6 +526,30 @@
"npm": ">=7.0.0"
}
},
+ "node_modules/discord.js/node_modules/@discordjs/builders": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz",
+ "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==",
+ "dependencies": {
+ "@sindresorhus/is": "^4.0.1",
+ "discord-api-types": "^0.22.0",
+ "ow": "^0.27.0",
+ "ts-mixer": "^6.0.0",
+ "tslib": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=14.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/discord.js/node_modules/@discordjs/builders/node_modules/discord-api-types": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz",
+ "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/discord.js/node_modules/@types/ws": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz",
@@ -1451,15 +1486,24 @@
},
"dependencies": {
"@discordjs/builders": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz",
- "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==",
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.8.2.tgz",
+ "integrity": "sha512-/YRd11SrcluqXkKppq/FAVzLIPRVlIVmc6X8ZklspzMIHDtJ+A4W37D43SHvLdH//+NnK+SHW/WeOF4Ts54PeQ==",
+ "dev": true,
"requires": {
- "@sindresorhus/is": "^4.0.1",
- "discord-api-types": "^0.22.0",
+ "@sindresorhus/is": "^4.2.0",
+ "discord-api-types": "^0.24.0",
"ow": "^0.27.0",
"ts-mixer": "^6.0.0",
"tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "discord-api-types": {
+ "version": "0.24.0",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.24.0.tgz",
+ "integrity": "sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A==",
+ "dev": true
+ }
}
},
"@discordjs/collection": {
@@ -1842,6 +1886,25 @@
"ws": "^8.2.3"
},
"dependencies": {
+ "@discordjs/builders": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz",
+ "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==",
+ "requires": {
+ "@sindresorhus/is": "^4.0.1",
+ "discord-api-types": "^0.22.0",
+ "ow": "^0.27.0",
+ "ts-mixer": "^6.0.0",
+ "tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "discord-api-types": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz",
+ "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg=="
+ }
+ }
+ },
"@types/ws": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz",
diff --git a/package.json b/package.json
index 32de1f0..13e77f3 100644
--- a/package.json
+++ b/package.json
@@ -12,8 +12,7 @@
"scripts": {
"build": "tsc --build",
"clean": "tsc --build --clean",
- "start": "node dist/app.js",
- "gcp-build": "tsc -p tsconfig.json"
+ "start": "node dist/app.js"
},
"dependencies": {
"@discordjs/opus": "^0.6.0",
diff --git a/src/app.ts b/src/app.ts
index 116db19..fdc2ee3 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -2,27 +2,8 @@
import { MyClient } from "./types/Client";
-const token = process.env.DISCORD_TOKEN;
+const token = "NzIyMjE0MTA3MjM5MDIyNjcy.Xuf0TQ.9uJbIhlTUDCsKnt0_UcuHOG7i94";
const client = new MyClient("./commands", "./events");
-client.on("ready", () => {
- if (!client.user)
- return;
- console.info(`Logged in as ${client.user.tag}!`);
- client.user.setActivity("on sound waves.", { type: "PLAYING" });
-});
-
-client.on("messageCreate", async (message) => {
- if (message.guild)
- await message.guild.commands.set(client.restCommands);
-});
-
-client.on("interactionCreate", interaction => {
- if (interaction.isCommand() && client.commands.has(interaction.commandName)) {
- const command = client.commands.get(interaction.commandName);
- command.run(client, interaction);
- }
-});
-
client.login(token);
\ No newline at end of file
diff --git a/src/commands/clear.ts b/src/commands/clear.ts
deleted file mode 100644
index 223ae92..0000000
--- a/src/commands/clear.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { design } from "../config";
-
-import { ButtonInteraction, ColorResolvable, CommandInteraction, Message, MessageActionRow, MessageButton, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-import { generateQueue } from "../types/Misc";
-import { EmojiIdentifierResolvable } from "discord.js";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- if (ctx.guildId === null)
- return;
-
- const player = client.players.getPlayer(ctx.guildId);
-
- if (player) {
- player.clear();
-
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle("Queue has been cleared.");
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
- }
-}
-
-const data = {
- name: "clear",
- description: "Clears queue.",
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/commands/connect.ts b/src/commands/connect.ts
deleted file mode 100644
index 6ff837c..0000000
--- a/src/commands/connect.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { design } from "../config";
-
-import { ColorResolvable, CommandInteraction, GuildMember, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-import { VoiceConnectionStatus } from "@discordjs/voice";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- if (ctx.guildId === null)
- return;
-
-
- let player = client.players.getPlayer(ctx.guildId);
-
- if (!player)
- player = client.players.genPlayer(ctx.guildId);
-
- if (!player.connection || player.connection.state.status === VoiceConnectionStatus.Disconnected) {
- const channel = (ctx.member as GuildMember).voice.channel;
- if (channel) {
- await player.connect(channel);
-
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle(`Successfully connected to ${channel.name}.`)
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
- }
- else {
- client.players.delPlayer(ctx.guildId);
-
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle("Please connect to a voice channel.")
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
- }
- }
- else {
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle("Already connected.")
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
- }
-}
-
-const data = {
- name: "connect",
- description: "Connect to voice channel."
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/commands/insert.ts b/src/commands/insert.ts
deleted file mode 100644
index 986ff6b..0000000
--- a/src/commands/insert.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { design } from "../config";
-
-import { ColorResolvable, CommandInteraction, GuildMember, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- const pos = ctx.options.getString("position");
- const query = ctx.options.getString("query");
-
- if (ctx.guildId === null || query === null)
- return;
-
-
- let player = client.players.getPlayer(ctx.guildId);
-
- if (!player)
- return;
-
- let state: boolean;
-
- if (!isNaN(Number(query))) {
- await player.addTrack(query, ctx.user, Number(query) - 1);
- }
-
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle("Inserted.");
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
-
-}
-
-const data = {
- name: "insert",
- description: "Insert new track to specific position.",
- options: [
- {
- name: "query",
- description: "Title or URL of the song.",
- type: "STRING",
- required: true
- },
- {
- name: "position",
- description: "Position to insert.",
- type: "STRING",
- required: true
- }
- ]
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/commands/music/clear.ts b/src/commands/music/clear.ts
new file mode 100644
index 0000000..f52229b
--- /dev/null
+++ b/src/commands/music/clear.ts
@@ -0,0 +1,32 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ await ctx.deferReply();
+ if (ctx.guild === null)
+ return;
+
+ const player = client.players.getPlayer(ctx.guild.id);
+
+ if (player) {
+ player.clear();
+
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Queue has been cleared.");
+
+ await ctx.editReply({ embeds: [embed] });
+ }
+}
+
+const data = {
+ name: "clear",
+ description: "Clears queue.",
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/music/connect.ts b/src/commands/music/connect.ts
new file mode 100644
index 0000000..6fe0988
--- /dev/null
+++ b/src/commands/music/connect.ts
@@ -0,0 +1,49 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, GuildMember, MessageEmbed, TextChannel } from "discord.js";
+import { MyClient } from "../../types/Client";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction, reply = true) {
+ if (ctx.guild === null)
+ return;
+
+ if (reply)
+ await ctx.deferReply();
+
+ const player = client.players.genPlayer(ctx.guild, client.players, ctx.channel as TextChannel);
+
+ let embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Mistake in connection.")
+
+ if (!player.connection) {
+ const channel = (ctx.member as GuildMember).voice.channel;
+ if (channel) {
+ await player.connect(channel);
+
+ embed.setTitle(`Successfully connected to ${channel.name}.`)
+ }
+ else {
+ client.players.delPlayer(ctx.guild.id);
+
+ embed.setTitle("Please connect to a voice channel.")
+ }
+ }
+ else {
+ embed.setTitle("Already connected to ${channel.name}..")
+ }
+
+ if (reply)
+ await ctx.editReply({ embeds: [embed] });
+ else
+ return player;
+}
+
+const data = {
+ name: "connect",
+ description: "Connect to voice channel."
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/music/insert.ts b/src/commands/music/insert.ts
new file mode 100644
index 0000000..f2563ce
--- /dev/null
+++ b/src/commands/music/insert.ts
@@ -0,0 +1,56 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ const pos = ctx.options.getInteger("position");
+ const query = ctx.options.getString("query");
+
+ if (!ctx.guild || !query || pos === null)
+ return;
+
+ const player = client.players.getPlayer(ctx.guild.id);
+
+ if (!player)
+ return;
+
+ await ctx.deferReply()
+
+ const track = await player.addTrack(query, ctx.user, pos - 1);
+
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle(track.title)
+ .setDescription("Has been inserted to queue.")
+ .setURL(track.url)
+ .setThumbnail(track.thumbnail)
+ .setAuthor(`@${ctx.user.tag}`, ctx.user.avatarURL() as string);
+
+ console.log(`${track.title} added to ${ctx.guildId}`);
+
+ await ctx.editReply({ embeds: [embed] });
+}
+
+const data = {
+ name: "insert",
+ description: "Insert new track to specific position.",
+ options: [
+ {
+ name: "query",
+ description: "Title or URL of the song.",
+ type: "STRING",
+ required: true
+ },
+ {
+ name: "position",
+ description: "Position to insert.",
+ type: "INTEGER",
+ required: true
+ }
+ ]
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/jump.ts b/src/commands/music/jump.ts
similarity index 59%
rename from src/commands/jump.ts
rename to src/commands/music/jump.ts
index 094cff0..e000243 100644
--- a/src/commands/jump.ts
+++ b/src/commands/music/jump.ts
@@ -1,22 +1,24 @@
-import { design } from "../config";
+import { design } from "../../config";
-import { ColorResolvable, CommandInteraction, GuildMember, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
export async function run(client: MyClient, ctx: CommandInteraction) {
const query = ctx.options.getString("position");
- if (ctx.guildId === null || query === null)
+ if (ctx.guild === null || query === null)
return;
- let player = client.players.getPlayer(ctx.guildId);
+ let player = client.players.getPlayer(ctx.guild.id);
if (!player)
return;
+ await ctx.deferReply();
+
let state: boolean;
if (!isNaN(Number(query))) {
@@ -25,16 +27,17 @@ export async function run(client: MyClient, ctx: CommandInteraction) {
state = await player.jump(query);
}
+ let embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Could not find track specified.");
+
if (state) {
- const embed = new MessageEmbed()
+ embed = new MessageEmbed()
.setColor(design.color as ColorResolvable)
.setTitle("Jumped.");
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
}
+ await ctx.editReply({ embeds: [embed] });
}
const data = {
diff --git a/src/commands/music/loop.ts b/src/commands/music/loop.ts
new file mode 100644
index 0000000..3d3b145
--- /dev/null
+++ b/src/commands/music/loop.ts
@@ -0,0 +1,61 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ const query = ctx.options.getString("position");
+
+ if (ctx.guild === null || query === null)
+ return;
+
+
+ let player = client.players.getPlayer(ctx.guild.id);
+
+ if (!player)
+ return;
+
+ await ctx.deferReply();
+
+ let state: boolean;
+
+ if (!isNaN(Number(query))) {
+ state = await player.jump(Number(query) - 1);
+ } else {
+ state = await player.jump(query);
+ }
+
+ let embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Could not find track specified.");
+
+ if (state) {
+ embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Jumped.");
+ }
+
+ await ctx.editReply({ embeds: [embed] });
+}
+
+const data = {
+ name: "loop",
+ description: "Set player loop option.",
+ options: [
+ {
+ name: "option",
+ description: "Set player to...",
+ type: "STRING",
+ required: true,
+ choices: [
+ { name: "loop queue", value: "LOOP" },
+ { name: "loop current track", value: "SONG" },
+ { name: "Destroy player on end", value: "NONE" }
+ ]
+ }
+ ]
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/next.ts b/src/commands/music/next.ts
similarity index 50%
rename from src/commands/next.ts
rename to src/commands/music/next.ts
index 6bb6a80..07e549a 100644
--- a/src/commands/next.ts
+++ b/src/commands/music/next.ts
@@ -1,27 +1,26 @@
-import { design } from "../config";
+import { design } from "../../config";
import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
+import { MyClient } from "../../types/Client";
export async function run(client: MyClient, ctx: CommandInteraction) {
- if (ctx.guildId === null)
+ if (ctx.guild === null)
return;
- const player = client.players.getPlayer(ctx.guildId);
+ const player = client.players.getPlayer(ctx.guild.id);
- if (player)
+ if (player) {
player.skip();
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle("Skipped.");
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Skipped.");
- try {
await ctx.reply({ embeds: [embed] });
- } catch { }
+ }
}
const data = {
diff --git a/src/commands/pause.ts b/src/commands/music/pause.ts
similarity index 59%
rename from src/commands/pause.ts
rename to src/commands/music/pause.ts
index 7f2d44e..4f413dd 100644
--- a/src/commands/pause.ts
+++ b/src/commands/music/pause.ts
@@ -1,28 +1,26 @@
-import { design } from "../config";
+import { design } from "../../config";
import { ButtonInteraction, ColorResolvable, CommandInteraction, Message, MessageActionRow, MessageButton, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-import { generateQueue } from "../types/Misc";
+import { MyClient } from "../../types/Client";
+import { generateQueue } from "../../types/Misc";
import { EmojiIdentifierResolvable } from "discord.js";
export async function run(client: MyClient, ctx: CommandInteraction) {
- if (ctx.guildId === null)
+ if (ctx.guild === null)
return;
- const player = client.players.getPlayer(ctx.guildId);
+ const player = client.players.getPlayer(ctx.guild.id);
if (player) {
const state = player.pause();
const embed = new MessageEmbed()
.setColor(design.color as ColorResolvable)
- .setTitle(`Pause is now ${state ? "on" : "off"}.`);
+ .setTitle(`Pause is now ${state ? "resumed" : "paused"}.`);
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
+ await ctx.reply({ embeds: [embed] });
}
diff --git a/src/commands/music/play.ts b/src/commands/music/play.ts
new file mode 100644
index 0000000..fbf13fc
--- /dev/null
+++ b/src/commands/music/play.ts
@@ -0,0 +1,57 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+import { run as connect } from "./connect";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ const query = ctx.options.getString("query");
+
+ const player = await connect(client, ctx, false);
+
+ if (!player)
+ return;
+
+ await ctx.deferReply();
+
+ let embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Now playing.")
+ .setAuthor(`@${ctx.user.tag}`, ctx.user.avatarURL() as string);
+
+ if (query) {
+ const track = await player.addTrack(query, ctx.user);
+ embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle(track.title)
+ .setDescription("Has been pushed to queue.")
+ .setURL(track.url)
+ .setThumbnail(track.thumbnail)
+ .setAuthor(`@${ctx.user.tag}`, ctx.user.avatarURL() as string);
+
+ console.log(`${track.title} added to ${ctx.guildId}`);
+ }
+
+ await ctx.editReply({ embeds: [embed] });
+
+ if (!player.nowPlaying) {
+ await player.play();
+ }
+}
+
+const data = {
+ name: "play",
+ description: "Play a song or add it to queue.",
+ options: [
+ {
+ name: "query",
+ description: "Title or URL of the song.",
+ type: "STRING",
+ required: true
+ }
+ ]
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/music/queue.ts b/src/commands/music/queue.ts
new file mode 100644
index 0000000..051a458
--- /dev/null
+++ b/src/commands/music/queue.ts
@@ -0,0 +1,85 @@
+import { design } from "../../config";
+
+import { ButtonInteraction, CollectorFilter, ColorResolvable, CommandInteraction, Message, MessageActionRow, MessageButton, MessageComponentInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+import { generateQueue } from "../../types/Misc";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ if (ctx.guild === null)
+ return;
+
+ const player = client.players.getPlayer(ctx.guild.id);
+
+ if (!player)
+ return;
+
+ await ctx.deferReply();
+ const queue = player.queue;
+
+ if (queue.length === 0) {
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Queue is empty.");
+
+ await ctx.editReply({ embeds: [embed] });
+ return;
+ }
+
+ let page = 0;
+ const maxPage = Math.floor(queue.length / 11);
+
+ const row = new MessageActionRow()
+ .addComponents(
+ new MessageButton()
+ .setCustomId("QueueTop")
+ .setLabel("TOP")
+ .setStyle("SECONDARY"),
+ new MessageButton()
+ .setCustomId("QueueUp")
+ .setLabel("UP")
+ .setStyle("SECONDARY"),
+ new MessageButton()
+ .setCustomId("QueueDown")
+ .setLabel("DOWN")
+ .setStyle("SECONDARY"),
+ new MessageButton()
+ .setCustomId("QueueEnd")
+ .setLabel("END")
+ .setStyle("SECONDARY")
+ );
+
+ await ctx.editReply({
+ content: generateQueue(queue, page, player.queuePosition),
+ components: [row]
+ });
+
+ const filter: CollectorFilter = (btn) => {
+ return btn.message === ctx.fetchReply() as unknown as Message;
+ };
+
+ if (ctx.channel) {
+ const collector = ctx.channel.createMessageComponentCollector({ filter, time: 15000 });
+
+ collector.on("collect", async (btn: ButtonInteraction) => {
+ switch (btn.customId) {
+ case "QueueTop": page = 0;
+ case "QueueUp": page = Math.max(page - 1, 0);
+ case "QueueDown": page = Math.min(page + 1, maxPage);
+ case "QueueEnd": page = maxPage;
+ }
+
+ await btn.update({
+ content: generateQueue(queue, page, player.queuePosition)
+ });
+ });
+ }
+}
+
+const data = {
+ name: "queue",
+ description: "Send player queue.",
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/remove.ts b/src/commands/music/remove.ts
similarity index 59%
rename from src/commands/remove.ts
rename to src/commands/music/remove.ts
index b46ae99..c60185d 100644
--- a/src/commands/remove.ts
+++ b/src/commands/music/remove.ts
@@ -1,22 +1,24 @@
-import { design } from "../config";
+import { design } from "../../config";
-import { ColorResolvable, CommandInteraction, GuildMember, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
export async function run(client: MyClient, ctx: CommandInteraction) {
const query = ctx.options.getString("position");
- if (ctx.guildId === null || query === null)
+ if (ctx.guild === null || query === null)
return;
- let player = client.players.getPlayer(ctx.guildId);
+ let player = client.players.getPlayer(ctx.guild.id);
if (!player)
return;
+ await ctx.deferReply();
+
let state: boolean;
if (!isNaN(Number(query))) {
@@ -25,16 +27,17 @@ export async function run(client: MyClient, ctx: CommandInteraction) {
state = await player.remove(query);
}
+ let embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle("Could not find track specified.");
+
if (state) {
- const embed = new MessageEmbed()
+ embed = new MessageEmbed()
.setColor(design.color as ColorResolvable)
.setTitle("Removed.");
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
}
+ await ctx.editReply({ embeds: [embed] });
}
const data = {
diff --git a/src/commands/music/seek.ts b/src/commands/music/seek.ts
new file mode 100644
index 0000000..064fda5
--- /dev/null
+++ b/src/commands/music/seek.ts
@@ -0,0 +1,66 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ const hours = ctx.options.getInteger("hrs");
+ const minutes = ctx.options.getInteger("mins");
+ const seconds = ctx.options.getInteger("secs");
+
+ if (ctx.guild === null || (hours === null && minutes === null && seconds === null))
+ return;
+
+ let time = 0;
+
+ if (hours !== null)
+ time += hours * 3600;
+ if (minutes !== null)
+ time += minutes * 60;
+ if (seconds !== null)
+ time += seconds;
+
+
+ let player = client.players.getPlayer(ctx.guild.id);
+
+ if (player) {
+ await ctx.deferReply();
+
+ await player.seek(time);
+
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle(`Fastforwarded to ${hours}:${minutes}.${seconds}.`);
+
+ await ctx.editReply({ embeds: [embed] });
+ }
+}
+
+const data = {
+ name: "seek",
+ description: "Fastforward to timecode.",
+ options: [
+ {
+ name: "hrs",
+ description: "Hour to seek.",
+ type: "INTEGER",
+ required: false
+ },
+ {
+ name: "mins",
+ description: "Minute to seek.",
+ type: "INTEGER",
+ required: false
+ },
+ {
+ name: "secs",
+ description: "Second to seek.",
+ type: "INTEGER",
+ required: false
+ }
+ ]
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/music/stop.ts b/src/commands/music/stop.ts
new file mode 100644
index 0000000..aa679c8
--- /dev/null
+++ b/src/commands/music/stop.ts
@@ -0,0 +1,32 @@
+import { design } from "../../config";
+
+import { ColorResolvable, CommandInteraction, MessageEmbed } from "discord.js";
+import { MyClient } from "../../types/Client";
+
+
+
+export async function run(client: MyClient, ctx: CommandInteraction) {
+ if (ctx.guild === null)
+ return;
+
+ const player = client.players.getPlayer(ctx.guild.id);
+
+ if (player) {
+ player.destroy();
+
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle(`Player is now destroyed.`);
+
+ await ctx.reply({ embeds: [embed] });
+ }
+
+
+}
+
+const data = {
+ name: "stop",
+ description: "Destroys player.",
+}
+
+export { data }
\ No newline at end of file
diff --git a/src/commands/play.ts b/src/commands/play.ts
deleted file mode 100644
index fee4850..0000000
--- a/src/commands/play.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { design } from "../config";
-
-import { ColorResolvable, CommandInteraction, GuildMember, Message, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-import { VoiceConnectionStatus } from "@discordjs/voice";
-import { run as connect } from "./connect";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- const query = ctx.options.getString("query");
-
- if (ctx.guildId === null || query === null)
- return;
-
- connect(client, ctx);
-
- const player = client.players.genPlayer(ctx.guildId);
-
- const track = await player.addTrack(query, ctx.user);
-
- if (!player.nowPlaying) {
- await player.play();
- }
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle(track.title)
- .setDescription("Has been pushed to queue.")
- .setURL(track.url)
- .setThumbnail(track.thumbnail)
- .setAuthor(`@${ctx.user.tag}`, ctx.user.avatarURL() as string);
-
- if (ctx.channel)
- player.setMessage(await ctx.channel.send({ embeds: [embed] }));
-
- console.log(`${track.title} added to ${ctx.guildId}`);
-}
-
-const data = {
- name: "play",
- description: "Play a song or add it to queue.",
- options: [
- {
- name: "query",
- description: "Title or URL of the song.",
- type: "STRING",
- required: true
- }
- ]
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/commands/queue.ts b/src/commands/queue.ts
deleted file mode 100644
index 928abce..0000000
--- a/src/commands/queue.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { design } from "../config";
-
-import { ButtonInteraction, CollectorFilter, ColorResolvable, CommandInteraction, Message, MessageActionRow, MessageButton, MessageComponentInteraction, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-import { generateQueue } from "../types/Misc";
-import { EmojiIdentifierResolvable } from "discord.js";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- if (ctx.guildId === null)
- return;
-
- const player = client.players.getPlayer(ctx.guildId);
-
- if (player) {
- const queue = player.queue;
-
- if (queue.length === 0) {
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle("Queue is empty.");
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
- }
- else {
- let page = 0;
- const maxPage = Math.floor(queue.length / 11);
-
- const row = new MessageActionRow()
- .addComponents(
- new MessageButton()
- .setCustomId("QueueTop")
- .setLabel("TOP")
- .setStyle("SECONDARY"),
- new MessageButton()
- .setCustomId("QueueUp")
- .setLabel("UP")
- .setStyle("SECONDARY"),
- new MessageButton()
- .setCustomId("QueueDown")
- .setLabel("DOWN")
- .setStyle("SECONDARY"),
- new MessageButton()
- .setCustomId("QueueEnd")
- .setLabel("END")
- .setStyle("SECONDARY")
- );
-
- await ctx.reply({
- content: generateQueue(queue, page, player.queuePosition),
- components: [row]
- });
-
- const filter: CollectorFilter = (btn) => {
- return btn.message === ctx.fetchReply() as unknown as Message;
- };
-
- if (ctx.channel) {
- const collector = ctx.channel.createMessageComponentCollector({ filter, time: 15000 });
-
- collector.on("collect", async (btn: ButtonInteraction) => {
- switch (btn.customId) {
- case "QueueTop": page = 0;
- case "QueueUp": page = Math.max(page - 1, 0);
- case "QueueDown": page = Math.min(page + 1, maxPage);
- case "QueueEnd": page = maxPage;
- }
-
- await btn.update({
- content: generateQueue(queue, page, player.queuePosition)
- });
- });
- }
-
- }
- }
-
-
-}
-
-const data = {
- name: "queue",
- description: "Send player queue.",
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/commands/seek.ts b/src/commands/seek.ts
deleted file mode 100644
index ce2ceff..0000000
--- a/src/commands/seek.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { design } from "../config";
-
-import { ColorResolvable, CommandInteraction, GuildMember, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- const time = ctx.options.getInteger("time");
-
- if (ctx.guildId === null || time === null)
- return;
-
-
- let player = client.players.getPlayer(ctx.guildId);
-
- if (player)
- await player.seek(time);
-}
-
-const data = {
- name: "seek",
- description: "Fastforward to timecode.",
- options: [
- {
- name: "time",
- description: "Timecode to seek.",
- type: "INTEGER",
- required: true
- }
- ]
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/commands/stop.ts b/src/commands/stop.ts
deleted file mode 100644
index 81478f2..0000000
--- a/src/commands/stop.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { design } from "../config";
-
-import { ButtonInteraction, ColorResolvable, CommandInteraction, Message, MessageActionRow, MessageButton, MessageEmbed } from "discord.js";
-import { MyClient } from "../types/Client";
-import { generateQueue } from "../types/Misc";
-import { EmojiIdentifierResolvable } from "discord.js";
-
-
-
-export async function run(client: MyClient, ctx: CommandInteraction) {
- if (ctx.guildId === null)
- return;
-
- const player = client.players.getPlayer(ctx.guildId);
-
- if (player) {
- player.destroy();
-
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle(`Destroyed.`);
-
- try {
- await ctx.reply({ embeds: [embed] });
- } catch { }
- }
-
-
-}
-
-const data = {
- name: "stop",
- description: "Destroys player.",
-}
-
-export { data }
\ No newline at end of file
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
new file mode 100644
index 0000000..1966e8e
--- /dev/null
+++ b/src/events/interactionCreate.ts
@@ -0,0 +1,13 @@
+import { Interaction } from "discord.js";
+import { MyClient } from "../types/Client";
+
+export async function run(args: Interaction[], client: MyClient): Promise {
+ const [interaction] = args;
+
+ if (interaction.isCommand() && client.commands.has(interaction.commandName)) {
+ const command = client.commands.get(interaction.commandName);
+ command.run(client, interaction);
+ }
+}
+
+export const name = "interactionCreate";
\ No newline at end of file
diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts
new file mode 100644
index 0000000..72007d7
--- /dev/null
+++ b/src/events/messageCreate.ts
@@ -0,0 +1,12 @@
+import { Message } from "discord.js";
+import { MyClient } from "../types/Client";
+
+export async function run(args: Message[], client: MyClient): Promise {
+ const [message] = args;
+
+ if (message.guild)
+ await message.guild.commands.set(client.restCommands);
+}
+
+
+export const name = "messageCreate";
\ No newline at end of file
diff --git a/src/events/ready.ts b/src/events/ready.ts
new file mode 100644
index 0000000..8a584b9
--- /dev/null
+++ b/src/events/ready.ts
@@ -0,0 +1,11 @@
+import { MyClient } from "../types/Client";
+
+export async function run(args: unknown[], client: MyClient): Promise {
+ if (!client.user)
+ return;
+ console.log(`Logged in as ${client.user.tag}!`);
+ client.user.setActivity("on sound waves.", { type: "PLAYING" });
+}
+
+
+export const name = "ready";
\ No newline at end of file
diff --git a/src/types/Client.ts b/src/types/Client.ts
index 9097045..9072559 100644
--- a/src/types/Client.ts
+++ b/src/types/Client.ts
@@ -1,9 +1,9 @@
-import { ApplicationCommandData, Client, Intents } from "discord.js";
+import { ApplicationCommandData, Client as DiscordClient, Intents } from "discord.js";
import { readdirSync } from "fs";
import { Music } from "./Music";
-export class MyClient extends Client {
+export class MyClient extends DiscordClient {
commands = new Map();
restCommands: ApplicationCommandData[] = [];
players = new Music();
@@ -18,14 +18,28 @@ export class MyClient extends Client {
]
});
- const cmdFiles = readdirSync(commandsPath).filter(file => file.endsWith(".js"));
+ readdirSync(commandsPath).forEach((dir) => {
+ const cmdFiles = readdirSync(`${commandsPath}/${dir}`).filter(file => file.endsWith(".js"));
- for (const file of cmdFiles) {
- import(`.${commandsPath}/${file}`).then((command) => {
- const name = command.data.name;
- this.restCommands.push(command.data);
- this.commands.set(name, command);
+ for (const file of cmdFiles) {
+ import(`.${commandsPath}/${dir}/${file}`).then((command) => {
+ const name = command.data.name;
+ this.restCommands.push(command.data);
+ this.commands.set(name, command);
+ });
+ }
+ });
+
+ const evntFiles = readdirSync(eventsPath).filter(file => file.endsWith(".js"));
+
+ for (const file of evntFiles) {
+ import(`.${eventsPath}/${file}`).then((event) => {
+ this.on(event.name, (...args: unknown[]) => {
+ event.run(args, this);
+ });
});
}
+
}
+
}
\ No newline at end of file
diff --git a/src/types/Misc.ts b/src/types/Misc.ts
index d70aa8a..5668cfd 100644
--- a/src/types/Misc.ts
+++ b/src/types/Misc.ts
@@ -1,4 +1,8 @@
-import { track } from "./interfaces";
+import { track } from "./Types";
+
+export async function sleep(ms: number): Promise {
+ return new Promise(r => setTimeout(r, ms));
+}
export function random_shuffle(array: Array) {
let currentIndex = array.length, randomIndex;
@@ -20,7 +24,7 @@ export function generateQueue(queue: track[], page: number, pos: number): string
const track = queue[i];
if (i === pos)
- response += `${i + 1}. ${'Current =>' + track.title.slice(0, 35).padEnd(45, " ")} ${track.duration / 60}:${track.duration % 60}\n`;
+ response += `${i + 1}. ${"Current => " + track.title.slice(0, 35).padEnd(45, " ")} ${Math.floor(track.duration / 60)}:${track.duration % 60}\n`;
else
response += `${ i + 1 }. ${track.title.slice(0, 35).padEnd(45, " ")} ${track.duration / 60}:${track.duration % 60}\n`;
diff --git a/src/types/Music.ts b/src/types/Music.ts
index 52f32d6..862ab9c 100644
--- a/src/types/Music.ts
+++ b/src/types/Music.ts
@@ -1,36 +1,46 @@
-import { VoiceConnection, AudioPlayer, createAudioResource, AudioPlayerStatus, joinVoiceChannel, createAudioPlayer, AudioResource, DiscordGatewayAdapterCreator } from "@discordjs/voice";
-import { ColorResolvable, Guild, Message, MessageEmbed, StageChannel, User, VoiceChannel } from "discord.js";
+import {
+ VoiceConnection, AudioPlayer, createAudioResource,
+ AudioPlayerStatus, joinVoiceChannel, createAudioPlayer,
+ AudioResource, DiscordGatewayAdapterCreator, VoiceConnectionStatus,
+ entersState
+} from "@discordjs/voice";
+
+import {
+ ColorResolvable, Guild, Message,
+ MessageEmbed, StageChannel, TextChannel, User,
+ VoiceChannel
+} from "discord.js";
+
import { design } from "../config";
import ytdl from "discord-ytdl-core";
-import { track, filter } from "./interfaces";
+import { track, filter, loopOption } from "./Types";
import { random_shuffle } from "./Misc";
import yts from "yt-search";
export class Player {
- guild: Guild;
- music: Music;
+ public guild: Guild;
+ public music: Music;
- connection: VoiceConnection | undefined;
- player: AudioPlayer | undefined;
- message: Message | undefined;
+ public connection: VoiceConnection | undefined;
+ public player: AudioPlayer | undefined;
- queue: track[] = [];
- queuePosition = 0;
- nowPlaying: AudioResource | undefined = undefined;
- filters: filter[] = [];
- repeatMode = 0;
+ public queue: track[] = [];
+ public queuePosition: number = 0;
+ public nowPlaying: AudioResource | undefined;
+ public filters: filter = {};
+ public repeatMode: loopOption = "LOOP";
- constructor(clientMusic: Music, playerGuild: Guild) {
+ public channel: TextChannel;
+ public message: Message | undefined;
+
+ constructor(playerGuild: Guild, clientMusic: Music, ctxChannel: TextChannel) {
this.music = clientMusic;
this.guild = playerGuild;
+ this.channel = ctxChannel;
}
- async play(seek = 0) {
- if (!this.connection || this.queue.length === 0)
- return;
-
-
- const track = this.queue[this.queuePosition];
+ private async _playerCreator(track: track, seek: number): Promise {
+ const player = createAudioPlayer();
const stream = ytdl(track.url, {
opusEncoded: true,
@@ -39,54 +49,103 @@ export class Player {
seek: seek
});
- const resource = createAudioResource(stream, {
- inlineVolume: true
+ this.nowPlaying = createAudioResource(stream, {
+ inlineVolume: true,
+ metadata: track
});
- this.player = createAudioPlayer();
- this.connection.subscribe(this.player);
+ await player.play(this.nowPlaying);
- await this.player.play(resource);
- this.nowPlaying = resource;
+ return player;
+ }
+ private _resourceEndResolvable(): boolean {
+ switch (this.repeatMode) {
+ case "NONE": {
+ if (++this.queuePosition >= this.queue.length) {
+ this.queuePosition = 0;
+ this.nowPlaying = undefined;
+ return false;
+ }
+ return true;
+ }
+ case "LOOP": {
+ this.queuePosition = (this.queuePosition + 1) % this.queue.length;
+ return true;
+ }
+ case "SONG": return true;
+ }
+
+ return true;
+ }
+
+ private async _messageResolvable(track: track): Promise {
+
if (this.message) {
- const channel = this.message.channel;
+ this.channel = this.message.channel as TextChannel;
try {
await this.message.delete();
} catch (err) {
console.log(err);
}
-
- const embed = new MessageEmbed()
- .setColor(design.color as ColorResolvable)
- .setTitle(track.title)
- .setURL(track.url)
- .setThumbnail(track.thumbnail)
- .setAuthor(`@${track.requester.tag}`, track.requester.avatarURL() as string)
- .setDescription("Is now beeing played.");
-
- this.message = await channel.send({ embeds: [embed] });
}
-
- this.player.on(AudioPlayerStatus.Idle, async () => {
- this.queuePosition = (this.queuePosition + 1) % this.queue.length;
- await this.play();
- });
+ const embed = new MessageEmbed()
+ .setColor(design.color as ColorResolvable)
+ .setTitle(track.title)
+ .setURL(track.url)
+ .setThumbnail(track.thumbnail)
+ .setAuthor(`@${track.requester.tag}`, track.requester.avatarURL() as string)
+ .setDescription("Is now beeing played.");
+
+ this.message = await this.channel.send({ embeds: [embed] });
}
- async connect(channel: VoiceChannel | StageChannel) {
+ private async _songFinder(query: string) {
+ return (await yts(query)).videos[0];
+ }
+
+ public async play(seek: number = 0): Promise {
+ if (!this.connection || this.queue.length === 0)
+ return;
+
+ const track = this.queue[this.queuePosition];
+
+ this.player = await this._playerCreator(track, seek);
+ this.connection.subscribe(this.player);
+
+ this.player.on(AudioPlayerStatus.Idle, async () => {
+ if (this._resourceEndResolvable())
+ await this.play();
+ });
+
+ await this._messageResolvable(track);
+ }
+
+ connect(channel: VoiceChannel | StageChannel): void {
this.connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guildId,
selfDeaf: true,
adapterCreator: channel.guild.voiceAdapterCreator as unknown as DiscordGatewayAdapterCreator
});
+
+ this.connection.on(VoiceConnectionStatus.Disconnected, async (oldState, newState) => {
+ try {
+ await Promise.race([
+ entersState(this.connection as VoiceConnection, VoiceConnectionStatus.Signalling, 5_000),
+ entersState(this.connection as VoiceConnection, VoiceConnectionStatus.Connecting, 5_000),
+ ]);
+ }
+ catch (error) {
+ this.destroy();
+ }
+ });
}
async addTrack(query: string, requester: User, index?: number): Promise