Automating a Twitter Post with JavaScript

09-17-2020

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

1
2
3
4
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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.