Creating on-the-fly MP3 playlists on the NMT

I bought the excellent Popcorn Hour media server a couple of years ago, and I’ve always loved the job it does on my video files, especially with the equally fantastic YAMJ that rebuilds the video jukebox every time I get a new TV show or movie.

But I’ve never really gotten the NMT to play well with my audio files — it doesn’t handle standard playlist formats like .pls or .m3u, so you’re stuck playing one song at a time unless you can figure out its own insane .jsp playlist format.

Most of the music jukebox programs that I found for the NMT seemed needlessly complicated, creating dozens of files (playlists, album cover images, html and XML) and forcing you to put your MP3s into a certain folder structure.  I didn’t need to be able to pick and choose any song from my extensive collection.  While my MP3s are generally pretty well-tagged, I do have dozens of files where I don’t know the album name, and that would mess up most of these playlist generators.

All I wanted was a way to quickly and easily get some music going on my nice home theater through my Popcorn Hour, preferably with a “shuffle” option — start it up and let it run.

A couple of weeks ago, I was getting desperate, so I tried the Music Jukebox program that so many people recommended on the NMT forum.  I gave it a subset of my music and turned it loose to create its myriad files.  Its output turned out as I expected — an index page, plus a page for each album, with playlists for each song and a “play all” playlist.  But I was interested in the “shuffle” option at the top of the page.  It took the regular album playlist .jsp file and fed it to a shuffle.php script running on the MyiHome server on the NMT.  “Ah,” I thought. “I can reverse-engineer this bad boy.”

I dove into the PHP code and found that it was reading in the playlist file, then putting each line (which corresponded to an individual song) into an array, shuffling that array, and echoing the whole thing back out to the server as the new “playlist.”  I figured I could do the same thing with PHP’s glob function to find all of my MP3 files, shuffle them, and output a line for each of them back to the NMT.  That’s what this first simple script does (you may have to update the specific paths to match your folder scheme):

// get all of the MP3s in my "Music" folder's subfolders
$glob_files = glob("../Music/*/*.mp3");

// randomize
shuffle($glob_files);

// output in a playlist format that the NMT understands
foreach ($glob_files as $filename) {
    echo "$filename|0|0|file:///opt/sybhttpd/localhost.drives/HARD_DISK/Music/$filename|
";
}

It was super simple, but it worked great.  I was listening to a random playlist of every single MP3 on my Popcorn Hour’s hard drive, with the album art and meta-data that the NMT’s default music player could read from the ID3 tags in my files.  (I still wish that the player had support for showing the lyrics of the currently-playing song, but that’s another quibble.)

Next, I wanted to recreate some of the smart-playlist functionality that you get with iTunes or Winamp or Songbird.  There are certain artists in my music library whose songs my wife doesn’t enjoy listening to, and on Sundays I only want to hear LDS and classical music.  So I came up with the idea of specific modes that would filter the songs according to an artist whitelist or blacklist:

$glob_files = glob("../Music/*/*.mp3");
$mode = ( $_GET['mode'] ? $_GET['mode'] : "normal");

$artistWhitelist = null;
$artistBlacklist = null;

switch ($mode) {
	case "sarah":
		$artistBlacklist = array_map('strtolower', array(
			'Bush',
			[ ... ],
			'Weird Al Yankovic',
		));
		break;
	case "sunday":
		$artistWhitelist = array_map('strtolower', array(
			'Alan Silvestri',
			[ ... ],
			'Vivaldi',
		));
		break;
	default:
		break;
}
shuffle($glob_files);

foreach ($glob_files as $filepath) {

	// set the output as normal
	$output = "$filepath|0|0|file:///opt/sybhttpd/localhost.drives/HARD_DISK/Music/$filepath|
";
	$filename = basename($filepath, 'mp3');
	// my MP3 files are named like "Artist - Track.mp3"
	$splodedFilename = explode(' - ', $filename);
	$artist = strtolower($splodedFilename[0]);
	if (
		(!empty($artistWhitelist) && !in_array($artist, $artistWhitelist)) || // if there's a whitelist and the artist isn't in that array, blank out the output for this file
		(!empty($artistBlacklist) && in_array($artist, $artistBlacklist)) // if there's a blaclist and the artist is in that array, blank out the output for this file
	) {
		$output = "";
	}
    echo $output;
}

That also worked well.  It does take a bit more time to start playing the first song than a normal playlist (usually about 5 – 10 seconds), but given that it’s chewing through more than 5,000 tracks, I’m okay with a few seconds of delay.

The code that I use in my NMT index file I borrowed from the generated HTML from Music Menu:

Music
Sunday Music
Sarah-Safe Music

The next step would be to use one of the MP3 functions or libraries to actually read the ID3 tag from the MP3 file, to filter by genre and remove all of the Christmas songs, for example.  But I’m guessing that would take quite a bit longer to generate the playlist, and for now, I’m happy to either skip or listen to the odd holiday song that occasionally pops up.

In general, I now enjoy listening to my music through the Popcorn Hour on my big TV and nice stereo speakers.  Now if only I could make it scrobble my tracks to Last.fm

This entry was posted on Tuesday, March 1st, 2011 at 8:17 am and is filed under Programming. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply