add basic play command
Marco Andronaco andronacomarco@gmail.com
Sun, 22 Jan 2023 19:59:34 +0100
3 files changed,
205 insertions(+),
3 deletions(-)
A
commands/play.js
@@ -0,0 +1,112 @@
+const path = require("node:path"); +const { SlashCommandBuilder } = require("discord.js"); +const { + createAudioResource, + createAudioPlayer, + joinVoiceChannel, + NoSubscriberBehavior, + AudioPlayerStatus, +} = require("@discordjs/voice"); + +const ytdl = require("ytdl-core"); +const ytsr = require("ytsr"); + +async function reply_efemeral(interaction, reply) { + return await interaction.reply({ content: reply, ephemeral: true }); +} + +function get_player(resource) { + const player = createAudioPlayer({ + behaviors: { noSubscriber: NoSubscriberBehavior.Pause }, + }); + player.on("error", (error) => + console.error( + `Error: ${error.message} with resource ${error.resource.metadata.title}` + ) + ); + player.on(AudioPlayerStatus.Idle, () => { + player.stop(); + player.subscribers.forEach((element) => element.connection.disconnect()); + }); + + player.play(createAudioResource(resource)); + return player; +} + +module.exports = { + data: new SlashCommandBuilder() + .setName("play") + .setDescription("Play something off YouTube.") + .addStringOption((option) => + option + .setName("query") + .setDescription("YouTube URL or search query") + .setRequired(true) + ), + + async execute(interaction) { + const member = interaction.member; + if (!member) + return await reply_efemeral( + interaction, + "Please use this in your current server." + ); + + const user_connection = member.voice; + const channel = user_connection.channel; + if (!channel) + return await reply_efemeral( + interaction, + "You're not in a voice channel." + ); + + const guild = channel.guild; + + // Get the YouTube URL or search query + const url = interaction.options.getString("query"); + + // If the URL is not a valid YouTube URL, treat it as a search query and try to get the first result + + if (!ytdl.validateURL(url)) { + return await reply_efemeral(interaction, "This bot only supports URLs (for now)."); + try { + const searchResults = await ytsr(url); + results = searchResults.items; + + url = null + for(result in results){ + if (result.type == "video"){ + url = result.url; + console.log("Using", url) + break; + } + } + if(url == null) { + console.log("No results found"); + throw new Error("No results found"); + } + } catch (error) { + return await reply_efemeral( + interaction, + `Invalid YouTube URL or search query! ${error}` + ); + } + } + + const stream = ytdl(url, { + filter: "audioonly", + opusEncoded: true, + encoderArgs: ["-af", "bass=g=10,dynaudnorm=f=200"], + }); + + // Connect to the user's voice channel + const connection = joinVoiceChannel({ + channelId: channel.id, + guildId: guild.id, + adapterCreator: guild.voiceAdapterCreator, + }); + + connection.subscribe(get_player(stream)); + return await reply_efemeral(interaction, `Playing.`); + }, +};
M
package-lock.json
→
package-lock.json
@@ -12,7 +12,9 @@ "dependencies": {
"@discordjs/rest": "^1.1.0", "@discordjs/voice": "^0.11.0", "discord.js": "^14.3.0", - "libsodium-wrappers": "^0.7.10" + "libsodium-wrappers": "^0.7.10", + "ytdl-core": "^4.11.2", + "ytsr": "^3.8.0" }, "devDependencies": { "eslint": "^8.23.1"@@ -1052,6 +1054,18 @@ "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" }, + "node_modules/m3u8stream": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz", + "integrity": "sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==", + "dependencies": { + "miniget": "^4.2.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",@@ -1072,6 +1086,14 @@ "picomatch": "^2.3.1"
}, "engines": { "node": ">=8.6" + } + }, + "node_modules/miniget": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.2.tgz", + "integrity": "sha512-a7voNL1N5lDMxvTMExOkg+Fq89jM2vY8pAi9ZEWzZtfNmdfP6RXkvUtFnCAXoCv2T9k1v/fUJVaAEuepGcvLYA==", + "engines": { + "node": ">=12" } }, "node_modules/minimatch": {@@ -1405,6 +1427,11 @@ "url": "https://feross.org/support"
} ] }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",@@ -1646,6 +1673,30 @@ },
"funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/ytdl-core": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.11.2.tgz", + "integrity": "sha512-D939t9b4ZzP3v0zDvehR2q+KgG97UTgrTKju3pOPGQcXtl4W6W5z0EpznzcJFu+OOpl7S7Ge8hv8zU65QnxYug==", + "dependencies": { + "m3u8stream": "^0.8.6", + "miniget": "^4.2.2", + "sax": "^1.1.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ytsr": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ytsr/-/ytsr-3.8.0.tgz", + "integrity": "sha512-R+RfYXvBBMAr2e4OxrQ5SBv5x/Mdhmcj1Q8TH0f2HK5d2jbhHOtK4BdzPvLriA6MDoMwqqX04GD8Rpf9UNtSTg==", + "dependencies": { + "miniget": "^4.2.2" + }, + "engines": { + "node": ">=8" + } } }, "dependencies": {@@ -2428,6 +2479,15 @@ "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" }, + "m3u8stream": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz", + "integrity": "sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==", + "requires": { + "miniget": "^4.2.2", + "sax": "^1.2.4" + } + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",@@ -2443,6 +2503,11 @@ "requires": {
"braces": "^3.0.2", "picomatch": "^2.3.1" } + }, + "miniget": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.2.tgz", + "integrity": "sha512-a7voNL1N5lDMxvTMExOkg+Fq89jM2vY8pAi9ZEWzZtfNmdfP6RXkvUtFnCAXoCv2T9k1v/fUJVaAEuepGcvLYA==" }, "minimatch": { "version": "3.1.2",@@ -2632,6 +2697,11 @@ "safe-buffer": {
"version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "shebang-command": { "version": "2.0.0",@@ -2795,6 +2865,24 @@ "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "ytdl-core": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.11.2.tgz", + "integrity": "sha512-D939t9b4ZzP3v0zDvehR2q+KgG97UTgrTKju3pOPGQcXtl4W6W5z0EpznzcJFu+OOpl7S7Ge8hv8zU65QnxYug==", + "requires": { + "m3u8stream": "^0.8.6", + "miniget": "^4.2.2", + "sax": "^1.1.3" + } + }, + "ytsr": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ytsr/-/ytsr-3.8.0.tgz", + "integrity": "sha512-R+RfYXvBBMAr2e4OxrQ5SBv5x/Mdhmcj1Q8TH0f2HK5d2jbhHOtK4BdzPvLriA6MDoMwqqX04GD8Rpf9UNtSTg==", + "requires": { + "miniget": "^4.2.2" + } } } }
M
package.json
→
package.json
@@ -9,10 +9,12 @@ },
"author": "", "license": "ISC", "dependencies": { - "@discordjs/voice": "^0.11.0", "@discordjs/rest": "^1.1.0", + "@discordjs/voice": "^0.11.0", "discord.js": "^14.3.0", - "libsodium-wrappers": "^0.7.10" + "libsodium-wrappers": "^0.7.10", + "ytdl-core": "^4.11.2", + "ytsr": "^3.8.0" }, "devDependencies": { "eslint": "^8.23.1"