From d61ebaa47dd704f4df1c06741c545f8391d204eb Mon Sep 17 00:00:00 2001 From: Struck713 Date: Thu, 22 Feb 2024 19:02:25 -0500 Subject: [PATCH] Updated embed code --- src/app.ts | 41 ++++-------- src/commands/deploy.ts | 9 +-- src/commands/help.ts | 7 +- src/commands/index.ts | 4 +- src/commands/minecraft.ts | 41 ------------ src/commands/oob.ts | 5 +- src/commands/poll.ts | 15 +++-- src/commands/status.ts | 5 +- src/commands/voice/play.ts | 125 +++++++++--------------------------- src/commands/voice/queue.ts | 10 +-- src/commands/voice/skip.ts | 15 +++-- src/commands/voice/stop.ts | 14 ++-- src/lib/command.ts | 10 +-- src/lib/utils/embeds.ts | 24 +++---- src/lib/utils/server.ts | 25 -------- src/lib/utils/youtube.ts | 6 +- src/lib/voice.ts | 65 ++++++++----------- 17 files changed, 134 insertions(+), 287 deletions(-) delete mode 100644 src/commands/minecraft.ts delete mode 100644 src/lib/utils/server.ts diff --git a/src/app.ts b/src/app.ts index ce15a5f..2e50424 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,23 +1,26 @@ import { ActivityType, Client, Events, GatewayIntentBits } from "discord.js"; -import { YOUTUBE, TOKEN } from '../config.json'; -import { COMMANDS } from "./commands"; -import { VoiceManager } from "./lib/voice"; +import { youtube, TOKEN } from '../config.json'; +import commands from "./commands"; import { StateManager } from "./lib/state"; import YTDlpWrap from "yt-dlp-wrap"; import { Embeds } from "./lib/utils/embeds"; import { PollManager } from "./commands/poll"; -export const ytdl = new YTDlpWrap(YOUTUBE.BINARY); -export const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent ] }); -export const voiceManager = new VoiceManager(); +export const ytdl = new YTDlpWrap(youtube.binary_path); +export const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent + ] +}); + export const stateManager = new StateManager(); export const pollManager = new PollManager(); client.once(Events.ClientReady, async client => { console.log(`Logged in as ${client.user.tag}`); - console.log(`| Registered ${COMMANDS.length} commands!`); - console.log(`| Voice Manager Status: ${voiceManager ? "ONLINE" : "OFFLINE"}`); - client.user.setPresence({ status: "idle", activities: [ @@ -31,7 +34,7 @@ client.once(Events.ClientReady, async client => { client.on(Events.InteractionCreate, async interaction => { if (interaction.isChatInputCommand()) { - const command = COMMANDS.find(command => command.data.name === interaction.commandName); + const command = commands.find(command => command.data.name === interaction.commandName); if (!command) { await Embeds.error(interaction, "Something went terribly wrong! Contact the developer."); return; @@ -42,21 +45,3 @@ client.on(Events.InteractionCreate, async interaction => { }); client.login(TOKEN); - -// const REPLIES = [ -// "https://media.discordapp.net/attachments/709446245516574860/1153875831857352784/gideobn_lala.gif", -// "https://media.discordapp.net/attachments/1072009407497515059/1150969108008017960/brett.gif", -// "https://images-ext-2.discordapp.net/external/nqpPlVXUTEYQzmBZuYAhWBNyCRaxTVQ_GT8cNjfQaCQ/https/media.tenor.com/GEuUa7wY5JwAAAPo/sad-speech-bubble.mp4", -// "https://media.discordapp.net/attachments/709446245516574860/1150672443426484246/maletic.gif", -// "https://images-ext-1.discordapp.net/external/zSnVZqNRKx3g9Rc4D1kc7Hl_p2Qs5uomscPH6p9lp2E/https/media.tenor.com/HrUh7_ReprYAAAPo/police-help-speech-bubble.mp4", -// "https://media.tenor.com/ESD9F3r4uXIAAAPo/bubble-text-owl-text-bubble.mp4", -// "https://media.discordapp.net/attachments/709446245516574860/1151728821150695464/fridge.gif?width=507&height=676" -// ] - -// client.on(Events.MessageCreate, async message => { -// if (Math.random() < 0.03) { -// await message.reply({ files: [ REPLIES[Math.floor(Math.random() * REPLIES.length)] ]}); -// return; -// } -// }) - \ No newline at end of file diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index b198e06..cab5482 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from "discord.js"; import { Command, deploy } from "../lib/command"; import { Embeds } from "../lib/utils/embeds"; -import { COMMANDS } from "."; +import commands from "."; const MY_SNOWFLAKE = "140520164629151744"; @@ -9,12 +9,13 @@ export const Deploy: Command = { data: new SlashCommandBuilder() .setName('deploy') .setDescription('Deploys slash commands for the bot.'), - execute: async (client, interaction) => { + execute: async (_, interaction) => { if (interaction.user.id === MY_SNOWFLAKE) { deploy(); - await Embeds.send(interaction, embed => embed + await Embeds.create() .setTitle("Deployed commands") - .setDescription(`${COMMANDS.length} commands have been deployed.`)); + .setDescription(`${commands.length} commands have been deployed.`) + .send(interaction); } else await Embeds.error(interaction, "You do not have permission to execute this command!"); }, } \ No newline at end of file diff --git a/src/commands/help.ts b/src/commands/help.ts index ea2f237..3e5eb5c 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,16 +1,17 @@ import { SlashCommandBuilder } from "discord.js"; import { Command } from "../lib/command"; import { Embeds } from "../lib/utils/embeds"; -import { COMMANDS } from "."; +import commands from "."; export const Help: Command = { data: new SlashCommandBuilder() .setName('help') .setDescription('Lists all the available commands.'), execute: async (client, interaction) => { - await Embeds.send(interaction, embed => embed + await Embeds.create() .setTitle("Help") .setDescription(`There's a lot I can do for you. Here is a list of the avaliable commands:`) - .addFields(COMMANDS.map(command => ({ name: `/${command.data.name}`, value: command.data.description, inline: true })))); + .addFields(commands.map(command => ({ name: `/${command.data.name}`, value: command.data.description, inline: true }))) + .send(interaction); }, } \ No newline at end of file diff --git a/src/commands/index.ts b/src/commands/index.ts index ed19727..316358a 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -8,6 +8,6 @@ import { Meme } from "./meme"; import { Help } from "./help"; import { Poll } from "./poll"; import { Oobinate } from "./oob"; -import { Minecraft } from "./minecraft"; -export const COMMANDS = [ Help, Play, Skip, Queue, Stop, Meme, Oobinate, Poll, Status, Deploy, Minecraft ]; \ No newline at end of file +const commands = [ Help, Play, Skip, Queue, Stop, Meme, Oobinate, Poll, Status, Deploy ]; +export default commands; \ No newline at end of file diff --git a/src/commands/minecraft.ts b/src/commands/minecraft.ts deleted file mode 100644 index ea304e7..0000000 --- a/src/commands/minecraft.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { SlashCommandBuilder } from "discord.js"; -import { Command } from "../lib/command"; -import { Embeds } from "../lib/utils/embeds"; - -export const Minecraft: Command = { - data: new SlashCommandBuilder() - .setName('minecraft') - .setDescription('Gets the status of a Minecraft server') - .addStringOption(option => option.setName("address").setRequired(true).setDescription("The address of the server")) - .addIntegerOption(option => option.setName("port").setDescription("The port of the server")), - execute: async (client, interaction) => { - let address = interaction.options.getString("address", true); - let port = interaction.options.getNumber("port", false) ?? 25565; - - let status = await MinecraftServer.ping(address, port).catch(_ => null); - if (status) { - let embed = Embeds.create() - .setAuthor({ name: 'Minecraft Server Status' }) - .setTitle(`${address}${port == 25565 ? "" : `:${port}`}`) - .setDescription(status.description.text) - .addFields({ name: 'Players', value: `${status.players.online}/${status.players.max}` }); - if (status.favicon) embed.setThumbnail(status.favicon); - await Embeds.send(interaction, () => embed); - return; - } - - await Embeds.send(interaction, embed => embed - .setTitle(`${address}${port == 25565 ? "" : `:${port}`}`) - .setDescription(`Server did not respond to ping. :sad:`)); - // let embed = Embeds.create() - // .setAuthor({ name: 'Now Playing' }) - // .setTitle(playing.getTitle()) - // .setURL(playing.getUrl()) - // .setDescription(` - // by ${playing.getAuthor()} \n - // ${bar} ${Time.format(connection.resource?.playbackDuration)}/${Time.format(playing.getDuration(), "seconds")} - // `) - // .setThumbnail(playing.getThumbnailUrl()) - // .addFields({ name: '\u200B', value: `Next in the queue (${Text.number(queue.length, "song")}):` }) - }, -} \ No newline at end of file diff --git a/src/commands/oob.ts b/src/commands/oob.ts index 13dc620..67871d0 100644 --- a/src/commands/oob.ts +++ b/src/commands/oob.ts @@ -9,10 +9,11 @@ export const Oobinate: Command = { .addStringOption(option => option.setName("text").setRequired(true).setDescription("The text to oobinate.")), execute: async (client, interaction) => { let text = interaction.options.get("text", true); - await Embeds.send(interaction, embed => embed + await Embeds.create() .setTitle("Oobinator") .setDescription(` \`${(text.value as string).replace(/[aeiouAEIOU]/g, "oob")}\` - `)); + `) + .send(interaction); }, } \ No newline at end of file diff --git a/src/commands/poll.ts b/src/commands/poll.ts index a512894..aa90484 100644 --- a/src/commands/poll.ts +++ b/src/commands/poll.ts @@ -54,10 +54,11 @@ export const Poll: Command = { } pollManager.create(name as string, []); - await Embeds.send(interaction, embed => embed + await Embeds.create() .setAuthor({ name: "Poll" }) .setTitle(name as string) - .setDescription("Poll has been created.")); + .setDescription("Poll has been created.") + .send(interaction); return; } @@ -74,10 +75,11 @@ export const Poll: Command = { let { value: option } = interaction.options.get("option", true); poll.push({ key: option as string, value: 0 }); - await Embeds.send(interaction, embed => embed + await Embeds.create() .setAuthor({ name: "Poll" }) .setTitle(name as string) - .setDescription(`Added option, \`${option}\`.`)); + .setDescription(`Added option, \`${option}\`.`) + .send(interaction); return; } @@ -88,10 +90,11 @@ export const Poll: Command = { } let fields = poll.map((pair, index) => ({ name: `${Text.NUMBERS[index + 1]} ${pair.key}`, value: Text.number(pair.value, "vote") })); - let message = await Embeds.send(interaction, embed => embed + let message = await Embeds.create() .setAuthor({ name: "Poll" }) .setTitle(name as string) - .addFields(fields)); + .addFields(fields) + .send(interaction); await Promise.all(poll.map((_, index) => message.react(Text.NUMBERS[index + 1]))); return; } diff --git a/src/commands/status.ts b/src/commands/status.ts index f423407..e30e45e 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -12,12 +12,13 @@ export const Status: Command = { .setDescription('Shows the current status for the bot.'), execute: async (client, interaction) => { let sent = Date.now(); - await Embeds.send(interaction, embed => embed + await Embeds.create() .setTitle("Status") .setDescription(` Bot has a latency of \`${sent - interaction.createdTimestamp}ms\`. Currently running version \`${Style.VERSION}\` using \`${Style.ENGINE_VERSION}\`. ${Style.NAME} has been online for \`${Time.latestTime(Date.now() - STARTUP_TIME)}\`. - `)); + `) + .send(interaction); }, } \ No newline at end of file diff --git a/src/commands/voice/play.ts b/src/commands/voice/play.ts index 18abaa3..6840033 100644 --- a/src/commands/voice/play.ts +++ b/src/commands/voice/play.ts @@ -1,126 +1,59 @@ import { SlashCommandBuilder } from "discord.js"; -import { voiceManager } from "../../app"; import { Command } from "../../lib/command"; import { Embeds } from "../../lib/utils/embeds"; import YouTubeAPI, { YoutubeMetadata } from "../../lib/utils/youtube"; import { Text } from "../../lib/utils/misc"; +import * as VoiceManager from "../../lib/voice"; export const Play: Command = { data: new SlashCommandBuilder() .setName("play") .setDescription("Play sound in a voice channel using a URL.") - .addStringOption(option => option.setName("url").setRequired(false).setDescription("A valid YouTube URL.")) - .addStringOption(option => option.setName("search").setRequired(false).setDescription("A valid YouTube search, picking the top result.")), + .addStringOption(option => option.setName("search").setRequired(true).setDescription("A valid YouTube search, picking the top result.")), execute: async (client, interaction) => { - const playMetadata = async (metadata: YoutubeMetadata) => { - if (!interaction.guild || !interaction.member) { - await Embeds.error(interaction, "You are not in a guild!"); - return; - } - - let user = await interaction.guild.members.cache.get(interaction.member.user.id); - if (!user || !user.voice || !user.voice.channel) { - await Embeds.error(interaction, "You are not in a voice channel!"); + if (!interaction.guild || !interaction.member) { + await Embeds.error(interaction, "You are not in a guild!"); + return; + } + + let user = await interaction.guild.members.cache.get(interaction.member.user.id); + if (!user?.voice.channel) { + await Embeds.error(interaction, "You are not in a voice channel!"); + return; + } + + let search = interaction.options.get("search", false); + if (search) { + let metadata = await YouTubeAPI.search(search.value as string); + if (!metadata) { + await Embeds.error(interaction, `Could not find anything associated with \`${search.value}\``); return; } - - let connection = voiceManager.get(interaction.guild.id); + + let connection = VoiceManager.getVoiceFromGuildId(interaction.guild.id); if (connection) { connection.play(metadata); - await Embeds.send(interaction, embed => embed.setAuthor({ name: "Added to queue" }) + Embeds.create() + .setAuthor({ name: "Added to queue" }) .setTitle(metadata.getTitle()) .setURL(metadata.getUrl()) .setDescription(`by ${metadata.getAuthor()}`) - .setImage(metadata.getThumbnailUrl())); + .setImage(metadata.getThumbnailUrl()) + .send(interaction); return; } - connection = voiceManager.join(user.voice.channel); + connection = VoiceManager.initializeVoice(user.voice.channel); connection.play(metadata); - await Embeds.send(interaction, embed => embed.setAuthor({ name: "Now Playing"}) + await Embeds.create() + .setAuthor({ name: "Now Playing"}) .setTitle(metadata.getTitle()) .setURL(metadata.getUrl()) .setDescription(`by ${metadata.getAuthor()}`) - .setImage(metadata.getThumbnailUrl())); - } - - const playPlaylist = async (metadatas?: YoutubeMetadata[]) => { - if (!interaction.guild || !interaction.member) { - await Embeds.error(interaction, "You are not in a guild!"); - return; - } - - let user = await interaction.guild.members.cache.get(interaction.member.user.id); - if (!user || !user.voice || !user.voice.channel) { - await Embeds.error(interaction, "You are not in a voice channel!"); - return; - } - - if (!metadatas || metadatas.length === 0) { - await Embeds.error(interaction, `An invalid playlist was provided.`); - return; - } - - let connection = voiceManager.get(interaction.guild.id); - if (connection) { - connection.play(...metadatas); - await Embeds.send(interaction, embed => embed.setAuthor({ name: "Added to queue" }) - .setTitle(`Playlist with ${Text.number(metadatas.length, "song")}`) - .setThumbnail(metadatas[0].getThumbnailUrl()) - .addFields(metadatas.map((metadata, index) => - ({ - name: `${index + 1}. ${metadata.getTitle()}`, - value: `by ${metadata.getAuthor()}` - })))); - return; - } - - connection = voiceManager.join(user.voice.channel); - connection.play(...metadatas); - - let [ first, ...others ] = metadatas; - await Embeds.send(interaction, embed => embed.setAuthor({ name: "Now Playing"}) - .setTitle(first.getTitle()) - .setURL(first.getUrl()) - .setDescription(` - by ${first.getAuthor()} - - Added ${Text.number(others.length, "other song")} to the queue: - `).addFields(others.map(other => - ({ - name: `${other.getTitle()}`, - value: `by ${other.getAuthor()}` - }))) - .setImage(first.getThumbnailUrl()) - ); - } - - let url = interaction.options.get("url", false); - if (url) { - if (YouTubeAPI.isPlaylist(url.value as string)) { - playPlaylist(await YouTubeAPI.getPlaylistMetadata(url.value as string)); - return; - } - - let metadata = await YouTubeAPI.getMetadata(url.value as string); - if (!metadata) { - await Embeds.error(interaction, `\`${url.value}\` is not a valid YouTube URL.`); - return; - } - await playMetadata(metadata); - return; - } - - let search = interaction.options.get("search", false); - if (search) { - let metadata = await YouTubeAPI.search(search.value as string); - if (!metadata) { - await Embeds.error(interaction, `The search \`${search.value}\` did not return anything on YouTube.`); - return; - } - await playMetadata(metadata); + .setImage(metadata.getThumbnailUrl()) + .send(interaction); return; } diff --git a/src/commands/voice/queue.ts b/src/commands/voice/queue.ts index a85a60b..7e6ebff 100644 --- a/src/commands/voice/queue.ts +++ b/src/commands/voice/queue.ts @@ -1,5 +1,5 @@ import { Colors, EmbedBuilder, SlashCommandBuilder } from "discord.js"; -import { voiceManager } from "../../app"; +import * as VoiceManager from "../../lib/voice"; import { Command } from "../../lib/command"; import { Embeds } from "../../lib/utils/embeds"; import { Text } from "../../lib/utils/misc"; @@ -9,7 +9,7 @@ export const Queue: Command = { data: new SlashCommandBuilder() .setName("queue") .setDescription("View the current song queue."), - execute: async (client, interaction) => { + execute: async (_, interaction) => { if (!interaction.guild || !interaction.member) { await Embeds.error(interaction, "You are not in a guild!"); @@ -17,12 +17,12 @@ export const Queue: Command = { } let user = await interaction.guild.members.cache.get(interaction.member.user.id); - if (!user || !user.voice || !user.voice.channel) { + if (!user?.voice.channel) { await Embeds.error(interaction, "You are not in a voice channel!"); return; } - let connection = voiceManager.get(interaction.guild.id); + let connection = VoiceManager.getVoiceFromGuildId(interaction.guild.id); if (!connection) { await Embeds.error(interaction, "I am not in a voice channel!"); return; @@ -46,7 +46,7 @@ export const Queue: Command = { if (queue.length > 0) embed.addFields(queue.slice(0, Math.min(9, queue.length)).map((metadata, index) => ({ name: `${index + 2}. ${metadata.getTitle()}`, value: `by ${metadata.getAuthor()}` }))); else embed.addFields({ name: 'There is nothing next in the queue.', value: '\u200B' }) - await Embeds.send(interaction, () => embed); + await embed.send(interaction); return; } diff --git a/src/commands/voice/skip.ts b/src/commands/voice/skip.ts index 67199d5..788b8b2 100644 --- a/src/commands/voice/skip.ts +++ b/src/commands/voice/skip.ts @@ -1,36 +1,37 @@ import { SlashCommandBuilder } from "discord.js"; -import { voiceManager } from "../../app"; import { Command } from "../../lib/command"; import { Embeds } from "../../lib/utils/embeds"; +import * as VoiceManager from "../../lib/voice"; export const Skip: Command = { data: new SlashCommandBuilder() .setName("skip") .setDescription("Skip to the next song in the queue."), - execute: async (client, interaction) => { + execute: async (_, interaction) => { if (!interaction.guild || !interaction.member) { await Embeds.error(interaction, "You are not in a guild!"); return; } let user = await interaction.guild.members.cache.get(interaction.member.user.id); - if (!user || !user.voice || !user.voice.channel) { + if (!user?.voice.channel) { await Embeds.error(interaction, "You are not in a voice channel!"); return; } - let connection = voiceManager.get(interaction.guild.id); + let connection = VoiceManager.getVoiceFromGuildId(interaction.guild.id); if (!connection || connection.queue.length === 0) { await Embeds.error(interaction, "There are no queued songs."); return; } let metadata = connection.skip(); - await Embeds.send(interaction, embed => embed.setAuthor({ name: "Skipped - Now Playing"}) + await Embeds.create() + .setAuthor({ name: "Skipped - Now Playing"}) .setTitle(metadata.getTitle()) .setURL(metadata.getUrl()) .setDescription(`by ${metadata.getAuthor()}`) - .setImage(metadata.getThumbnailUrl())); - //await Embeds.error(`**Skipped last song - Now playing:** ${metadata.getTitle()} - ${metadata.getAuthor()}` }); + .setImage(metadata.getThumbnailUrl()) + .send(interaction); }, } \ No newline at end of file diff --git a/src/commands/voice/stop.ts b/src/commands/voice/stop.ts index 1806b87..26115a3 100644 --- a/src/commands/voice/stop.ts +++ b/src/commands/voice/stop.ts @@ -1,14 +1,13 @@ import { SlashCommandBuilder } from "discord.js"; import { Command } from "../../lib/command"; -import YouTubeAPI, { YoutubeMetadata } from "../../lib/utils/youtube"; -import { voiceManager } from "../../app"; import { Embeds } from "../../lib/utils/embeds"; +import * as VoiceManager from "../../lib/voice"; export const Stop: Command = { data: new SlashCommandBuilder() .setName("stop") .setDescription("Disconnect from voice and clear the queue."), - execute: async (client, interaction) => { + execute: async (_, interaction) => { if (!interaction.guild || !interaction.member) { await Embeds.error(interaction, "You are not in a guild!"); @@ -16,15 +15,18 @@ export const Stop: Command = { } let user = await interaction.guild.members.cache.get(interaction.member.user.id); - if (!user || !user.voice || !user.voice.channel) { + if (!user?.voice.channel) { await Embeds.error(interaction, "You are not in a voice channel!"); return; } - let connection = voiceManager.get(interaction.guild.id); + let connection = VoiceManager.getVoiceFromGuildId(interaction.guild.id); if (connection) { connection.disconnect(); - await Embeds.send(interaction, embed => embed.setAuthor({ name: "Disconnected" }).setDescription("Disconnected from voice and cleared the queue.")); + await Embeds.create() + .setAuthor({ name: "Disconnected" }) + .setDescription("Disconnected from voice and cleared the queue.") + .send(interaction); return; } diff --git a/src/lib/command.ts b/src/lib/command.ts index 713206d..079db81 100644 --- a/src/lib/command.ts +++ b/src/lib/command.ts @@ -1,9 +1,9 @@ -import { CommandInteraction, Client, REST, Routes, SlashCommandBuilder, ChatInputCommandInteraction } from "discord.js"; +import { CommandInteraction, Client, REST, Routes, SlashCommandBuilder, ChatInputCommandInteraction, SharedSlashCommandOptions, SlashCommandSubcommandsOnlyBuilder, SlashCommandSubcommandBuilder } from "discord.js"; import { TOKEN, DEVELOPMENT } from '../../config.json'; -import { COMMANDS } from "../commands"; +import commands from "../commands"; export interface Command { - data: Omit, + data: SlashCommandBuilder | Omit; execute: (client: Client, interaction: ChatInputCommandInteraction) => void; } @@ -14,12 +14,12 @@ export const deploy = () => { // and deploy your commands! (async () => { try { - console.log(`Started refreshing ${COMMANDS.length} application (/) commands.`); + console.log(`Started refreshing ${commands.length} application (/) commands.`); // The put method is used to fully refresh all commands in the guild with the current set // Routes.applicationGuildCommands(DEVELOPMENT.APPLICATION_ID, DEVELOPMENT.GUILD_ID) const data = await rest.put( Routes.applicationCommands(DEVELOPMENT.APPLICATION_ID), - { body: COMMANDS.map(command => command.data) }, + { body: commands.map(command => command.data) }, ) as any[]; console.log(`Successfully reloaded ${data.length} application (/) commands.`); diff --git a/src/lib/utils/embeds.ts b/src/lib/utils/embeds.ts index 3f29c9c..b6b0612 100644 --- a/src/lib/utils/embeds.ts +++ b/src/lib/utils/embeds.ts @@ -1,21 +1,21 @@ import { EmbedBuilder } from "@discordjs/builders"; -import { CacheType, CommandInteraction } from "discord.js"; +import { CacheType, CommandInteraction, Message } from "discord.js"; import { Style } from "./style"; -export namespace Embeds { +type SendEmbed = { send: (interaction: CommandInteraction) => Promise> }; +type EmbedBuilderWithSend = EmbedBuilder & SendEmbed; - export const create = () => { - return new EmbedBuilder() - .setColor(Style.Color.DEFAULT) - .setTimestamp() - .setFooter({ text: Style.ENGINE_VERSION, iconURL: Style.PROFILE_URL }); - } +export namespace Embeds { - export const send = async (interaction: CommandInteraction, callback: (embed: EmbedBuilder) => EmbedBuilder) => { - return await interaction.followUp({ embeds: [ callback(Embeds.create()) ] }); + export const create = (): EmbedBuilderWithSend => { + let embed = new EmbedBuilder() + .setColor(Style.Color.DEFAULT) + .setTimestamp() + .setFooter({ text: Style.ENGINE_VERSION, iconURL: Style.PROFILE_URL }); + return Object.assign(embed, { send: (interaction: CommandInteraction) => { return interaction.followUp({ embeds: [embed] }); } }); } - export const error = async (interaction: CommandInteraction, message: string, subtitle?: string) => { - return Embeds.send(interaction, embed => embed.setColor(Style.Color.ERROR).setAuthor({ name: `Error${subtitle ? ` - ${subtitle}` : ""}`}).setDescription(message)); + export const error = async (interaction: CommandInteraction, message: string, subtitle?: string) => { + return Embeds.create().setColor(Style.Color.ERROR).setAuthor({ name: `Error${subtitle ? ` - ${subtitle}` : ""}` }).setDescription(message).send(interaction); } } \ No newline at end of file diff --git a/src/lib/utils/server.ts b/src/lib/utils/server.ts deleted file mode 100644 index c9a88d6..0000000 --- a/src/lib/utils/server.ts +++ /dev/null @@ -1,25 +0,0 @@ - -namespace MinecraftServer { - - export interface Status { - previewsChat: boolean; - enforcesSecureChat: boolean; - preventsChatReports: boolean; - description: { - text: string; - }; - players: { - max: number; - online: number; - }; - version: { - name: string; - protocol: number; - } - favicon: string; - } - - export const ping = async (host: string, port: number = 25565, timeout: number = 3000, protocolVersion: number = 47): Promise => - new Promise((resolve, reject) => new (require('mcping-js')) - .MinecraftServer(host, port).ping(timeout, protocolVersion, (err: any, res: any) => res ? resolve(res) : reject(err))); -} \ No newline at end of file diff --git a/src/lib/utils/youtube.ts b/src/lib/utils/youtube.ts index 8b8b38c..3288624 100644 --- a/src/lib/utils/youtube.ts +++ b/src/lib/utils/youtube.ts @@ -1,5 +1,5 @@ import Axios from 'axios'; -import { YOUTUBE } from "../../../config.json"; +import { youtube } from "../../../config.json"; import { Text } from './misc'; import { ytdl } from '../../app'; @@ -7,7 +7,7 @@ const YOUTUBE_URL_REGEX = /^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube(-nocook const YOUTUBE_PLAYLIST_QUERY_REGEX = /\?list=(.+)/; const search = async (query: string): Promise => { - const res = await Axios.get(`https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelType=any&eventType=none&q=${query}&videoType=any&key=${YOUTUBE.KEY}`) + const res = await Axios.get(`https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelType=any&eventType=none&q=${query}&videoType=any&key=${youtube.api_key}`) .then(res => res.data) .catch(_ => undefined); if (!res) return undefined; @@ -19,7 +19,7 @@ const getPlaylistMetadata = async (url: string): Promise res.data) .catch(_ => undefined); if (!res) return undefined; diff --git a/src/lib/voice.ts b/src/lib/voice.ts index d633512..c0d1ecd 100644 --- a/src/lib/voice.ts +++ b/src/lib/voice.ts @@ -1,43 +1,35 @@ import { AudioPlayer, AudioPlayerStatus, AudioResource, createAudioPlayer, createAudioResource, getVoiceConnection, joinVoiceChannel } from "@discordjs/voice"; import { VoiceBasedChannel } from "discord.js"; -import { voiceManager, ytdl } from "../app"; +import { ytdl } from "../app"; import { YoutubeMetadata } from "./utils/youtube"; import { ChildProcessWithoutNullStreams } from "child_process"; -export class VoiceManager { +const connections: VoiceConnection[] = []; - private connections: VoiceConnection[]; +export const initializeVoice = (channel: VoiceBasedChannel) => { + let { id, guild } = channel; + joinVoiceChannel({ + channelId: id, + guildId: guild.id, + adapterCreator: guild.voiceAdapterCreator + }); - constructor() { - this.connections = []; - } - - join = (channel: VoiceBasedChannel) => { - let { id, guild } = channel; - joinVoiceChannel({ - channelId: id, - guildId: guild.id, - adapterCreator: guild.voiceAdapterCreator - }); - - let connection = new VoiceConnection(guild.id, id); - this.connections.push(connection); - return connection; - } + let connection = new VoiceConnection(guild.id, id); + connections.push(connection); + return connection; +} - get = (guildId: string) => { - return this.connections.find(connection => connection.guildId == guildId); - } +export const getVoiceFromGuildId = (guildId: string) => { + return connections.find(connection => connection.guildId == guildId); +} - destroy = (guildId: string) => { - let connection = this.get(guildId); - if (!connection) return; - - let index = this.connections.indexOf(connection); - if (index == -1) return; - this.connections.splice(index, 1); - } +export const destroyVoiceFromGuildId = (guildId: string) => { + let connection = getVoiceFromGuildId(guildId); + if (!connection) return; + let index = connections.indexOf(connection); + if (index == -1) return; + connections.splice(index, 1); } export class VoiceConnection { @@ -61,15 +53,10 @@ export class VoiceConnection { this.queue = []; this.audioPlayer = createAudioPlayer(); - this.audioPlayer.on(AudioPlayerStatus.Playing, () => console.log(`[GUILD ${this.guildId}] [VC ${this.channelId}] PLAYING - ${this.playing?.getUrl()}: ${this.playing?.getTitle()} by ${this.playing?.getAuthor()}`)) - this.audioPlayer.on(AudioPlayerStatus.Idle, () => { - console.log(`[GUILD ${this.guildId}] [VC ${this.channelId}] SONG FINISHED - Changing to next song in queue`) - this.next() - }); + this.audioPlayer.on(AudioPlayerStatus.Idle, () => this.next()); let voiceConnection = this.get(); if (voiceConnection) voiceConnection.subscribe(this.audioPlayer); - else console.error(`[GUILD ${this.guildId}] [VC ${this.channelId}] FAILED - Could not initialize voice connection.`); } get = () => getVoiceConnection(this.guildId); @@ -77,7 +64,7 @@ export class VoiceConnection { play = (...metadata: YoutubeMetadata[]) => { this.queue.push(...metadata); if (!this.playing) this.next(); - }; + } skip = () => { this.next(); @@ -112,8 +99,6 @@ export class VoiceConnection { let voiceConnection = this.get(); if (!voiceConnection) return; - console.log(`[GUILD ${this.guildId}] [VC ${this.channelId}] DISCONNECTED - Disconnected from voice (probably due to inactivity)`) - if (this.process) this.process.kill(); this.process = undefined; @@ -126,7 +111,7 @@ export class VoiceConnection { this.queue = []; if (this.timeout) clearInterval(this.timeout); - voiceManager.destroy(this.guildId); + destroyVoiceFromGuildId(this.guildId); } next = () => {