ChairNerd

Code, Design & Growth at SeatGeek

Putting Venue Maps in a Terminal: Introducing SGCLI

At SeatGeek we have regularly scheduled Hackathons–opportunities for all of us to drop what we’re doing for two days and work on whatever interesting, creative, or experimental projects we dream up. We had a Hackathon last week, and I decided to write a command-line client for SeatGeek, which I called SGCLI.

Back in 2005 I spent a couple of months using a box running FreeBSD without X as my main computer. I’m not sure exactly what the thought process was that led to that setup, but using it taught me that in some instances command-line applications can be much faster to work with than their graphical equivalents. With that in mind, I set out to try and replicate (and if possible, improve) the experience of searching for and buying tickets on SeatGeek.

The first step to building the project was to learn some curses. Luckily, there’s a great tutorial on curses programming with Python on python.org. It didn’t take long to have a basic application running (complete with an ASCII-art version of the SeatGeek logo):

SGCLI Welcome Screen

The rest of the first day was spent building out the main parts of the SeatGeek experience: the search page, selecting an event, browsing ticket listings and viewing an individual listing. There were some intense moments, but by the time I quit for the night (probably around 11:30 or so - and I was early!) it seemed like at least the basics would be working in time for Friday’s demo.

On Friday I focused mostly on the features that I thought would give some added spark to the demo, namely rendering SeatGeek’s beautiful maps into slightly-less-beautiful ASCII art, and meme integration. Rendering the maps proved to be a bit tricky, but in the end it worked out pretty well:

Yankee Stadium in SGCLI

Map rendering works using the map infrastructure we built for the SeatGeek mobile website. That allows SGCLI to get a single .png for an event that represents the map. Then, SGCLI uses PIL to scale the map down such that the size in pixels is the same as the size in characters of the final map we want to render (that final size depends on the size of the terminal window). An important note here is that the aspect ratio has to change during this operation: almost all fonts are much taller than they are wide and we need to correct for that. So, if we decide that our final map should be 20 characters high and 36 characters wide, we use PIL to scale the 320x320 .png down to 36x20.

After scaling down we use PIL to create two copies of the same image. One of the copies gets converted to grayscale, and the other copy gets “posterized” down to a single bit per color channel (that matches the color options I have available in my terminal). The final step is to actually output the ASCII art. For each pixel we use the grayscale image to select a character to display based on luminosity (darker pixels get characters like #, while brighter pixels become characters like . or -). We use the posterized image to figure out what color to draw the character in (out of the 7 options available to us). After rendering the map using curses, we draw a marker over the top to indicate where the selected tickets are located.

This method certainly could be smarter (for example, it doesn’t take into account the ‘shape’ of a character when deciding what character to use), but it worked pretty well and was easy to implement. Check it out in the source code for SGCLI to see it in all of its glory.

Check out the final project–it’s open source and easy to install and run. Just do:

pip install sgcli # or easy_install sgcli
sgcli

There are plenty of neat things that I didn’t mention here. Be sure to check out the support for autocompletion while searching, and make sure to hit “b” on a ticket listings page (even if you don’t follow through and buy the tickets) - you’ll get a nice surprise when you return to the app. There are some notes on keyboard shortcuts in the README.

If you have any questions about the project just let us know in the comments!

Comments