Being a bit old-fashioned, I still have my .mp3 music collection organized on my file system by genre and artist. I know, I know, download iTunes already, right?! Well I could but then I wouldn't have had as much fun writing my own code to automatically build play lists for me.
Once the Playlist Creator is finished building the .m3u files, you can double-click launch them through Windows Media Player or whatever media player/file extension you use.
After writing my original article about how to easily create music play lists using some simple recursion and LINQ, I reviewed my work and set out to make it better. One of the things I really wanted to "fix" in this version of the code was the ability to create a play list at each branch level of my folder tree. You see, I have my music collection organized by genre, then by artist, then by album. So I wanted the ability to launch a play list for, say the "Rock" folder which holds all my rock music, and so on and so forth anywhere in the tree.
The important topic of this code is to realize that creating play lists in this fashion would require multiple trips through the file system--with the end limbs getting hit time after time until they themselves get processed. Windows does a marvellous job at caching disc activity, but I'd rather attempt to write something efficient without having to lean on another efficiency process.
Using the Code
Once again, the main work accomplished by this code is:
- Traverse the file system collecting information about files and folders
- Dump this information into an in-memory typed-
- Iterate through the
DataSet memory creating the play list
DataSet looks like this:
A couple of simple
DataTables to house the collected disk information. I still find typed
DataSets handy for quick storage data tasks like this. They're easy to setup and seamless to code against.
Going for a bit more structure in my code, I have a separate assembly that provides all the work of finding the music files as well as building the playlists. All of the work tasks are done in the
PlaylistCreatorFP project and this project has a main class called
PCEngine that contains the main methods.
One of the interesting tid-bits I discovered while coding this re-write was the fact that the
System.IO.Directory class has a
static method for finding all the directories in a given path. Not ultra-new information, but I didn't realize that there is another parameter you can pass that will do the recursion for you:
string dirs = Directory.GetDirectories
(inPath, PCConstants.ALLFILES_SEARCH_PATTERN, SearchOption.AllDirectories);
Hooray! No more memory exhaustive manual recursion for my disk traversals!
The rest of the code is pretty readable [I hope ;o)] so I won't bore you all with the details here. The main methods in the
PCEngine class are
CreatePlayLists(...). The rest are supporting methods to these as well as an
event created to send update messages back to the main process thread.
The UI is another story. Talk about going overboard in a CodeProject article! The UI is a small WPF interface to allow the user to enter a few choices about where to start looking for music files, how to name the generated play list files, etc. Simple stuff just to make it more of a workable program. The work is preformed by a
System.ComponentModel.BackgroundWorker object to keep the UI running smoothly. Also there's a base class for the main window that uses Isolated Storage to store the window position and size upon close.
Points of Interest
While writing this, I learned:
- The "built-in" recursion of the
System.IO.Directory.GetDirectories(...) static method
- Creating Relations and using the
DataRelation class and its
ChildRelations(...) method along with the
.GetChildRows(...) row method to flatten the tree hierarchy
- How to create
delegate message events to easily pass messages back to the calling thread
- How to build a base class to extend the
Window class in WPF/XAML
- 27th April, 2009: Initial post
I'm probably going to leave this code for now. There's so many other interesting projects to tackle! But if you find bugs or have comments, please drop me a comment!