An AJAX Erlang Jukebox

Installation and Configuration

Very briefly,

The application is usually accessible on port 8888 (see httpd.conf if you want to change this), so once it's running, you should see the main user interface at

http://localhost:8888/

The first thing you'll need to do is add a root URL for the application to spider. Visit the configuration interface at

http://localhost:8888/config.html

Enter a URL (e.g. http://mymachine/path/to/my/iTunes%20Folder/) in the field next to the "Add root" button, and click on the button. The system will start scanning the directory hierarchy beneath the URL you entered.

When it's done, the URL will appear in the "All roots" section of the display.

Code Overview

The Music Server and Track Database

jukebox.erl, jukebox_supervisor.erl
This is the entry point for the whole server-side program. It starts the HTTP daemon, spider service, the track database, the player service, the volume control service, and the main history/chat recorder.
execdaemon.c, execdaemon.erl
These programs fill a gap in Erlang's support for POSIX process control and signalling. After having a good go at using its built-in mechanisms for spawning other Unix processes, I decided I wasn't getting the control I needed, so hacked together this external controller program to act as a buffer between Erlang and the Unix world. The execdaemon.c program speaks a simple command language over stdin/stdout, discards the output of its child processes, and provides an interface to two functions: execv(3) and kill(2). The execdaemon.erl module provides an Erlang wrapper around execdaemon.c's functionality.
history.erl
This module — all 41 lines of it! — implements a simple logging or chat service. It's used in the jukebox as a simple IRC-like AJAX chat panel, allowing Jukebox users to talk to each other via the Jukebox UI.
player.erl
This module maps filename extensions to player commands (such as mpg123, ogg123, etc.), and uses execdaemon.erl to manage an external player process. It also manages the main queue of tracks to play, supporting operations such as enqueueing a track or a .m3u playlist, moving a track around in the queue, removing a track from the queue, skipping the remainder of the currently-playing track, and pausing and unpausing the current player process.
spider.erl
This module recursively explores directory hierarchies exposed as HTML. A regular expression matching 'href="..."' extracts sub-URLs from each retrieved page. Leaf URLs are accumulated and returned to the caller, and Non-leaf (subdirectory) URLs are retrieved and processed in turn.
tqueue.erl, tqueue.hrl
This module implements a "track queue" data structure, built upon Erlang's library queue module. Each entry in a track queue consists of an ID, a track URL, and optionally a username associated with the entry. The track queue structure, and its contained track structures, are the core structures used in communication between the user interface and the server side of the application.
trackdb.erl
This module manages the database of all discovered tracks, using spider.erl to scan the root URLs. It provides procedures for listing, adding, removing and rescanning roots, as well as for searching the database.
volume.erl
This module uses the external program hmix to query and adjust mixer settings.
lastfm.erl, md5.erl
A last.fm interface module (and md5 support module) for sending played tracks to last.fm. Requires setting the LASTFM_* keys in settings.hrl.

The Main User-Interface

The user interface is constructed around static HTML pages which load static Javascript files from the server. The javascript files in turn access JSON-RPC services on the server using XmlHttpRequest.

index.html
Static HTML for the main Jukebox user interface. Loads prototype, json.js and jsonrpc.js support libraries before loading client.js.
client.js
This file contains the main body of the user interface code. The static HTML hooks into the code in this file, both via event handlers on particular HTML elements and via the registration of initClient() as a window onLoad callback. When client.js is loaded, the first thing it does is build a proxy to the (non-configuration) server-side functionality of the application.
json.js
This is a slightly modified copy of an old JSON implementation from json.org.
jsonrpc.js
This is a tiny, simple layer atop json.js and prototype that accesses JSON-RPC services.
jukeboxsession.erl
This module defines a single JSON-RPC service. It implements the core API to the jukebox application.

The Configuration Tool

The configuration tool is similar in construction to the main user interface, but is much simpler. It provides an interface to adding, removing and rescanning root URLs (with the functionality implemented by trackdb.erl, v.s.) and to saving a snapshot of the current in-memory database to the disk.

config.html
Static HTML for the configuration interface. Similar to index.html, except loads configclient.js instead of client.js.
configclient.js
This file contains the main body of the configuration tool code. Similar in structure to client.js, but based around a difference JSON-RPC service.
configsession.erl
JSON-RPC service definition and implementation for the configuration service.