Categories
Meta Technology

Hosting my own Twitter images on WordPress using Tweet Images

As you may know, I use Twitter. I sometimes use it to post images from my smartphone to the world too. Those images are first taken by the TweetDeck app, then uploaded to a photo hosting service (YFrog by default). The photo host returns a link to the media, which is usually a landing page that prominently shows the picture or video, plus advertisements and other stuff that may or may not be of interest.

Why host my own pictures?

It is easy to have a free large service host your pictures, but there are some drawbacks. They make money using your pictures, and they may even have claimed ownership of it when you uploaded it. After that, I usually lose track of the pictures I uploaded because the tweets in which they appear vanish after some time. And the copies that are stored in my phone lack the context of the tweet.

Since I already have webhosting, a WordPress install and space to add pictures, why not host my own pictures? Well, it turned out to be not so simple – mostly because the major image hosters are the only services you can choose from in the Twitter clients. For example, TweetDeck on Android only lets you choose between YFrog and Twitpic. More on this later.

Make your WordPress install your Twitter image host

Although I am not the only person to have done this, this story reflects the steps I took to get to making my WordPress my image host.

There’s a plugin for that

Sure enough, on the first result page for a search on “twitter images” I found Tweet Images, which promised to be pretty much what I envisioned: no OAuth fuzz, but a secret URI that only the authorized person(‘s Twitter client) knows. It separates the tweeting and image uploading, whereas the major image hosts require access to your Twitter account (reading tweets, sending tweets, following accounts) before accepting anything. Tweet Images takes (just) the image and tweet text, creates an image post and returns the URI of the new post. It uses the shortest possible URIs to return to the Twitter client: <blog address>?p=xxx, and that apparently only works when that is not already the permalink form of the blog.

The permalinks created for the image posts contain a somewhat ugly hash, instead of the usual slugs that WordPress creates. But again, there’s a plugin for that: Clean URLs for Tweet Images. Installed flawlessly.

(I should have another plugin that adds semantic markup to the picture, i.e. <picture> foaf:depicts <person/thing> based on Twitter handles included in the tweet. Perhaps I should first install a plugin that adds Open Graph metadata to the post.)

Trumpet, the only Twitter client that supports a custom image host

After updating my WordPress user profile – you have to check a box before Tweet Images accepts pictures for the user – I thought I was good to go. The included test script uploaded an image with message correctly and returned the URI of the post that contains the photo I uploaded.

As I had noticed TweetDeck doesn’t allow setting a custom image host (Twitter, the owner of TweetDeck doesn’t provide support pages for the TweetDeck app either). So after some searching and installing several Twitter clients, I had to conclude that Trumpet is the only Android app to support custom image upload URIs. Although it is still called a beta version, it seems to be pretty complete, stable and nice. I’ve had notifications that there were 20 new mentions when there were no new mentions at all, but that is the only flaw I discovered. Oh, and you have to take the picture outside Trumpet as it doesn’t ‘connect’ to the Camera app. From the Gallery, however, you can share images using Trumpet like you can with other apps via the Share command.

The real test…

… is of course to upload an image from my phone. I copied and pasted the URI to post to in Trumpet’s settings and tried. “Unable to upload, please try again.” So I tried again, but the result was the same. I checked the server error log, which showed that Mod Security blocked the upload:

[Wed Apr 18 15:03:50 2012] [error] [client <ip address>] mod_security: Access denied with code 500. Error processing request body: (null) [hostname "ben.companjen.name"] [uri "/tweetimage/<secret>"]

I’m not completely sure what “(null)” means in this context.

My webhosting provider will not make an exception in Mod Security for me or my specific client. After a second email to the customer service I received a useful answer: that (null) may mean that there is a null character in the request somewhere. I have yet to find it, but that would probably mean that the Twitter4J library (developed by Twitter, used by Trumpet) creates bad requests.

The workaround I used now is lowering the level of security (i.e. using some directives in .htaccess to turn off Mod Security for POST requests). I should be able to turn it off for a specific path, but figuring out how will take a little more time. It seems my hosting provider is very restrictive in what directives can be used in .htaccess files, which makes it hard to try out several options without making the whole site unavailable. Or that may just be me 🙂

Image previews in clients

One of the disadvanteges of building an image host yourself, is that there are no standards or even best practices for exposing its services to clients. Apparently Trumpet is okay with uploading to any URI that returns something like <mediaurl>http://…</mediaurl>, and so are a couple of clients for iOS. But Tweet Images returns the URI for the post, not the image itself (or one of the resized copies). This is just like any of the major hosters. However, it appears that each hoster has its own way of getting the (preview) image’s URI from the post’s URI. That means clients wanting to support image previews have to know how to interact with each host they want to support. In this light: how can any client know from the URIs I tweet where to find the preview images?

I have yet to try and find out if copying e.g. YFrog’s behaviour can work, although I’m afraid all these behaviours are hardcoded and only work with the right URIs. Some standardisation should be possible here, shouldn’t it?

If you have any ideas for improvement, please leave a comment.