Identi.ca
I’ve been absent from Identi.ca for a while, since they disabled their XMPP bot :( Now that my new operating system seems to be Emacs, I thought I’d find another way to read and post, using flat files and commandlines (no, I don’t want to use a bloody Web interface!)
The reading part is thankfully straightforward, since StatusNet generates RSS and Atom feeds of everything. The RSS 1 links seem to be broken, but the RSS 2 links point to http://identi.ca/api/statuses/friends_timeline/your-username.rss
There are loads of commandline RSS readers out there, so I won’t reiterate that. This is all, thankfully, standard.
Posting is a little more difficult, and I originally tried this commandline Identi.ca posting script but it was a little off from what I wanted.
Firstly, this requires storing my password in plaintext (or at least in an easily recoverable way). That’s just silly. Secondly I would prefer a dedicated status-posting REPL (Read Eval Print Loop) rather than having to prefix every line with the same command. An Emacs buffer would be nice, but a commandline is easier to throw together.
These two requirements actually go hand in hand; if we don’t store the password then we must take it as an argument, and since getting a password prompt every time woud be tedious, we may as well sit in a REPL and reuse the same password over and over.
Here’s the code I’ve come up with, based on the link above (replace
warbo
with your username):
#!/usr/bin/env python
"""Read a password then enter a REPL for posting messages to identi.ca"""
# Define this now, since its scope is quite wide
= ('quit', 'exit')
exit_commands
# Define some useful functions. We use def/call/del to capture state in closures
def make_out():
"""Returns a function for printing to stdout."""
from sys import stdout
return lambda msg: (lambda _: (stdout.write(msg), stdout.flush()))
= make_out()
out del(make_out)
def make_dent():
"""Creates a function for denting (posting to identi.ca)."""
from urllib import urlencode
from getpass import getpass
import urllib2 as u
= 'http://identi.ca/api/statuses/update.xml'
url = u.HTTPPasswordMgrWithDefaultRealm()
passman None, url, 'warbo', getpass())
passman.add_password(= u.build_opener(u.HTTPBasicAuthHandler(passman))
opener = u.Request(url)
req return lambda msg: opener.open(req, urlencode({'status': msg}))
= make_dent()
dent del(make_dent)
def quit(_):
"""Exit the program."""
print 'Bye!'
from sys import exit
0)
exit(
# Handle messages based on their content. Works like LISP's cond; pop off
# (condition, function) pairs until condition is True, then run function(msg)
= lambda(msg): filter(lambda (x, y): x, [
handle len(msg) > 140, out('Too long: ' + str(len(msg)) + '\n')),
(in exit_commands, quit),
(msg True, dent)
(0][1](msg.strip())
])[
# Finally 'tie the knot' between identi.ca and stdin, to make our REPL
print 'To quit, type ' + ' or '.join(map(repr, exit_commands))
while True: handle(raw_input('> '))
I’m not sure about the def
/call/del
style I’ve
used here; it’s reminiscent of Javascript, but Python doesn’t allow
anonymous procedures. Still, I quite like the way handle
works ;) Note that it doesn’t
try to handle any exceptions, but in this case I don’t see the point
uglifying the code when seeing a stack trace is the most helpful output
anyway.
I’ve stuck this in Git and will publish it somewhere as soon as I get non-stupid access to Gitorious (bloody cookies, ruining the stateless purity of HTTP!)