Refactoring and patches
This commit is contained in:
1 parent
7c438ed37b
commit
4368353a1e
32 files changed
+772
-544
No files matched your search
@@ -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/
|
||||
+1
-4
@@ -363,7 +363,4 @@ MigrationBackup/
|
||||
FodyWeavers.xsd
|
||||
|
||||
# typescript restrictions
|
||||
dist/
|
||||
|
||||
# safety
|
||||
env.yaml
|
||||
dist/
|
||||
+29
-14
@@ -4,6 +4,7 @@
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<Name>5a0b-bot</Name>
|
||||
<RootNamespace>NodejsConsoleApp1</RootNamespace>
|
||||
<SaveNodeJsSettingsInProjectFile>True</SaveNodeJsSettingsInProjectFile>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
@@ -17,11 +18,11 @@
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<OutputPath>./dist</OutputPath>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
|
||||
<EnableTypeScript>true</EnableTypeScript>
|
||||
<StartWebBrowser>false</StartWebBrowser>
|
||||
<StartWebBrowser>False</StartWebBrowser>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -38,24 +39,38 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="src\" />
|
||||
<Folder Include="src\commands\" />
|
||||
<Folder Include="src\commands\music\" />
|
||||
<Folder Include="src\events\" />
|
||||
<Folder Include="src\types\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TypeScriptCompile Include="src\app.ts" />
|
||||
<TypeScriptCompile Include="src\commands\clear.ts" />
|
||||
<TypeScriptCompile Include="src\commands\connect.ts" />
|
||||
<TypeScriptCompile Include="src\commands\insert.ts" />
|
||||
<TypeScriptCompile Include="src\commands\jump.ts" />
|
||||
<TypeScriptCompile Include="src\commands\next.ts" />
|
||||
<TypeScriptCompile Include="src\commands\pause.ts" />
|
||||
<TypeScriptCompile Include="src\commands\play.ts" />
|
||||
<TypeScriptCompile Include="src\commands\queue.ts" />
|
||||
<TypeScriptCompile Include="src\commands\remove.ts" />
|
||||
<TypeScriptCompile Include="src\commands\seek.ts" />
|
||||
<TypeScriptCompile Include="src\commands\stop.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\clear.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\connect.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\insert.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\jump.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\loop.ts">
|
||||
<SubType>Code</SubType>
|
||||
</TypeScriptCompile>
|
||||
<TypeScriptCompile Include="src\commands\music\next.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\pause.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\play.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\queue.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\remove.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\seek.ts" />
|
||||
<TypeScriptCompile Include="src\commands\music\stop.ts" />
|
||||
<TypeScriptCompile Include="src\config.ts" />
|
||||
<TypeScriptCompile Include="src\events\interactionCreate.ts">
|
||||
<SubType>Code</SubType>
|
||||
</TypeScriptCompile>
|
||||
<TypeScriptCompile Include="src\events\messageCreate.ts">
|
||||
<SubType>Code</SubType>
|
||||
</TypeScriptCompile>
|
||||
<TypeScriptCompile Include="src\events\ready.ts">
|
||||
<SubType>Code</SubType>
|
||||
</TypeScriptCompile>
|
||||
<TypeScriptCompile Include="src\types\Client.ts" />
|
||||
<TypeScriptCompile Include="src\types\interfaces.ts" />
|
||||
<TypeScriptCompile Include="src\types\Types.ts" />
|
||||
<TypeScriptCompile Include="src\types\Misc.ts" />
|
||||
<TypeScriptCompile Include="src\types\Music.ts" />
|
||||
</ItemGroup>
|
||||
|
||||
Generated
+75
-12
@@ -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",
|
||||
|
||||
+1
-2
@@ -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",
|
||||
|
||||
+1
-20
@@ -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);
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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 = {
|
||||
@@ -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 }
|
||||
@@ -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 = {
|
||||
@@ -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] });
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
@@ -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<MessageComponentInteraction[]> = (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 }
|
||||
@@ -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 = {
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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<MessageComponentInteraction[]> = (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 }
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Interaction } from "discord.js";
|
||||
import { MyClient } from "../types/Client";
|
||||
|
||||
export async function run(args: Interaction[], client: MyClient): Promise<void> {
|
||||
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";
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Message } from "discord.js";
|
||||
import { MyClient } from "../types/Client";
|
||||
|
||||
export async function run(args: Message[], client: MyClient): Promise<void> {
|
||||
const [message] = args;
|
||||
|
||||
if (message.guild)
|
||||
await message.guild.commands.set(client.restCommands);
|
||||
}
|
||||
|
||||
|
||||
export const name = "messageCreate";
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MyClient } from "../types/Client";
|
||||
|
||||
export async function run(args: unknown[], client: MyClient): Promise<void> {
|
||||
if (!client.user)
|
||||
return;
|
||||
console.log(`Logged in as ${client.user.tag}!`);
|
||||
client.user.setActivity("on sound waves.", { type: "PLAYING" });
|
||||
}
|
||||
|
||||
|
||||
export const name = "ready";
|
||||
+22
-8
@@ -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<string, any>();
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+6
-2
@@ -1,4 +1,8 @@
|
||||
import { track } from "./interfaces";
|
||||
import { track } from "./Types";
|
||||
|
||||
export async function sleep(ms: number): Promise<unknown> {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
export function random_shuffle(array: Array<any>) {
|
||||
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`;
|
||||
|
||||
|
||||
+118
-64
@@ -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<AudioPlayer> {
|
||||
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<void> {
|
||||
|
||||
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<void> {
|
||||
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<track> {
|
||||
const songInfo = (await yts(query)).videos[0];
|
||||
const songInfo = await this._songFinder(query);
|
||||
|
||||
const metadata: track = {
|
||||
url: songInfo.url,
|
||||
@@ -96,10 +155,10 @@ export class Player {
|
||||
requester: requester
|
||||
};
|
||||
|
||||
if (!index)
|
||||
if (!index || index >= this.queue.length)
|
||||
this.queue.push(metadata);
|
||||
else {
|
||||
this.queue.splice(index, 0, metadata)
|
||||
this.queue.splice(Math.max(0, index), 0, metadata)
|
||||
if (this.queuePosition >= index)
|
||||
this.queuePosition++;
|
||||
}
|
||||
@@ -117,7 +176,7 @@ export class Player {
|
||||
|
||||
destroy() {
|
||||
if (this.connection)
|
||||
this.connection.disconnect();
|
||||
this.connection.destroy();
|
||||
this.music.delPlayer(this.guild.id);
|
||||
}
|
||||
|
||||
@@ -143,20 +202,20 @@ export class Player {
|
||||
return false;
|
||||
}
|
||||
|
||||
remove(query: number | string): boolean {
|
||||
async remove(query: number | string): Promise<boolean> {
|
||||
if (typeof query === "number" && query < this.queue.length && query >= 0) {
|
||||
if (query === this.queuePosition && this.player)
|
||||
this.player.stop();
|
||||
this.queue.splice(query);
|
||||
if (query === this.queuePosition)
|
||||
await this.play();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
const track = this.queue[i];
|
||||
if (track.title.toLowerCase().includes(String(query).toLowerCase())) {
|
||||
if (i === this.queuePosition && this.player)
|
||||
this.player.stop();
|
||||
this.queue.splice(i);
|
||||
if (i === this.queuePosition)
|
||||
await this.play();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +241,7 @@ export class Player {
|
||||
}
|
||||
}
|
||||
|
||||
repeat(mode: number) {
|
||||
repeat(mode: loopOption): void {
|
||||
this.repeatMode = mode;
|
||||
}
|
||||
|
||||
@@ -194,19 +253,14 @@ export class Player {
|
||||
return false;
|
||||
}
|
||||
|
||||
shuffle() {
|
||||
shuffle(): void {
|
||||
this.queue = random_shuffle(this.queue);
|
||||
}
|
||||
|
||||
skip() {
|
||||
skip(): void {
|
||||
if (this.player)
|
||||
this.player.stop();
|
||||
}
|
||||
|
||||
setMessage(message: Message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class Music {
|
||||
@@ -218,11 +272,11 @@ export class Music {
|
||||
return player;
|
||||
}
|
||||
|
||||
genPlayer(guildId: string): Player {
|
||||
const player = this.players.get(guildId);
|
||||
genPlayer(guild: Guild, music: Music, channel: TextChannel): Player {
|
||||
const player = this.players.get(guild.id);
|
||||
if (!player) {
|
||||
const newPlayer = new module.exports.Player();
|
||||
this.players.set(guildId, newPlayer);
|
||||
const newPlayer = new module.exports.Player(guild, music, channel);
|
||||
this.players.set(guild.id, newPlayer);
|
||||
return newPlayer;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -42,4 +42,6 @@ export interface filter {
|
||||
fadein?: boolean;
|
||||
dim?: boolean;
|
||||
earrape?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export type loopOption = "LOOP" | "SONG" | "NONE" | "AUTO";
|
||||
Reference in new issue
Block a user