Artists – What many names can do

(this title brought to courtesy of Beres Hammond, who’s “What One Dance Can Do” bubbled to the front when coming up with names for this post)

I’ve had a recurring problem ladies and gentlemen, in that artist names have been driving me crazy.

Here’s the situation.  An artist is named “artist”, and she publishes albums in this name.  Then the artist decides to change her name to “artois”, and publishes further names under this new name.  And so on and so forth.

The problem, then, is trying to determine which albums belong to a particular artist, regardless of pseudonym.  The problem can even crop up when, say, a gospel artist works with a choir and publishes an album with the choir’s name.  You want to give credit where credit is due, so the album artist field dutifully contains both the primary artist and the contributing choir.  But what happens when the artist publishes a solo album?

I’ve turned this one around in my mind for some time.  It becomes a problem when listing artists, in which case a single artist can be listed 2, 3, even 4 times.  Or when trying to browse an artist’s discography.

Part 1 of the solution was to introduce an “artist alias” field into the backend database, which is intended to contain the most recent pseudonym for that artist.  This isn’t the same as “TLC” vs. “Left Eye”; rather, it’s intended for people like “Puff Daddy”, aka “P. Diddy” aka “Puff Daddy” aka “P. Diddy and the Bad Boy Family”, etc.

OK, so we then had the ability to search on alias.  And the alias field is a calculated field, in that it will return the value of the artist field if the alias is empty.  Groovy.

However there was still the problem of listing and browsing.  You’d think that the artist alias would be enough, but you’d be wrong.  Take Bobby Valentino, aka Bobby V., aka Bobby Wilson.  I don’t believe he’s published any names under Bobby Wilson, yet that’s his current psuedonym (in this case, his real name).

Now, it would be fine – I think – to browse Bobby’s discography using nothing other than the Bobby Wilson alias.  However, we get into major problems when we want to see all songs where Bobby Wilson is the primary artist.  Those songs may exist on albums that are not Bobby Wilson albums at all – ie, soundtracks – or he may have still been going by Bobby Valentino at the time.

Basically, you’d need to search by all known aliases in those cases.

So after much consternation, I finally put together the code to make this happen.  Works a treat.  You have to take some care when putting together a manual search, as you have to understand exactly what it is you’re searching.  This is a fairly standard condition though, I think.  Otherwise, use the plethora of buttons and links which will do the heavy lifting for you.

While I was at it, I decided to tackle another dilemma: handling artist names that contain quotes.

Quotes are Bad News(tm) in the programming world.  You have to escape them, which isn’t bad.  But still, they can cause major problems.  Take the following example:

Give me all albums by Damian "Junion Gong" Marley, or by Lisa "Left Eye" Lopes.

Those are both valid artist pseudonyms.  And, if you construct the search with two artist fields OR’d together, you’re fine.

But in some cases – and this is true for our discography browsing code – you use a search specified like this:

artist is "Lisa "Left Eye" Lopes" or "Damian "Junior Gong" Marley"

There may be any number of reasons why you have to use this format versus the one above.  In my case it’s due to restrictions in the code and how parms are passed around.

Regardless, what you’ve got there are nested quotes.  And previously, my code would spit it out and give some unknown result.

No longer.  There are some basic assumptions that you can make:

  • a quote followed by a non-whitespace character is an opening quote
  • a quote followed by a whitespace character (or end-of-line) is a closing quote

There may be more, and more complexity, but you get the picture.  And indeed, these may be rules that you enforce rather than simply assume to be true.  With those rules in place, the code can now track nesting levels.  Escaping is another simple step away.

Wifey say, wifey do: zone drag/drop active

I don’t really know what to say about the titles that I come up with.  I mean, they’re my ideas, so I can’t sit here and shake my head in disbelief or some mild form of pity.  But really, what the heck does this one mean?

Well, at least the second part is fairly self-explanatory – to a degree.  It’s now possible to drag-and-drop an album or song directly onto a zone while in the browse view.  The idea is that you can queue up – or begin playing – an album/song without going through the steps that previously existed (and still exist) to perform this apparently arduous task.

Yes – “apparently” – and this is where the first part of our interesting title is explained.  One day, a long long time ago, Shelly said that it really should be possible to drag-and-drop an album onto a zone.  I believe that I was in the midst of showing her the ability to drag-and-drop an album/song onto the working list and have the item added to the list.

I’m not sure what prompted her to make this suggestion.  The thing is, the drag/drop facility is only available on platforms that support dragging – like a laptop or desktop – and not at all on platforms like smartphones which have no concept of how to perform a drag/drop action.  And – you guessed it – Shelly users her smartphone to interact with the system.

Nevertheless, I said “yes ma’am” and eventually got to work.  And the fruits were fully realized today (well, a couple of days ago but polished a bit today) with code that makes Shelly’s suggestion a reality.  As I said, from the browse view, you can drag an album/song over the existing play icon, which will cause a popup to be dynamically created containing all of the zones.  Finish the drag/drop operation by dropping the album/song on one of these zones, et voila, Something Happens(tm).

That “something” is dependent on a few things.  For an unloaded/unlinked zone, the operation will always end with the zone being shown and playback started.  Depending on your prefs, you may be asked if you want the zone to be linked.

For a zone that is already linked, the operation will cause the dragged item to be added to the linked list.  You remain on the browse view, but there is a helpful popup that says “Added” just to confirm that, indeed, Something Was Done(tm).

Now, the 5-billion-dollar question is: is this really necessary?

Well let’s look at the title for the most obvious answer: Wifey say, wifey do.  Wifey said “Do it”, and now wifey can do it.  Easy breezy.

Okay, how about a more general discussion?

I’ll oblige.  If you have the ability to perform this drag/drop operation, then you have the ability to use the other nifty features presented by the interface – most notably, the ability to take advantage of dynamically-loaded popups and inline information.  Previously – and currently – the steps to play an album or song (we’ll just say an “entry”) could most easily be performed by clicking the popup icon for that entry, clicking the play icon in the resulting popup, and then clicking the zone in the resulting zone list that got dynamically loaded into the popup.  This operation would always result in you getting transferred to the zone, where playback would have been started.  In the case of a zone that was previously linked, the linked list would be overwritten (unless the list was not an auto-generated linked list – in which case you’d get an error).

So if anything, that’s three clicks and waiting around for two dynamic operations to complete (the popup and the inline zone list) before anything could happen.

With the new drag/drop ability, you really only click once and you have to wait for one dynamic operation to complete – ie, the popup containing the zone list.

So from that point of view, I suppose I can agree that the new method is indeed more efficient.  I have to wonder how many times in one session a user is likely to load an entry to a zone – or in other words, how much impact this increased efficiency would have in the real world – but I suppose one can’t argue when it comes to the inherent goodness that is “increasing efficiency”.

But wait… perhaps there’s more to this.

What really makes this worthwhile is that the code is linked-status-aware.  Meaning, it does different things depending on the linked status of the destination zone.  This was alluded to earlier, but allow me to focus on it in more detail.

While it’s all well and good to drop an album on a zone and call it a day for the next 60 minutes, what happens if you’re putting together a 4-hour playlist of albums – or a 60-minute playlist of songs?  Now we’re no longer talking about loading a single entry to a list.

The previous (and still existent) optimal method for doing this would have been to create a new playlist and select it as the working list – or perhaps to load the first entry to the zone, then select the resulting list as the working list.  This doesn’t always work well if you’re working with albums, as the system isn’t guaranteed to create a linked list for a single album depending on how your prefs are set.  But supposing that it’s set appropriately, either of these methods would get you pointed in the correct direction.

Then, you could drag/drop additional entries to the list – or use a pulldown, or a checkmark,  or whatever other method you liked.  But the point is that you’d want to select the list that ended up getting linked to the zone of interest.  Or, if you manually created the list, then you’d select this list as the one that you will eventually load to the zone of interest.

With this new method, the only thing you need to know is what zone you want to work with.  You could have an entirely different list selected, or no list at all.  The list is not important – only the zone.  So the new sequence of events becomes: drag/drop an entry to the zone, return to your browse results, and drag/drop more entries to the zone.  The backend will take those additional entries and add them to the list associated with the zone.

You can see that this method offers clear benefits.  Again, there’s no need to work with or even know which list is linked to the zone.  This is especially useful if your current working list was used as part of the criteria in your current search.  Changing your working list to become the linked list would alter your search results, which may make it difficult to select more entries to add to the working list.

But most crucially, you get to take advantage of the increased efficiency that we discovered previously.  Yes, you could already drag/drop entries onto your working list – ie, the same efficiency that drag/drop onto a zone offers (better efficiency in fact, since there’s even less dynamic loading going on) but again, this only factors in if you select the linked list as your working list.  Now, even without selecting the relevant linked list, you can drag/drop and end up at the same place.

So ya, that’s cool.  I did some initial work in the backend to allow the user to drop a search result onto a zone as well.  I don’t have  draggable defined for this, but once I define one then it should Just Work(tm).  Truthfully it would also be nice to be able to drag/drop multiple items at once.   This may be straightforward for the backend to handle, but I imagine the frontend would need some serious work.  I’ll hold off on getting that going, but I suppose it is a project to look forward to.

From a technical point of view, I will say that getting this to work took a few days, but the hooks were mostly present to make it all go.  The stuff that I added amounted to handling a new breed of popups, which are non-modal and presented more as a menu anchored by an element on the page.  This comes with the need to define a relationship to that anchor, manage timers (which close the menu appropriately), clean up everything when a drop occurs or a drag is cancelled, and defined special “action” elements to overcome z-index issues.  The action elements – “actionables”, as I call them – were already necessary for regular drag/drop operations (again, due to z-index issues) but needed to be extended to work with menu-ish popups.

C’est tout.

What fresh eyes can bring

Last week I attended a 5-day training course, and on the last day (Friday) I came back to the office since training ended at about 12PM.  This course of action was frowned upon by some, who insisted that when you attend “this sort of thing” the expectation is that you go home if it finishes early.

That didn’t sit well with me, so like I said, I found myself at work.  I felt strangely refreshed and renewed.  Not sure why, but it was almost like coming back from vacation.  Except better – for me at least, since being away on vacation often carries stressors of its own.

Anyhoo, today I came in and went about my usual routine – which includes connecting to home so that I can stream music from the audio system.  At some point I needed to move some entries around in a playlist, and for whatever reason it hit me that there was some trivial code that I could implement to make that process (moving entries around) nicer.

You may recall that I spent a whole bunch of time in the past coding my own dynamic-reordering solution, which lets me reorder records in a table without having to refresh the whole page.  The concept isn’t novel, but in my case I was never comfortable with using DHTML to simply swap rows around; I wanted to the backend to feed updated info to the frontend, since there’s more happening than just swapping visual elements.  So my solution was to clear the table and have it refresh itself from the backend.

I was never 100% comfortable with this, for a number of reasons, but it dawned on my today that I didn’t need to refresh the whole table; rather, I only needed to refresh those rows that would be affected by the reorder.

So that’s what I did.  And it’s quite nice, if I may say so myself.

This is the sort of thing I hope to bring to web-based projects at work – finding little, novel evolutions to the code that bring noticeable improvements to the UI.

Anyhow, that’s all.

A proper zone in the master bedroom

So here’s the scenario.

We’ve got this handy system called the Whole Home Audio system, and it allows us to play networked music to a number of physical and virtual zones.  We can use it to play music in the basement, or in the family room, or even in a car doing 100+ km/h on the highway.

Without question the physical zones are cool.  The family room zone is the coolest, since I can use my (dying) Harmony universal remote to issue transport controls and the system will respond accordingly.  That’s a pretty nice example of bridging hardware and software; in the family room, the nature of the audio system is completely* hidden.

* (the caveat is that, currently, you can’t select anything to play if nothing is loaded on that zone.  Minor issue, but I’m mentioning it in the interest of full disclosure).

The basement is somewhat unique in that the volume controls exist in the home audio interface, so you mash buttons on the interface page to increase/decrease volume.

In both cases, being physical zones, the requirement exists that we have sound hardware in the server to pump analog audio to the zones, and obviously, that there’s a physical connection between this sound hardware and the amplifying sound hardware at the destination.  This has worked for the basement and the family room, due to their proximity to the server.

The master bedroom, on the other hand, has never gotten to enjoy this sort of seamless/impressive hardware/software bridge.  It has always relied on a streaming client – functionally equivalent to my phone, or WinAMP on my work computer – to stream music through the floors and walls.  The streaming client in this case is GSPlayer running on a no-longer-used-but-still-loved PocketPC PDA, which itself is connected to a 2.1 speaker setup.

So playing anything to the master bedroom has meant:

  1. Play something to a particular zone – usually streaming zone 3
  2. Turn on the PDA and mash the play button repeatedly until WiFi connects and GSPlayer connects to the streaming zone
  3. When your musical enjoyment has ended, power off the PDA

This works, but it’s less than convenient.  And as you can imagine, I wouldn’t be posting about it here if I didn’t come up with a solution.

And so, fresh off of my success with GSPlayer modifications, I once again delved into GSPlayer’s inner workings and gave it the ability to accept incoming TCP/IP connections.  That was part 1.  Part 2, was to give the home audio system the ability to connect to said GSPlayer and tell it to Do The Damned Thing(tm).

Okay, I’ll explain.  The idea here is that the user should only ever have to interact with the home audio interface/system when it comes to selecting joints and loading a zone.  You can use controls at the zone to control playback, once started, but starting playback should itself be a homogeneous process.  So obviously, pressing play on a home audio interface page, then powering on a PDA and pressing play repeatedly… well, that didn’t cut it.

The fact is that it’s the home audio system which receives your request to load a zone, so armed with that knowledge, it should be able to do Whatever Is Necessary(tm) to complete that request.  For the family room and the basement, this culminates in WinAMP being loaded with relevant song data and audio suddenly starts to stream out of the respective speakers.  Streaming zones will always* require a two-step process, and that’s to be expected given their nature.

* (there may be exceptions to this in the future; see this post for one example)

So yes, it’s true that the master bedroom needs to rely on a streaming zone since its physical proximity to the server can’t be (easily) overcome.  However, as a user of the system, your perception is that you’re at home, you’re in a static environment (ie, a room) and therefore you consider it a physical zone and hence you want it to behave as such.

Back to the technical stuff.  The GSPlayer modification allows the home audio system to tell the PDA to connect to the streaming zone and start playing.  And in a nutshell, that’s the crux of it.  You load the master bedroom zone using the home audio interface, and the system loads WinAMP and tells the master bedroom to connect.  The PDA must stay powered on all the time in order for this to work, but that’s trivial – much as the basement amp must be powered on to play music in the basement (it’s always left turned on).

Now, in practice, there were many considerations that had to be dealt with in order for this to work as expected.  A third component had to be modified – specifically, the WinAMP general purpose plugin that’s currently used to give certain feedback to the home audio system.  That plugin, being intimately tied to the guy that actually plays music, is the ultimate source for information on what’s happening.  And for the master bedroom, I decided that we wanted the “start playing darnit!” notification to be event driven and fired by the guy who knows when playback has actually started – ie, WinAMP, ie – the WinAMP plugin.

There are timing issues that help to lead one to this logical conclusion as well – as I said, there were many considerations.  But conceptually, the event-driven (ie, WinAMP-plugin-driven) approach it makes the most sense.  And the things that make the most sense are usually the things that are easily capable of resolving related, niggling issues.

So here’s what happens.  You select some Brian McKnight and send it to the Master Bedroom zone.  The home audio system goes through the motions of sending a playlist down to WinAMP.  WinAMP may churn and burn for a while, but we don’t care – nothing happens until WinAMP starts playing.  Once WinAMP does start playing, the plugin fires an event back in to the home audio system.  The system parses this, determines that the Master Bedroom has an “RPC-capable” client, and sends a suitable command to said client.  The client – GSPlayer in the master bedroom – gets the command to start playing and connects to the appropriate streaming zone.

And Bob is your uncle.

Once playback stops on the zone, GSPlayer will disconnect since the stream has stopped.  Or, if you’re no longer jonesing for Mr. McKnight, you press stop in a home audio interface page, and the system sends a command to GSPlayer to stop playback immediately – vs. waiting for the streaming buffer to empty.

So most of this has been tested successfully.  Today I cleaned it up and “properized”  it, so I’ve still got to make sure it works exactly as expected.  I may – or may not – post back here with my results 🙂

Whole Home Automation – what’s new?

Time sure is flying.  Sometime in spring I made tentative plans to see “The Expendables” with a friend in August.  At the time I thought that the date – August 13th – was soooo far away.

Ya, right.

I’m not here to bemoan the rapid passing of Time though; I’ll leave that for another entry – which may or may not ever get written btw.  No, I’m here to continue the chronicle that is my Whole Home Automation journey.

Now, I can’t say that the scope of the project has changed.  It’s still limited to audio and surveillance.  On the surveillance side there’s not much to report; occupant detection is working, and although I haven’t hacked any USB Bluetooth dongles I can also say that the system is working acceptably as-is so I’m in no rush to change things.

On the audio front it’s been a case of small updates and bugfixes here and there.  One of the bigger useability updates has been to allow the download of a .zip file of select tracks.  This makes it easy to download a selection of tracks to a local device, or download an entire album to Shelly’s phone.  It’s not something that I’ll use often, but it’s nice to have.

Something that should be more useful for me, however, is a project I just completed that’s physically removed from the system at home – but interacts with it nonetheless.  I’m talking about playback of streaming zones, and in particular, playback of streaming zones using _my_ Windows Mobile smartphone.

Here’s the scenario.  I’ve got some tracks queued on a streaming zone.  I hop in the car, connect to home, and start playing that zone through my phone (and obviously through the car stereo).  Then I hit a joint that’s bangin’ – or lame – and I want to repeat that joint or skip it altogether.

Traditionally this has been possible, but it meant having a browser open on the phone and connected to the zone page for the streaming zone in question.  You press a transport control on the webpage, and some seconds later (up to 15 seconds in some cases) the streaming buffer gets around to reflecting the changes.

“Wouldn’t it better”, I wondered, “if you could use the player’s transport controls to control the zone directly?!?”

Yes, it would.  And so now it is.

I toyed with the idea of writing an app from scratch.  And while this is something I may still do, the opening lines of this entry are quite clear in this respect: Time is at a premium.  Sometimes you have to settle with something that works rather than something that’s perfect.  It’s not a mantra that I usually adopt, but in some cases – as with the Bluetooth dongle – it’s acceptable.

So as it turns out, GSPlayer is open-source.  It’s a player I’ve used in the past, and I think that I passed it over in favour of PocketMusic because the latter is purtier and has bigger buttons.  But if the buttons aren’t useful, then who cares?  That, and PocketMusic has some stability issues – to the tune of often requiring a soft-reset of the entire phone.

Anyhow, I modified GSPlayer and captured transport control events so that it will send RPC commands to the backend server.  So if I press the “next track” button in GSPlayer, it will tell the backend to move to the next track.  It will also disconnect/reconnect the stream to make sure the streaming buffer is cleared.

And of course, it only does all of this if a stream is active *and* that stream appears to be connected to my server.

So ya, that’s that.  I did a quick test on my phone and it seems to work.  I’m off to run a few errands shortly and I’ll do the trial-by-fire at that point.

Are you Home? Scratch that, I have the answer!

Yessir, as the title suggests – occupant-awareness of functional!

It works, surprisingly.  The gotcha now is that range is limited – it will happen multiple times overnight that the system will switch from Home to/from Away, as it has trouble finding our phones.  But I knew that that might happen – part 2 of this project is hardware in nature, to modify my USB Bluetooth dongle with an external antenna (and hence, greater range).

But ya – it’s uber-cool.  As always there were/are some bugs to work out.  Not with the detection steps per-se, as that seems to be rock solid.  Rather, with the tie-in of the surveillance system.  I had to think for a while about what and when a state change should occur.

Here’s the thing.  While it may be sufficient to poll to see when occuapants have left, it’s not really sufficient to poll to see when occupants have arrived.  By the time that a polling run occurs, the system may have already detected me or my wife coming home and send an alert.  And it may continue to send alerts until the polling run determines that our phones are home and – hence – the system state should change to Home.

That’s one.  Two, is that it’s very possible for either myself or the wife to forget our phones at home when we leave (you can determine who’s more likely to do this…)  It’s possible to set the system to an explicit Away state during which it will not poll for Bluetooth radios… but the problem is that the system (as currently designed) can’t expose this state to the polling process.

That means that the polling process is only used to determine when we’re away.  To determine when we’re home, the system relies on a surveillance event.

Which is fine – in theory that’s a great solution.  In practice we’ve got some implementation issues.  One, is that the limited range of the USB Bluetooth dongle means that an audio event will likely be the one to switch the system to Home – and audio events are most likely to fire for sounds inside the house (this isn’t always the case, but is a guaranteed case).  So an alert will still be generated due to exterior motion detection.

That problem can be solved with an increased Bluetooth detection range.  So we’re good there.

BUT… the reliability of the cammies’ detection events must be high if we’re going to use them to set the Home status.  That’s what I’ve been struggling with.  Not that they’re not reliable – rather, it’s the age-old problem of some required process going into La-La-Land(tm) and messing everything up.

And let me tell you, I’ve struggled with those problems over and over and over.  I thought things were pretty stable, until I found out that audio monitoring likes to… stop… …. .  Anyhow I think I’ve got that one worked out now.

So ya, once I get that external antenna hacked together we should be good!

Are you Home? The project takes shape…

Wow.

For a Long Time(tm) I’ve wanted some way to add “occupant awareness” to my fledgling home automation system.  There are some really cool things that you can do if you’ve got the hardware and software: announce missed calls and playback voicemails on your networked phone system; turn on the TV and list the shows that have been recorded; turn on the audio system and start some background mood music.

And so on and so forth.  Personally I’m not sure that I want that level of personalization, but one thing I’d really love to make occupant-aware is the networked surveillance system.

Currently the system has two macro states: Home and  Away.  There are various micro settings that can be configured; which cammies have audio monitoring enabled, the size of the detection field, the sensitivity of the detection field… but for the most part the system will switch between a set of Home micro settings and Away micro settings.  Those macro states also dictate how the system determines which events should trigger an alert.

The system currently changes states based on a hard-coded schedule.  It also considers sunset/sunrise, but again that only serves to change some micro settings.

The problem with a schedule is that we don’t always adhere to it, especially on weekends.  I’m pretty diligent about sending commands from my phone to change the state of the surveillance system, but I can’t expect the wifey to do so as well.

Soooo… I started looking at automated solutions, and those solutions would most certainly involve phones.  For the most part it’s a safe bet that we carry our phones with us when we leave the house so it would be great if we could use the phone locations to determine if we’re Home or Away.

I started off looking at some way to have the phones updated their location to the home system.  This can be done using some custom programming and tying into the GPS coordinates, but GPS is a power hog.  Okay, then we can use the cell towers to get an approximate fix, then turn on GPS when the phone is on the “home” cell tower.  That may work, but it’s still troublesome.

So I went back to Bluetooth.  “Back”, because I had done some reading about a year ago and thought it looked promising but had no clue how to write a solution.  The idea is simple – the phones have Bluetooth turned on 24/7 and a computer on the home network simply polls the Bluetooth radios to see who’s around and who isn’t.  Both myself and the wife leave Bluetooth turned on so that our phones can connect to our cars automatically.

So the hurdle then was to see if I could code a simple program that could detect when a Bluetooth is in range.  Any by George, I could!  It’s  a proof of concept, but it’s remarkably small and simple.  In my testing it takes 2-3 seconds to determine that a device is *not* in range.  I make an attempt to connect to the OBEX Push Service, since pretty much every phone supports this Bluetooth profile.

So the next step will be to install this program on a laptop and see what kind of detection range we can get.

Looking good!

Useful, or crammed?

New article on Piper’s Pages:

Something was bothering me with my fancy-shmancy AJAX/DHTML popups in the Home Audio interface.

It manifested itself mostly when adjusting track BPMs for a new album.  Basically, one has the ability to browse on an album’s tracks, then get the track popup for any particular track and – using forward/back navigation in the popup – move around the browse entries via the track popup.

This is cool in practice.  You can see more detailed deets for browse entries (as well as options like track suggestions) and quickly compare between tracks by clicking prev/next.  No need to display the popup, close it, then display the popup for another track in the results.  Same goes for albums, of course.

So when BPM’ing an album, I had two options: 1) use the quick-edit links so that I could get the edit popup straight from the browse results, or (2) display track details and use the edit link from the popup which then loaded the edit popup.

It was kinda nice using the second option, because sometimes you don’t need to edit the BPM and you can just next-next-next through the entire list – no need to scroll the list, figure out which track you’re working on, then click to get the details popup or the edit popup.

BUT… sometimes you’re not sure if the BPM that’s in the DBMS is correct, you want to use the edit popup so that you can tap out the beats and see if it’s a match.  If it’s a match, you close the edit popup – but the entry doesn’t highlight since you didn’t change anything, so you lose visual reference as to where you are in the list.

You could use the details popup, then go to the edit popup, but same problem – once you closed the edit popup you were back to a list of tracks with no visual reference as to what you last looked at.

And this underlined a more general problem – with all these dynamic popups, what happens if you want to go back one popup?  What happens if you want to display the details popup, then the edit popup, but then go back to the details popup so you can “next” to the next entry?

One way to do this is to keep a history in the backend of popups you’ve looked at.  Problem is – and this has cropped up before – the application is purposely free-flowing, and you can have multiple windows/tabs open all using the same session (sharing the same search history, context, etc.)  If you’ve got popups going in two windows, the history will be intermingled and thus useless.

So I took a different approach.  Instead of a popup yielding more popups, I decided that additional popups could be dynamically loaded into the first popup.  So for example, you get track details in a popup, then click to edit BPMs and the edit dialog is loaded into the current popup rather than appearing as a new popup.  Submit your changes and the main popup remains.

Works a treat.

The only problem is that the popup is meant to be somewhat small relative to the main interface, and when we start dynamically inserting some of these other popups – ie, the zone selector – the popup gets to be a little large and looks a little “crammed” – hence the title of this article.  But I think that’s a small price to pay for the increased usefulness (again, linking back to the title of this article), and I can probably make it more palatable with careful application of visual styling elements (via CSS).

Yup, so that’s that yo.

I also added the ability to start a new search using a popup – not just a saved search as before, but actually specifying search conditions.  Not all of the fields are displayed in the popup as they are when you actually navigate over to the search page, but in concert with dynamic search fields it offers a handy way of firing off a quick search.

Werd up.

Eat my shorts! AJAX drag-and-drop baby!

New article on Piper’s Pages:

In my neverending quest to learn (everything?) AJAX, I decided to dip my fingertips into the pond that is drag-and-drop.

Probably the most famous of AJAX techniques, it allows you to grab something on a page and move it somewhere else – either because you like to assert your creativity, or because you want to Do Something(tm) (like add an item to shopping cart).

Well ladies and gents, we’ve taken our implementation of drag-and-drop to a Whole New Level(tm).

You may recall that we’ve had AJAX popups for ages now (ages <= 1 year) and you could grab those popups and move ’em around, just cause they might be covering stuff you want to see. Cool, but… that didn’t DO anything really.

So here’s what I envisioned.

I envisioned an interface with multiple panes – one for browsing, one may contain a zone, and another may contain a list. It would be wicked and wild if you could drag an album on your list or onto the zone to queue that album.

This obviously requires more kung-fu than just moving popups around the screen.

So…. if I’m not mistaken I’ve been using Scriptaculous for the popup dragging, and after trying to bake my own more-advanced solution I realized that Scriptaculous could do what I wanted (and it was even using the same terminology I was using – “draggables” and “droppables”).

So the first crack at this yielded the ability to drag stuff from the browse view onto the link that indicates your working list. That causes the album/song to be added (or removed) from said list, which also happens to flick the checkmark for that item (this happens as a result of existing code).

Okay, so that’s cool I guess, but said checkmark could simply be clicked to achieve the same results. Nothing really new here folks, so move along!

My pleasure. My next effort was to enable drag-and-drop table reordering. Currently, in list view, you’ve got teeny weeny icons that you can use to move a row up or down, one at a time. Sure, you can select a bunch of rows and move them all up or down at once, but again they’ll move one at a time.

With these handy dandy scrolling tables, it sure would be nice to grab a row by the scruff of its neck and manhandle it into a new position, right?

Yes, it would. And while Scriptaculous provides an easy breezy way to get this done, fact is that my implementation of dynamic tables is slightly incompatible with Scriptaculous. If I had to actually take time to explain why, I would say that it has to do with my padding process – which means that in any given table, some of the rows have actual data and some do not. I use different DOM ID prefixes to track this, but even if I used a seperate array to do the same thing I’m pretty sure we’d run into context issues: does it make sense to reorder a row that hasn’t been filled in yet?

Sure, the way I’m registering draggable items means those rows wouldn’t be considered draggable by Scriptaculous until they were force-fed useable data by backend, but… why are you trying to convince me to use Scriptaculous for this??? Look, the fact is I wanted to keep my DOM ID convention, and I don’t like the way Scriptaculous reports the new ordering to the backend. When you’ve got a table that can contain, oh, 30000 rows the last thing you want to do is iterate through a serialized list of row IDs and tell a DBMS to reorder based on that list. Ugh.

So I baked my own solution, which was based on the work I did (and partially abandoned) for effort 1.

And… it works!

At least in Firefox. It looks like it wants to work in Chrome and Opera, but I’ve got stoopid text selection issues to overcome still. But at least the concept works, and admittedly it’s quite handy.

So ya – drag-and-drop/table-reordering with backend updates. Funky fresh.

What the HECK is this Whole Home Audio thing?

Glad you asked.

For the past x years I’ve been toiling away on a combination of software and hardware at home that allows me and the wifey to play selections from my vast collection of music to various rooms around the house (and beyond).

If you visit Piper’s Pages, you’ll find a post (login as guest) that begins the record of how this endeavour began.  Yes, it began 4 years ago.

And it’s still going strong.

Browse interface

Browse interface

The project, in today’s form, uses a web interface to browse/search the collection.  The search options are quite powerful (confusingly so?) and can be saved for frequent use, you can create playlists of songs and albums, you can have the system suggest similar music.  There are statistics – including scoring and ranking – and metadata pulled from external sources.  We’ve even got BPM info.

music_zoneThere are a slew of maintenance scripts that power this thing, and no less than three disparate “servers” that go into making it all happen. Currently we’ve got two physical zone – family room and basement – and another four virtual zones for streaming.

So that’s the short intro.  For more you’ll have to visit Piper’s Pages and check out the DP’s Corner database.