all repos — simple-discord-music-bot @ ee48e4f6561bef07c4fda9326fd805761a0030fd

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

add some types
Bi-Rabittoh andronacomarco@gmail.com
Tue, 09 Jan 2024 01:34:02 +0100
commit

ee48e4f6561bef07c4fda9326fd805761a0030fd

parent

9028915a52f199d9c710a9cf35f8903433faec88

M .vscode/launch.json.vscode/launch.json

@@ -7,7 +7,13 @@ "configurations": [

{ "type": "node", "request": "launch", - "name": "Launch Program", + "name": "Launch", + "program": "${workspaceFolder}/build/index.js", + }, + { + "type": "node", + "request": "launch", + "name": "Build & launch", "program": "${workspaceFolder}/src/index.ts", "preLaunchTask": "tsc: build - tsconfig.json", "outFiles": ["${workspaceFolder}/build/**/*.js"]
M src/commands/clear.tssrc/commands/clear.ts

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

-import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import * as music from '../functions/music'; module.exports = {

@@ -6,7 +6,7 @@ data: new SlashCommandBuilder()

.setName('clear') .setDescription('Clear the queue.'), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await music.getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true });
M src/commands/outro.tssrc/commands/outro.ts

@@ -1,9 +1,9 @@

-import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import { playOutro, getChannel } from '../functions/music'; import path from 'node:path'; const { outros } = require(path.join(process.cwd(), 'config.json')); -function getOutroUrl(outro) { +function getOutroUrl(outro: string): string { if (outro) return outro; const randomIndex = Math.floor(Math.random() * (outros.length)); return outros[randomIndex].value;

@@ -24,7 +24,7 @@ .setDescription('Do you actually want to log off?')

.setRequired(false) .addChoices({ name: 'Yes', value: 'true' }, { name: 'No', value: 'false' })), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true });

@@ -35,7 +35,9 @@ const outroUrl = getOutroUrl(outro);

await playOutro(outroUrl, channel); if (kick !== 'false') { - setTimeout(() => interaction.member.voice.disconnect(), 20_000); + const member = interaction.member; + if ("voice" in member) + setTimeout(() => member.voice.disconnect(), 20_000); return await interaction.reply({ content: 'Prepare for takeoff!', ephemeral: true }); } return await interaction.reply({ content: 'Playing outro.', ephemeral: true });
M src/commands/play.tssrc/commands/play.ts

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

-import { SlashCommandBuilder } from 'discord.js'; +import { BaseInteraction, ChatInputCommandInteraction, CommandInteraction, SlashCommandBuilder } from 'discord.js'; import play from 'play-dl'; import { playUrls, getChannel } from '../functions/music';

@@ -12,13 +12,14 @@ .setDescription('YouTube URL or search query')

.setRequired(true), ), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true }); await interaction.deferReply(); - const url = interaction.options.getString('query'); + const opt = interaction.options; + const url = opt.getString('query'); let video, yt_info; switch (play.yt_validate(url)) {
M src/commands/queue.tssrc/commands/queue.ts

@@ -1,9 +1,9 @@

-import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import { getChannel, getQueue } from '../functions/music'; const CHARACTER_LIMIT_API = 2000; -function getReply(result) { +function getReply(result: string[]): string { const nowPlaying = "Now playing: " + result.shift() if (!result.length) {

@@ -30,7 +30,7 @@ data: new SlashCommandBuilder()

.setName('queue') .setDescription('Show current queue status.'), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true });
M src/commands/radio.tssrc/commands/radio.ts

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

-import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import { playStream, getChannel } from '../functions/music'; import path from 'node:path'; const { radios } = require(path.join(process.cwd(), 'config.json'));

@@ -13,7 +13,7 @@ .setDescription('Select which radio to play')

.setRequired(false) .addChoices(...radios)), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true });
M src/commands/skip.tssrc/commands/skip.ts

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

-import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import { getChannel, skipMusic } from '../functions/music'; module.exports = {

@@ -6,7 +6,7 @@ data: new SlashCommandBuilder()

.setName('skip') .setDescription('Skip current track.'), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true });
M src/commands/stop.tssrc/commands/stop.ts

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

-import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import { getChannel, stopMusic } from '../functions/music'; module.exports = {

@@ -6,7 +6,7 @@ data: new SlashCommandBuilder()

.setName('stop') .setDescription('Stop the music.'), - async execute(interaction) { + async execute(interaction: ChatInputCommandInteraction) { const channel = await getChannel(interaction); if (typeof channel == 'string') return await interaction.reply({ content: channel, ephemeral: true });
M src/functions/music.tssrc/functions/music.ts

@@ -1,9 +1,10 @@

-import { createAudioResource, joinVoiceChannel, AudioPlayerStatus, CreateAudioResourceOptions, StreamType } from '@discordjs/voice'; +import { createAudioResource, joinVoiceChannel, StreamType } from '@discordjs/voice'; +import { ChatInputCommandInteraction, GuildMember, VoiceBasedChannel } from 'discord.js' import MyQueue from './myqueue'; const q = new MyQueue(); -export function getChannelConnection(channel) { +export function getChannelConnection(channel: VoiceBasedChannel) { const guild = channel.guild; return joinVoiceChannel({ channelId: channel.id,

@@ -12,17 +13,17 @@ adapterCreator: guild.voiceAdapterCreator

}); } -export async function playUrls(urls, channel) { +export async function playUrls(urls: string[], channel: VoiceBasedChannel): Promise<boolean> { if (!channel) { console.log('Channel error:', channel); return; } q.connection = getChannelConnection(channel); - return q.addArray(urls); + return await q.addArray(urls); } -export async function playStream(url, channel) { +export async function playStream(url: string, channel: VoiceBasedChannel) { if (!channel) { console.log('Channel error:', channel); return;

@@ -31,7 +32,7 @@ q.connection = getChannelConnection(channel);

q.add(createAudioResource(url, { inputType: StreamType.Opus })); } -export async function playOutro(url, channel) { +export async function playOutro(url: string, channel: VoiceBasedChannel) { if (!channel) { console.log('Channel error:', channel); return;

@@ -40,16 +41,16 @@ q.connection = getChannelConnection(channel);

q.outro(url); } -export async function getChannel(interaction) { +export async function getChannel(interaction: ChatInputCommandInteraction): Promise<string | VoiceBasedChannel>{ 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.'; + const vc_error = 'You\'re not in a voice channel.'; - return channel; + if (!("voice" in member)) return vc_error; + const channel: VoiceBasedChannel = member.voice.channel; + return channel ? channel : vc_error; } export async function stopMusic() {
M src/index.tssrc/index.ts

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

import fs from 'node:fs'; import path from 'node:path'; -import { Client, Collection, GatewayIntentBits, ActivityType } from 'discord.js'; +import { Client, Collection, GatewayIntentBits, ActivityType, BaseInteraction } from 'discord.js'; import { SlashCommand } from "./types"; const { token } = require(path.join(process.cwd(), 'config.json'));

@@ -24,7 +24,7 @@ client.user.setActivity('FOSS', { type: ActivityType.Competing });

console.log('Bot online!'); }); -client.on('interactionCreate', async interaction => { +client.on('interactionCreate', async (interaction: BaseInteraction) => { if (!interaction.isChatInputCommand()) return; const command = client.slashCommands.get(interaction.commandName); if (!command) return;