Creating Middleware to Automate Our Tumblr Queue

October 17th, 2017

On the WeedPornDaily Tumblr page, we queue 12-18 posts per day, every day of the year. That equates to 4380 posts per year minimally, and that's not even counting syndicated content from Instagram, or posts we create - not queue.

That's a lot of posts to manually create or even curate. To put it into perspective, on average it takes about 2 minutes to find and share content to Tumblr using their Javascript bookmarklet. If we were to manually input each post, we'd spend approximately 8760 minutes or 146 hours clicking, typing, and repeating the process.

I've always known to work smarter, not harder. So how do we automate this process?

The Old Way

IFTTT is our friend. We've got plenty of efficient ways to fill up the queue, especially when it comes to original content we don't have to source. We've got a Dropbox folder we can drop GIFs into and sync them to our Tumblr drafts. It works great for making 30-50 individual GIF posts instantly.

But how did we handle syndicating 3rd party content from cannabis photographers and brands? It was pretty simple before IFTTT limited their Instagram services: we had an IFTTT middleware that drafted any posts we "liked" on Instagram. This allowed us to go through IG normally, spread the love with likes, and simultaneously share the post to Tumblr.

Once IFTTT removed the feature, we were forced to transition temporarily to Zapier. The only problem? We quickly hit the Zapier free monthly limit on requests within the first week.

The Open Source Solution

I was finally forced to develop our own self-hosted middleware solution for synchronizing the Instagram and Tumblr APIs. But before coding anything from scratch, I searched around for similar open source solutions. My first stop was the official Tumblr API library for PHP. Their documentation was so poor I opted to look for an pre-existing app using the library.

After a bit of research and avoiding convoluted solutions, I found exactly what I was looking for on Github - "Tumblr Photobot" by @rachelmcgrane. It was a dead simple OOP style PHP script that pulled random photos from Unsplash and posted them on Tumblr.

Introducing OAuth 1.0

The only thing missing from the "photobot" script was a way to authenticate the app. Since Tumblr's API features an OAuth authentication layer, we have to register every application we plan to use with the API.

When we register the app, we're given a unique ID (a consumer key and secret) to distinguish our API requests. Before we make a request for data, our app has to authenticate it's session between the API. This prevents anyone with the app's ID from posting to our Tumblr without first receiving explicit permission from the logged in Tumblr user.

We get the OAuth keys we need by creating a simple authorization script. Again, there's no clear documentation on the Tumblr site (and I don't need to reinvent the wheel here), so we find an open source library that accomplishes what we need. Namely, the ShareAPI by @thinkingboxmedia was the perfect example we needed.

"Did You Request the Activation Codes Captain?"

We have a script that posts to Tumblr, but needs OAuth tokens. And now we have a script that generates those tokens. Let's put the two together, and make magic happen.

With a little adaption of the verification script, we ended up with three files. A class with the verification functions, a 'login' page that sends the user to Tumblr's API authorization page, and a page to send the OAuth's callback data to (where Tumblr sends the token after it verifies the login).

We start a new session up if there isn't one. Include the verification class and config file. And then define a new instance of the class and spin up the login link function. That function is set to return a URL, so we echo it in an HTML link.

Another super simple script. We include our class and config file, create an instance of our class, and run the HandleResponse function.

Here's where the authorization magic really happens, and this is what I struggled to discern without wasting time backward engineering the API myself. Here's a rough breakdown of what's going down:

  1. Call an instance of the Tumblr API ($client)
  2. Define a variable ($requestHandler) with the getRequestHandler() Tumblr API class
  3. Use the $requestHandler's baseURL function to set it to Tumblr's domain.
  4. Use the Tumblr API's setToken function to the app's consumer key and secret.
  5. Grab the oauth_verifier variable from the Tumblr callback's GET response (where was this in the docs? 🔍⁉️)
  6. And the gold: we use the $requestHandler's aptly named request function to send a POST request to the Tumblr API with the data from the Tumblr OAuth callback.
  7. We grab the results from the request, and parse the encoded string data into an array using the parse_str function.
  8. And whala - we have our data in the array under the key's oauth_token and oauth_token_secret.

Compiling the Components

The "photobot" script was basically what we needed. It'd be perfect if we removed the Unsplash random photo part and replaced it with an Instagram photo randomizer. And rather than accessing the Instagram API, it's much easier to use their public JSON feeds by adding /media to the end of profile pages (e.g. 'instagram.com/stayregularmedia/media').

We need to loop through an array of Instagram users, grab JSON data of 10 latest photos, then loop through each photo to draft it on Tumblr. The "photobot" script gives us the ability to post, so we'll just use that same function in our loop:

We call the blog class, which contains the Tumblr API script. Then we define an array of Instagram users we'd like to import photos from. We loop through each user in the array and run the Instagram class with each user. It grabs the data, we loop through each photo, run them through the Photo class, then post it to Tumblr.

We'll create a new class to handle grabbing Instagram data:

It's made of a basic cURL function that pulls data when you construct the class, and a simple function to pump out the data it collected.

Done Before Dinner

Let's break down the steps for you to successfully authenticate this application, and post to Tumblr:

  1. First go to the login.php page and click the OAuth link generated by the TumblrVerify class.
  2. That sends us to the Tumblr API authorization, asking for permission to post to the assigned blog.
  3. If we approve, that sends a callback with an OAuth token to our auth.php script.
  4. Our TumblrVerify class handles the request, and sends a POST request back to the API to confirm the token from the same callback URL you assigned originally in the Tumblr Dev console.
  5. Tumblr responds back with your OAuth tokens, and the class prints them for you to write down.
  6. Place the tokens into the config.php file.
  7. Navigate to index.php, which will run the script automatically.

You'll be able to visually confirm a successful sync since the script print out the photo and username of every item it uploads to Tumblr. If your tokens didn't work, you'll get an error saying it. And if you misconfigure the post data in any way, it'll give a distinct error for that too.

Making it Material Design and Safer

Since this is a powerful script that eats up limited API requests (1,000 per day), and we don't want to flood the drafts with any repeat images accidentally -- I added a simple form element with a submit button to the index.php. That way you can load the script without worrying about it automatically running.

I also took the time to style the script with company branding. I used the materialize CSS framework by @Dogfalo to quickly style a production ready frontend interface. Using their basic template as a foundation, I placed the script in the content area and we were good to go.

Middleware Everything

This technology opens the door for a lot of different solutions beyond this Instagram importation module. I'm already thinking of ditching Dropbox and writing a more concise importation script that reads a YML or TXT file a bunch of directories and imports GIFs with proper categorical tags. Or a script that displays the Tumblr drafts in a dashboard and allows quick editing and posting (because the New XKit is great, but could be better a standalone React app).

I hope you can utilize this script as a basis or inspiration for plugins or modules. I want to emphasize to everyone how powerful of a tool Tumblr is as a social platform compared to Twitter or Instagram's API. We've used Tumblr as a content hub of sorts for years because of it's API's flexibility and ease of integration with other platforms and apps.

You can find the complete code on the Stay Regular github here, along with complete instructions on how to properly install it on your server and configure it.

Hope that helps!
Stay regular,
Oscar


References: