Add an MP3 Player to EasyBe 32 comments   |   Tags: EasyBe   MP3   |   Sorta-Perma-Link
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; ?>
<?php endif; ?>
</xml>

Nothing 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.
Font Problem...Resolved! 63 comments   |   Tags: DfontSplitter   Mac Hates PC   |   Sorta-Perma-Link

Recently, one of my clients sent me a purchased font in the dreaded .dfont format (.dfont is how Macs save fonts...it stands for "Data Fork Font"...dumb!).  While this is nice on Macs [several fonts can be bundled in one .dfont file], it's not great for a PC because, well, Windows has no idea what to do with it.

Fortunately, Google provided an answer pretty quickly.  Apparently, there's a nifty little bit of freeware out there called DfontSplitter.  If the name isn't obvious, DfontSplitter basically breaks up the .dfont file from the Mac and converts it into individual True Type Font files...these Windows understands :)

So for those of you out there who have a Mac and are making fun of me for my lack thereof, bite me! For those that are in the same boat as me, check out DfontSplitter--it pretty much rocks!

Quick connectionString Epiphany 51 comments   |   Tags: connectionString   SQL Server 2005   |   Sorta-Perma-Link
Ok, if you're like me and aren't the smartest cookie in the jar, something like specifying a connectionString in a web.config file can be maddening.  Of course, it doesn't help that there are literally 123 billion possible ways to do a connection string...but I digress.

While searching for an answer, I ran across a pretty neat little technique that will make the development of your connection string quite painless.

First, open Explorer, and create a new file. Now, rename the file to X.UDL. Double-clicking this file will open up a Data Link Properties dialog window.

The super nifty thing about the DLP is that you can actually create a full-on connection to a datasource, and test out various settings.  Nice.

But the really beneficial part (well, besides verifying that, yes, this particular service account does, in fact, have access to SQL Server...) is the "All" tab.  Here, you'll see all of the properties of your connection.  While nice information, this is super sweet because these properties are precisely the parameters that you need to enter into your web.config connection string in order to make SQL Server happy.  That's awesome, and a huge time saver if building connection strings isn't something that you do on a routine basis :)