Automating a Twitter Post with JavaScript

Sep 17, 2020 min read

In this article, I’ll walk through a simple implementation I use to automatically post a link to a random blog article I’ve written to my Twitter feed. This implementation is written in JavaScript, but the concepts are easily translated to other languages.

The breakdown:

I have a blog (The one you’re reading right now. Welcome!) that uses Hexo to turn Markdown files into a static website. As a static site generator, Hexo also produces an RSS feed that contains basic information about each article (e.g. Title, Date, Author). In this solution I read the RSS feed and randomly select an article. Then I send the tweet. The solution below can be run on an “ad hoc” basis from your local machine OR be automated. I’m currently using a GitHub Action to automate the tweet on a cron schedule.

There are two main components to the solution, the solution itself AND the Twitter Developer credentials that grant access to the Twitter API. I’ll start with the Twitter credentials.

From the Twitter developer console we need to create an app, and from the app we can create a set of tokens and keys. We need to capture those tokens and keys and save them somewhere safe. These are effectively usernames and passwords so they should be treated as such. I prefer to store and pass these values as environment variables, using a .env file for NodeJs. **NEVER EVER commit these values or this file into any type of source control (i.e. GIT).**

NOTE: You may need to regenerate credentials when switching environments or when things just stop working.

.env

API_KEY= < API KEY >
API_SECRET_KEY= < API SECRET KEY >
ACCESS_TOKEN= < ACCESS TOKEN >
ACCESS_TOKEN_SECRET= < ACCESS TOKEN SECRET >

The tweeting solution has few components, the solution below will simply, read the RSS feed, randomly select an article, craft a tweet, send a tweet. Easy peazy.

tweet-amazingness.js

const dotenv = require("dotenv");
const Twitter = require("twitter");
const Parser = require("rss-parser");

dotenv.config();

// get RSS feed
const parser = new Parser();

// Create a Twitter client to manage credentials
const client = new Twitter({
  consumer_key: process.env.API_KEY,
  consumer_secret: process.env.API_SECRET_KEY,
  access_token_key: process.env.ACCESS_TOKEN,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET,
});

// Generate a random integer, somewhere between 0 and the 'max' value provided
const getRandomInt = (max) => {
  return Math.floor(Math.random() * Math.floor(max));
};

// Inspired by: https://www.geeksforgeeks.org/get-the-relative-timestamp-difference-between-dates-in-javascript/
const timeDiff = (prev) => {
  if (!prev) {
    return null;
  }

  const curr = new Date();
  const ms_Min = 60 * 1000; // milliseconds in Minute
  const ms_Hour = ms_Min * 60; // milliseconds in Hour
  const ms_Day = ms_Hour * 24; // milliseconds in day
  const ms_Mon = ms_Day * 30; // milliseconds in Month
  const ms_Yr = ms_Day * 365; // milliseconds in Year
  const diff = curr - prev; // difference between dates.

  // If the diff is less then milliseconds in a minute
  if (diff < ms_Min) {
    return "A few seconds ago";

    // If the diff is less then milliseconds in a Hour
  } else if (diff < ms_Hour) {
    return "A few minutes ago";

    // If the diff is less then milliseconds in a day
  } else if (diff < ms_Day) {
    return "A few hours ago";

    // If the diff is less then milliseconds in a Month
  } else if (diff < ms_Mon) {
    return "A few days ago";

    // If the diff is less then milliseconds in a year
  } else if (diff < ms_Yr) {
    return "A few months ago";
  } else {
    return "A few years ago";
  }
};

// Using an IIFE to call teh file, automatically run the function, and move on :)
(async () => {
  let feed = await parser.parseURL("https://brianchildress.co/atom.xml");

  // Select a post
  const postNumber = getRandomInt(feed.items.length);
  const selectedPost = feed.items[postNumber];

  // Determine what the time stamp is
  const postDate = Date.parse(selectedPost.pubDate);
  const timeSincePost = timeDiff(postDate);
  // Generate and send post
  const postLink = selectedPost.link;
  const status = `${timeSincePost} I wrote an article called, "${selectedPost.title}". ${postLink}`;

  client.post(
    "statuses/update",
    {
      status: status,
    },
    function (error, tweet, response) {
      if (error) {
        console.log(error);
      } else {
        console.log(tweet);
      }
    }
  );
})();

Hopefully this solution has some components that might be helpful for other projects, from parsing an RSS feed, to creating a basic Tweet.