I recently worked on a project which, among other things, involved implementing the "easybe 1-2-3" music store software (basically, it's a pretty simple-to-use platform for managing for-sale music downloads).

One of the major drawbacks of this software is that it doesn't come pre-built with a music player.  While it does provide links to file samples that users can download and listen to (way too many steps for 30 seconds…), there's no one-step player for checking out clips from all the songs on an album.  

No fear!  There are ways around this, and in the following I'll walk you through the simple steps to deploy a free, light-weight mp3 player that can play the music you want your visitors to hear.

First, let's get the mp3 player.  While you could use many of the freely-available mp3 players out there, I like the one from premiumbeat.com.  It's super-stipped down and simple to use.  Plus, it accepts an XML file, which will work perfectly for our needs.

Once you have the mp3 player of your choice, go ahead and deploy it on your server.  Don't worry, I'll wait until you're done.

All set?  Excellent.  The next step is to open up the Album Details template file in easybe.  It's in the 123-music-shop/templates/shop/ directory, named something like "albumdetails.tpl".  Why this page?  Well, when this page is active, certain data is exposed via PHP that we can access and pass on to other pages that we'll need to modify.  So for example, on the album details page, an object named "Album" is available, and from this we can access the "id" value, which identifies our album in the database.  (NOTE: I'm not sure this is documented.  I found it out simply by playing around and making good guesses!)

So here's what we'll add to the "albumdetails.tpl" page:

<script type="text/javascript" src="swfobject.js"></script>
<div id="flashPlayer">
  This text will be replaced by the flash music player.
</div>
<script type="text/javascript">
   var so = new SWFObject("playerMultipleList.swf", "mymovie", "295", "160", "7", "#FFFFFF");  
   so.addVariable("autoPlay","no")
   so.addVariable("playlistPath","playlist.php?albumid={$Album.id}")
   so.addVariable("playerSkin","2")
   so.write("flashPlayer");
</script>

Pretty simple.  Basically, we simply initialize the mp3 player (the one from premiumbeats.com, in this instance), passing a dynamic path in our playlistPath variable.  Notice that I'm passing {$Album.id} — this is id of the album I mentioned before that is exposed.

Ok, so we're almost there!  All that's left now is to generate the XML that will build our playlist and feed the mp3 player.

Now go ahead an open up a new file.  I creatively named mine "playlist.php", but feel free to be more generic if it suits you 🙂

In this file, we need to do a couple things.  First, we need to evaluate the "albumid" that we pass through the URL query string.  Next, we need to query the database to get all the songs for the albumid that we've passed.  And finally, we need to generate some XML that the mp3 can understand.

(I'm going to assume you know how to set up your database connection in PHP, and hopefully you also know how to parse out the query string.  WIth that assumption, let's move on to the database query.)

So one of the odd things about easybe is their db structure.  Rather than storing info about albums, songs, etc. in a flat, relational way, they store the data in an almost key-value pair (or trio or quad…) manner.  While not impossible to work with, it can make getting at the data a little less that straightforward if you're not used to seeing this kind of thing.

For example, 1 song in the "productav" table spans at least 7 rows, producing a structure like this:

ID    Name                        Ord        Value
1     artist                   NULL     Seth Condrey
1     title                     NULL     Jesus Paid It All
1     running_time        NULL     5:17
1     free_download      NULL     true
1     song_file_name    NULL     Jesus Paid It All_1.mp3
1     demo_file_name   NULL     Jesus Paid It All 30sec_1.mp3
1     single                  NULL     yes

Obviously, a regular relational approach will not serve your queries very well!  Of course, there are several ways to accomplish the desired result, but here's the final query that I arrived at:

select     p.id,
    (select value from productav pv where name = 'artist' and pv.productid = p.id limit 1) as artist,
    (select value from productav pv where name = 'title' and pv.productid = p.id  limit 1) as title,
    (select value from productav pv where name = 'demo_file_name' and pv.productid = p.id  limit 1) as path
from product p
join bundleproductasm b on p.id = b.productid
where bundleid = $albumid
order by childorder
 
The most interesting thing to note here is the use of the subqueries in the select statement.  If you're not familiar with this approach, what I'm doing is to basically create a faux column of data, based on the results of another query within the scope of the currently executed statement. In other words, I can take the 7 or so rows from the productav table and flip them into a structure that I can actually use.

Ok, so much for mySQL.  Now our last step is to write the PHP code that will produce the XML.  What follows is a very limited approach: you may want to try something a little more robust if you have more extensive needs:

<?php
    // Send the headers
    header('Content-type: text/xml');
    header('Pragma: public');        
    header('Cache-control: private');
    header('Expires: -1');
?>
<?php echo('<?xml version="1.0" encoding="utf-8"?>'); ?>
<xml>
<?php if ($count > 0): ?>
    <?php while($row=mysql_fetch_array($rsongs)): ?>
    <track>
        <path>public/demos/<?php echo $row['path']?></path>
        <title><?php echo $row['title']?> – <?php echo $row['artist']?></title>
    </track>
    <?php endwhile; ?>
<?
ph
p endif; ?>
</xml>

N
othing even worth pointing out here.  A simple loop of the data, and we have some nice XML to spit back at our mp3 player.

And that's about it.  Even though easybe is pretty limited OOTB, it is easily hackable, so adding on some nice little touches here and there are relatively easy and make for a much better product when it's all said and done.