Wednesday, 10 April 2013

Building a new squeezebox ui.

I've been a user of the Logitech SqueezeBox system for years, and I'm a bit gutted that they've decided to kill it as a product, and replace it with ultimate ears.

It's a great little system, that connects multiple hardware audio players to an open source backend server, written largely in perl, which manages the library, and enables a bunch of plug-ins (eg BBC iPlayer, RSS readers for the hardware displays etc).
It's got a great feature which synchronises multiple players (less good on Wi-Fi, but great on ethernet)
There's a software version of the client which could easily turn a Rasberry Pi with a decent audio card into a headless player, given that Logitech are not going to make any more, I can make them cheaper!

But there's one thing I absolutely despise about it. It's web front end. I spend a HUGE amount of time in front of this thing, and while five years ago, I thought it was just fine, these days it just looks dated.

Yuck


I have an itch. That itch needs scratching. So I will build my own UI that I actually like.

Bit more technically, here's a list of gripes.

Ajax is so not 2013

The server itself has a fairly well documented (if imperfect) telnet interface. The web application polls every 5 seconds for server status, and every request from the client uses a new HTTP connection. Now, ok, this is running on my local network, so the overhead of so many request/responses is minimal, but the latency for updates sucks. I want the app to use WebSockets, proxying the telnet interface straight to the browser.

My server is tiny, my Mac Book Pro is awesome

The box that my squeezebox server runs on is pathetically small. It stays on 24x7, and is headless (no monitor etc). My primary thinking here is power consumption and noise. I want to downgrade it from an old netbook to a Raspberry PI in due course (fyi, I run CentOS on the netbook, just the server, no desktop or x-windows installed)
Every time the existing web app searches the database, the server makes about 5 or 6 queries to it's SQLLite database. I have a large music library, around 50,000 tracks, and searches can take sometimes up to 30 seconds. That is just WAY too long. The more users and players that are current, the worse this is.
Modern browsers have IndexedDB, File APIs etc. I want the app to copy and synchronise the entire database to the client and perform searches locally.

It looks like a piece of $hit

Text is tiny. It's a bunch of iframes, limited drag and drop. There IS a way of skinning the UI based on a bunch of Ext-JS widgets, and I've been down that road in the past. But I don't really like Ext-JS, and I'm still left with too much happening on the server, and HTTP polling - see the above gripes.
Ok, so I like the iTunes 11 user interface - and I never thought I'd ever like anything about iTunes. In particular I like this view - I like seeing the albums laid out with their covers.
I'm meticulous at making sure that I have album art - though of course with a large library this isn't perfect.  I like the way that the colours of the UI match the album cover, it's graphically very pleasing. I want the same thing for my squeezeboxes!





Time to roll my own

Logitech aren't going to build a super sexy new front end. So what's my Minimum Viable Product?
Well, I'm not too bothered about the plug-ins, etc, my primary goal is to have a beautiful view of my networked music library. I'm going to continue to use the stock ui in parallel for admin type things.

A week off work, and a bunch of long days, and I have something functional

Here's the ingredients thus far
  • node.js - I'm not much of a perl head, and I want my solution to sit alongside the existing code. I don't want to interfere with the squeezebox server code base. These additional pieces
  • nginx with Web Socket support for exposure outside my home network (I use Dynamic DNS)
The server side architecture, at least in the first pass, largely just serves static web assets, and proxies the telnet connection to the app via socket.io

Client side - well, everything I write is a web app!
  • Webkit ONLY! Who cares, this is for me, I don't need to support IE. Long term I may well wrap the whole thing in Chromium embedded anyway.
  • Web Sockets
  • FileReader/FileWriter API. Every cover is cached in the client using persistent storage.
  • IndexedDB. The database is (largely) copied from the server to the client on first run 
  • As much as possible, all UI effects in CSS3, no Javascript interactions
  • ColorThief - Thanks @lokesh, that saved me a bunch of time!
  • Single page app. No page refreshes

Where am I so far?

It's not ready for anyone else to use, but here's a screenshot or two

SEARCH VIEW

COLOUR MATCHING

Here's what I have so far:

  • Library synchronisation. But this needs rework, as it takes three hours at the moment (but only the first time the app is opened)! I think this is because the squeezebox server likes to stat every track when pulling back the list. That sucks.
  • Playlist synchronisation.
  • Search is super fast - cached in IndexedDB, but loaded entirely into RAM in the client as well. I've observed the app using up to 500MB of memory, but that bothers me none, it doesn't (seem to) leak. I discovered that I built in support for regex searches, by accident, which was nice.
  • Aggressive artwork caching using FileAPI
  • Drag and drop to change playlist order, or to drag in tracks from albums
  • Sweet CSS animations
  • 'New' Music view

Here's what I need to do

  • Super sexy fullscreen now playing view. 
  • Might pull in the songkick api.
  • Display a view of 'titles' in the search - it's just artists, albums so far (though the search itself is done)
  • I scrobble all the tracks I play. I'm going to add the last.fm api to pull this back somehow
  • bugs bugs bugs bugs bugs
  • Multiple player support
  • Saving/Retrieving playlists.

7 comments:

Steve Ellwood said...

awesome.

I have 3 Squeezeboxen (old v1 boxes) and use Squeezeplay on my PC. All Ethernet and they just work.

Most of my control is done with iPeng on my iPhone...

Tim Stevens said...

Hey Steve!

I do use the Logitech supplied app on my android phone, which is pretty good.

I am building this with tablets, and, in fact, TVs, in mind - i have a cunning plan - but I don't think the patterns I'm choosing will easily shift to phones - as web apps go it's pretty hungry for RAM and CPU, and hence battery.

Anonymous said...

Really nice project Tim! I also like the iTunes interface and yours is much better than the default in LMS for sure :)

I hope you continue on this project. I like it, and I might help beta testing if you think is a good idea...

Tanguy Kernoa said...

Hello
Is this project dead ?
Have you a minimal readme for using it
many thanks for any help

my goal is to use you project and make some evolution to have the simpliest interface for an handicap adult

So many thanks for any help
Tanguy

Tim Stevens said...
This comment has been removed by the author.
Tim Stevens said...

I use this daily. I haven't moved the code on much for ages.
It's an itch-based-development; ie, when I have an itch (I want a feature), I scratch it (write code)
That hasn't happened for a while. Sorry, no readme.md or anything worth mentioning.

Anonymous said...

have you a conf.json sample
Thanks
Tanguy

Tim Stevens

Tim Stevens
Work
Consume
Obey
Be Silent
Die