const Discord = require('discord.js'); require('dotenv').config(); const tts = require('google-tts-api'); const fetch = require('node-fetch'); const fs = require('fs'); const sha1 = require('sha1'); let joinedVoiceChannels = []; const bot = new Discord.Client(); bot.on('message', (message) => { console.log("I got a message", message); }) bot.on('ready', async () => { console.log("Bot initialized and listening"); const guild = await bot.guilds.fetch(process.env.GUILD); const channel = await bot.channels.fetch(process.env.CHANNEL); await joinChannel(channel); speak(channel, `Hi! I'm alive. It is now ${new Date().toLocaleTimeString()} on ${new Date().toLocaleDateString()}`); }) bot.on('voiceStateUpdate', async (oldState, newState) => { if (newState.member.user.bot) return; if (oldState.channel && newState.channel) return; const channel = oldState.channel || newState.channel; if (!channel) return; if (channel.members.array().length < 2) { return await leaveChannel(channel); } await joinChannel(channel); let joined = false; if (!oldState.channel) { joined = true; } let username = newState.member.displayName; let str = ""; if (!joined) { str = username + " left the channel"; } else { str = username + " joined the channel"; } speak(channel, str); }) bot.login(process.env.TOKEN); function isInVoiceChannel(channel) { return joinedVoiceChannels.includes(channel); } function getConnectionForVoiceChannel(channel) { return bot.voice.connections.find((conn) => conn.channel === channel); } async function generateVoice(string) { const hash = sha1(string); const filepath = process.env.VOICE_TMP_PATH + hash + ".mp3"; if (!fs.existsSync(filepath)) { const url = tts.getAudioUrl(string, {lang: "en-us"}); console.log("Generated url: " + url); const data = await fetch(url); const contents = await data.arrayBuffer(); const buf = Buffer.from(contents); fs.writeFileSync(filepath, buf); } return filepath; } async function joinChannel(channel) { if (!isInVoiceChannel(channel)) { const res = await channel.join(); joinedVoiceChannels.push(channel); } } async function leaveChannel(channel) { if (joinedVoiceChannels.includes(channel)) { joinedVoiceChannels = joinedVoiceChannels.filter((chan) => chan !== channel); await channel.leave(); } } async function speak(channel, message) { const conn = getConnectionForVoiceChannel(channel); const filepath = await generateVoice(message); if (conn) conn.play(filepath); }