Fleegix.org

Fun with the Twitter API -- JavaScript bookmarklets and Ruby

2007-02-24 06:51:00

I just recently joined Twitter, and have been enjoying it immensely so far. I like the steady stream of updates, and for someone like me who works at home, it's a nice way to get a sense of what other people I work with are up to during the day.

Being the OCD-type-of-guy that I am, I naturally wanted a simple, consistent way to post my blog updates to Twitter as well. Fortunately the folks at Twitter have thoughtfully provided a nice API for the service.

Typo doesn't seem to have much in the way of a plugin ecosystem, and I wasn't too thrilled about the idea of hacking Typo source, so I decided to take the easy way out, and do my posts to the Twitter API with a bookmarklet.

I knew there'd be a bit of code involved in scraping the page to get the title and categories for the blog entry in question, so the first thing I needed to do was to embed a script on the page that could pull down a good-sized chunk of JavaScript code. The bookmarklet for that looks like this:

javascript:(
  function () { 
  var scr = document.createElement('script');
  scr.src = 'http://yourdomain.com' +
    '/some_sizable_script.js';
  document.getElementsByTagName(
    'head')[0].appendChild(scr);
} )()

Just point it at the script you want, strip out all the linebreaks and spaces, and put it in a bookmark. When you click it, it'll pull down the desired file and execute all the code in it in the context of the current page.

Here's the code mine pulls down and runs. (I'm chucking out my Typo-specific stuff in the hope that it'll be more generally useful.)

var timeoutIncr = 0;
var scr = document.createElement('script');
scr.src = 'http://downloads.fleegix.org/fleegix_js' +
    '/releases/fleegix-0.3/fleegix.js';
document.getElementsByTagName(
  'head')[0].appendChild(scr);

var twitterUpdate = function () {
  if (typeof fleegix == 'undefined') {
    timeoutIncr++;
    if (timeoutIncr > 5) { 
      alert('Could not load fleegix.js library.'); 
      return false; 
    }
    setTimeout(twitterUpdate, 3000);
  }
  // -----
  // Do stuff here to grab the blog post title
  // -----
  var s = 'The-blog-post-title';
  if (s.length > 140) {
    s = s.substr(0, 136) + '...';
  }
  s = 'status=' + encodeURIComponent(s);
  fleegix.xhr.doPost(handleTwitterResponse, 
    '/backend_proxy.rbx', s);
};
var handleTwitterResponse = function (s) {
  var resp = eval('(' + s + ')');
  alert('Submitted: ' + resp.text);
}

setTimeout(twitterUpdate, 1000);

The first thing the script does is go out and grab a copy of the Fleegix.js JavaScript Toolkit, and add that to the current page, so as to have a working XHR library to do the XHR post. (Typo does actually ship with Prototype, so in theory I could use that, but this way it works no matter the blogging platform) The nice thing about this remote scripting stuff is that the code you want to use can live anywhere on the 'Net you want. Just make sure you're pulling code from a trusted source.

I've added a bit of timeout fu there so that the main code won't execute until it's got a fleegix object to work with. If it never can pull down the fleegix.js file, it will eventually give up with an error.

The twitterUpdate code grabs the title of the blog post and the categories (in my case it uses some ugly DOM-groveling and regex -- you can do it however you like), and formats it as a query-string for an XHR POST.

That takes care of the client side. Since this is an XHR POST, we have the annoying cross-domain security issue to deal with, so we have to submit to a backend page that will proxy the request to Twitter for us.

I initially looked at the Ruby Twitter gem for a backend script -- reuse is a good thing -- but unfortunately it doesn't seem to be kept up to date with its dependencies. (It wants a very specific version -- not the latest -- of Hpricot to be installed from WhyTheLuckyStiff's source repo.)

In the end I went with a basic mod_ruby script, since it's just an HTTP proxy -- super-simple, and easily done with the stuff in a base Ruby install. Here's the script:

#!/usr/bin/ruby

require 'base64'
require 'net/http'
require 'cgi'

cgi = CGI.new

email = 'address@yourdomain.com'
pass = 'your-twitter-pass'
auth = Base64.encode64(email + ':' + pass)
status = cgi['status']

h = Net::HTTP.new('twitter.com', 80)
resp, data = h.post('/statuses/update.json',
  "status=" + status,
  { 'Authorization' => 'Basic ' + auth })

h = Hash.new
h['Content-type'] = resp['content-type']
h['Status'] = resp['status']
h['Content-length'] = resp['content-length']

cgi.out(h) { data }

As you can see, it's a simple script that posts whatever it gets in the 'status' CGI param to Twitter, and passes the response from Twitter back to JavaScript. Easy as pie.

Sure it's one extra click of a bookmark after finishing a blog post, but I'm really happy I didn't have to muck around in the innards of Typo (making sure it only posts to Twitter on the initial save and not when I update the post, and so on). Plus, this was a nice excuse to play around with bookmarklets. Fun stuff.

Caveat emptor: I've only used this in Firefox 2, although it ought to work in most major browsers -- even IE6.

About

This is the blog for Matthew Eernisse. I currently work at Yammer as a developer, working mostly with JavaScript. All opinions expressed here are my own, not my employer's.

Related

Previous posts

All previous posts ยป

This blog is a GeddyJS application.