✏️ Discord.js v14 port
This commit is contained in:
parent
c7a6bf2ec1
commit
6571e2a3c1
19 changed files with 559 additions and 3856 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -1 +1,2 @@
|
|||
* text=auto eol=lf
|
||||
*.js,*.mjs linguist-language=TypeScript
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -14,3 +14,5 @@ example/test
|
|||
example/music-bot/node_modules
|
||||
example/music-bot/package-lock.json
|
||||
example/music-bot/.env
|
||||
|
||||
dev/
|
|
@ -1,2 +0,0 @@
|
|||
# Discord Player Examples
|
||||
This section contains example bot(s) made with Discord Player.
|
|
@ -1,2 +0,0 @@
|
|||
# Music Bot
|
||||
Slash commands music bot backed by **[Discord Player](https://discord-player.js.org)**.
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = {
|
||||
token: process.env.DISCORD_TOKEN
|
||||
};
|
|
@ -1,331 +0,0 @@
|
|||
require("dotenv").config({
|
||||
path: __dirname+"/.env"
|
||||
});
|
||||
const { Client, GuildMember, Intents } = require("discord.js");
|
||||
const config = require("./config");
|
||||
const { Player, QueryType, QueueRepeatMode } = require("discord-player");
|
||||
const client = new Client({
|
||||
intents: [Intents.FLAGS.GUILD_VOICE_STATES, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILDS]
|
||||
});
|
||||
|
||||
client.on("ready", () => {
|
||||
console.log("Bot is online!");
|
||||
client.user.setActivity({
|
||||
name: "🎶 | Music Time",
|
||||
type: "LISTENING"
|
||||
});
|
||||
});
|
||||
client.on("error", console.error);
|
||||
client.on("warn", console.warn);
|
||||
|
||||
// instantiate the player
|
||||
const player = new Player(client, {
|
||||
ytdlOptions: {
|
||||
headers: {
|
||||
cookie: process.env.YT_COOKIE
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
player.on("error", (queue, error) => {
|
||||
console.log(`[${queue.guild.name}] Error emitted from the queue: ${error.message}`);
|
||||
});
|
||||
player.on("connectionError", (queue, error) => {
|
||||
console.log(`[${queue.guild.name}] Error emitted from the connection: ${error.message}`);
|
||||
});
|
||||
|
||||
player.on("trackStart", (queue, track) => {
|
||||
queue.metadata.send(`🎶 | Started playing: **${track.title}** in **${queue.connection.channel.name}**!`);
|
||||
});
|
||||
|
||||
player.on("trackAdd", (queue, track) => {
|
||||
queue.metadata.send(`🎶 | Track **${track.title}** queued!`);
|
||||
});
|
||||
|
||||
player.on("botDisconnect", (queue) => {
|
||||
queue.metadata.send("❌ | I was manually disconnected from the voice channel, clearing queue!");
|
||||
});
|
||||
|
||||
player.on("channelEmpty", (queue) => {
|
||||
queue.metadata.send("❌ | Nobody is in the voice channel, leaving...");
|
||||
});
|
||||
|
||||
player.on("queueEnd", (queue) => {
|
||||
queue.metadata.send("✅ | Queue finished!");
|
||||
});
|
||||
|
||||
client.on("messageCreate", async (message) => {
|
||||
if (message.author.bot || !message.guild) return;
|
||||
if (!client.application?.owner) await client.application?.fetch();
|
||||
|
||||
if (message.content === "!deploy" && message.author.id === client.application?.owner?.id) {
|
||||
await message.guild.commands.set([
|
||||
{
|
||||
name: "play",
|
||||
description: "Plays a song from youtube",
|
||||
options: [
|
||||
{
|
||||
name: "query",
|
||||
type: "STRING",
|
||||
description: "The song you want to play",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "soundcloud",
|
||||
description: "Plays a song from soundcloud",
|
||||
options: [
|
||||
{
|
||||
name: "query",
|
||||
type: "STRING",
|
||||
description: "The song you want to play",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "volume",
|
||||
description: "Sets music volume",
|
||||
options: [
|
||||
{
|
||||
name: "amount",
|
||||
type: "INTEGER",
|
||||
description: "The volume amount to set (0-100)",
|
||||
required: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "loop",
|
||||
description: "Sets loop mode",
|
||||
options: [
|
||||
{
|
||||
name: "mode",
|
||||
type: "INTEGER",
|
||||
description: "Loop type",
|
||||
required: true,
|
||||
choices: [
|
||||
{
|
||||
name: "Off",
|
||||
value: QueueRepeatMode.OFF
|
||||
},
|
||||
{
|
||||
name: "Track",
|
||||
value: QueueRepeatMode.TRACK
|
||||
},
|
||||
{
|
||||
name: "Queue",
|
||||
value: QueueRepeatMode.QUEUE
|
||||
},
|
||||
{
|
||||
name: "Autoplay",
|
||||
value: QueueRepeatMode.AUTOPLAY
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "skip",
|
||||
description: "Skip to the current song"
|
||||
},
|
||||
{
|
||||
name: "queue",
|
||||
description: "See the queue"
|
||||
},
|
||||
{
|
||||
name: "pause",
|
||||
description: "Pause the current song"
|
||||
},
|
||||
{
|
||||
name: "resume",
|
||||
description: "Resume the current song"
|
||||
},
|
||||
{
|
||||
name: "stop",
|
||||
description: "Stop the player"
|
||||
},
|
||||
{
|
||||
name: "np",
|
||||
description: "Now Playing"
|
||||
},
|
||||
{
|
||||
name: "bassboost",
|
||||
description: "Toggles bassboost filter"
|
||||
},
|
||||
{
|
||||
name: "ping",
|
||||
description: "Shows bot latency"
|
||||
}
|
||||
]);
|
||||
|
||||
await message.reply("Deployed!");
|
||||
}
|
||||
});
|
||||
|
||||
client.on("interactionCreate", async (interaction) => {
|
||||
if (!interaction.isCommand() || !interaction.guildId) return;
|
||||
|
||||
if (interaction.commandName === "ping") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guild);
|
||||
|
||||
return void interaction.followUp({
|
||||
embeds: [
|
||||
{
|
||||
title: "⏱️ | Latency",
|
||||
fields: [
|
||||
{ name: "Bot Latency", value: `\`${Math.round(client.ws.ping)}ms\`` },
|
||||
{ name: "Voice Latency", value: !queue ? "N/A" : `UDP: \`${queue.connection.voiceConnection.ping.udp ?? "N/A"}\`ms\nWebSocket: \`${queue.connection.voiceConnection.ping.ws ?? "N/A"}\`ms` }
|
||||
],
|
||||
color: 0xFFFFFF
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (!(interaction.member instanceof GuildMember) || !interaction.member.voice.channel) {
|
||||
return void interaction.reply({ content: "You are not in a voice channel!", ephemeral: true });
|
||||
}
|
||||
|
||||
if (interaction.guild.me.voice.channelId && interaction.member.voice.channelId !== interaction.guild.me.voice.channelId) {
|
||||
return void interaction.reply({ content: "You are not in my voice channel!", ephemeral: true });
|
||||
}
|
||||
|
||||
if (interaction.commandName === "play" || interaction.commandName === "soundcloud") {
|
||||
await interaction.deferReply();
|
||||
|
||||
const query = interaction.options.get("query").value;
|
||||
const searchResult = await player
|
||||
.search(query, {
|
||||
requestedBy: interaction.user,
|
||||
searchEngine: interaction.commandName === "soundcloud" ? QueryType.SOUNDCLOUD_SEARCH : QueryType.AUTO
|
||||
})
|
||||
.catch(() => {});
|
||||
if (!searchResult || !searchResult.tracks.length) return void interaction.followUp({ content: "No results were found!" });
|
||||
|
||||
const queue = await player.createQueue(interaction.guild, {
|
||||
metadata: interaction.channel
|
||||
});
|
||||
|
||||
try {
|
||||
if (!queue.connection) await queue.connect(interaction.member.voice.channel);
|
||||
} catch {
|
||||
void player.deleteQueue(interaction.guildId);
|
||||
return void interaction.followUp({ content: "Could not join your voice channel!" });
|
||||
}
|
||||
|
||||
await interaction.followUp({ content: `⏱ | Loading your ${searchResult.playlist ? "playlist" : "track"}...` });
|
||||
searchResult.playlist ? queue.addTracks(searchResult.tracks) : queue.addTrack(searchResult.tracks[0]);
|
||||
if (!queue.playing) await queue.play();
|
||||
} else if (interaction.commandName === "volume") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const vol = interaction.options.get("amount");
|
||||
if (!vol) return void interaction.followUp({ content: `🎧 | Current volume is **${queue.volume}**%!` });
|
||||
if ((vol.value) < 0 || (vol.value) > 100) return void interaction.followUp({ content: "❌ | Volume range must be 0-100" });
|
||||
const success = queue.setVolume(vol.value);
|
||||
return void interaction.followUp({
|
||||
content: success ? `✅ | Volume set to **${vol.value}%**!` : "❌ | Something went wrong!"
|
||||
});
|
||||
} else if (interaction.commandName === "skip") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const currentTrack = queue.current;
|
||||
const success = queue.skip();
|
||||
return void interaction.followUp({
|
||||
content: success ? `✅ | Skipped **${currentTrack}**!` : "❌ | Something went wrong!"
|
||||
});
|
||||
} else if (interaction.commandName === "queue") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const currentTrack = queue.current;
|
||||
const tracks = queue.tracks.slice(0, 10).map((m, i) => {
|
||||
return `${i + 1}. **${m.title}** ([link](${m.url}))`;
|
||||
});
|
||||
|
||||
return void interaction.followUp({
|
||||
embeds: [
|
||||
{
|
||||
title: "Server Queue",
|
||||
description: `${tracks.join("\n")}${
|
||||
queue.tracks.length > tracks.length
|
||||
? `\n...${queue.tracks.length - tracks.length === 1 ? `${queue.tracks.length - tracks.length} more track` : `${queue.tracks.length - tracks.length} more tracks`}`
|
||||
: ""
|
||||
}`,
|
||||
color: 0xff0000,
|
||||
fields: [{ name: "Now Playing", value: `🎶 | **${currentTrack.title}** ([link](${currentTrack.url}))` }]
|
||||
}
|
||||
]
|
||||
});
|
||||
} else if (interaction.commandName === "pause") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const paused = queue.setPaused(true);
|
||||
return void interaction.followUp({ content: paused ? "⏸ | Paused!" : "❌ | Something went wrong!" });
|
||||
} else if (interaction.commandName === "resume") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const paused = queue.setPaused(false);
|
||||
return void interaction.followUp({ content: !paused ? "❌ | Something went wrong!" : "▶ | Resumed!" });
|
||||
} else if (interaction.commandName === "stop") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
queue.destroy();
|
||||
return void interaction.followUp({ content: "🛑 | Stopped the player!" });
|
||||
} else if (interaction.commandName === "np") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const progress = queue.createProgressBar();
|
||||
const perc = queue.getPlayerTimestamp();
|
||||
|
||||
return void interaction.followUp({
|
||||
embeds: [
|
||||
{
|
||||
title: "Now Playing",
|
||||
description: `🎶 | **${queue.current.title}**! (\`${perc.progress}%\`)`,
|
||||
fields: [
|
||||
{
|
||||
name: "\u200b",
|
||||
value: progress
|
||||
}
|
||||
],
|
||||
color: 0xffffff
|
||||
}
|
||||
]
|
||||
});
|
||||
} else if (interaction.commandName === "loop") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
const loopMode = interaction.options.get("mode").value;
|
||||
const success = queue.setRepeatMode(loopMode);
|
||||
const mode = loopMode === QueueRepeatMode.TRACK ? "🔂" : loopMode === QueueRepeatMode.QUEUE ? "🔁" : "▶";
|
||||
return void interaction.followUp({ content: success ? `${mode} | Updated loop mode!` : "❌ | Could not update loop mode!" });
|
||||
} else if (interaction.commandName === "bassboost") {
|
||||
await interaction.deferReply();
|
||||
const queue = player.getQueue(interaction.guildId);
|
||||
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
|
||||
await queue.setFilters({
|
||||
bassboost: !queue.getFiltersEnabled().includes("bassboost"),
|
||||
normalizer2: !queue.getFiltersEnabled().includes("bassboost") // because we need to toggle it with bass
|
||||
});
|
||||
|
||||
return void interaction.followUp({ content: `🎵 | Bassboost ${queue.getFiltersEnabled().includes("bassboost") ? "Enabled" : "Disabled"}!` });
|
||||
} else {
|
||||
interaction.reply({
|
||||
content: "Unknown command!",
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
client.login(config.token);
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"name": "music-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "Simple music bot created with discord-player",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
},
|
||||
"author": "Snowflake107",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@discordjs/opus": "^0.5.3",
|
||||
"discord-player": "^5.2.1",
|
||||
"discord.js": "^13.0.1",
|
||||
"dotenv": "^10.0.0"
|
||||
}
|
||||
}
|
17
jsdoc.json
17
jsdoc.json
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"source": {
|
||||
"includePattern": ".+\\.ts(doc|x)?$"
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown",
|
||||
"node_modules/jsdoc-babel"
|
||||
],
|
||||
"babel": {
|
||||
"extensions": ["ts"],
|
||||
"babelrc": false,
|
||||
"presets": [
|
||||
["@babel/preset-env", { "targets": { "node": true } }],
|
||||
"@babel/preset-typescript"
|
||||
]
|
||||
}
|
||||
}
|
55
package.json
55
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "discord-player",
|
||||
"version": "5.2.2",
|
||||
"version": "6.0.0-dev",
|
||||
"description": "Complete framework to facilitate music commands using discord.js",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
@ -23,9 +23,9 @@
|
|||
"build:check": "tsc --noEmit --incremental false",
|
||||
"prepublishOnly": "rollup-type-bundler -e stream",
|
||||
"build:esm": "gen-esm-wrapper ./dist/index.js ./dist/index.mjs",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"example/**/*.ts\"",
|
||||
"docs": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml --output docs/docs.json",
|
||||
"docs:test": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml",
|
||||
"format": "prettier --write \"src/**/*.ts\"",
|
||||
"docs": "typedoc --json docs/typedoc.json src/index.ts",
|
||||
"postdocs": "node scripts/docgen.js",
|
||||
"lint": "eslint src --ext .ts",
|
||||
"prepare": "husky install",
|
||||
"lint:fix": "eslint src --ext .ts --fix"
|
||||
|
@ -65,37 +65,32 @@
|
|||
},
|
||||
"homepage": "https://discord-player.js.org",
|
||||
"dependencies": {
|
||||
"@discordjs/voice": "^0.8.0",
|
||||
"@discordjs/voice": "^0.10.0",
|
||||
"discord-ytdl-core": "^5.0.4",
|
||||
"libsodium-wrappers": "^0.7.9",
|
||||
"libsodium-wrappers": "^0.7.10",
|
||||
"soundcloud-scraper": "^5.0.2",
|
||||
"spotify-url-info": "^2.2.5",
|
||||
"tiny-typed-emitter": "^2.1.0",
|
||||
"youtube-sr": "^4.1.13",
|
||||
"ytdl-core": "^4.10.0"
|
||||
"spotify-url-info": "^3.1.2",
|
||||
"tslib": "^2.4.0",
|
||||
"youtube-sr": "^4.1.17",
|
||||
"ytdl-core": "^4.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.16.0",
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/preset-env": "^7.16.4",
|
||||
"@babel/preset-typescript": "^7.16.0",
|
||||
"@devsnowflake/docgen": "devsnowflake/docgen#ts-patch",
|
||||
"@discord-player/extractor": "^3.0.2",
|
||||
"@discordjs/opus": "github:discordjs/opus",
|
||||
"@favware/rollup-type-bundler": "^1.0.6",
|
||||
"@types/node": "^16.11.10",
|
||||
"@types/ws": "^8.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"discord-api-types": "^0.24.0",
|
||||
"discord.js": "^13.6.0",
|
||||
"eslint": "^8.3.0",
|
||||
"@discordjs/ts-docgen": "^0.4.1",
|
||||
"@favware/rollup-type-bundler": "^1.0.7",
|
||||
"@types/node": "^17.0.43",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||
"@typescript-eslint/parser": "^5.28.0",
|
||||
"discord-api-types": "^0.34.0",
|
||||
"discord.js": "^14.0.0-dev.1655165434-b4e28a8",
|
||||
"eslint": "^8.17.0",
|
||||
"gen-esm-wrapper": "^1.1.3",
|
||||
"husky": "^7.0.4",
|
||||
"jsdoc-babel": "^0.5.0",
|
||||
"prettier": "^2.5.0",
|
||||
"husky": "^8.0.1",
|
||||
"opusscript": "^0.0.8",
|
||||
"prettier": "^2.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^4.5.2"
|
||||
"ts-node": "^10.8.1",
|
||||
"typedoc": "^0.22.17",
|
||||
"typescript": "^4.7.3"
|
||||
}
|
||||
}
|
||||
|
|
11
scripts/docgen.js
Normal file
11
scripts/docgen.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* eslint-disable */
|
||||
const { runGenerator } = require("@discordjs/ts-docgen");
|
||||
const fs = require("node:fs");
|
||||
|
||||
runGenerator({
|
||||
existingOutput: "docs/typedoc.json",
|
||||
custom: "docs/config.yml",
|
||||
output: "docs/docs.json"
|
||||
});
|
||||
|
||||
fs.unlinkSync(`${__dirname}/../docs/typedoc.json`);
|
|
@ -1,4 +1,4 @@
|
|||
import { Client, Collection, GuildResolvable, Snowflake, User, VoiceState, Intents } from "discord.js";
|
||||
import { Client, Collection, GuildResolvable, Snowflake, User, VoiceState, IntentsBitField } from "discord.js";
|
||||
import { TypedEmitter as EventEmitter } from "tiny-typed-emitter";
|
||||
import { Queue } from "./Structures/Queue";
|
||||
import { VoiceUtils } from "./VoiceInterface/VoiceUtils";
|
||||
|
@ -45,8 +45,8 @@ class Player extends EventEmitter<PlayerEvents> {
|
|||
*/
|
||||
this.client = client;
|
||||
|
||||
if (this.client?.options?.intents && !new Intents(this.client?.options?.intents).has(Intents.FLAGS.GUILD_VOICE_STATES)) {
|
||||
throw new PlayerError('client is missing "GUILD_VOICE_STATES" intent');
|
||||
if (this.client?.options?.intents && !new IntentsBitField(this.client?.options?.intents).has(IntentsBitField.Flags.GuildVoiceStates)) {
|
||||
throw new PlayerError('client is missing "GuildVoiceStates" intent');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,8 +78,8 @@ class Player extends EventEmitter<PlayerEvents> {
|
|||
if (!queue) return;
|
||||
|
||||
if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId) {
|
||||
if (queue?.connection && newState.member.id === newState.guild.me.id) queue.connection.channel = newState.channel;
|
||||
if (newState.member.id === newState.guild.me.id || (newState.member.id !== newState.guild.me.id && oldState.channelId === queue.connection.channel.id)) {
|
||||
if (queue?.connection && newState.member.id === newState.guild.members.me.id) queue.connection.channel = newState.channel;
|
||||
if (newState.member.id === newState.guild.members.me.id || (newState.member.id !== newState.guild.members.me.id && oldState.channelId === queue.connection.channel.id)) {
|
||||
if (!Util.isVoiceEmpty(queue.connection.channel)) return;
|
||||
const timeout = setTimeout(() => {
|
||||
if (!Util.isVoiceEmpty(queue.connection.channel)) return;
|
||||
|
@ -90,20 +90,20 @@ class Player extends EventEmitter<PlayerEvents> {
|
|||
queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
|
||||
}
|
||||
|
||||
if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.me.id) {
|
||||
if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.members.me.id) {
|
||||
if (newState.serverMute || !newState.serverMute) {
|
||||
queue.setPaused(newState.serverMute);
|
||||
} else if (newState.suppress || !newState.suppress) {
|
||||
if (newState.suppress) newState.guild.me.voice.setRequestToSpeak(true).catch(Util.noop);
|
||||
if (newState.suppress) newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util.noop);
|
||||
queue.setPaused(newState.suppress);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldState.channelId === newState.channelId && oldState.member.id === newState.guild.me.id) {
|
||||
if (oldState.channelId === newState.channelId && oldState.member.id === newState.guild.members.me.id) {
|
||||
if (oldState.serverMute !== newState.serverMute) {
|
||||
queue.setPaused(newState.serverMute);
|
||||
} else if (oldState.suppress !== newState.suppress) {
|
||||
if (newState.suppress) newState.guild.me.voice.setRequestToSpeak(true).catch(Util.noop);
|
||||
if (newState.suppress) newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util.noop);
|
||||
queue.setPaused(newState.suppress);
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ class Player extends EventEmitter<PlayerEvents> {
|
|||
return { playlist: null, tracks: res };
|
||||
}
|
||||
case QueryType.SPOTIFY_SONG: {
|
||||
const spotifyData = await Spotify.getData(query).catch(Util.noop);
|
||||
const spotifyData = await Spotify(Util.getFetch()).getData(query).catch(Util.noop);
|
||||
if (!spotifyData) return { playlist: null, tracks: [] };
|
||||
const spotifyTrack = new Track(this, {
|
||||
title: spotifyData.name,
|
||||
|
@ -359,7 +359,9 @@ class Player extends EventEmitter<PlayerEvents> {
|
|||
}
|
||||
case QueryType.SPOTIFY_PLAYLIST:
|
||||
case QueryType.SPOTIFY_ALBUM: {
|
||||
const spotifyPlaylist = await Spotify.getData(query).catch(Util.noop);
|
||||
const spotifyPlaylist = await Spotify(await Util.getFetch())
|
||||
.getData(query)
|
||||
.catch(Util.noop);
|
||||
if (!spotifyPlaylist) return { playlist: null, tracks: [] };
|
||||
|
||||
const playlist = new Playlist(this, {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Collection, Guild, StageChannel, VoiceChannel, Snowflake, SnowflakeUtil, GuildChannelResolvable } from "discord.js";
|
||||
import { Collection, Guild, StageChannel, VoiceChannel, SnowflakeUtil, GuildChannelResolvable, ChannelType } from "discord.js";
|
||||
import { Player } from "../Player";
|
||||
import { StreamDispatcher } from "../VoiceInterface/StreamDispatcher";
|
||||
import Track from "./Track";
|
||||
|
@ -22,7 +22,7 @@ class Queue<T = unknown> {
|
|||
public playing = false;
|
||||
public metadata?: T = null;
|
||||
public repeatMode: QueueRepeatMode = 0;
|
||||
public readonly id: Snowflake = SnowflakeUtil.generate();
|
||||
public readonly id = SnowflakeUtil.generate().toString();
|
||||
private _streamTime = 0;
|
||||
public _cooldownsTimeout = new Collection<string, NodeJS.Timeout>();
|
||||
private _activeFilters: any[] = []; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
@ -152,16 +152,16 @@ class Queue<T = unknown> {
|
|||
async connect(channel: GuildChannelResolvable) {
|
||||
if (this.#watchDestroyed()) return;
|
||||
const _channel = this.guild.channels.resolve(channel) as StageChannel | VoiceChannel;
|
||||
if (!["GUILD_STAGE_VOICE", "GUILD_VOICE"].includes(_channel?.type))
|
||||
throw new PlayerError(`Channel type must be GUILD_VOICE or GUILD_STAGE_VOICE, got ${_channel?.type}!`, ErrorStatusCode.INVALID_ARG_TYPE);
|
||||
if (![ChannelType.GuildStageVoice, ChannelType.GuildVoice].includes(_channel?.type))
|
||||
throw new PlayerError(`Channel type must be GuildVoice or GuildStageVoice, got ${_channel?.type}!`, ErrorStatusCode.INVALID_ARG_TYPE);
|
||||
const connection = await this.player.voiceUtils.connect(_channel, {
|
||||
deaf: this.options.autoSelfDeaf
|
||||
});
|
||||
this.connection = connection;
|
||||
|
||||
if (_channel.type === "GUILD_STAGE_VOICE") {
|
||||
await _channel.guild.me.voice.setSuppressed(false).catch(async () => {
|
||||
return await _channel.guild.me.voice.setRequestToSpeak(true).catch(Util.noop);
|
||||
if (_channel.type === ChannelType.GuildStageVoice) {
|
||||
await _channel.guild.members.me.voice.setSuppressed(false).catch(async () => {
|
||||
return await _channel.guild.members.me.voice.setRequestToSpeak(true).catch(Util.noop);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -473,10 +473,10 @@ class Queue<T = unknown> {
|
|||
|
||||
/**
|
||||
* Removes a track from the queue
|
||||
* @param {Track|Snowflake|number} track The track to remove
|
||||
* @param {Track|string|number} track The track to remove
|
||||
* @returns {Track}
|
||||
*/
|
||||
remove(track: Track | Snowflake | number) {
|
||||
remove(track: Track | string | number) {
|
||||
if (this.#watchDestroyed()) return;
|
||||
let trackFound: Track = null;
|
||||
if (typeof track === "number") {
|
||||
|
@ -496,10 +496,10 @@ class Queue<T = unknown> {
|
|||
|
||||
/**
|
||||
* Returns the index of the specified track. If found, returns the track index else returns -1.
|
||||
* @param {number|Track|Snowflake} track The track
|
||||
* @param {number|Track|string} track The track
|
||||
* @returns {number}
|
||||
*/
|
||||
getTrackPosition(track: number | Track | Snowflake) {
|
||||
getTrackPosition(track: number | Track | string) {
|
||||
if (this.#watchDestroyed()) return;
|
||||
if (typeof track === "number") return this.tracks[track] != null ? track : -1;
|
||||
return this.tracks.findIndex((pred) => pred.id === (track instanceof Track ? track.id : track));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { User, Util, SnowflakeUtil, Snowflake } from "discord.js";
|
||||
import { User, escapeMarkdown, SnowflakeUtil } from "discord.js";
|
||||
import { Player } from "../Player";
|
||||
import { RawTrackData, TrackJSON } from "../types/types";
|
||||
import { Playlist } from "./Playlist";
|
||||
|
@ -16,7 +16,7 @@ class Track {
|
|||
public requestedBy!: User;
|
||||
public playlist?: Playlist;
|
||||
public readonly raw: RawTrackData = {} as RawTrackData;
|
||||
public readonly id: Snowflake = SnowflakeUtil.generate();
|
||||
public readonly id = SnowflakeUtil.generate().toString();
|
||||
|
||||
/**
|
||||
* Track constructor
|
||||
|
@ -109,7 +109,7 @@ class Track {
|
|||
}
|
||||
|
||||
private _patch(data: RawTrackData) {
|
||||
this.title = Util.escapeMarkdown(data.title ?? "");
|
||||
this.title = escapeMarkdown(data.title ?? "");
|
||||
this.author = data.author ?? "";
|
||||
this.url = data.url ?? "";
|
||||
this.thumbnail = data.thumbnail ?? "";
|
||||
|
|
|
@ -68,6 +68,7 @@ class StreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
*/
|
||||
this.paused = false;
|
||||
|
||||
// @ts-expect-error ???
|
||||
this.voiceConnection.on("stateChange", async (_, newState) => {
|
||||
if (newState.status === VoiceConnectionStatus.Disconnected) {
|
||||
if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
|
||||
|
@ -110,6 +111,7 @@ class StreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
}
|
||||
});
|
||||
|
||||
// @ts-expect-error ???
|
||||
this.audioPlayer.on("stateChange", (oldState, newState) => {
|
||||
if (newState.status === AudioPlayerStatus.Playing) {
|
||||
if (!this.paused) return void this.emit("start", this.audioResource);
|
||||
|
|
|
@ -95,6 +95,15 @@ class Util {
|
|||
}
|
||||
|
||||
static noop() {} // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
|
||||
static async getFetch() {
|
||||
if ("fetch" in globalThis) return globalThis.fetch;
|
||||
try {
|
||||
return await import("undici").then((res) => res.default);
|
||||
} catch {
|
||||
// uh?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Util };
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.js"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
|
|
Loading…
Reference in a new issue