It’s post-Halloween, so I might as well own up to my own peculiar brand of trick or treating.
You might recall that, half a year back, I ranted a bit (well, nearly 140 characters’ worth) about John Gruber’s use of his IDN-based domain for posting Daring Fireball links on Twitter, since I couldn’t follow those links on a number of devices.
Which particular ones isn’t relevant – Nokia phones, my Blackberry, the secret webpads I’ve been testing crammed with bastardized Area 51 technology defiled with Adobe AIR, you name it – most of what I used broke (and still breaks) when clicking on @daringfireball’s links, and I decided I’d build a way to get around the hassle.
So, after a bout of inspiration, some rummaging in my Python tool-chest and checking the Twitter TOS to make sure that a parody was at least tolerated, @darlingfireball was born, and has been chugging along for a few months now.
Here are the obligatory “before” and “after” screenshots, for your perusal and (hopefully) amusement:
The ground rules were:
- I’d only re-post tweets with links.
- All the “normal” shortened versions would resolve to the exact same location.
- The profile (username, look, and where possible, feel) would be as much as possible a visible and detailed parody (hence the “darling”, the pink, the hard-coded choice of
is.gdas a shortener and the heart Unicode glyph).
- Re-posting would be throttled and delayed so as to not compete with the original (the twisted little linkages that legal work has wrought in my neural pathways told me that it was best to do so).
The exercise consisted of a mere half hour tapping out the following Python script, and it’s proven to be useful to me for many reasons, including streamlining my URL-shortening snippets and learning a bit more about the Twitter API:
#!/usr/bin/env python # encoding: utf-8 """ darling.py Created by Rui Carmo on 2009-07-21. Copyright (c) 2009 __MyCompanyName__. All rights reserved. """ import sys, os, re, codecs import twitter, simplejson, sqlite3 import expander trim = 140 # snug fit ellipsis = u'\u2026' separator = u' ' def main(): e = expander.URLExpander() s = expander.URLShortener() db = sqlite3.connect("cache.db") c = db.cursor() c.execute('create table if not exists status (id text, status text, seen boolean)') c.execute('create unique index if not exists id on status (id asc)') db.commit() api = twitter.Api(username='darlingfireball', password='********', input_encoding=None) items = api.GetUserTimeline('daringfireball') for i in items: c.execute('insert or ignore into status (id, status) values (?,?)', (i.id, i.text)) db.commit() c.execute("select * from status where seen is NULL order by id asc") queue =  for row in c: (key, status, state) = row queue.append((key,status)) for i in queue: (key,status) = i match = re.search("(http://.+)", status) if match: longurl = e.query(match.group(1)) shorturl = s.query(longurl) # we got a valid shortened URL, so we're good to go if 'http://is.gd' in shorturl: # remove original shortlink and replace the unicode markers, if any title = status.replace(match.group(1),'').replace(u'\u2605',u'\u2665').replace(ellipsis,'').strip() # make sure it fits, and add an ellipsis and a space if necessary if len(title) > (trim + len(separator) + len(shorturl)): shortened = title[0:trim - len(ellipsis) - len(separator) - len(shorturl)] + ellipsis + separator + shorturl else: shortened = title + separator + shorturl status = api.PostUpdate(shortened,key) c.execute("update or replace status set seen=? where id=?", ('1',key)) db.commit() return if __name__ == '__main__': main()
Removing very old tweets and compacting the database automatically are left as an exercise to the reader (I now do that every time I use SQLite as a persistent queue, but at the time I was going for a quick, fun hack).