Web Site Scripts

by Jamie Zawinski

These are the scripts I use to maintain the web site you're reading right now. The web site is constructed solely of static HTML pages that are regenerated as needed. For example, when I've added an event to the master calendar file, I just type "make cal" to re-generate any of the calendar HTML pages that should have new information on them.

Many people build web sites like this one using PHP or ASP or similar tools where the web server generates the pages on the fly. That's very wasteful. My philosophy is that that, for a primarily-non-dynamic site like this one (where only a very small number of pages change daily) the pages should instead be generated only once, at the time the change happens. Not only is it a more efficient use of server resources, but it also avoids opening you up to the kind of security holes that are endemic to tools like PHP.

I doubt these scripts will be directly useful to many people, but several people have asked how I do it, so here it is.

These scripts are all driven by a Makefile which contains shorthand, but you can guess what that looks like.

HTML Templates

Menuify.pm This module reads a "template" file and updates the given HTML file to match the template. This is what splices the left-side menu onto each page. The content of the menu is defined in this file. It also takes care of the logic of not having a page link to itself: for example, on the menu on the Directions page, the "Directions" menu item is not clickable.

There are magic comments in the HTML pages that specify which part of the page the text should go in: for example, text that goes underneath the menu is bracketed by lines that say <!-- %%LEFT_START%% --> and <!-- %%LEFT_END%% -->.

This script also contains a simple HTML validator, a more general version of which can be found over at jwz.org in validate.pl.

update-latest-links.pl The menu itself points to URLs like "/calendar/latest.html", but there is no file on the site called "latest.html": instead there is an entry in the "/.htaccess" file that does an HTTP 302 redirect to a more specific URL like "/calendar/2005/02-17.html". This script runs nightly.

Calendar Pages

generate-calendar.pl The raw calendar lives in a simple file called "calendar.txt" and all of the HTML pages under /calendar/ are generated from that. The syntax of that file has a bunch of features (e.g., for repeating events) but mainly it contains the date of the event, followed by the text describing it.

This script also generates the RSS and iCal presentations of the calendar data, and a whole bunch of other things. Basically if it's a presentation of our calendar data, it's generated from here. The amount of stuff this script generates keeps growing as the years go by.

Markdown.pm The event-description text is kind-of like Markdown. It's a very idiosyncratic variant that allows me to identify performers as bands, DJs, or "other". I need to do that in order to generate the statistics on the ledger.html page. (There's also a self-test.)




If you have ever called our telephone infoline, you've noticed that it reads the calendar to you in a computer-generated voice!

The text for that is created by generate-calendar.pl. Then infoline-sable.pl massages it into something more easily readable by the speech synthesizer: basically, it has a zillion special-case regexps to convert words that the synth mispronounces into like-sounding words that it can say, e.g., "Fauxnique" to "Foe-Neek".

The script is called "Sable" because originally we used the Festival speech synthesizer, which has a markup language called Sable. Later, we switched to /usr/bin/say, the build-in MacOS speech synthesizer. The script that invokes that is infoline-mp3.pl, which creates an MP3. It re-tries a few times until it ends up with an MP3 file that is less than 3 minutes long (since that's the limit our phone system gives us.)

Then (believe it or not) we used to updated the outgoing message on our voicemail by holding the telephone up to the computer's speaker, because there was no easier way.

These days, however, we're using Twilio, an online telephone service. Basically, we feed an XML file to Twilio that contains the text we want them to say, and they feed it into the speech synth on their end. What we feed them is pretty much just the output of infoline-sable.pl, wrapped in the XML they expect. So we don't have to generate the MP3 on our end at all, we just hand them text, and it's fully automated. It's much nicer.

Flyer Gallery

flyerize.pl Every time a promoter sends me an image of their event's flyer, I run this script on it, and it resizes the image(s) to the right size; copies them to the proper subdirectory and filename; and creates thumbnails.
wrap-flyers.pl This regenerates any changed HTML files under the /flyers/ directory, including updating the by-month and by-year indexes. It also puts in the "<< prev event_name" links that let you navigate to all the flyers of a given series of events.

Photo Gallery

gallery.pl This is the script that I use to generate the photo galleries themselves. It makes thumbnails and HTML wrappers for each image. It's pretty general-purpose.
wrap-gallery.pl This regenerates any changed HTML files under the /gallery/ directory, including updating the by-month and by-year indexes. It also puts in the "<< prev band_name" links that let you navigate to other photo sets of bands who have performed here more than once.


twit.pl This is a script that posts to Twitter. It is run from various cron-based things to post messages like "XYZ starting now", and "Tickets now on sale for XYZ".
fbmirror.pl We also want those things posted to Facebook. It is possible to have Facebook subscribe to an RSS feed, but sometimes they wait 3+ days to update the feeds, so that's no good. This script reads our Twitter feed and re-posts it to Facebook. We do it this way instead of just posting to both at the same time so that when other things are posted to twitter by other (non-automated) means (such as the various bartenders posting our drink specials) those also show up on Facebook.

One clever thing this script does is, if the twit contains a URL to a DNA Lounge event, it extracts the flyer image and text description for that event and posts it as an attachment/thumbnail along with the rest of the text.

Top Level Page

randomize-snapshots.pl This picks a random set of six images from the whole image gallery and creates cleverly-sized thumbnails of them. The first 3 are random images from past instances of events that are coming up soon, and the next 3 are random. Notice how there are always 6 images on two lines, but the individual images are scaled so that each line is the same width, and each image on that line is the same height. That's the tricky bit. This writes the HTML to a "staging" file for use by:
splice-frontpage.pl This takes the HTML snippet generated by randomize-snapshots.pl and splices it in to the top-level /index.html file. It does a similar trick for the "Calendar Overview", "Next Event", and "Upcoming live shows" boxes. This script runs nightly.