Below is the file 'poetweb.py' from this revision. You can also download the file.

#!/usr/bin/env python2.4

#
# LiveJournal Haiku 2
# Copyright (C) 2006 Grahame Bowland
# All rights reserved.
#

import datetime
import urlparse
import web
from poet3 import Poet3
from forms import haiku
import cPickle
import config
import syslog
import re

# for debugging, logging of referrers, etc.
syslog.openlog("poetweb")
# valid sites
site_id_re = r'[A-Za-z\.]+'
# specific to livejournal-based sites
username_re = r'[A-Za-z0-9\_\-]+'
username_re_c = re.compile(username_re)

class NewLivejournal:
    @classmethod
    def user_uri(self, site, username):
        if username.startswith('-') or username.startswith('_') or \
                    username.endswith('-') or username.endswith('_'):
            return 'http://users.%s/%s/' % (site, username)
        else:
            return 'http://%s.%s/' % (username, site)
    @classmethod
    def rss_uri(self, site, username):
        return NewLivejournal.user_uri(site, username) + 'data/rss'

rss_lookup = {
    'livejournal.com' : NewLivejournal,
    'deadjournal.com' : NewLivejournal,
}

urls = (
    '/', 'IndexView',
    '/post/([A-Za-z]+)', 'PostMemeView',
    '/forms/haiku', 'HaikuFormView',
    '.*/(' + site_id_re + ')/(' + username_re + ')' + '/haiku', 'HaikuView',
    '/robots.txt', 'RobotsView',
)

def gen_haiku(rss_uri):
    poet = Poet3(rss_uri)
    last_update = poet.storage.mtime('last_update')
    if datetime.datetime.now() - last_update > config.update_interval:
        poet.update()
        # FIXME this doesn't work..
        poet.storage.open('last_update', 'w').write('')
    poet.build_state()
    if poet.symbol_state.forward_markov.total == 0:
        return -1, None

    # if there has been no upwriting yet, then let's do some now.
    # we save the resulting combined tokens, so the code uses those
    # when adding new tokens to the corpus from now on
    if not poet.upwritten_seqs:
        to_upwrite = poet.symbol_state.chunkable()
        cPickle.dump(to_upwrite, poet.storage.open('upwritten.txt', 'w'))
        poet.upwrite(to_upwrite)

    for attempt in xrange(config.haiku_attempts):
        poem = haiku(poet)
        if poem != None:
            break

    return attempt, poem

class Renderer:
    def __init__(self):
        # any templates that can be inherited from, should be added to the list here
        self.templates = [ ('base.html', 'base') ]
        self._templates_loaded = False

        # these variables will be available to any template
        self.terms = {
                'context' : web.context, # fugly
                'dynamic_uri_path' : config.dynamic_uri_path,
                'dynamic_join' : lambda path: urlparse.urljoin(config.dynamic_uri_path, path),
                'static_uri_path' : config.static_uri_path,
                'static_join' : lambda path: urlparse.urljoin(config.static_uri_path, path),
                }

    def load_templates(self):
        if self._templates_loaded: return
        for template, mod_name in self.templates:
            web.render(template, None, True, mod_name)
        self._templates_loaded = True

    def render(self, template, **kwargs):
        self.load_templates()
        terms = self.terms.copy()
        terms.update(kwargs)
        web.render(template, terms)

renderer = Renderer()

haiku_base = '''<form action="%(dynamic_uri_path)spost/haiku" method="post"><table align="center" border="0" bgcolor="#DDDDFF" style="border: 1px solid black;"><tr><th>LJ-Haiku<sup>2</sup> for %(username)s</th></tr><tr><td><blockquote align="right" style="text-align:right;border-right:1px solid #808080; padding:5px;">	%(haiku)s</blockquote></td></tr><tr><td align="center"><input type="text" size=8 name="haiku_username" value="%(username)s" /> @ <select name="haiku_server"><option selected value="%(mysite)s">%(mysite)s</option><option value="x">Other...</option></select><input value="%(username)s" type="hidden" name="haiku_referrer" /></td></tr><tr><td align="center"><input type="submit" value="What's my Haiku?"></td></tr><tr><td align="center" bgcolor="#CCCCCC"><small><a href="http://www.livejournal.com/users/grahame/">Created by Grahame</a></small></td></tr></table></form>'''

class HaikuView:
    def GET(self, site, username):
        if not rss_lookup.has_key(site):
            ## fixme; this is a site we don't know about; let's return a friendly
            ## page suggesting the user might want to ask about adding it
            return web.notfound()
        uri = rss_lookup[site].rss_uri(site, username)
        web.debug(uri)
        attempts, haiku = gen_haiku(uri)
        if haiku == None:
            haiku_code = None
        else:
            haiku_code = haiku_base % { 'mysite' : site,
                                        'dynamic_uri_path' : config.dynamic_uri_path,
                                        'username' : username,
                                        'haiku' : '<br />'.join(' '.join(t) for t in haiku) }
        web.debug("haiku_code=%s" % haiku_code)
        renderer.render("haiku.html",
                        attempts=attempts,
                        page_title="your haiku",
                        username=username,
                        haiku_code=haiku_code )

class PostMemeView:
    def GET(self, meme_name):
        web.seeother(config.dynamic_uri_path)
    def POST(self, meme_name):
        meme_name = meme_name.lower()
        i = web.input()
        if meme_name == "haiku" and i.has_key('haiku_username') and i.has_key('haiku_referrer') and i.has_key('haiku_server'):
            username, referrer, server = i['haiku_username'], i['haiku_referrer'], i['haiku_server']
            if not username_re_c.match(username):
                web.seeother(config.dynamic_uri_path)
            if not rss_lookup.has_key(server):
                web.seeother(urlparse.urljoin(config.dynamic_uri_path, "forms/haiku"))
            syslog.syslog("haiku: username=%s referrer=%s server=%s" % (username, referrer, server))
            web.seeother(urlparse.urljoin(config.dynamic_uri_path, server + '/' + username + '/haiku'))
        else:
            web.seeother(config.dynamic_uri_path)
        print "hello, you posted!"

class IndexView:
    def GET(self, *args, **kwargs):
        renderer.render("index.html", page_title="welcome")

class RobotsView:
    def GET(self, *args, **kwargs):
        print "User-agent: *"
        for key in rss_lookup.keys():
            print "Disallow: /%s/" % (key)

if __name__ == '__main__':
    web.internalerror = web.debugerror
    web.run(urls, web.reloader)