From 53fb5708e380b65874bfbff55b7023f4b84ef321 Mon Sep 17 00:00:00 2001 From: "Jonny_Bro (Nikita)" <48434875+JonnyBro@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:57:02 +0500 Subject: [PATCH] Rewrite Music module to Lavalink (#17) --- .gitignore | 3 - base/Client.js | 70 ++-- commands/{ => !DISABLED}/Music/back.js | 0 commands/{ => !DISABLED}/Music/clips.js | 0 commands/{ => !DISABLED}/Music/nowplaying.js | 0 commands/Fun/number.js | 70 +++- commands/Music/loop.js | 35 +- commands/Music/play.c.js | 49 ++- commands/Music/play.js | 107 +++--- commands/Music/queue.js | 52 +-- commands/Music/seek.js | 7 +- commands/Music/shuffle.js | 6 +- commands/Music/skip.js | 35 +- commands/Music/skipto.js | 59 ---- commands/Music/stop.js | 6 +- commands/Music/volume.js | 9 +- commands/Tickets/createticketembed.js | 328 +++++++++-------- config.sample.js | 8 + events/ready.js | 4 + helpers/extenders.js | 20 +- helpers/functions.js | 6 +- index.js | 4 +- languages/en-US/fun/number.json | 3 +- languages/en-US/music/play.json | 2 +- languages/en-US/music/seek.json | 4 +- languages/en-US/music/skip.json | 11 +- languages/en-US/music/skipto.json | 9 - languages/ru-RU/fun/number.json | 3 +- languages/ru-RU/music/play.json | 2 +- languages/ru-RU/music/skip.json | 11 +- languages/ru-RU/music/skipto.json | 9 - languages/uk-UA/fun/number.json | 3 +- languages/uk-UA/music/play.json | 2 +- languages/uk-UA/music/skip.json | 11 +- languages/uk-UA/music/skipto.json | 9 - package.json | 6 +- pnpm-lock.yaml | 351 +------------------ 37 files changed, 505 insertions(+), 809 deletions(-) rename commands/{ => !DISABLED}/Music/back.js (100%) rename commands/{ => !DISABLED}/Music/clips.js (100%) rename commands/{ => !DISABLED}/Music/nowplaying.js (100%) delete mode 100644 commands/Music/skipto.js delete mode 100644 languages/en-US/music/skipto.json delete mode 100644 languages/ru-RU/music/skipto.json delete mode 100644 languages/uk-UA/music/skipto.json diff --git a/.gitignore b/.gitignore index 6812fc8b..d81631d1 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,3 @@ node_modules # Dashboard DB /json.sqlite - -# Cookies -cookies.json \ No newline at end of file diff --git a/base/Client.js b/base/Client.js index 7c8bcc5d..231f535d 100644 --- a/base/Client.js +++ b/base/Client.js @@ -1,7 +1,7 @@ const { Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder, EmbedBuilder, PermissionsBitField, ChannelType } = require("discord.js"), - { Player } = require("discord-player"), { GiveawaysManager } = require("discord-giveaways"), { REST } = require("@discordjs/rest"), + { LavalinkManager } = require("lavalink-client"), { Routes } = require("discord-api-types/v10"); const BaseEvent = require("./BaseEvent.js"), @@ -25,8 +25,6 @@ class JaBaClient extends Client { this.usersData = require("../base/User"); this.membersData = require("../base/Member"); this.dashboard = require("../dashboard/dashboard"); - this.states = {}; - this.knownGuilds = []; this.databaseCache = {}; this.databaseCache.users = new Collection(); @@ -34,39 +32,61 @@ class JaBaClient extends Client { this.databaseCache.members = new Collection(); this.databaseCache.usersReminds = new Collection(); - this.player = new Player(this); + this.lavalink = new LavalinkManager({ + nodes: [this.config.lavalinkNodes], + sendToShard: (guildId, payload) => this.guilds.cache.get(guildId)?.shard?.send(payload), + client: { + id: this.config.userId, + username: "JaBa", + }, + autoSkip: true, + playerOptions: { + defaultSearchPlatform: "ytmsearch", + volumeDecrementer: 1, + onDisconnect: { + autoReconnect: false, + destroyPlayer: true, + }, + onEmptyQueue: { + destroyAfterMs: 5000, + }, + }, + }); - this.player.extractors.loadDefault(); + this.lavalink.on("trackStart", async (player, track) => { + const guildData = await this.findOrCreateGuild(player.guildId), + channel = this.channels.cache.get(player.textChannelId); - this.player.events.on("playerStart", async (queue, track) => { const m = ( - await queue.metadata.channel.send({ - content: this.translate("music/play:NOW_PLAYING", { songName: `${track.title} - ${track.author}` }, queue.metadata.data.guild.language), + await channel.send({ + content: this.translate("music/play:NOW_PLAYING", { songName: `${track.info.title} - ${track.info.author}` }, guildData.language), }) ).id; - if (track.durationMS > 1) + if (track.info.duration > 1) setTimeout(() => { - const message = queue.metadata.channel.messages.cache.get(m); + const message = channel.messages.cache.get(m); if (message && message.deletable) message.delete(); - }, track.durationMS); + }, track.info.duration); else setTimeout(() => { - const message = queue.metadata.channel.messages.cache.get(m); + const message = channel.messages.cache.get(m); if (message && message.deletable) message.delete(); }, 5 * 60 * 1000); }); - this.player.events.on("emptyQueue", queue => queue.metadata.channel.send(this.translate("music/play:QUEUE_ENDED", null, queue.metadata.data.guild.language))); - this.player.events.on("emptyChannel", queue => queue.metadata.channel.send(this.translate("music/play:STOP_EMPTY", null, queue.metadata.data.guild.language))); - this.player.events.on("playerError", (queue, e) => { - queue.metadata.channel.send({ content: this.translate("music/play:ERR_OCCURRED", { error: e.message }, queue.metadata.data.guild.language) }); - console.log(e); + this.lavalink.on("queueEnd", async player => { + const guildData = await this.findOrCreateGuild(player.guildId), + channel = this.channels.cache.get(player.textChannelId); + + channel.send(this.translate("music/play:QUEUE_ENDED", null, guildData.language)); }); - this.player.events.on("error", (queue, e) => { - queue.metadata.channel.send({ content: this.translate("music/play:ERR_OCCURRED", { error: e.message }, queue.metadata.data.guild.language) }); - console.log(e); + this.lavalink.on("trackError", async player => { + const guildData = await this.findOrCreateGuild(player.guildId), + channel = this.channels.cache.get(player.textChannelId); + + channel.send({ content: this.translate("music/play:ERR_OCCURRED", null, guildData.language) }); }); this.giveawaysManager = new GiveawaysManager(this, { @@ -186,7 +206,7 @@ class JaBaClient extends Client { * @param {Object[]} [data.fields] - An array of field objects for the embed. * @param {string} [data.image] - The URL of the image for the embed. * @param {string} [data.url] - The URL to be used as the embed's hyperlink. - * @param {number} [data.color] - The color of the embed's border. If not provided, the default color from the client's configuration will be used. + * @param {string} [data.color] - The HEX color of the embed's border. If not provided, the default color from the client's configuration will be used. * @param {string} [data.footer] - The text to be displayed as the embed's footer. If not provided, the default footer from the client's configuration will be used. * @param {Date} [data.timestamp] - The timestamp to be displayed in the embed's footer. If not provided, the current timestamp will be used. * @param {string|Object} [data.author] - The author information for the embed. Can be a string (name) or an object with `name` and/or `iconURL` properties. @@ -296,8 +316,8 @@ class JaBaClient extends Client { /** * Finds or creates a user in the database based on the provided user ID. * @param {string} userID - The ID of the user to find or create. - * @returns {Promise} The user data object, either retrieved from the database or newly created. - */ + * @returns {Promise} The user data object, either retrieved from the database or newly created. + */ async findOrCreateUser(userID) { let userData = await this.usersData.findOne({ id: userID }); @@ -321,7 +341,7 @@ class JaBaClient extends Client { * @param {Object} options - The options for finding or creating the member. * @param {string} options.id - The ID of the member to find or create. * @param {string} options.guildId - The ID of the guild the member belongs to. - * @returns {Promise} The member data object, either retrieved from the database or newly created. + * @returns {Promise} The member data object, either retrieved from the database or newly created. */ async findOrCreateMember({ id: memberID, guildId }) { let memberData = await this.membersData.findOne({ guildID: guildId, id: memberID }); @@ -352,7 +372,7 @@ class JaBaClient extends Client { /** * Finds or creates a guild in the database based on the provided guild ID. * @param {string} guildId - The ID of the guild to find or create. - * @returns {Promise} The guild data object, either retrieved from the database or newly created. + * @returns {Promise} The guild data object, either retrieved from the database or newly created. */ async findOrCreateGuild(guildId) { let guildData = await this.guildsData.findOne({ id: guildId }).populate("members"); diff --git a/commands/Music/back.js b/commands/!DISABLED/Music/back.js similarity index 100% rename from commands/Music/back.js rename to commands/!DISABLED/Music/back.js diff --git a/commands/Music/clips.js b/commands/!DISABLED/Music/clips.js similarity index 100% rename from commands/Music/clips.js rename to commands/!DISABLED/Music/clips.js diff --git a/commands/Music/nowplaying.js b/commands/!DISABLED/Music/nowplaying.js similarity index 100% rename from commands/Music/nowplaying.js rename to commands/!DISABLED/Music/nowplaying.js diff --git a/commands/Fun/number.js b/commands/Fun/number.js index 0c12b27d..e13c5e35 100644 --- a/commands/Fun/number.js +++ b/commands/Fun/number.js @@ -1,4 +1,4 @@ -const { SlashCommandBuilder, MessageCollector } = require("discord.js"); +const { SlashCommandBuilder, MessageCollector, ButtonBuilder, ActionRowBuilder, ButtonStyle, ThreadAutoArchiveDuration } = require("discord.js"); const BaseCommand = require("../../base/BaseCommand"), currentGames = {}; @@ -35,39 +35,47 @@ class Number extends BaseCommand { await interaction.replyT("fun/number:GAME_START"); - const gameCreatedAt = Date.now(); + let channel; + if (interaction.channel.isThread()) channel = interaction.channel; + else + channel = await interaction.channel.threads.create({ + name: `number-guessing-${client.functions.randomNum(10000, 20000)}`, + autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, + }); + + const gameCreatedAt = Date.now(); const filter = m => !m.author.bot; - const collector = new MessageCollector(interaction.channel, { + const collector = new MessageCollector(channel, { filter, time: 5 * 60 * 1000, }); currentGames[interaction.guildId] = true; collector.on("collect", async msg => { - if (!participants.includes(msg.author.id)) participants.push(msg.author.id); + if (!participants.includes(msg.author)) participants.push(msg.author); if (msg.content === "STOP") return collector.stop("force"); if (isNaN(msg.content)) return; const parsedNumber = parseInt(msg.content, 10); if (parsedNumber === number) { - interaction.channel.send({ + channel.send({ content: interaction.translate("fun/number:GAME_STATS", { winner: msg.author.toString(), number, time: ``, participantCount: participants.length, - participants: participants.map(p => `<@${p}>`).join(", "), + participants: participants.map(p => p.toString()).join(", "), }), }); if (participants.length > 1) { const won = 100 * (participants.length * 0.5); - interaction.channel.send({ + channel.send({ content: interaction.translate("fun/number:WON", { - winner: msg.author.username, + winner: msg.author.toString(), credits: `**${won}** ${client.functions.getNoun(won, interaction.translate("misc:NOUNS:CREDIT:1"), interaction.translate("misc:NOUNS:CREDIT:2"), interaction.translate("misc:NOUNS:CREDIT:5"))}`, }), }); @@ -91,6 +99,31 @@ class Number extends BaseCommand { await memberData.save(); } + interaction.editReply({ + content: interaction.translate("fun/number:GAME_STATS", { + winner: msg.author.toString(), + number, + time: ``, + participantCount: participants.length, + participants: participants.map(p => p.toString()).join(", "), + }), + }); + + const deleteYes = new ButtonBuilder() + .setCustomId("number_delete_yes") + .setLabel(interaction.translate("common:YES")) + .setStyle(ButtonStyle.Danger); + const deleteNo = new ButtonBuilder() + .setCustomId("number_delete_no") + .setLabel(interaction.translate("common:NO")) + .setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(deleteYes, deleteNo); + + channel.send({ + content: interaction.translate("fun/number:DELETE_CHANNEL"), + components: [row], + }); + collector.stop(); } @@ -106,10 +139,31 @@ class Number extends BaseCommand { collector.on("end", (_, reason) => { delete currentGames[interaction.guildId]; + if (reason === "time") return interaction.editReply({ content: interaction.translate("fun/number:DEFEAT", { number }) }); else if (reason === "force") return interaction.editReply({ content: interaction.translate("misc:FORCE_STOP", { user: interaction.member.toString(), number }) }); }); } + + /** + * + * @param {import("../../base/Client")} client + */ + async onLoad(client) { + client.on("interactionCreate", async interaction => { + if (!interaction.isButton()) return; + + if (interaction.customId.startsWith("number_")) { + await interaction.deferUpdate(); + + if (interaction.customId === "number_delete_yes") interaction.channel.delete(); + else if (interaction.customId === "number_delete_no") { + await interaction.message.delete(); + interaction.channel.setArchived(true); + } + } + }); + } } module.exports = Number; diff --git a/commands/Music/loop.js b/commands/Music/loop.js index 00519b71..2203dbbe 100644 --- a/commands/Music/loop.js +++ b/commands/Music/loop.js @@ -1,5 +1,4 @@ -const { SlashCommandBuilder } = require("discord.js"), - { QueueRepeatMode } = require("discord-player"); +const { SlashCommandBuilder } = require("discord.js"); const BaseCommand = require("../../base/BaseCommand"); class Loop extends BaseCommand { @@ -27,10 +26,10 @@ class Loop extends BaseCommand { }) .setRequired(true) .setChoices( - { name: client.translate("music/loop:AUTOPLAY"), value: "3" }, - { name: client.translate("music/loop:QUEUE"), value: "2" }, - { name: client.translate("music/loop:TRACK"), value: "1" }, - { name: client.translate("music/loop:DISABLE"), value: "0" }, + // { name: client.translate("music/loop:AUTOPLAY"), value: "3" }, + { name: client.translate("music/loop:QUEUE"), value: "queue" }, + { name: client.translate("music/loop:TRACK"), value: "track" }, + { name: client.translate("music/loop:DISABLE"), value: "off" }, ), ), dirname: __dirname, @@ -44,25 +43,25 @@ class Loop extends BaseCommand { * @param {import("discord.js").ChatInputCommandInteraction} interaction */ async execute(client, interaction) { + await interaction.deferReply(); + const voice = interaction.member.voice.channel; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true }); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true }); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING", null, { edit: true }); + + const type = interaction.options.getString("option"); const translated = { - "3": interaction.translate("music/loop:AUTOPLAY_ENABLED"), - "2": interaction.translate("music/loop:QUEUE_ENABLED"), - "1": interaction.translate("music/loop:TRACK_ENABLED"), - "0": interaction.translate("music/loop:LOOP_DISABLED"), + // "3": interaction.translate("music/loop:AUTOPLAY_ENABLED"), + "queue": interaction.translate("music/loop:QUEUE_ENABLED"), + "track": interaction.translate("music/loop:TRACK_ENABLED"), + "off": interaction.translate("music/loop:LOOP_DISABLED"), }; - const type = interaction.options.getString("option"), - mode = type === "3" ? QueueRepeatMode.AUTOPLAY : type === "2" ? QueueRepeatMode.QUEUE : type === "1" ? QueueRepeatMode.TRACK : QueueRepeatMode.OFF; - - queue.setRepeatMode(mode); - - interaction.reply({ content: translated[type] }); + await player.setRepeatMode(type); + interaction.editReply({ content: translated[type] }); } } diff --git a/commands/Music/play.c.js b/commands/Music/play.c.js index 7c57fa97..8330a12e 100644 --- a/commands/Music/play.c.js +++ b/commands/Music/play.c.js @@ -29,42 +29,37 @@ class PlayContext extends BaseCommand { if (!links) return interaction.error("music/play:NO_LINK", null, { edit: true }); const query = links[0], - voice = interaction.member.voice.channel; + voice = interaction.member.voice; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true }); - const perms = voice.permissionsFor(client.user); + const perms = voice.channel.permissionsFor(client.user); if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.error("music/play:VOICE_CHANNEL_CONNECT", null, { edit: true }); - const searchResult = await client.player.search(query, { - requestedBy: interaction.user, + const player = await client.lavalink.createPlayer({ + guildId: interaction.guildId, + voiceChannelId: voice.channelId, + textChannelId: interaction.channelId, + selfDeaf: true, + selfMute: false, + volume: 100, }); - if (!searchResult.hasTracks()) return interaction.error("music/play:NO_RESULT", { query }, { edit: true }); - else { - const { queue } = await client.player.play(interaction.member.voice.channel, searchResult, { - nodeOptions: { - metadata: interaction, - }, - selfDeaf: true, - leaveOnEnd: false, - leaveOnStop: true, - skipOnNoStream: true, - maxSize: 200, - maxHistorySize: 50, - }); + await player.connect(); - interaction.editReply({ - content: interaction.translate("music/play:ADDED_QUEUE", { - songName: searchResult.hasPlaylist() ? searchResult.playlist.title : searchResult.tracks[0].title, - }), - }); + const res = await player.search({ query }, interaction.member); - if (client.player.nodes.get(interaction.guildId).currentTrack.url === query && query.match(/&t=[[0-9]+/g) !== null) { - const time = query.match(/&t=[[0-9]+/g)[0].split("=")[1]; + if (res.loadType === "playlist") await player.queue.add(res.tracks); + else if (res.loadType === "search") await player.queue.add(res.tracks[0]); + else if (res.loadType === "track") await player.queue.add(res.tracks[0]); + else console.log(res); - queue.node.seek(time * 1000); - } - } + if (!player.playing) await player.play(); + + interaction.editReply({ + content: interaction.translate("music/play:ADDED_QUEUE", { + songName: res.loadType === "playlist" ? res.playlist.name : `${res.tracks[0].info.title} - ${res.tracks[0].info.author}`, + }), + }); } } diff --git a/commands/Music/play.js b/commands/Music/play.js index bb57998d..658b8f0c 100644 --- a/commands/Music/play.js +++ b/commands/Music/play.js @@ -1,5 +1,4 @@ -const { SlashCommandBuilder, PermissionsBitField } = require("discord.js"), - { QueryType } = require("discord-player"); +const { SlashCommandBuilder, PermissionsBitField } = require("discord.js"); const BaseCommand = require("../../base/BaseCommand"); class Play extends BaseCommand { @@ -25,8 +24,7 @@ class Play extends BaseCommand { uk: client.translate("music/play:QUERY", null, "uk-UA"), ru: client.translate("music/play:QUERY", null, "ru-RU"), }) - .setRequired(true) - .setAutocomplete(true), + .setRequired(true), ), dirname: __dirname, ownerOnly: false, @@ -42,36 +40,37 @@ class Play extends BaseCommand { await interaction.deferReply(); const query = interaction.options.getString("query"), - voice = interaction.member.voice.channel; + voice = interaction.member.voice; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true }); - const perms = voice.permissionsFor(client.user); + const perms = voice.channel.permissionsFor(client.user); if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.error("music/play:VOICE_CHANNEL_CONNECT", null, { edit: true }); - const searchResult = await client.player.search(query, { - requestedBy: interaction.user, + const player = await client.lavalink.createPlayer({ + guildId: interaction.guildId, + voiceChannelId: voice.channelId, + textChannelId: interaction.channelId, + selfDeaf: true, + selfMute: false, + volume: 100, }); - if (!searchResult.hasTracks()) return interaction.error("music/play:NO_RESULT", { query }, { edit: true }); - else { - await client.player.play(interaction.member.voice.channel, searchResult, { - nodeOptions: { - metadata: interaction, - }, - selfDeaf: true, - leaveOnEnd: false, - leaveOnStop: true, - skipOnNoStream: true, - maxSize: 200, - maxHistorySize: 50, - }); + await player.connect(); - interaction.editReply({ - content: interaction.translate("music/play:ADDED_QUEUE", { - songName: searchResult.hasPlaylist() ? searchResult.playlist.title : `${searchResult.tracks[0].title} - ${searchResult.tracks[0].author}`, - }), - }); - } + const res = await player.search({ query }, interaction.member); + + if (res.loadType === "playlist") await player.queue.add(res.tracks); + else if (res.loadType === "search") await player.queue.add(res.tracks[0]); + else if (res.loadType === "track") await player.queue.add(res.tracks[0]); + else console.log(res); + + if (!player.playing) await player.play(); + + interaction.editReply({ + content: interaction.translate("music/play:ADDED_QUEUE", { + songName: res.loadType === "playlist" ? res.playlist.name : `${res.tracks[0].info.title} - ${res.tracks[0].info.author}`, + }), + }); } /** @@ -80,40 +79,34 @@ class Play extends BaseCommand { * @param {import("discord.js").AutocompleteInteraction} interaction * @returns */ - async autocompleteRun(client, interaction) { - const query = interaction.options.getString("query"); + // async autocompleteRun(client, interaction) { // TODO: Works from time to time + // const query = interaction.options.getString("query"); + // if (query === "") return; - if (query === "") return; - if (query.startsWith("http")) - return interaction.respond([ - { - name: "Current link", - value: query, - }, - ]); + // if (!client.lavalink.players.get(interaction.guildId)) { + // const player = await client.lavalink.createPlayer({ + // guildId: interaction.guildId, + // voiceChannelId: interaction.member.voice.channelId, + // textChannelId: interaction.channelId, + // selfDeaf: true, + // selfMute: false, + // volume: 100, + // }); - const youtubeResults = await client.player.search(query, { searchEngine: QueryType.YOUTUBE }); - const spotifyResults = await client.player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH }); - const tracks = []; + // const results = await player.search({ query }, interaction.member); + // if (results.loadType === "empty") return interaction.respond([{ name: "Nothing found", "value": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }]); + // const tracks = []; - youtubeResults.tracks - .slice(0, 5) - .map(t => ({ - name: `YouTube: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`, - value: t.url, - })) - .forEach(t => tracks.push({ name: t.name, value: t.value })); + // results.tracks + // .map(t => ({ + // name: `YouTube: ${`${t.info.title} - ${t.info.author} (${client.functions.printDate(client, t.info.duration, null, interaction.data.guild.lanugage)})`.length > 75 ? `${`${t.info.title} - ${t.info.author}`.substring(0, 75)}... (${client.functions.printDate(client, t.info.duration, null, interaction.data.guild.lanugage)})` : `${t.info.title} - ${t.info.author} (${client.functions.printDate(client, t.info.duration, null, interaction.data.guild.lanugage)})`}`, + // value: t.info.uri, + // })) + // .forEach(t => tracks.push({ name: t.name, value: t.value })); - spotifyResults.tracks - .slice(0, 5) - .map(t => ({ - name: `Spotify: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`, - value: t.url, - })) - .forEach(t => tracks.push({ name: t.name, value: t.value })); - - return interaction.respond(tracks); - } + // return interaction.respond(tracks); + // } + // } } module.exports = Play; diff --git a/commands/Music/queue.js b/commands/Music/queue.js index f39b9aba..33c451a8 100644 --- a/commands/Music/queue.js +++ b/commands/Music/queue.js @@ -31,12 +31,12 @@ class Queue extends BaseCommand { if (interaction.customId.startsWith("queue_")) { interaction.data = []; - interaction.data.guld = await client.findOrCreateGuild(interaction.guildId); + interaction.data.guild = await client.findOrCreateGuild(interaction.guildId); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING"); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING"); - const { embeds, size } = generateQueueEmbeds(interaction, queue); + const { embeds, size } = generateQueueEmbeds(interaction, player); let currentPage = Number(interaction.message.content.match(/\d+/g)[0]) - 1 ?? 0; @@ -124,10 +124,10 @@ class Queue extends BaseCommand { * @param {import("discord.js").ChatInputCommandInteraction} interaction */ async execute(client, interaction) { - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING"); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING"); - const { embeds, size } = generateQueueEmbeds(interaction, queue), + const { embeds, size } = generateQueueEmbeds(interaction, player), row = new ActionRowBuilder().addComponents( new ButtonBuilder().setCustomId("queue_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"), new ButtonBuilder().setCustomId("queue_next_page").setStyle(ButtonStyle.Primary).setEmoji("➡️"), @@ -152,28 +152,28 @@ class Queue extends BaseCommand { /** * * @param {import("discord.js").ChatInputCommandInteraction} interaction - * @param {import("discord-player").GuildQueue} queue + * @param {import("lavalink-client").Player} player * @returns */ -function generateQueueEmbeds(interaction, queue) { +function generateQueueEmbeds(interaction, player) { const embeds = [], - currentTrack = queue.currentTrack, + currentTrack = player.queue.current, translated = { - "3": interaction.translate("music/loop:AUTOPLAY"), - "2": interaction.translate("music/loop:QUEUE"), - "1": interaction.translate("music/loop:TRACK"), - "0": interaction.translate("common:DISABLED"), + // "3": interaction.translate("music/loop:AUTOPLAY"), + "queue": interaction.translate("music/loop:QUEUE"), + "track": interaction.translate("music/loop:TRACK"), + "off": interaction.translate("common:DISABLED"), }; let k = 10; - if (!queue.tracks.size) { + if (!player.queue.tracks.length) { const embed = interaction.client.embed({ title: interaction.translate("music/nowplaying:CURRENTLY_PLAYING"), - thumbnail: currentTrack.thumbnail || null, - description: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\`\n${ - currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})` - }\n> ${interaction.translate("music/queue:ADDED")} ${currentTrack.requestedBy}\n\n**${interaction.translate("music/queue:NEXT")}**\n${interaction.translate("music/queue:NO_QUEUE")}`, + thumbnail: currentTrack.info.artworkUrl || null, + description: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[player.repeatMode]}\`\n${ + currentTrack.info.uri.startsWith("./clips") ? `${currentTrack.info.title} (clips)` : `[${currentTrack.info.title}](${currentTrack.info.uri})` + }\n> ${interaction.translate("music/queue:ADDED")} ${currentTrack.requester.toString()}\n\n**${interaction.translate("music/queue:NEXT")}**\n${interaction.translate("music/queue:NO_QUEUE")}`, }); embeds.push(embed); @@ -181,19 +181,19 @@ function generateQueueEmbeds(interaction, queue) { return { embeds: embeds, size: embeds.length }; } - for (let i = 0; i < queue.getSize(); i += 10) { - const current = queue.tracks.toArray().slice(i, k); + for (let i = 0; i < player.queue.tracks.length; i += 10) { + const current = player.queue.tracks.slice(i, k); let j = i; k += 10; - const info = current.map(track => `${++j}. ${track.url.startsWith("./clips") ? `${track.title} (clips)` : `[${track.title}](${track.url})`}\n> ${interaction.translate("music/queue:ADDED")} ${track.requestedBy}`).join("\n"); + const info = current.map(track => `${++j}. ${track.info.uri.startsWith("./clips") ? `${track.info.title} (clips)` : `[${track.info.title}](${track.info.uri})`}\n> ${interaction.translate("music/queue:ADDED")} ${track.requester.toString()}`).join("\n"); const embed = interaction.client.embed({ title: interaction.translate("music/nowplaying:CURRENTLY_PLAYING"), - thumbnail: currentTrack.thumbnail || null, - description: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\`\n${ - currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})` - }\n * ${interaction.translate("music/queue:ADDED")} ${currentTrack.requestedBy}\n\n**${interaction.translate("music/queue:NEXT")}**\n${info}`, + thumbnail: currentTrack.info.artworkUrl || null, + description: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[player.repeatMode]}\`\n${ + currentTrack.info.uri.startsWith("./clips") ? `${currentTrack.info.title} (clips)` : `[${currentTrack.info.title}](${currentTrack.info.uri})` + }\n * ${interaction.translate("music/queue:ADDED")} ${currentTrack.requester.toString()}\n\n**${interaction.translate("music/queue:NEXT")}**\n${info}`, }); embeds.push(embed); diff --git a/commands/Music/seek.js b/commands/Music/seek.js index 86b560aa..1a58b40d 100644 --- a/commands/Music/seek.js +++ b/commands/Music/seek.js @@ -40,10 +40,11 @@ class Seek extends BaseCommand { voice = interaction.member.voice.channel; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL"); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING"); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING"); + + await player.seek(time * 1000); - queue.node.seek(time * 1000); interaction.success("music/seek:SUCCESS", { time: `**${time}** ${client.functions.getNoun(time, interaction.translate("misc:NOUNS:SECONDS:1"), interaction.translate("misc:NOUNS:SECONDS:2"), interaction.translate("misc:NOUNS:SECONDS:5"))}`, }); diff --git a/commands/Music/shuffle.js b/commands/Music/shuffle.js index 8d5890c1..f88f2d2d 100644 --- a/commands/Music/shuffle.js +++ b/commands/Music/shuffle.js @@ -30,10 +30,10 @@ class Shuffle extends BaseCommand { const voice = interaction.member.voice.channel; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { ephemeral: true }); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true }); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true }); - queue.tracks.shuffle(); + await player.queue.shuffle(); interaction.success("music/shuffle:SUCCESS"); } } diff --git a/commands/Music/skip.js b/commands/Music/skip.js index 340d5b17..60170f5b 100644 --- a/commands/Music/skip.js +++ b/commands/Music/skip.js @@ -15,7 +15,17 @@ class Skip extends BaseCommand { uk: client.translate("music/skip:DESCRIPTION", null, "uk-UA"), ru: client.translate("music/skip:DESCRIPTION", null, "ru-RU"), }) - .setDMPermission(false), + .setDMPermission(false) + .addIntegerOption(option => + option + .setName("position") + .setDescription(client.translate("music/skip:POSITION")) + .setDescriptionLocalizations({ + uk: client.translate("music/skip:POSITION", null, "uk-UA"), + ru: client.translate("music/skip:POSITION", null, "ru-RU"), + }) + .setRequired(false), + ), dirname: __dirname, ownerOnly: false, }); @@ -30,11 +40,26 @@ class Skip extends BaseCommand { const voice = interaction.member.voice.channel; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL"); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING"); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING"); + + const position = interaction.options.getInteger("position"); + + if (position) { + if (position <= 0) return interaction.error("music/skip:NO_PREV_SONG"); + + if (player.queue.tracks[position]) { + await player.skip(position); + + return interaction.success("music/skip:SUCCESS", { + track: player.queue.current.info.title, + }); + } else return interaction.error("music/skip:ERROR", { position }); + } else { + await player.skip(); + interaction.success("music/skip:SUCCESS"); + } - queue.node.skip(); - interaction.success("music/skip:SUCCESS"); } } diff --git a/commands/Music/skipto.js b/commands/Music/skipto.js deleted file mode 100644 index f906b69c..00000000 --- a/commands/Music/skipto.js +++ /dev/null @@ -1,59 +0,0 @@ -const { SlashCommandBuilder } = require("discord.js"); -const BaseCommand = require("../../base/BaseCommand"); - -class Skipto extends BaseCommand { - /** - * - * @param {import("../base/Client")} client - */ - constructor(client) { - super({ - command: new SlashCommandBuilder() - .setName("skipto") - .setDescription(client.translate("music/skipto:DESCRIPTION")) - .setDescriptionLocalizations({ - uk: client.translate("music/skipto:DESCRIPTION", null, "uk-UA"), - ru: client.translate("music/skipto:DESCRIPTION", null, "ru-RU"), - }) - .setDMPermission(false) - .addIntegerOption(option => - option - .setName("position") - .setDescription(client.translate("music/skipto:POSITION")) - .setDescriptionLocalizations({ - uk: client.translate("music/skipto:POSITION", null, "uk-UA"), - ru: client.translate("music/skipto:POSITION", null, "ru-RU"), - }) - .setRequired(true), - ), - dirname: __dirname, - ownerOnly: false, - }); - } - - /** - * - * @param {import("../../base/Client")} client - * @param {import("discord.js").ChatInputCommandInteraction} interaction - */ - async execute(client, interaction) { - const voice = interaction.member.voice.channel; - if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL"); - - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING"); - - const position = interaction.options.getInteger("position"); - if (position <= 0) return interaction.error("music/skipto:NO_PREV_SONG"); - - if (queue.tracks.at(position - 1)) { - queue.node.skipTo(queue.tracks.at(position - 1)); - - interaction.success("music/skipto:SUCCESS", { - track: queue.tracks.at(0).title, - }); - } else return interaction.error("music/skipto:ERROR", { position }); - } -} - -module.exports = Skipto; diff --git a/commands/Music/stop.js b/commands/Music/stop.js index a5e34364..0e1b6c3a 100644 --- a/commands/Music/stop.js +++ b/commands/Music/stop.js @@ -30,10 +30,10 @@ class Stop extends BaseCommand { const voice = interaction.member.voice.channel; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL"); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING"); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING"); - queue.delete(); + await player.destroy(); interaction.success("music/stop:SUCCESS"); } } diff --git a/commands/Music/volume.js b/commands/Music/volume.js index 00a72d7d..04ff38a3 100644 --- a/commands/Music/volume.js +++ b/commands/Music/volume.js @@ -1,5 +1,6 @@ const { SlashCommandBuilder } = require("discord.js"); const BaseCommand = require("../../base/BaseCommand"); +const numbers = Array.from({ length: 100 }, (_, k) => k + 1); class Volume extends BaseCommand { /** @@ -41,13 +42,13 @@ class Volume extends BaseCommand { const voice = interaction.member.voice.channel; if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { ephemeral: true }); - const queue = client.player.nodes.get(interaction.guildId); - if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true }); + const player = client.lavalink.getPlayer(interaction.guildId); + if (!player) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true }); const volume = interaction.options.getInteger("int"); if (volume <= 0 || volume > 100) return interaction.error("misc:INVALID_NUMBER_RANGE", { min: 1, max: 100 }); - queue.node.setVolume(volume); + await player.setVolume(volume); interaction.success("music/volume:SUCCESS", { volume, }); @@ -61,7 +62,7 @@ class Volume extends BaseCommand { */ async autocompleteRun(client, interaction) { const int = interaction.options.getInteger("int"), - results = Array.from({ length: 100 }, (_, k) => k + 1).filter(i => i.toString().includes(int)); + results = numbers.filter(i => i.toString().includes(int)); return await interaction.respond( results.slice(0, 25).map(i => ({ diff --git a/commands/Tickets/createticketembed.js b/commands/Tickets/createticketembed.js index 886b86b8..f459bb2c 100644 --- a/commands/Tickets/createticketembed.js +++ b/commands/Tickets/createticketembed.js @@ -30,176 +30,174 @@ class CreateTicketEmbed extends BaseCommand { client.on("interactionCreate", async interaction => { if (!interaction.isButton()) return; - if (interaction.isButton()) { - interaction.data = []; - interaction.data.guild = await client.findOrCreateGuild(interaction.guildId); + interaction.data = []; + interaction.data.guild = await client.findOrCreateGuild(interaction.guildId); - const guildData = interaction.data.guild, - ticketsCategory = guildData.plugins?.tickets?.ticketsCategory, - ticketLogs = guildData.plugins?.tickets?.ticketLogs, - transcriptionLogs = guildData.plugins?.tickets?.transcriptionLogs; + const guildData = interaction.data.guild, + ticketsCategory = guildData.plugins?.tickets?.ticketsCategory, + ticketLogs = guildData.plugins?.tickets?.ticketLogs, + transcriptionLogs = guildData.plugins?.tickets?.transcriptionLogs; - const button = interaction.component; + const button = interaction.component; - if (button.customId === "support_ticket") { - if (interaction.guild.channels.cache.get(ticketsCategory).children.cache.size >= 50) { - const sorted = interaction.guild.channels.cache.get(ticketsCategory).children.cache.sort((ch1, ch2) => ch1.createdTimestamp - ch2.createdTimestamp); + if (button.customId === "support_ticket") { + if (interaction.guild.channels.cache.get(ticketsCategory).children.cache.size >= 50) { + const sorted = interaction.guild.channels.cache.get(ticketsCategory).children.cache.sort((ch1, ch2) => ch1.createdTimestamp - ch2.createdTimestamp); - await sorted.first().delete(); - } - - if (guildData.plugins.tickets.count === undefined) guildData.plugins.tickets.count = 0; - - guildData.plugins.tickets.count++; - - guildData.markModified("plugins.tickets"); - await guildData.save(); - - const channel = await interaction.guild.channels.create({ - name: `${interaction.user.username}-support-${guildData.plugins.tickets.count}`, - topic: interaction.user.id, - type: ChannelType.GuildText, - parent: ticketsCategory, - permissionOverwrites: [ - { - id: interaction.user.id, - allow: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], - }, - { - id: interaction.guild.roles.everyone, - deny: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], - }, - ], - }); - - const logChannel = interaction.guild.channels.cache.get(ticketLogs); - const logEmbed = client.embed({ - title: interaction.translate("tickets/createticketembed:TICKET_CREATED_TITLE"), - description: `${interaction.user.toString()} (${channel.toString()})`, - }); - - await logChannel.send({ embeds: [logEmbed] }); - await interaction.success("tickets/createticketembed:TICKET_CREATED", { - channel: channel.toString(), - }, { ephemeral: true }); - - await channel.send(`<@${interaction.user.id}>`); - - const embed = client.embed({ - author: { - name: interaction.user.getUsername(), - iconURL: interaction.user.displayAvatarURL(), - }, - title: "Support Ticket", - description: interaction.translate("tickets/createticketembed:TICKET_CREATED_DESC"), - }); - - const closeButton = new ButtonBuilder() - .setCustomId("close_ticket") - .setLabel(interaction.translate("tickets/closeticket:CLOSE_TICKET")) - .setStyle(ButtonStyle.Danger); - const transcriptButton = new ButtonBuilder() - .setCustomId("transcript_ticket") - .setLabel(interaction.translate("tickets/closeticket:TRANSCRIPT_TICKET")) - .setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(closeButton, transcriptButton); - - await channel.send({ embeds: [embed], components: [row] }); - } else if (button.customId === "close_ticket") { - const embed = client.embed({ - title: interaction.translate("tickets/closeticket:CLOSING_TITLE"), - description: interaction.translate("tickets/closeticket:CLOSING_DESC"), - fields: [ - { - name: interaction.translate("common:TICKET"), - value: interaction.channel.name, - }, - { - name: interaction.translate("tickets/closeticket:CLOSING_BY"), - value: interaction.user.getUsername(), - }, - ], - }); - - const button = new ButtonBuilder().setCustomId("cancel_closing").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger); - const row = new ActionRowBuilder().addComponents(button); - - await interaction.reply({ - embeds: [embed], - components: [row], - }); - - const filter = i => i.customId === "cancel_closing"; - const collector = interaction.channel.createMessageComponentCollector({ filter, time: 5000 }); - - collector.on("collect", async i => { - await i.update({ content: interaction.translate("tickets/closeticket:CLOSING_CANCELED"), components: [] }); - collector.stop("canceled"); - }); - - collector.on("end", async (_, reason) => { - if (reason !== "canceled") { - const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); - const messages = Array.from(reversedMessages.values()).reverse(); - - if (messages.length > 1) { - let transcript = "---- TICKET CREATED ----\n"; - messages.forEach(message => { - transcript += `[${client.functions.printDate(client, message.createdTimestamp, null, interaction.getLocale())}] ${message.author.getUsername()}: ${message.content}\n`; - }); - transcript += "---- TICKET CLOSED ----\n"; - - if (transcriptionLogs !== null) interaction.guild.channels.cache.get(transcriptionLogs).send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - - try { - await interaction.user.send({ - content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: interaction.channel.name }), - files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], - }); - } catch (e) { - interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); - } - } - - const logChannel = interaction.guild.channels.cache.get(ticketLogs); - const logEmbed = client.embed({ - title: interaction.translate("tickets/createticketembed:TICKET_CLOSED_TITLE"), - description: `${interaction.user.toString()} (${interaction.channel.toString()})`, - }); - - logChannel.send({ embeds: [logEmbed] }); - - interaction.channel.send("Closed!"); - - const member = interaction.guild.members.cache.find(u => u.user.id === interaction.channel.topic); - - await interaction.channel.permissionOverwrites.edit(member, { ViewChannel: false, SendMessages: null }); - await interaction.channel.setName(`${interaction.channel.name}-closed`); - } - }); - } else if (button.customId === "transcript_ticket") { - await interaction.deferUpdate(); - - const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); - const messages = Array.from(reversedMessages.values()).reverse(); - - if (messages.length > 1) { - let transcript = "---- TICKET CREATED ----\n"; - messages.forEach(message => { - transcript += `[${client.functions.printDate(client, message.createdTimestamp, null, interaction.getLocale())}] ${message.author.getUsername()}: ${message.content}\n`; - }); - transcript += "---- TICKET CLOSED ----\n"; - - try { - await interaction.user.send({ - content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), - files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], - }); - } catch (error) { - interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); - } - } else return; + await sorted.first().delete(); } + + if (guildData.plugins.tickets.count === undefined) guildData.plugins.tickets.count = 0; + + guildData.plugins.tickets.count++; + + guildData.markModified("plugins.tickets"); + await guildData.save(); + + const channel = await interaction.guild.channels.create({ + name: `${interaction.user.username}-support-${guildData.plugins.tickets.count}`, + topic: interaction.user.id, + type: ChannelType.GuildText, + parent: ticketsCategory, + permissionOverwrites: [ + { + id: interaction.user.id, + allow: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], + }, + { + id: interaction.guild.roles.everyone, + deny: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], + }, + ], + }); + + const logChannel = interaction.guild.channels.cache.get(ticketLogs); + const logEmbed = client.embed({ + title: interaction.translate("tickets/createticketembed:TICKET_CREATED_TITLE"), + description: `${interaction.user.toString()} (${channel.toString()})`, + }); + + await logChannel.send({ embeds: [logEmbed] }); + await interaction.success("tickets/createticketembed:TICKET_CREATED", { + channel: channel.toString(), + }, { ephemeral: true }); + + await channel.send(`<@${interaction.user.id}>`); + + const embed = client.embed({ + author: { + name: interaction.user.getUsername(), + iconURL: interaction.user.displayAvatarURL(), + }, + title: "Support Ticket", + description: interaction.translate("tickets/createticketembed:TICKET_CREATED_DESC"), + }); + + const closeButton = new ButtonBuilder() + .setCustomId("close_ticket") + .setLabel(interaction.translate("tickets/closeticket:CLOSE_TICKET")) + .setStyle(ButtonStyle.Danger); + const transcriptButton = new ButtonBuilder() + .setCustomId("transcript_ticket") + .setLabel(interaction.translate("tickets/closeticket:TRANSCRIPT_TICKET")) + .setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(closeButton, transcriptButton); + + await channel.send({ embeds: [embed], components: [row] }); + } else if (button.customId === "close_ticket") { + const embed = client.embed({ + title: interaction.translate("tickets/closeticket:CLOSING_TITLE"), + description: interaction.translate("tickets/closeticket:CLOSING_DESC"), + fields: [ + { + name: interaction.translate("common:TICKET"), + value: interaction.channel.name, + }, + { + name: interaction.translate("tickets/closeticket:CLOSING_BY"), + value: interaction.user.getUsername(), + }, + ], + }); + + const button = new ButtonBuilder().setCustomId("cancel_closing").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger); + const row = new ActionRowBuilder().addComponents(button); + + await interaction.reply({ + embeds: [embed], + components: [row], + }); + + const filter = i => i.customId === "cancel_closing"; + const collector = interaction.channel.createMessageComponentCollector({ filter, time: 5000 }); + + collector.on("collect", async i => { + await i.update({ content: interaction.translate("tickets/closeticket:CLOSING_CANCELED"), components: [] }); + collector.stop("canceled"); + }); + + collector.on("end", async (_, reason) => { + if (reason !== "canceled") { + const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); + const messages = Array.from(reversedMessages.values()).reverse(); + + if (messages.length > 1) { + let transcript = "---- TICKET CREATED ----\n"; + messages.forEach(message => { + transcript += `[${client.functions.printDate(client, message.createdTimestamp, null, interaction.getLocale())}] ${message.author.getUsername()}: ${message.content}\n`; + }); + transcript += "---- TICKET CLOSED ----\n"; + + if (transcriptionLogs !== null) interaction.guild.channels.cache.get(transcriptionLogs).send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); + + try { + await interaction.user.send({ + content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: interaction.channel.name }), + files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], + }); + } catch (e) { + interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); + } + } + + const logChannel = interaction.guild.channels.cache.get(ticketLogs); + const logEmbed = client.embed({ + title: interaction.translate("tickets/createticketembed:TICKET_CLOSED_TITLE"), + description: `${interaction.user.toString()} (${interaction.channel.toString()})`, + }); + + logChannel.send({ embeds: [logEmbed] }); + + interaction.channel.send("Closed!"); + + const member = interaction.guild.members.cache.find(u => u.user.id === interaction.channel.topic); + + await interaction.channel.permissionOverwrites.edit(member, { ViewChannel: false, SendMessages: null }); + await interaction.channel.setName(`${interaction.channel.name}-closed`); + } + }); + } else if (button.customId === "transcript_ticket") { + await interaction.deferUpdate(); + + const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); + const messages = Array.from(reversedMessages.values()).reverse(); + + if (messages.length > 1) { + let transcript = "---- TICKET CREATED ----\n"; + messages.forEach(message => { + transcript += `[${client.functions.printDate(client, message.createdTimestamp, null, interaction.getLocale())}] ${message.author.getUsername()}: ${message.content}\n`; + }); + transcript += "---- TICKET CLOSED ----\n"; + + try { + await interaction.user.send({ + content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), + files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], + }); + } catch (error) { + interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); + } + } else return; } }); } diff --git a/config.sample.js b/config.sample.js index 8c8b514c..4a698a95 100644 --- a/config.sample.js +++ b/config.sample.js @@ -8,6 +8,14 @@ module.exports = { /* Set to true for production */ /* If set to false, commands only will be registered on the support.id server */ production: true, + /* Lavalink Nodes */ + lavalinkNodes: { + id: "localhost", + host: "localhost", + port: 2333, + authorization: "strongpassword", + secure: true, + }, /* Support server */ support: { id: "123456789098765432", // The ID of the support server diff --git a/events/ready.js b/events/ready.js index 96bc66b9..06e32a68 100644 --- a/events/ready.js +++ b/events/ready.js @@ -61,6 +61,10 @@ class Ready extends BaseEvent { if (status[i + 1]) i++; else i = 0; }, 30 * 1000); // Every 30 seconds + + await client.lavalink.init({ ...client.user }); + client.on("raw", d => client.lavalink.sendRawData(d)); + client.logger.ready("Lavalink ready."); } } diff --git a/helpers/extenders.js b/helpers/extenders.js index dfc70e07..db55c4f0 100644 --- a/helpers/extenders.js +++ b/helpers/extenders.js @@ -5,7 +5,7 @@ User.prototype.getUsername = function () { }; BaseInteraction.prototype.getLocale = function () { - return this.guild ? this.data?.guild?.language : "en-US"; + return this.data?.guild?.language ?? "en-US"; }; BaseInteraction.prototype.translate = function (key, args) { @@ -19,24 +19,24 @@ BaseInteraction.prototype.replyT = async function (key, args, options = {}) { const translated = this.translate(key, args, this.getLocale()); const string = options.prefixEmoji ? `${this.client.customEmojis[options.prefixEmoji]} | ${translated}` : translated; - if (options.edit) return await this.editReply({ content: string, ephemeral: options.ephemeral || false }); - else return await this.reply({ content: string, ephemeral: options.ephemeral || false }); + if (options.edit) return this.editReply({ content: string, ephemeral: options.ephemeral || false }); + else return this.reply({ content: string, ephemeral: options.ephemeral || false }); }; BaseInteraction.prototype.success = async function (key, args, options = {}) { options.prefixEmoji = "success"; - return await this.replyT(key, args, options); + return this.replyT(key, args, options); }; BaseInteraction.prototype.error = async function (key, args, options = {}) { options.prefixEmoji = "error"; - return await this.replyT(key, args, options); + return this.replyT(key, args, options); }; Message.prototype.getLocale = function () { - return this.guild ? this.data?.guild?.language : "en-US"; + return this.data?.guild?.language ?? "en-US"; }; Message.prototype.translate = function (key, args) { @@ -50,18 +50,18 @@ Message.prototype.replyT = async function (key, args, options = {}) { const translated = this.translate(key, args, this.getLocale()); const string = options.prefixEmoji ? `${this.client.customEmojis[options.prefixEmoji]} | ${translated}` : translated; - if (options.edit) return await this.edit({ content: string, allowedMentions: { repliedUser: options.mention ? true : false } }); - else return await this.reply({ content: string, allowedMentions: { repliedUser: options.mention ? true : false } }); + if (options.edit) return this.edit({ content: string, allowedMentions: { repliedUser: options.mention ? true : false } }); + else return this.reply({ content: string, allowedMentions: { repliedUser: options.mention ? true : false } }); }; Message.prototype.success = async function (key, args, options = {}) { options.prefixEmoji = "success"; - return await this.replyT(key, args, options); + return this.replyT(key, args, options); }; Message.prototype.error = async function (key, args, options = {}) { options.prefixEmoji = "error"; - return await this.replyT(key, args, options); + return this.replyT(key, args, options); }; diff --git a/helpers/functions.js b/helpers/functions.js index 4941069c..afdf2ebe 100644 --- a/helpers/functions.js +++ b/helpers/functions.js @@ -61,11 +61,11 @@ module.exports = { /** * Generates a random integer between the specified minimum and maximum values (inclusive). * - * @param {number} min - The minimum value (inclusive). - * @param {number} max - The maximum value (inclusive). + * @param {number} [min=0] - The minimum value (inclusive). + * @param {number} [max=100] - The maximum value (inclusive). * @returns {number} A random integer between min and max. */ - randomNum(min, max) { + randomNum(min = 0, max = 100) { min = Math.ceil(min); max = Math.floor(max); diff --git a/index.js b/index.js index 164fb19f..28f23b00 100644 --- a/index.js +++ b/index.js @@ -21,8 +21,8 @@ const client = new Client({ client .on("disconnect", () => client.logger.warn("Bot is disconnecting...")) .on("reconnecting", () => client.logger.warn("Bot reconnecting...")) - .on("warn", warn => client.logger.warn(warn)) - .on("error", e => client.logger.error(`${e.message}\n${e.stack}`)); + .on("warn", warn => console.log(warn)) + .on("error", e => console.log(e)); process .on("unhandledRejection", e => console.log(e)) diff --git a/languages/en-US/fun/number.json b/languages/en-US/fun/number.json index f142e972..29e5151a 100644 --- a/languages/en-US/fun/number.json +++ b/languages/en-US/fun/number.json @@ -8,5 +8,6 @@ "WON": "{{winner}} has won {{credits}}", "DEFEAT": "No one guessed the number! It was **{{number}}**", "GAME_STATS": "🎉 | {{winner}} has guessed the number! It was **{{number}}**!\n\n**Statistics:**\n*-* __**Duration**__: {{time}}\n*-* __**Participants ({{participantCount}})**__: {{participants}}", - "GAME_RUNNING": "The game is already in progress" + "GAME_RUNNING": "The game is already in progress", + "DELETE_CHANNEL": "Game has ended. Do you want to delete this channel?" } \ No newline at end of file diff --git a/languages/en-US/music/play.json b/languages/en-US/music/play.json index 753401de..3cf86997 100644 --- a/languages/en-US/music/play.json +++ b/languages/en-US/music/play.json @@ -13,5 +13,5 @@ "ADDED_QUEUE": "**{{songName}}** has been added to the queue", "STOP_DISCONNECTED": "Playback stopped because I left the voice channel", "STOP_EMPTY": "Playback stopped because everyone has left the voice channel", - "ERR_OCCURRED": "An error occurred...\n```{{error}}```" + "ERR_OCCURRED": "An error occurred, skipping track..." } \ No newline at end of file diff --git a/languages/en-US/music/seek.json b/languages/en-US/music/seek.json index 654bc100..211d858f 100644 --- a/languages/en-US/music/seek.json +++ b/languages/en-US/music/seek.json @@ -1,7 +1,7 @@ { - "DESCRIPTION": "Rewinds the current track to the specified position", + "DESCRIPTION": "Seeks the current track to the specified time", "USAGE": "[time]", "EXAMPLES": "seek time:60", "TIME": "Time in seconds", - "SUCCESS": "Track rewinded to {{time}}" + "SUCCESS": "Seeked to {{time}}" } \ No newline at end of file diff --git a/languages/en-US/music/skip.json b/languages/en-US/music/skip.json index ee7676e2..5fcee3d1 100644 --- a/languages/en-US/music/skip.json +++ b/languages/en-US/music/skip.json @@ -1,6 +1,9 @@ { - "DESCRIPTION": "Skips the current track", - "USAGE": "", - "EXAMPLES": "skip", - "SUCCESS": "Track skipped" + "DESCRIPTION": "Jumps to a specified track", + "USAGE": "[position]", + "EXAMPLES": "skipto position:3", + "POSITION": "Track number in the queue", + "SUCCESS": "Jumped to track **{{track}}**", + "ERROR": "Nothing found at position {{position}}", + "NO_PREV_SONG": "You cannot go back, use the `back` command for that" } \ No newline at end of file diff --git a/languages/en-US/music/skipto.json b/languages/en-US/music/skipto.json deleted file mode 100644 index 5fcee3d1..00000000 --- a/languages/en-US/music/skipto.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "DESCRIPTION": "Jumps to a specified track", - "USAGE": "[position]", - "EXAMPLES": "skipto position:3", - "POSITION": "Track number in the queue", - "SUCCESS": "Jumped to track **{{track}}**", - "ERROR": "Nothing found at position {{position}}", - "NO_PREV_SONG": "You cannot go back, use the `back` command for that" -} \ No newline at end of file diff --git a/languages/ru-RU/fun/number.json b/languages/ru-RU/fun/number.json index 7273a716..870a4b11 100644 --- a/languages/ru-RU/fun/number.json +++ b/languages/ru-RU/fun/number.json @@ -8,5 +8,6 @@ "WON": "{{winner}} выиграл {{credits}}", "DEFEAT": "Никто не угадал число! Им было **{{number}}**", "GAME_STATS": "🎉 | {{winner}} угадал число! Им было **{{number}}**!\n\n**Статистика:**\n*-* __**Длительность**__: {{time}}\n*-* __**Участники ({{participantCount}})**__: {{participants}}", - "GAME_RUNNING": "Игра уже идёт" + "GAME_RUNNING": "Игра уже идёт", + "DELETE_CHANNEL": "Игра окончена. Вы хотите удалить этот канал?" } \ No newline at end of file diff --git a/languages/ru-RU/music/play.json b/languages/ru-RU/music/play.json index 8d8579cf..592d9966 100644 --- a/languages/ru-RU/music/play.json +++ b/languages/ru-RU/music/play.json @@ -13,5 +13,5 @@ "ADDED_QUEUE": "**{{songName}}** добавлен в очередь", "STOP_DISCONNECTED": "Воспроизведение окончено, т.к. я вышел из голосового канала", "STOP_EMPTY": "Воспроизведение окончено, т.к. все вышли из голосового канала", - "ERR_OCCURRED": "Произошла ошибка...\n```{{error}}```" + "ERR_OCCURRED": "Произошла ошибка, пропускаю трек..." } \ No newline at end of file diff --git a/languages/ru-RU/music/skip.json b/languages/ru-RU/music/skip.json index 50554b35..98ebf998 100644 --- a/languages/ru-RU/music/skip.json +++ b/languages/ru-RU/music/skip.json @@ -1,6 +1,9 @@ { - "DESCRIPTION": "Пропустить текущий трек", - "USAGE": "", - "EXAMPLES": "skip", - "SUCCESS": "Трек пропущен" + "DESCRIPTION": "Пропустить текущий трек или перейти на заданный", + "USAGE": "(position)", + "EXAMPLES": "skip position:3", + "POSITION": "Номер трека в очереди", + "SUCCESS": "Выполнен переход на трек **{{track}}**", + "ERROR": "На позиции {{position}} ничего не найдено", + "NO_PREV_SONG": "Вы не можете перейти назад, для этого используйте команду `back`" } \ No newline at end of file diff --git a/languages/ru-RU/music/skipto.json b/languages/ru-RU/music/skipto.json deleted file mode 100644 index 12b8f103..00000000 --- a/languages/ru-RU/music/skipto.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "DESCRIPTION": "Перейти на заданный трек", - "USAGE": "[position]", - "EXAMPLES": "skipto position:3", - "POSITION": "Номер трека в очереди", - "SUCCESS": "Выполнен переход на трек **{{track}}**", - "ERROR": "На позиции {{position}} ничего не найдено", - "NO_PREV_SONG": "Вы не можете перейти назад, для этого используйте команду `back`" -} \ No newline at end of file diff --git a/languages/uk-UA/fun/number.json b/languages/uk-UA/fun/number.json index 19e26b27..54906ce7 100644 --- a/languages/uk-UA/fun/number.json +++ b/languages/uk-UA/fun/number.json @@ -8,5 +8,6 @@ "WON": "{{winner}} виграв {{credits}}", "DEFEAT": "Ніхто не вгадав число! Їм було **{{number}}**", "GAME_STATS": "🎉 | {{winner}} вгадав число! Їм було **{{number}}**!\n\n**Статистика:**\n*-* __**Тривалість**__: {{time}}\n*-* __**Учасники ({{participantCount}})**__: {{participants}}", - "GAME_RUNNING": "Гра вже йде" + "GAME_RUNNING": "Гра вже йде", + "DELETE_CHANNEL": "Гру закінчено. Ви хочете видалити цей канал?" } \ No newline at end of file diff --git a/languages/uk-UA/music/play.json b/languages/uk-UA/music/play.json index cbd23342..b5b0e6bb 100644 --- a/languages/uk-UA/music/play.json +++ b/languages/uk-UA/music/play.json @@ -13,5 +13,5 @@ "ADDED_QUEUE": "**{{songName}}** додано до черги", "STOP_DISCONNECTED": "Відтворення закінчено, тому що я вийшов з голосового каналу", "STOP_EMPTY": "Відтворення закінчено, тому що всі вийшли з голосового каналу", - "ERR_OCCURRED": "Відбулася помилка...\n```{{error}}```" + "ERR_OCCURRED": "Відбулася помилка, пропускаю трек..." } \ No newline at end of file diff --git a/languages/uk-UA/music/skip.json b/languages/uk-UA/music/skip.json index fed5e375..20e24c55 100644 --- a/languages/uk-UA/music/skip.json +++ b/languages/uk-UA/music/skip.json @@ -1,6 +1,9 @@ { - "DESCRIPTION": "Пропустити поточний трек", - "USAGE": "", - "EXAMPLES": "skip", - "SUCCESS": "Трек пропущено" + "DESCRIPTION": "Перейти на заданий трек", + "USAGE": "[position]", + "EXAMPLES": "skipto position:3", + "POSITION": "Номер треку в черзі", + "SUCCESS": "Перехід на трек **{{track}}**", + "ERROR": "На позиції {{position}} нічого не знайдено", + "NO_PREV_SONG": "Ви не можете перейти назад, для цього використовуйте команду `back`" } \ No newline at end of file diff --git a/languages/uk-UA/music/skipto.json b/languages/uk-UA/music/skipto.json deleted file mode 100644 index 20e24c55..00000000 --- a/languages/uk-UA/music/skipto.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "DESCRIPTION": "Перейти на заданий трек", - "USAGE": "[position]", - "EXAMPLES": "skipto position:3", - "POSITION": "Номер треку в черзі", - "SUCCESS": "Перехід на трек **{{track}}**", - "ERROR": "На позиції {{position}} нічого не знайдено", - "NO_PREV_SONG": "Ви не можете перейти назад, для цього використовуйте команду `back`" -} \ No newline at end of file diff --git a/package.json b/package.json index cdf937fc..1f22fc58 100644 --- a/package.json +++ b/package.json @@ -8,23 +8,21 @@ "start": "node .", "lint": "eslint . --ext .js --ignore-pattern \"dashboard-core/\"" }, - "author": "Discord: @jonny_bro", + "author": "@jonny_bro", "dependencies": { - "@discord-player/extractor": "^4.4.7", "@discordjs/opus": "^0.9.0", "@discordjs/rest": "^2.2.0", "@discordjs/voice": "^0.16.1", - "@distube/ytdl-core": "^4.13.3", "canvas": "^2.11.2", "chalk": "^4.1.2", "cron": "^2.4.4", "discord-api-types": "^0.37.71", "discord-giveaways": "^6.0.1", - "discord-player": "^6.6.8", "discord.js": "^14.14.1", "gamedig": "^4.1.0", "i18next": "^21.10.0", "i18next-fs-backend": "^1.2.0", + "lavalink-client": "^2.1.7", "md5": "^2.3.0", "moment": "^2.29.4", "mongoose": "^7.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfb5962a..69ffba04 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,6 @@ settings: excludeLinksFromLockfile: false dependencies: - '@discord-player/extractor': - specifier: ^4.4.7 - version: 4.4.7 '@discordjs/opus': specifier: ^0.9.0 version: 0.9.0 @@ -17,9 +14,6 @@ dependencies: '@discordjs/voice': specifier: ^0.16.1 version: 0.16.1(@discordjs/opus@0.9.0) - '@distube/ytdl-core': - specifier: ^4.13.3 - version: 4.13.3 canvas: specifier: ^2.11.2 version: 2.11.2 @@ -35,9 +29,6 @@ dependencies: discord-giveaways: specifier: ^6.0.1 version: 6.0.1(discord.js@14.14.1) - discord-player: - specifier: ^6.6.8 - version: 6.6.8(@discord-player/extractor@4.4.7)(@discordjs/opus@0.9.0) discord.js: specifier: ^14.14.1 version: 14.14.1 @@ -50,6 +41,9 @@ dependencies: i18next-fs-backend: specifier: ^1.2.0 version: 1.2.0 + lavalink-client: + specifier: ^2.1.7 + version: 2.1.7 md5: specifier: ^2.3.0 version: 2.3.0 @@ -85,39 +79,6 @@ packages: regenerator-runtime: 0.14.0 dev: false - /@discord-player/equalizer@0.2.3: - resolution: {integrity: sha512-71UAepYMbHTg2QQLXQAgyuXYHrgAYpJDxjg9dRWfTUNf+zfOAlyJEiRRk/WFhQyGu6m23iLR/H/JxgF4AW8Csg==} - dev: false - - /@discord-player/extractor@4.4.7: - resolution: {integrity: sha512-XHG9Y45rQVWk3quf0IJqAj1ybTqiRgAy6vr5hnlaDZeaxXlsHRlDSzmSYl+teFVw2G9bjzR0jIvm8a4BW9hCBw==} - dependencies: - file-type: 16.5.4 - genius-lyrics: 4.4.6 - isomorphic-unfetch: 4.0.2 - node-html-parser: 6.1.11 - reverbnation-scraper: 2.0.0 - soundcloud.ts: 0.5.2 - spotify-url-info: 3.2.9 - youtube-sr: 4.3.9 - transitivePeerDependencies: - - encoding - dev: false - - /@discord-player/ffmpeg@0.1.0: - resolution: {integrity: sha512-0kW6q4gMQN2B4Z4EzmUgXrKQSXXmyhjdZBBZ/6jSHZ9fh814oOu+JXP01VvtWHwTylI7qJHIctEWtSyjEubCJg==} - dev: false - - /@discord-player/opus@0.1.2: - resolution: {integrity: sha512-yF0m+pW7H9RCbRcgk/i6vv47tlWxaCHjp6/F0W4GXZMGZ0pcvZaxk8ic7aFPc3+IoDvrAHvWNomLq+JeFzdncA==} - dev: false - - /@discord-player/utils@0.2.2: - resolution: {integrity: sha512-UklWUT7BcZEkBgywM9Cmpo2nwj3SQ9Wmhu6ml1uy/YRQnY8IRdZEHD84T2kfjOg4LVZek0ej1VerIqq7a9PAHQ==} - dependencies: - '@discordjs/collection': 1.5.3 - dev: false - /@discordjs/builders@1.7.0: resolution: {integrity: sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==} engines: {node: '>=16.11.0'} @@ -234,21 +195,6 @@ packages: - utf-8-validate dev: false - /@distube/ytdl-core@4.13.3: - resolution: {integrity: sha512-WHVzp0NyUkmdxRkfU8tN7eRquL7bnia2U/EDNWVupCptRo7EToTdBKHwJrDFqvavbXsdqLG/kR1r+1LaPglrFQ==} - engines: {node: '>=12'} - dependencies: - http-cookie-agent: 5.0.4(tough-cookie@4.1.3)(undici@5.27.2) - m3u8stream: 0.8.6 - miniget: 4.2.3 - sax: 1.2.4 - tough-cookie: 4.1.3 - undici: 5.27.2 - transitivePeerDependencies: - - deasync - - supports-color - dev: false - /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -388,10 +334,6 @@ packages: defer-to-connect: 2.0.1 dev: false - /@tokenizer/token@0.3.0: - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - dev: false - /@types/http-cache-semantics@4.0.3: resolution: {integrity: sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==} dev: false @@ -465,15 +407,6 @@ packages: - supports-color dev: false - /agent-base@7.1.1: - resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} - engines: {node: '>= 14'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: false - /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -678,11 +611,6 @@ packages: engines: {node: '>= 6'} dev: false - /data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - dev: false - /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -750,47 +678,6 @@ packages: serialize-javascript: 6.0.1 dev: false - /discord-player@6.6.8(@discord-player/extractor@4.4.7)(@discordjs/opus@0.9.0): - resolution: {integrity: sha512-aZQxtWbHaQPYs0KWU3XObxQLabWg7RWvLlytEitVsqbyfoBFKv2KMYX4swq0/I6eBbu2755z80pbvwU7ycjmsw==} - peerDependencies: - '@discord-player/extractor': ^4.4.7 - dependencies: - '@discord-player/equalizer': 0.2.3 - '@discord-player/extractor': 4.4.7 - '@discord-player/ffmpeg': 0.1.0 - '@discord-player/utils': 0.2.2 - discord-voip: 0.1.3(@discordjs/opus@0.9.0) - ip: 1.1.8 - libsodium-wrappers: 0.7.13 - transitivePeerDependencies: - - '@discordjs/opus' - - bufferutil - - ffmpeg-static - - node-opus - - opusscript - - utf-8-validate - dev: false - - /discord-voip@0.1.3(@discordjs/opus@0.9.0): - resolution: {integrity: sha512-9DWY5/BLPXeldVwPr8/ggGjggTYOTw77aGQc3+4n5K54bRbbiJ9DUJc+mJzDiSLoHN3f286eRGACJYtrUu27xA==} - engines: {node: '>=16.9.0'} - dependencies: - '@discord-player/ffmpeg': 0.1.0 - '@discord-player/opus': 0.1.2 - '@types/ws': 8.5.10 - discord-api-types: 0.37.71 - prism-media: 1.3.5(@discordjs/opus@0.9.0) - tslib: 2.6.2 - ws: 8.14.2 - transitivePeerDependencies: - - '@discordjs/opus' - - bufferutil - - ffmpeg-static - - node-opus - - opusscript - - utf-8-validate - dev: false - /discord.js@14.14.1: resolution: {integrity: sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==} engines: {node: '>=16.11.0'} @@ -977,14 +864,6 @@ packages: reusify: 1.0.4 dev: true - /fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.2.1 - dev: false - /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -992,15 +871,6 @@ packages: flat-cache: 3.1.1 dev: true - /file-type@16.5.4: - resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==} - engines: {node: '>=10'} - dependencies: - readable-web-to-node-stream: 3.0.2 - strtok3: 6.3.0 - token-types: 4.2.1 - dev: false - /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1027,13 +897,6 @@ packages: engines: {node: '>= 14.17'} dev: false - /formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - dependencies: - fetch-blob: 3.2.0 - dev: false - /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -1086,13 +949,6 @@ packages: xmlrpc: 1.3.2 dev: false - /genius-lyrics@4.4.6: - resolution: {integrity: sha512-TeSF4qXwLm+Nl8wUX+WUTJlEhPBanMw9EWpIHE2a/Qs4y2NBK99AHYfZJc73H1HVkZj4zPfscuGWlkQbbh0pDA==} - dependencies: - node-html-parser: 6.1.11 - undici: 5.27.2 - dev: false - /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -1151,15 +1007,6 @@ packages: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: false - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: false - - /himalaya@1.1.0: - resolution: {integrity: sha512-LLase1dHCRMel68/HZTFft0N0wti0epHr3nNY7ynpLbyZpmrKMQ8YIpiOV77TM97cNpC8Wb2n6f66IRggwdWPw==} - dev: false - /htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} dependencies: @@ -1173,26 +1020,6 @@ packages: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} dev: false - /http-cookie-agent@5.0.4(tough-cookie@4.1.3)(undici@5.27.2): - resolution: {integrity: sha512-OtvikW69RvfyP6Lsequ0fN5R49S+8QcS9zwd58k6VSr6r57T8G29BkPdyrBcSwLq6ExLs9V+rBlfxu7gDstJag==} - engines: {node: '>=14.18.0 <15.0.0 || >=16.0.0'} - peerDependencies: - deasync: ^0.1.26 - tough-cookie: ^4.0.0 - undici: ^5.11.0 - peerDependenciesMeta: - deasync: - optional: true - undici: - optional: true - dependencies: - agent-base: 7.1.1 - tough-cookie: 4.1.3 - undici: 5.27.2 - transitivePeerDependencies: - - supports-color - dev: false - /http2-wrapper@2.2.0: resolution: {integrity: sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==} engines: {node: '>=10.19.0'} @@ -1228,10 +1055,6 @@ packages: safer-buffer: 2.1.2 dev: false - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: false - /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -1259,10 +1082,6 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - /ip@1.1.8: - resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} - dev: false - /ip@2.0.0: resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} dev: false @@ -1305,13 +1124,6 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /isomorphic-unfetch@4.0.2: - resolution: {integrity: sha512-1Yd+CF/7al18/N2BDbsLBcp6RO3tucSW+jcLq24dqdX5MNbCNTw1z4BsGsp4zNmjr/Izm2cs/cEqZPp4kvWSCA==} - dependencies: - node-fetch: 3.3.2 - unfetch: 5.0.0 - dev: false - /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -1340,6 +1152,17 @@ packages: dependencies: json-buffer: 3.0.1 + /lavalink-client@2.1.7: + resolution: {integrity: sha512-MtXtyTowC+SGmnZRZ7aNuShQ7ADc2ULC8ib31sJTKzYqJ7gvjxfay9P21ewwOHtmnsOvN4999s1bPeP8K6vJOg==} + dependencies: + tslib: 2.6.2 + undici: 5.27.2 + ws: 8.14.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -1348,16 +1171,6 @@ packages: type-check: 0.4.0 dev: true - /libsodium-wrappers@0.7.13: - resolution: {integrity: sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw==} - dependencies: - libsodium: 0.7.13 - dev: false - - /libsodium@0.7.13: - resolution: {integrity: sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw==} - dev: false - /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1398,14 +1211,6 @@ packages: engines: {node: '>=12'} dev: false - /m3u8stream@0.8.6: - resolution: {integrity: sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==} - engines: {node: '>=12'} - dependencies: - miniget: 4.2.3 - sax: 1.2.4 - dev: false - /magic-bytes.js@1.5.0: resolution: {integrity: sha512-wJkXvutRbNWcc37tt5j1HyOK1nosspdh3dj6LUYYAvF6JYNqs53IfRvK9oEpcwiDA1NdoIi64yAMfdivPeVAyw==} dev: false @@ -1446,11 +1251,6 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: false - /miniget@4.2.3: - resolution: {integrity: sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA==} - engines: {node: '>=12'} - dev: false - /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -1578,11 +1378,6 @@ packages: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} dev: false - /node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - dev: false - /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -1595,22 +1390,6 @@ packages: whatwg-url: 5.0.0 dev: false - /node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - dev: false - - /node-html-parser@6.1.11: - resolution: {integrity: sha512-FAgwwZ6h0DSDWxfD0Iq1tsDcBCxdJB1nXpLPPxX8YyVWzbfCjKWEzaynF4gZZ/8hziUmp7ZSaKylcn0iKhufUQ==} - dependencies: - css-select: 5.1.0 - he: 1.2.0 - dev: false - /nopt@5.0.0: resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} engines: {node: '>=6'} @@ -1714,11 +1493,6 @@ packages: engines: {node: '>=8'} dev: true - /peek-readable@4.1.0: - resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} - engines: {node: '>=8'} - dev: false - /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -1748,18 +1522,10 @@ packages: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: false - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - dev: false - /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} - /querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - dev: false - /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -1805,21 +1571,10 @@ packages: util-deprecate: 1.0.2 dev: false - /readable-web-to-node-stream@3.0.2: - resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==} - engines: {node: '>=8'} - dependencies: - readable-stream: 3.6.2 - dev: false - /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} dev: false - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - dev: false - /resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: false @@ -1841,14 +1596,6 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /reverbnation-scraper@2.0.0: - resolution: {integrity: sha512-t1Mew5QC9QEVEry5DXyagvci2O+TgXTGoMHbNoW5NRz6LTOzK/DLHUpnrQwloX8CVX5z1a802vwHM3YgUVOvKg==} - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - dev: false - /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true @@ -1952,12 +1699,6 @@ packages: smart-buffer: 4.2.0 dev: false - /soundcloud.ts@0.5.2: - resolution: {integrity: sha512-/pc72HWYJpSpup+mJBE9pT31JsrMcxJGBlip3Vem+0Fsscg98xh1/7I2nCpAKuMAeV6MVyrisI8TfjO6T7qKJg==} - dependencies: - undici: 5.27.2 - dev: false - /sparse-bitfield@3.0.3: resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} requiresBuild: true @@ -1966,19 +1707,6 @@ packages: dev: false optional: true - /spotify-uri@4.0.0: - resolution: {integrity: sha512-ZAJKcnfx73glWG+3SCDRvW4nkVMzA2hqZwJtSDZ/o87EoGawh/CZ8YkqZIoVcLkg94suicEa/ZOiBFSz1MJ6Pg==} - engines: {node: '>= 16'} - dev: false - - /spotify-url-info@3.2.9: - resolution: {integrity: sha512-e/hXlXMecNKtxQLLr2MOoQD3m8VVTru+L0zQk5oTMvXhRrnIGK1JFSUqay7GNyEn8dQgBpwH/lZ5aJ3uzoU0Cw==} - engines: {node: '>= 12'} - dependencies: - himalaya: 1.1.0 - spotify-uri: 4.0.0 - dev: false - /string-to-stream@1.1.1: resolution: {integrity: sha512-QySF2+3Rwq0SdO3s7BAp4x+c3qsClpPQ6abAmb0DGViiSBAkT5kL6JT2iyzEVP+T1SmzHrQD1TwlP9QAHCc+Sw==} dependencies: @@ -2022,14 +1750,6 @@ packages: engines: {node: '>=8'} dev: true - /strtok3@6.3.0: - resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==} - engines: {node: '>=10'} - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 4.1.0 - dev: false - /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2052,24 +1772,6 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - /token-types@4.2.1: - resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==} - engines: {node: '>=10'} - dependencies: - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - dev: false - - /tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} - engines: {node: '>=6'} - dependencies: - psl: 1.9.0 - punycode: 2.3.0 - universalify: 0.2.0 - url-parse: 1.5.10 - dev: false - /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: false @@ -2112,28 +1814,12 @@ packages: '@fastify/busboy': 2.0.0 dev: false - /unfetch@5.0.0: - resolution: {integrity: sha512-3xM2c89siXg0nHvlmYsQ2zkLASvVMBisZm5lF3gFDqfF2xonNStDJyMpvaOBe0a1Edxmqrf2E0HBdmy9QyZaeg==} - dev: false - - /universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - dev: false - /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 dev: true - /url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - dev: false - /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: false @@ -2142,11 +1828,6 @@ packages: resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} dev: false - /web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} - engines: {node: '>= 8'} - dev: false - /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false @@ -2222,7 +1903,3 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true - - /youtube-sr@4.3.9: - resolution: {integrity: sha512-wPGEgVevSn32BJu5jiSHdvoryUCTCIM9LYT+yMDDpUfaev2Dh46dB+4qU31NgJ9XOsNxGlEKmc9qxUO5L0CE/Q==} - dev: false