Now that my MT -> LJ bridge is finally working the way I want it to, I’ll take the time to do a little documentation.
The basic architecture is as follows. I have an MT template containing a verbose RSS .91 feed, which is an index template, so the page it produces is rebuilt every time I post. I added a CGI script residing on my server to the list of URLs to ping when my blog is updated. The CGI runs blagg (an RSS aggregator) with the LiveJournal plugin, which pushes the post to my LiveJournal.
Notes:
Blagg is not a very smart parser; it expects the RSS tags to come in a certain order. Specifically, it requires first <title>, then <link> then <description>. As it happens, this is not the order in which the default MT RSS .91 template presents the tags, so I had to modify a copy of the template to put things in an order blagg would understand. I also expanded the description field to contain the entire post, since I wanted people to be able to read the full entry without leaving the LJ page. Finally, I replaced encode_xml=”1” with encode_html=”1” throughout the template, since encode_xml encodes some characters in a way that most browsers won’t understand. Specifically, IE can’t make sense of '.
My CGI script looks like this:
#!/usr/bin/perl -w use strict; use XMLRPC::Transport::HTTP; my $server = XMLRPC::Transport::HTTP::CGI -> dispatch_to('weblogUpdates') -> handle ; package weblogUpdates; sub ping { `/home/durrell/bin/pushlj.sh &`; return "OK"; }
pushlj.sh is this:
#!/bin/sh lockfile=/tmp/lj-bridge.lck blagg=/home/durrell/bin/blagg plugin=-plugin=livejournal mode=-mode=automatic login=-login=bryant REQUEST_METHOD= i=1 while [ $i -lt 5 ]; do if [ ! -e $lockfile ]; then touch $lockfile $blagg $plugin $mode $login rm $lockfile i=5 else sleep 60 i=$(( $i + 1 )) fi done
Why a separate script? Because in case I run into a lock, I don’t want the CGI to sit around waiting for the lock to vanish. Also, I intend to put a five minute delay in there to give me time to edit a bad post before it hits LJ.
Why the REQUEST_METHOD= bit? Because blagg processes its command line switches with CGI.pm. This is a very clever method of processing arbitrary switches in an elegant manner, but if REQUEST_METHOD is set, then CGI.pm won’t look for parameters on the command line. So I have to unset it somewhere. Getopt::Long really ought to have a method for processing arbitrary switches, but that’s a rant for another post.
Finally, since I’m using version 1.0 of the livejournal plugin, I had to edit the plugin a little to make it set the preformatted flag for posting. I also tweaked it a little to store the password in the plugin itself, since I don’t like the idea of exposing the password on the command line (and thus in the process table). Version 1.1 of the plugin allows you to specify preformatted mode with a command line switch, but I haven’t upgraded yet.
6 Comments
I’ve thought some about ways to work with this. I’m thinking about upgrading it to work with RSS 2.0. Currently blagg assumes that post titles are unique, which at least for me they aren’t. However, the link to a post is unique so I could use that to track if I have mirrored posts.
The thing I’d like to know is if I post to LJ via a script if there’s a way to then go and modify that post via a script at a later point, and if so what is required for that (Since I sometimes like to go back and modify posts, and currently that wouldn’t be reflected on LJ).
Of course this is becoming a more complex project, but heck, I’m unemployed, this will keep me busy.
Pleasantly, LJ does return a unique item ID when you post via the API, and you can use that to edit previous entries. There’s a perl module, LJ::Simple, which makes a lot of this easy but it doesn’t support editing previous entries just yet.
http://www.bpfh.net/computing/software/LJ%3a%3aSimple/
Still, the basic framework is there on the LJ side. (Assume you keep a database of LJ item IDs to blog item IDs, of course.)
I’m just not sure how I’d trigger a rebuild of a specific entry from the blogging side… RSS is really the wrong answer for this, since you’d have to go back and run through the entire RSS file to find the changed entry. What you really want to do is send the entire entry somehow every time you edit, check and see if the item has been posted to LJ yet, post it if not, and edit the existing LJ post if so.
Bryant of Population One succeeded where I failed – in migrating to MovableType and then having his fresh MT posts automatically nailed to the LiveJournal wall simultaneously. His solution – set up a CGI that does the push via blagg, then create an MT …
I’ve attempted to setup a similar system, using your XMLRPC code here, but with my own script, which is written in perl and posts directly to LJ using the LiveJournal perl module. It works well, the only issue being that MT thinks the ping failed. It doesn’t give much in the way of explaination for it, just that the ping failed. Not sure what’s going wrong with it.
When I tried to run lj.cgi, it got a 500 server error. Running it from a shell gave me the error “Status: 411 Length Required”. Any idea what that means?
Bryant, thanks again for your reply to my email “back then”, but I’m gonna have to give up on this… really don’t know what I’m doing. Maybe someone with a better understanding than me will come up with a step by step guide for the rest of us 🙂 Still sounds great though, thanks for sharing this.