Out of boredom I automated sending useless facts to my friends group chat in WhatsApp.

I used this API with Puppeteer to automate sending messages to a group chat at random times of the day all day long :)

The setup

My setup is a microservices architect where I use Docker to deploy small services to build the whole application. So, in this case I have 2 services:

WhatsApp Sender

This is a server running Puppeteer and receives requests via a REST API with the recipient name and message content, then it sends the message.

I use this service for other purposes, so I keep it separate from the other one that fetches the random fact.

Random Useless Fact Generator

This service calls the Useless Facts API, and sends a POST request to WhatsApp Sender to send the message.

The Code

WhatsApp Sender

For this service I used code from a project that creates command line interface for WhatsApp. I modified it to be able to include it as a Node JS module and call the send function from my server code.

const whatsapp = require('./cli/chat_module.js')
...
...
whatsapp.send(to, msg)

The main change in that project code was to make a chat_module by copying the chat.js code into a new file and exporting the module.

I had to first run the code locally on my computer to login to WhatsApp web, then copy the tmp directory that contains the authentication cookies to the server.

This is the NodeJS server:

const http = require('http')
const whatsapp = require('./cli/chat_module.js')

const ALLOWED = ['Test']
const server = http.createServer(function(request, response) {
  if (request.method == 'POST') {
    var body = ''
    request.on('data', function(data) {
      body += data
    })
    request.on('end', function() {
      let req = JSON.parse(body)
      if(req.do == 'send') {
        if(ALLOWED.includes(req.to)) {
          console.log('sending msg to ' + req.to + '\n' + req.msg)
          sendMessage(req.to, req.msg)
        }
      }
      response.writeHead(200, {'Content-Type': 'application/json'})
      response.end('OK')
    })
  } else {
    console.log('GET')
    var html = 'Hello world!'
    response.writeHead(200, {'Content-Type': 'text/html'})
    response.end(html)
  }
})


function sendMessage(to, msg) {
  whatsapp.send(to, msg)
}
const port = process.env.PORT || 3000
const host = '0.0.0.0'
server.listen(port, host)
console.log(`Listening at http://${host}:${port}`)

Random Useless Fact Generator

This is the trivial part, I call the API then I make a POST request to my WhatsApp Sender service.

const cron = require('node-cron');
const axios = require('axios');
const path = require('path');
const fs = require('fs');

const randomFactsApi = 'https://uselessfacts.jsph.pl/random.json?language=en';
const whatsappApi = '<my whatsapp api url>';

// file to store the ids that were sent to avoid duplication
const rawSentIds = fs.readFileSync(path.join(__dirname, 'sent_ids.json'));
let sentIds = JSON.parse(rawSentIds)['ids'];

// sleeps to randomize the time I send the message
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// cron job to run certain time of the day
cron.schedule('50 8,10,12,14,16,18,20,22 * * *', function() {
    let randomNum = Math.random() * 1200000; //between 1 and 20 minutes
    console.log('running a task every 3 hours');
    sendFact(randomNum);
});

// Gets a random fact and checks if it was never sent, otherwise it keeps getting another fact until new one is found
async function getFact() {
    let fact = await axios.get(randomFactsApi);
    if (sentIds.includes(fact.data.id)) {
        console.log('The fact with id = ' + fact.data.id + ' was previously sent. Getting another one...');
        getFact();
    } else {
        console.log('Returning fact with id = ' + fact.data.id);
        return fact;
    }
}

// Sending the message via WhatsApp API after some sleep time.
async function sendFact(ms) {
    console.log('will send message after ' + ms / 1000 / 60 + ' mins')
    await sleep(ms);
    let fact = await getFact();
    sentIds.push(fact.data.id);
    let jsonObj = {'ids': sentIds};
    console.log('Calling WhatsApp API');
    axios.post(whatsappApi, {
        do: 'send',
        to: '<the group name>',
        msg: fact.data.text
    }).then((res) => {
        console.log(res.data);
    }).catch((err) => {
        console.log(err);
    });
    console.log('Storing the id in sent ids to avoid sending it again');
    fs.writeFileSync(path.join(__dirname, 'sent_ids.json'), JSON.stringify(jsonObj));
}