Playlist Maker
by Jim Chapman
Home| Where we live | Jim| Isabel| James| Edward]
/*
*
* PlaylistMaker/Class1.cs
* Copyright (C) 2002 Jim Chapman
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 (and no other version)
* of the GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* If you require a copy of the GNU General Public License write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Jim Chapman may be reached at: home@jim-chapman.net
*
*
* Revision History
* ================
* Who When What
* --- ---- ----
* Jim Chapman 11 May 2002 Released.
*
*
* How to Use the Program
* ======================
* This program requires the .NET Framework to be installed
* on the computer you're running it on. If you haven't already
* installed the framework, go to
* http://msdn.microsoft.com/netframework/prodinfo/getdotnet.asp
* to do so.
*
* This program should be run from a console window.
*
* If there is a command line argument, it should be the name of
* a directory. The program will use that directory as its base
* directory. If there is no command line argument, the
* program's base directory will be the console window's current
* directory.
*
* The program (like it says on the label) makes playlists.
* That is to say it traverses the base directory and the entire
* directory tree below it, looking for MP3 files. For every
* directory it finds which contains MP3 files, it build a M3U
* (playlist) file listing the names of all those MP3 files, in
* the order of their last-modified dates/times.
* Actually, it builds two files - one, it places in the base directory,
* and the other it places in the same directory as the MP3 files.
* The names of the playlist files begin with "!_PLAY", and then
* consist of the names of all intermediate directories between
* the base directory and the MP3 file directory, concatenated
* together and separated by "_" characters.
*
* This behaviour is simpler than it sounds. Run the program on
* a directory structure containg some MP3 files, and the results
* will make it clear what is going on.
*
*/
using System;
using System.IO;
using System.Collections;
using System.Text;
namespace PlaylistMaker
{
/// <summary>
/// Summary description for Class1. Class1 is a playlist-maker, but I
/// can't call it that, because the VisualStudio already decided to use that
/// name for the namespace. Thanks, Bill!
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Class1 c = new Class1();
// If there is a first command line argument, treat it
// as a directory name, and try to CD to it.
if(args.Length>0)
{
try
{
Directory.SetCurrentDirectory(args[0]);
}
catch
{
Console.WriteLine("Cannot change to directory "+args[0]);
}
}
// Call the method that does all the work. Begin with
// an empty 'directory path' list, because the path
// that is of interest begins at the base directory.
c.MakePlaylists(new ArrayList());
}
/// <summary>
/// MakePlaylists
/// -------------
/// This method performs all the functions of the program.
/// Its parameter is a list of directory names on the path
/// leading from the base directory to the current one.
/// </summary>
public void MakePlaylists(ArrayList path)
{
// First, list all the directories in the current
// directory, and work through them, CDing to each
// in turn, and recursively calling this method
// for each.
string [] dirs = Directory.GetFileSystemEntries(Directory.GetCurrentDirectory());
foreach (string s in dirs)
{
FileInfo d=new FileInfo(s);
string dirname=d.Name;
if((d.Attributes & FileAttributes.Directory)!=0)
{
ArrayList childDir=new ArrayList(path);
childDir.Add(dirname);
Directory.SetCurrentDirectory(s);
MakePlaylists(childDir);
Directory.SetCurrentDirectory("..");
}
}
// Now list all the MP3 files in the current
// directory.
string [] files = Directory.GetFiles(Directory.GetCurrentDirectory(),"*.mp3");
if(files.Length>0)
{
// Build up the name of the playlist file. For
// instance, if the base directory were
// C:\FOO\BAR and the current directory were
// C:\FOO\BAR\WITH\BILL\GATES then the playlist
// name would end up being:
// "!_PLAY_WITH_BILL_GATES.M3U"
string plname="!_PLAY";
foreach (string d in path)
{
plname+="_"+d;
}
plname+=".m3u";
// Sort the file names into ascending order of
// their last-updated times. This is done
// inefficiently (or at least, I'm relying on Bill
// Gates to cache file information for me, which
// is somewhat optimistic).
Array.Sort(files,new CompareTimes());
// Now create the playlist file in the current
// directory. The only slightly complex bit is that
// I use codepage-1252 encoding for the text in the
// file. That's the 'Windows' codepage (i.e. the one
// that the OS uses for filenames and suchlike, and
// it seems to be the encoding that MediaPlayer
// and similar programs expect to use for the
// filenames in playlists.
FileStream fs = new FileStream(plname, FileMode.Create);
StreamWriter sr = new StreamWriter (fs, Encoding.GetEncoding(1252));
foreach (string s in files)
{
FileInfo f=new FileInfo(s);
sr.WriteLine(f.Name);
}
sr.Close();
// Next create the playlist file in the base
// directory. Two things change - firstly, the
// name of the playlist file (because, to open
// it from the current directory, we need to
// prefix it with some ..\ strings, to represent
// the fact it's up some number of directory levels,
// and secondly all the MP3 filenames in the
// playlist file need a bunch of directory names
// (separated by "/") prefixed onto them, in order
// to identify the subdirectory in which the MP3
// file resides, relative to the base directory.
// The 'firstly' part of this convoluted explanation
// is handled by rootPath; the 'secondly' part by
// 'mp3path'.
string rootPath=".";
string mp3path="";
foreach (string d in path)
{
rootPath+="\\..";
mp3path+=d+"\\";
}
plname=rootPath+"\\"+plname; // the name of the M3U file
fs = new FileStream(plname, FileMode.Create);
sr = new StreamWriter (fs, Encoding.GetEncoding(1252));
foreach (string s in files)
{
FileInfo f=new FileInfo(s);
sr.WriteLine(mp3path+f.Name);
}
sr.Close();
}
}
}
/// <summary>
/// CompareTimes
/// -------------
/// This class is for use in the sorting logic above. It
/// lets us compare two strings, which are treated as file
/// names, and which sort according to the last-updated
/// times of the files named by those strings. This is
/// probably grossly inefficient.
/// </summary>
class CompareTimes : IComparer
{
public int Compare(Object o1, Object o2)
{
FileInfo f1=new FileInfo((string)o1);
FileInfo f2=new FileInfo((string)o2);
return f1.LastWriteTime.CompareTo(f2.LastWriteTime);
}
}
}
home@jim-chapman.net