Recent blog entries by dan

I said this morning that I was going to replace the browser-native
audio controls with something which looks (approximately, at least)
consistent everywhere. There’s another couple of reasons for wanting
to revisit the way we render the audio element

on the default Android browser, we don’t get an ended event when
the player gets to the end of the track, which means every five
minutes I have to pick the phone up and unlock it and press ‘remove’
in the play queue to trigger the next track

when the screen is sleeping or the tab is hidden, the
requestAnimationFrame handler that triggers Om repaints is called
late or not at all. Again, time to pick the phone up and unlock and …

I want/need to make it run on Windows, which does not support Ogg in
the audio element. Although in principle I could hang multiple
source children onto the audio element and let the browser choose
which one it likes best, rewriting the DOM after it has been parsed
is said to be not a good
idea which means using info from the JS canPlayType method to choose the bext format for each track from those available for that track.

The nice thing about Om application state is that it’s also a
perfectly ordinary Clojure atom and we can call add-watch on it to
have a perfectly ordinary Clojure(Script) function called whenever it
changes. So what we’re going to do is

a new key in app-state to contain the desired player state

an Om component to render a player UI, and update this desired state
when buttons are clicked

some event handlers to get news from the audio element and figure
out what it might be doing (principally, has it reached the end of
the track, or is it having connectivity issues) and update the
desired state correspondingly

a watch on app-state that calls the function currently named
sync-player-state, which compares the desired state to what the
audio element is actually doing, and updates the audio element
appropriately

I’m only showing you pictures of the new Sledge UI as a stopgap, as
it will shortly be replaced with the new new Sledge UI.

I Am Keeping: the way we allow search refining. Each search you
request (either by typing something in or by clicking an artist or
title name) is turned into one of those little yellow label things and
then you can remove it again just by clicking the ‘x’ (I stole this
idiom from the amazon ec2 console ui, but it’s also what the gmail
composer does when you type addresses into the to/from lines).

I Am Losing: the link to ‘view play queue’. Rather than a ‘tabs’
metaphor, we will have an ‘expand’ button in the player area at the
bottom which causes the queue to roll up and overlay the search
results.

Also To Go: the browser-native audio controls, which are getting
replaced with something that is consistent across browsers.

But the bigger reason for writing: already gone, the Lucene interface
for storing the music database. I started working on having Sledge
monitor its music folders for additions/deletions, and realised just
how hard it is to persuade Lucene to search for an exact match on a
particular field with no ambiguity or helpful tokenising – which is
necessary when you want to delete the record for a file that’s not in
the filesytsem any more. So now we’re using a flat file and EDN and
doing our own tokenising into a bunch of maps that are created at load
time. It’s actually faster too, but I don’t think that’s anything to
do with Lucene, more with it being the second stab at the problem.

This has now taken substantially more than one weekend and it’s still
not done. Damn scope creep.

There was a point about three weeks ago when I thought I had a working
audio player, then I tried using it on the phone and I got awkward
screeches every thirty seconds through my stereo when I told it to
play Ziggy Stardust. No, I’m not talking about David Bowie’s voice
here, this was genuine “a dog ate my CD” style digital audio
corruption. The problem seemed to appear only on Wifi: I could
replicate it on my laptop, but it didn’t show up on localhost and it
didn’t show up over an ssh tunnel: I suspect it was something related
to buffering/backpressure, and facing the prospect of debugging Java
code wth locks in it I punted and decided to try
switching HTTP server instead.

Documentation on HTTP streaming from core.async channels with
Aleph is kind of sparse, at least
insofar as it is lacking a simple example of the kind of thing that
should work. So here is my simple example of the kind of thing that
worked for me: wrap the channel in a call to
manifold.stream/->source and make sure that the things received on
it are byte-array

I’m sure there are other things you could put on the channel that
would also work, but I don’t know what. java.nio.ByteBufferdoesn’t
seem to be one of them, but I’m only going on git commit history and a
very fuzzy recollection of what I was doing that day, it might be that
I did something else wrong.

This might be because React has to be taught about each event that
each element can trigger and it doesn’t know about this one, or it
might be because (it is alleged that) event handling in React is done by placing a single event handler on the top-level component and then expecting events on subelements to bubble up. According to Stack Overflow, audio events don’t bubble

The workaround is to add the event listener explicitly in IDidMount,
and to call addEventListener with its third parameter true, meaning
that the event is captured by the parent before it even gets gets to
the sub-element to be swallowed.
Like this

At the time I write this, the latest release of clj-webdriver is
0.6.1. There are two separate problems with this version, at least as far as I can make out

1) some kind of bug which causes it to fail with the message No such
var: clojure.core.cache/through. I haven’t tracked this to its root
cause but am guessing that the [org.clojure/core.cache "0.5.0"] in
clj-webdriver’s project.clj was too old a version for some other
dependency I am pulling in. I added an explicit
[org.clojure/core.cache “0.6.4”] in my project and that seems to have
fixed it. See clj-webdriver issue 132

2) The version of Selenium it pulls in is 2.39, which is too old to
work properly with even the vaguely recent version of firefox I’m
using (33.1.1). Fixing this is again just a matter of adding the more
recent versions of Selenium stuffz as explicit dependencies in project.clj

With those two changes clj-webdriver now seems pretty happy and I can
start adding some basic smoke tests to
Sledge so that I don’t have to manually
test client-side behaviours whenever I change it

Done: use reference cursors instead of channels for enqueuing/dequeing
tracks

Next up: use a channel for xhr search instead of quite so many
callbacks

Forthcoming: more work on UI/UX. Add tabs to switch between search
view and play queue, unify the different-for-no-good-reason “search”
and “filters”.

The branch/commit policy from hereon in is

it is a bug if master doesn’t pass regression tests on my machine

but there could be any kind of rubbish on branches

but I firmly subscribe to the Kanban notion of limiting
work-in-progress, so will be striving to keep each of these branches
short-lived or to declare them moribund at the earliest opportunity

Note that the tests currently depend on having a music collection
containing at least four tracks by Queen. This is not ideal and I
will fix it some day but in the meantime you’ll just have to work
around it somehow. Maybe try
leaving a USB stick in the car for two weeks or
something