Talk through your bot tutorial!

I decided to make a small tutorial on “how to talk to your server through your bot” without any commands!

Tutorial

First of all, we have 2 channels.

49
32

“Main Server” is the server we want to talk to
“main-chat” will be our channel we want to talk to

“Talk Through Bot” is the server we will talk through the bot (can be the same server as main server)
“talk-thru-bot” will be the channel we will talk to send messages in ‘main server main-chat’ "

  1. Create file index.js or simply use server.js file.

  2. Add “discord.js” dependency in your package.json file (will make an eris tutorial aswell + botkit)

  3. Clear out your .env file and add TOKEN=YOURTOKEN , replacing YOURTOKEN with your Discord bot token (no spaces)

  4. Rename ‘talk-thru-bot’ channel to the name of the channel you wish to send messages to (in my case its ‘main-chat’ without quotations)

  5. Inside your code file, paste this in (will explain everything bot does in detail)

//replace 'ID OF talk-thru-bot channel' with the talk-thru-bot channel ID
const ttb_channel = "ID OF talk-thru-bot channel"

//replace 'ID OF main-chat server' with the server ID of main-chat
const ttb_guild = "ID OF main-chat server"

const Discord = require("discord.js");
const client = new Discord.Client();

//our message cache that points to messages sent in talk-thru-bot to messages that will be sent in main-chat, for things like editing and deletion to work
let messageCache = new Discord.Collection();

//our ready event, will log 'bottag is ready!' when bot is online
client.on("ready", () => {
  console.log(`${client.user.tag} is ready!`)
});

//our message event
client.on("message", async message => {

//if the channel isn't talk-thru-bot, don't do anything
  if(message.channel.id !== ttb_channel) return;

//fetching channel  
let channel = client.guilds.get(ttb_guild).channels.find(c => c.name === message.channel.name)

//throw an error if the channel you named the 'talk-thru-bot' does not exist
  if(!channel) throw new Error(`Channel ${message.channel.name} not found`)

//if message starts with '!!', don't send it to the 'main-chat' channel
  if(message.content.startsWith("!!")) return;
  
//if message contains attachments, it will send them
  let attachments = message.attachments.map(a => a.url);
  
//send the message to 'main-chat' channel, if TTS is enabled on that message, it will send as TTS to 'main-chat' channel aswell, if there is attachments, it will attach those attachments too.
  channel.send(message.content, { tts: message.tts, files: attachments }).then(msg => {

//add the message IDs to the message cache
  messageCache.set(message.id, msg.id); 

  });
  
});

//our message delete event
//i'll skip over the same stuff we added in the message event

client.on("messageDelete", async message => {
  if(message.channel.id !== ttb_channel) return;
  let channel = client.guilds.get(ttb_guild).channels.find(c => c.name === message.channel.name)
  if(!channel) throw new Error(`Channel ${message.channel.name} not found`)

//getting the deleted messages ID, to delete the one in 'main-chat' aswell
  let msgId = messageCache.get(message.id)

//if message isn't in cache, ignore it
  if(!msgId) return;
  
//fetches the message in 'main-chat'
  channel.fetchMessage(msgId).then(msg => {

//deletes the message in 'main-chat'
    msg.delete();

  })
//logs error if there was a problem
  .catch(err => console.log(err));
  
//deletes the message IDs from the message cache, since their not needed anymore
  messageCache.delete(message.id);
  
});

//our message edit event

client.on("messageUpdate", async (oldMessage, newMessage) => {
  if(newMessage.channel.id !== tb_channel) return;
  let channel = client.guilds.get(ttb_guild).channels.find(c => c.name === newMessage.channel.name)
  if(!channel) throw new Error(`Channel ${newMessage.channel.name} not found`)

  let msgId = messageCache.get(newMessage.id)
  if(!msgId) return;
  
  channel.fetchMessage(msgId).then(msg => {

//edits the message in 'main-chat'
   msg.edit(newMessage.content);
  })
  .catch(err => console.log(err))
  
});

//our reaction add event

client.on("messageReactionAdd", async (reaction, user) => {
  if(reaction.message.channel.id !== ttb_channel) return;
  let channel = client.guilds.get(ttb_guild).channels.find(c => c.name === reaction.message.channel.name)
  if(!channel) throw new Error(`Channel ${reaction.message.channel.name} not found`)

  let msgId = messageCache.get(reaction.message.id)
  if(!msgId) return;
  
  channel.fetchMessage(msgId).then(msg => {

//reacts to the message in 'main-chat'
   msg.react(reaction.emoji.name);

  })
  .catch(err => console.log(err));
  
});

//logs into discord
client.login(process.env.TOKEN);

Features:

  • Sending messages in ‘talk-thru-bot’ channel will send it to ‘main-chat’

  • Sending messages in ‘talk-thru-bot’ channel starting with !! will not be sent to ‘main-chat’

  • Deleting the message sent in ‘talk-thru-bot’ will also delete it in ‘main-chat’

  • Editing the message send in ‘talk-thru-bot’ will also edit it in ‘main-chat’

  • Sending a TTS message in ‘talk-thru-bot’ will also send a TTS message in ‘main-chat’

  • Reacting to the message in ‘talk-thru-bot’ will also react to it in ‘main-chat’ (NOTE: for custom emote support, you have to use the emote from the ‘main-chat’ servers, default emotes such as :slight_smile: will always work)

Note: All features will not work if the message was sent after bot restart or vice versa, it is a planned feature

Features Planned:

  • Support for uncached messages (send before restart) using better-sqlite3 database package

  • Bulk/removing all reactions on message in ‘talk-thru-bot’ will also do so in ‘main-chat’

  • Removing a reaction in ‘talk-thru-bot’ channel will also remove it in ‘main-chat’

  • Attachments sent in ‘talk-thru-bot’ channel will be sent in ‘main-chat’

More features also planned!

Here is a project of the whole thing, without commentary + beautified code

If you have any suggestions or tutorial suggestions, please leave them below!

1 Like

Good job! However, there are a few things I would like to point out:

  1. Use a JavaScript formatter to beautify the code for various reasons.
  2. Add an if-statement checking if the guild is not null:
const guild = client.guilds.get(ttbGuild);
if (!guild) throw new Error('Guild not found');
const channel = guild.channels.find(chnl => chnl.name === message.channel.name);
if (!channel) throw new Error('Channel not found');
  1. Use const wherever you can to avoid redefinition of variables.

And lastly, good job again!

1 Like