An AJAX Erlang Jukebox
Installation and Configuration
Very briefly,
- Install Erlang.
-
Make sure your copy of VLC works
properly.
-
If you want support for a volume control, ensure pactl is present and
works properly.
-
Download and install the Erlang RFC4627/JSON/JSON-RPC module
by git clone git://github.com/tonyg/erlang-rfc4627
,
compiling it, and making sure it's available on your Erlang
path (e.g. by symlinking it into your
/usr/lib/erlang/lib
directory, or by copying
the *.beam
files into the Erlang Jukebox's
ebin
directory).
-
Copy src/settings.hrl.example to src/settings.hrl and edit
as appropriate for your local system.
-
Type make
. If all goes well, try make
run
, which will start the application in an
interactive Erlang shell. Running make daemon
will start the application running in the
background. Running make stop
will shut down a
running jukebox.
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.