all repos — simple-discord-music-bot @ 61364f5fe32e6420a82abd998c4a0baa264184e0

A Discord bot making use of discord.js and play-yt.

better code reuse and storage efficiency
Bi-Rabittoh andronacomarco@gmail.com
Mon, 23 Jan 2023 13:24:14 +0100
commit

61364f5fe32e6420a82abd998c4a0baa264184e0

parent

f47db6558591aa10292c163eeb24ceed1becab50

9 files changed, 79 insertions(+), 82 deletions(-)

jump to
M commands/outro.jscommands/outro.js

@@ -1,30 +1,14 @@

-const path = require('node:path'); const { SlashCommandBuilder } = require('discord.js'); -const { createAudioResource, createAudioPlayer, joinVoiceChannel, NoSubscriberBehavior, AudioPlayerStatus } = require('@discordjs/voice'); +const { playUrl, getChannel } = require("../functions/music"); const outros = [ { name: 'Random!', value: 'random' }, - { name: 'TheFatRat - Xenogenesis', value: 'thefatrat_xenogenesis.mp3' }, - { name: 'OMFG - Hello', value: 'omfg_hello.mp3' }, - { name: 'Pegboard Nerds - Disconnected', value: 'pegboard_nerds_disconnected.mp3' }, - { name: 'Gym Class Heroes - Stereo Hearts', value: 'gym_class_heroes_stereo_hearts.mp3' }, + { name: 'TheFatRat - Xenogenesis', value: 'https://www.youtube.com/watch?v=6N8zvi1VNSc' }, + { name: 'OMFG - Hello', value: 'https://www.youtube.com/watch?v=5nYVNTX0Ib8' }, + { name: 'Pegboard Nerds - Disconnected', value: 'https://www.youtube.com/watch?v=YdBtx8qG68w' }, + { name: 'Gym Class Heroes - Stereo Hearts', value: 'https://www.youtube.com/watch?v=ThctmvQ3NGk' }, ]; -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('outro')

@@ -41,15 +25,10 @@ .setRequired(false)

.addChoices({ name: 'Yes', value: 'true' }, { name: 'No', value: 'false' })), 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; - const bot_connection = joinVoiceChannel({ channelId: channel.id, guildId: guild.id, adapterCreator: guild.voiceAdapterCreator }); + + channel = await getChannel(interaction); + if (typeof channel == "string") + return await interaction.reply({ content: channel, ephemeral: true }); const outro = interaction.options.getString('which'); const kick = interaction.options.getString('kick');

@@ -58,15 +37,13 @@ let outro_file = outro ? outro : 'random';

if (outro_file == 'random') outro_file = outros[Math.floor(Math.random() * (outros.length - 1)) + 1].value; - const song_path = path.join(process.cwd(), 'resources', outro_file); - const outro_title = outros.find(element => element.value == outro_file).name; - bot_connection.subscribe(get_player(song_path)); + await playUrl(outro_file, channel); const kick_switch = kick ? kick : 'true'; if (kick_switch == 'true') { - setTimeout(() => user_connection.disconnect(), 20_000); - return await reply_efemeral(interaction, `Prepare for takeoff with ${outro_title}!`); + setTimeout(() => interaction.member.voice.disconnect(), 20_000); + return await interaction.reply({ content: `Prepare for takeoff!`, ephemeral: true }); } - return await reply_efemeral(interaction, `Playing ${outro_title}.`); + return await interaction.reply({ content: `Playing outro.`, ephemeral: true }); }, };
M commands/play.jscommands/play.js

@@ -1,14 +1,6 @@

-const path = require("node:path"); const { SlashCommandBuilder } = require("discord.js"); -const { - createAudioResource, - createAudioPlayer, - joinVoiceChannel, - NoSubscriberBehavior, - AudioPlayerStatus, -} = require("@discordjs/voice"); - -const play = require('play-dl') +const play = require('play-dl'); +const { playUrl, getChannel } = require("../functions/music"); //const reg = /^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube(-nocookie)?\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/;

@@ -23,18 +15,12 @@ .setRequired(true)

), async execute(interaction) { - const member = interaction.member; - if (!member) - return await interaction.reply({ content: "Please use this in your current server.", ephemeral: true }); - - const user_connection = member.voice; - const channel = user_connection.channel; - - if (!channel) - return await interaction.reply({ content: "You're not in a voice channel.", ephemeral: true }); + + channel = await getChannel(interaction); + if (typeof channel == "string") + return await interaction.reply({ content: channel, ephemeral: true }); await interaction.deferReply(); - const guild = channel.guild; // Get the YouTube URL or search query let url = interaction.options.getString("query");

@@ -57,30 +43,8 @@

default: return await interaction.editReply(`Not supported.`); } - let stream = await play.stream(video.url); - // Connect to the user's voice channel - const connection = joinVoiceChannel({ - channelId: channel.id, - guildId: guild.id, - adapterCreator: guild.voiceAdapterCreator, - }); - - let resource = createAudioResource(stream.stream, { - inputType: stream.type - }) - - player = createAudioPlayer({ - behaviors: { noSubscriber: NoSubscriberBehavior.Play } - }); - - player.on(AudioPlayerStatus.Idle, () => { - player.stop(); - player.subscribers.forEach((element) => element.connection.disconnect()); - }); - - player.play(resource); - connection.subscribe(player); + playUrl(video.url, channel); return await interaction.editReply(`Playing ${video.url}`); }, };
M config.json.exampleconfig.json.example

@@ -1,3 +1,4 @@

{ - "token": "your-token-goes-here" + "clientId": "your-client-id-here", + "token": "your-token-here" }
A functions/music.js

@@ -0,0 +1,56 @@

+const { + createAudioResource, + createAudioPlayer, + joinVoiceChannel, + NoSubscriberBehavior, + AudioPlayerStatus, +} = require("@discordjs/voice"); +const play = require('play-dl'); + +module.exports = { + async playUrl(url, channel) { + if(!channel){ + console.log("Channel error:", channel); + return; + } + let stream = await play.stream(url); + + // Connect to the user's voice channel + const guild = channel.guild; + + const connection = joinVoiceChannel({ + channelId: channel.id, + guildId: guild.id, + adapterCreator: guild.voiceAdapterCreator, + }); + + let resource = createAudioResource(stream.stream, { + inputType: stream.type + }) + + player = createAudioPlayer({ + behaviors: { noSubscriber: NoSubscriberBehavior.Play } + }); + + player.on(AudioPlayerStatus.Idle, () => { + player.stop(); + player.subscribers.forEach((element) => element.connection.disconnect()); + }); + + player.play(resource); + connection.subscribe(player); + }, + async getChannel(interaction) { + + const member = interaction.member; + if (!member) + return "Please use this in your current server."; + + const channel = member.voice.channel; + + if (!channel) + return "You're not in a voice channel."; + + return channel + } +};
M index.jsindex.js

@@ -9,7 +9,7 @@ client.commands = new Collection();

const commandsPath = path.join(__dirname, 'commands'); const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); -var player; +let player; for (const file of commandFiles) { const filePath = path.join(commandsPath, file);

@@ -31,7 +31,6 @@

client.once('ready', () => { const random = Math.floor(Math.random() * (activities.length)); const choice = activities[random]; - client.user.setActivity(choice.subject, { type: choice.activity }); console.log('Bot online!'); });