Automatic iTunes Folder Playlist in Javascript and F#

The other day, I was struggling with my playlist on itunes. As you may know iTunes doesn’t have the notion of the folder structure of your mp3s. So if you do organise your music in folders you won’t have them in iTunes. I decided to write a script using the iTunes COM SDK for doing that.

Here is the scenario all the music is stored in d:\Music. So the script starts exploring everything inside in the folder and create an entry in iTunes, and it happens only in one level. First I did it with JavaScript with a lot of pain. I was pain because of the ugly interface and also unclear documentation. Luckily there were the samples in the SDK to play with it.

var	iTunesApp = WScript.CreateObject("iTunes.Application");
var	mainLibrary = iTunesApp.LibraryPlaylist;
var	mainLibrarySource = iTunesApp.LibrarySource;
var	tracks = mainLibrary.Tracks;
var	numTracks = tracks.Count;
var numPlaylistsCreated = 0;
var ITTrackKindFile	= 1;
var	albumArray = new Array();
var	playlists = mainLibrarySource.Playlists;
 
for (var i = 1; i <= numTracks; i++)
{
	var	currTrack = tracks.Item(i);
	if (currTrack.Kind == ITTrackKindFile)
	{
		if (currTrack.Location != "")
		{
            var p =currTrack.Location
 
            var location = p  
	        if ((location != undefined) && (location != ""))
	        {
		        if (albumArray[location] == undefined)
		        {		    
			        albumArray[location] = new Array();
		        }
 
		        albumArray[location].push(currTrack);
	        }
         }
	}
}
WScript.Echo("   Tracks Read " + numTracks);
for (var albumNameKey in albumArray)
{
    var trackArray = albumArray[albumNameKey];
    var p = albumNameKey;
    var ignoreFirst =   p.indexOf("music",0); //3     
    var firstChar = 0;             
    var secondChar = 0;         
    var firstChar = ignoreFirst +5 ;
    var myArr = new Array();
    while (true)
    {
        var firstChar = p.indexOf("\\", firstChar);
        var secondChar = p.indexOf("\\", firstChar+1);
 
        if (secondChar == -1 )
            break;
        var newStr = p.substring(firstChar+1, secondChar)
        myArr.push(newStr);
        firstChar = secondChar;
    }
    var plist = null;
    if (myArr.length == 0)
    {
        if (playlists.ItemByName("_") != null)
        {
          plist = playlists.ItemByName("_")   ;
        }
        else
        { 
            plist = iTunesApp.CreatePlaylist("_");
            numPlaylistsCreated++;
        }
    }
   else if ( playlists.ItemByName(myArr[0]) != null)
    {
        plist = playlists.ItemByName(myArr[0])
    }
    else 
    {
        plist = iTunesApp.CreatePlaylist( myArr[0]);
        numPlaylistsCreated++;
    }
    for (var trackIndex in trackArray)
    {
        var		currTrack = trackArray[trackIndex];
 
        plist.AddTrack(currTrack);
    }
}
	    //create playlist
if (numPlaylistsCreated > 0)
{
		WScript.Echo( numPlaylistsCreated + " (s) created.");
}
else
{
	WScript.Echo("No playlist createds");
}

.

(It is written in a quick way without caring about the beauty :) )

It was doing its job that I wanted but I also wanted to have my folder structure in itunes rather than a single entry for a folder. This time I implemented in F#. I have chosen F# mainly because of the type inference and the intellisense. In JavaScript without the documentation, you couldn’t do anything. F# is also chosen because of interoperability with COM and friends. So I have to admit that I didn’t like the COM interface of iTunes. All the best F# implementation with more functionality gave %40 less code

#light
#r "Interop.iTunesLib.dll";;
open iTunesLib;
open System.IO;
open System.Text.RegularExpressions
 
let itunes = new iTunesLib.iTunesAppClass()
let playLists = itunes.LibrarySource.Playlists  
let tracks = itunes.LibraryPlaylist.Tracks
 
let track = tracks.Item(2)
for track in tracks do
    if track.Kind = ITTrackKind.ITTrackKindFile &&
 (track:?> IITFileOrCDTrack).Location <> null then
        let track = track :?> IITFileOrCDTrack        
        let regex = new System.Text.RegularExpressions.Regex( @"^( ?<Drive>([a-zA-Z])):\\_music\\
((?< directory>[\w\W]+)\\)*((?< 
playlist>[\w\W]+)\\)(?< 
filename>([\w\W]+.mp3))",
            RegexOptions.IgnoreCase)
 
        printf "%d\n" track.Index
 
        let resMatch = regex.Match(track.Location)       
        if resMatch.Length = 0 
            ()
        else                       
            let lastFolder = 
             resMatch.Groups.Item("directory").Captures |> Seq.untyped_fold
                (fun (acc:IITPlaylist) (a: (System.Text.RegularExpressions.Capture)) ->                 
                    match (playLists.ItemByName(a.Value))  with
                    | null -> 
                        if acc.Index = 1 then
                            itunes.CreateFolder(a.Value)     
                        else
                            (acc :?> IITUserPlaylist).CreateFolder(a.Value)
 
                    | a1 -> 
                        if (a1 :?> IITUserPlaylist).SpecialKind = ITUserPlaylistSpecialKind.ITUserPlaylistSpecialKindFolder then
                            a1
                        else 
                          itunes.CreateFolder(a.Value)                          
                )
                (playLists.Item(1) )
 
            let pListName = resMatch.Groups.Item("playlist").Captures.Item(0).Value
 
            let lastPlayList= 
                match (playLists.ItemByName(pListName))  with
                | null ->
                    if lastFolder.Index = 1 then
                        itunes.CreatePlaylist(pListName) :?>    IITUserPlaylist    
                    else 
                        let fol = lastFolder :?> IITUserPlaylist                
                        fol.CreatePlaylist(pListName) :?>  IITUserPlaylist
                | a2 ->
                     if (a2 :?> IITUserPlaylist).SpecialKind = ITUserPlaylistSpecialKind.ITUserPlaylistSpecialKindFolder then                    
                        match (playLists.ItemByName("_" + pListName))      with
                        | null ->   (a2:?> IITUserPlaylist).CreatePlaylist("_" + pListName) :?> IITUserPlaylist
                        | a3 ->a3    :?> IITUserPlaylist
                     else
                        a2     :?> IITUserPlaylist
 
 
            lastPlayList.AddTrack(ref (track :> obj)) |> ignore
done

.

The folder playlist is not implemented on iPod. Although it make sense to use in iTunes, there is no point doing it for iPod. I was a bit frustrated, it was my sole purpose. Anyway it was nice to play with it…

So I hope it will be helpful in a way, the folder playlist didn’t help me, maybe in the next firmware update… On the other hand, I still use the first implementation for my automatic one-level folder playlist.

Happy New Year

Happy new year to everyone! 2007 has been a great year for me. 2008 didn’t start bad either, I hope to start a new project in a week or so which I’m really excited about it.

I wish you a great new year with lots of fun and happiness. I hope a lot more positive new year for all.

Recently I received a copy of the book “Expert F#’. I will write a broad review when I finish it. For the moment it really keeps me busy (in a good way). Although I have read more than half of the book, I still enjoy and find a lot of interesting topics. So I would definitely recommend to have it in your bookshelf if you want to have an advanced look at the functional programming in .NET.

Anyway it’s time to work again.And yes! Revitalised for more coding this year!

Redirect a System Process into Java Application for Windows and Linux

The output or input redirection is often used by the command line script guys. The output redirection (“>”) is usually to the file instead of the standard output. The input redirection (“<”) is to have a file as input instead of the standard input. It is sometimes needed in the programs too.

Interoperability with other programs is another concept especially when developing interoperable application. To do that the programming framework often sports different libraries for interoperability. However sometimes, for a simple code you don’t want to call the low level heavy libraries for doing the operation while there is a simple workaround.

There might be three ways of doing it.

  1. Trusting to the environment shell or command prompt.
  2. Use the Java internal process libraries and do the redirection ourselves.
  3. Use JNI class libraries for doing cross platform operation with the native code.

In one of the projects I was working with one of the earthquake modules that does some calculations. The program is in compiled form that it won’t worth the reimplementation. Instead I needed to call from the environment and display the output.

In order to use the system command prompt it is needed to use the “exec” method of the Runtime. This solution might not be guaranteed to work if the command line is broken or it is not with the standard names. Also it is not really beautiful to have if statements detecting the operating system and behaving on that.

Runtime.getRuntime().exec(cmdCommand);

void creatproc()
{
	String osName = System.getProperty("os.name");
	Process p;
 
	if (osName.startsWith("Windows"))
	{
		String cmdwin = "cmd /c C:EWv6.2binhyp2000.exe < C:EWv6.2bininput.txt";
		try
		{
			File f = new File("C:EWv6.2bin");
			Runtime.getRuntime().exec(cmdwin, null, f);
		}
		catch (IOException e)
		{
 
			e.printStackTrace();
		}
	}
	else
	{
		String[] cmdlinux = new String[3];
		cmdlinux[0] = "/bin/sh";
		cmdlinux[1] = "-c";
		cmdlinux[2] = "hypo2000 < input.txt";
		try
		{
			Runtime.getRuntime().exec(cmdlinux);
		}
		catch (IOException e)
		{
 
			e.printStackTrace();
		}
	}
}

After detecting the operating system it for windows it is needed to call cmd and for Linux> it is needed to call sh. There is one implementation between the command prompt of those operating systems as well. Likewise Windows could tell the difference of a single string while in Linux you have to specify the command arguments as the arrays of string. Other than that everything works exactly the same as you would expect.

A better implementation would be to use the java.io.BufferedReader; and feed the process that we have opened with the file contents. It is like implementing the behind scenes in our Java code. We create the process and write to the process output while reading from the file.

public void Redirect()
{
	BufferedReader freader = null;
	PrintStream fout = null;
	java.io.PipedReader pRead = null;
	PipedOutputStream po = null;
	Process p = null;
	try
	{
		freader = new BufferedReader(new FileReader("C:EWv6.2bininput.txt"));
 
	}
	catch (FileNotFoundException e1)
	{
 
		e1.printStackTrace();
	}
	try
	{
		File f = new File("C:EWv6.2bin");
 
		p = Runtime.getRuntime().exec("C:EWv6.2binhyp2000.exe",
				null, f);
		fout = new PrintStream(p.getOutputStream());
	}
	catch (IOException e)
	{
 
		e.printStackTrace();
	}
	String line = "";
	try
	{
		while ((line = freader.readLine()) != null)
		{
			fout.println(line);
		}
		fout.flush();
	}
	catch (IOException e1)
	{
 
		e1.printStackTrace();
	}
	try
	{
		p.waitFor();
	}
	catch (InterruptedException e)
	{
 
		e.printStackTrace();
	}
}

I found the usage of Java process libraries better than the others, but for quick solution the others might be helpful as well. Also it doesn’t look good in terms of “portability” of the application code.

LINQ and XLINQ with Visual Basic Literals

I really liked the XML expressiveness of Visual Basic, let’s build a very simple MSN History Search Engine using LINQ and XML Literals in Visual Basic.

The best thing is those literals could be used in LINQ expressions. Remember the simple XML file that MSN stores as a history.

  • .@AttributeName : Accesses the attribute element in XML
  • .<ElementName> : Accesses the element in XML
  • …<Descendant name>: Accesses the descendant name in XML

Modifying the XML content is very neat as well either using the LINQ expressions or even in loops.

In .NET Framework 2.0 VB has one more feature called MY namespaces. It is very nice to access some dynamic data available like application or forms information. It also contains some helper functions to do some common tasks. Now I also found it very handy in a Windows Forms application.

Get the history files from the location and operate the XLINQ query:

Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
 
For Each file In My.Computer.FileSystem.GetFiles(dirLocation)
ProcessFile(file)
Next
txtOutput.Text = sBuild.ToString()
 
End Sub

The XLINQ query that does search magic for the messages is as follows :

Function ProcessFile(ByVal s As String) As Boolean
If s.EndsWith("xml") Then
Dim msn = XElement.Load(s)
Dim q = From message In msn.<message> _
Where message.<text>.Value.Contains(txtSearch.Text) _
Select From = (message.<from>.@FriendlyName), Too = (message.<to>.@FriendlyNam), _
Message = message.<text>.Value
For Each msgFound In q
sBuild.AppendLine(msgFound.From + " says to " + msgFound.Too + _
" :  " + msgFound.Message)
Next
End If
End Function

What makes this different is the usage of literals. In C# that query would be longer than that.
In the sample message.<From>.@FriendlyName
means that it will get the From element and get the friendlyname attribute from it.

It is basically like having the XML data in your hands but there is no need to parse it or access the elements using the classes provided rather this work is done by the compiler at the compile time.

In a couple lines of code we have a fully featured MSN history searching. Let me know if you still want the source code (although that is all about it) or even the executable in case you are not into programming.

C# 3.0 vs. VB 9.0 and XML in the Language

Here is the summary of new language features as mentioned on the “What’s new on ORCAS

  • C# 3.0 Language Support: This CTP implements all of the C#3.0 language features from the May LINQ CTP including:
    • Query Expressions
    • Object and Collection Initializers
    • Extension Methods
    • Local Variable Type Inference and Anonymous Types
    • Lambdas bound to Delegates and Expression trees
    • Complete design-time support: Intellisense, Formatting, Colorization

  • VB 9.0 Language Support: This CTP contains the following language features:
    • Query Expressions: Basic querying, filtering, and ordering support
    • Object Initializers
    • Extension Methods
    • Local Variable Type Inference
    • Anonymous Types
    • XML literals
    • XML properties
    • New Line and Expression IntelliSense

LINQ is all in both of the languages and indeed this is the main feature for .NET Framework 3.5. Writing any type of queries is the purpose of LINQ at the end. Considering the abilities of LINQ, everything was possible before as well. LINQ makes us to get rid of the strings (the red coloured stuff) from the program in order to minimise the typo errors, easy to read programs by syntax highlighting. But all the best is that gives the ability to write declarative and functional style programs.

Beside the new language features, as a compiler improvement, it is very surprising that C# still doesn’t have background compilation. There is background syntax checking but no compilation. I believe this is a definite need for C# because it is really helpful. For instance the F# projects do background compilation and syntax checks, that way it easy to investigate “silly errors” while coding. Also this was one of the powerful features that I found on eclipse while working on a Java project.

Visual basic has that feature moreover it has also automatic syntax fixing as well. Likewise if you call a method with lower case letters it is automatically converted to the actual method on the next line. Actually in a type inferenced language this is needed, because it is not easy to recognise the type information of all the members.

Anyway I just wrote a quick macro to give the feeling of background compilation for C#. It is not really sophisticated but it works. Just put it into EnvironmentEvent macro in Visual Stuio.

Dim lastbuilt As DateTime
    Private Sub TextDocumentKeyPressEvents_AfterKeyPress(ByVal Keypress As String, ByVal Selection As EnvDTE.TextSelection, ByVal InStatementCompletion As Boolean) Handles TextDocumentKeyPressEvents.AfterKeyPress
        Dim doc = DTE.ActiveDocument
        Dim diff = DateTime.Now.Subtract(lastbuilt)
 
        If Not Char.IsLetterOrDigit(Keypress(0)) And diff.Seconds > 5 Then
            DTE.ExecuteCommand("Build.BuildSelection")
            lastbuilt = DateTime.Now
            doc.Activate()
        End If
    End Sub

XML in Language

All of the best is that now XML is a first class citizen in VB. I wouldn’t expect this as a serious feature but after trials it makes extremely relevant to use XML in Visual Basic. You get syntax highlighting and even intellisense for XML if the namespaces are specified and even more.

Having XML literals in the language, it makes really sense to use XLinq with VB.

Like consider the xml stored by messenger. You could just assign to a variable just like that.

        Dim msn = <?xml version="1.0"?>
                  <?xml-stylesheet type='text/xsl' href='MessageLog.xsl'?>
                  <Log FirstSessionID="1" LastSessionID="1">
                      <Message Date="25/03/2007" Time="22:35:47" DateTime="2007-03-25T21:35:47.173Z" SessionID="1">
                          <From><User FriendlyName="koko"/></From>
                          <To><User FriendlyName="opopop"/></To>
                          <Text Style="font-family:Comic Sans MS; font-weight:bold; color:#0000a0; ">151515</Text>
                      </Message>
                      <Message Date="25/03/2007" Time="22:35:55" DateTime="2007-03-25T21:35:55.344Z" SessionID="1">
                          <From><User FriendlyName="koko"/></From>
                          <To><User FriendlyName="opopop"/></To>
                          <Text Style="font-family:Comic Sans MS; font-weight:bold; color:#0000a0; ">5959959</Text></Message>
                  </Log>

It will have the type of System.Xml.Linq.XDocument.

Let’s define the XML Stylesheet :

        Dim xslt = <?xml version="1.0"?>
                   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                       <xsl:template match="Log">
                           <html>
                               <head>
                                   <title> Message Log for </title>
                               </head>
                               <body style='margin:0'>
                                   <table border='1'>
                                       <tr>
                                           <td> From </td>
                                           <td> To </td>
                                           <td> Message </td>
                                       </tr>
                                       <xsl:for-each select="/Log/Message">
                                           <tr>
                                               <td><xsl:value-of select="From/User/@FriendlyName"/></td>
                                               <td><xsl:value-of select="To/User/@FriendlyName"/></td>
                                               <td><xsl:value-of select="Text"/></td>
                                           </tr>
                                       </xsl:for-each>
                                   </table>
                               </body>
                           </html>
                       </xsl:template>
                   </xsl:stylesheet>

If we want to do an XSLT transformation to that snippet, it is even easier than it used to be.

Dim xTransform = New System.Xml.Xsl.XslCompiledTransform()
xTransform.Load(xslt.CreateReader())
xTransform.Transform(msn.CreateReader(), New System.Xml.XmlTextWriter("test.html", New System.Text.UnicodeEncoding()))

I think working with xml data using Visual Basic should be considered as a manipulation language. Since we are all becoming multilingual this shouldn’t be a problem.

JSON Tools for .NET

JSON (JavaScript Object Notation) is a lightweight data-interchange format. JSON is an object notation in text format that Javacript engine fully understands and there is no need to parse for it.

The library contains some basic types that Javascript requires. IJSONObject, JSONElement, JSONNumber<T>, JSONString, JSONBoolean, JSONCollection, JSONArray and JSONObject.

  • JSONObject : Represents JSON objects beginning and ending with curly braces ({}). It is a collection of JSONElement objects. Object members consist if string and values separated by colon in JSON notation.
  • JSONArray : Represents a javascript array that begin and end with braces and contain values. In the notation values are separated by commas, but the library does all the syntactic issues.
  • JSONCollection : A base type for JSONObject and JSONArray.
  • JSONElement : Base class for all JSON types. It has the base properties and can be used with arrays or objects or individually.
  • JSONString : Represents JavaScript string type and created by double quotes. It is inherited from a JSONElement
  • JSONBoolean : Represents JavaScript boolean type
  • JSONNumber<T> : Represents a javascript number type, it can be integer, or floating point numbers.

JSON Tools for .NET is the library that helps to build JSON objects from .NET Framework objects. I just wanted to share the code that I was working previously. It is not a complete library. There is a need for some helper classes for working with dynamic objects and collections. JSONReflector might be useful as a new feature.

You can download the JSON Tools for .NET and play with it. Also, you are very welcome to join and contribute to the project.

A simple example of JSON output looks like this:

{ 
"Total" : 45500, 
"Offset" : 0, 
"Result_List" : [ 
   { "Description" : "JSON (JavaScript Object Notation) (Pronounced like Jason, IPA /d?e?s?n/ ) is a lightweight computer data interchange format. It is a text-based, human-readable format for ... ", 
     "Title" : "JSON - Wikipedia, the free encyclopedia", 
     "URL" : "http://en.wikipedia.org/wiki/Json" } , 
 
   { "Description" : "object {} { members } members pair pair , members pair string : value array [] [ elements ] elements value value , elements value string number object array true false null", 
     "Title" : "JSON", 
     "URL" : "http://www.json.org/" } , 
 
] }

This example is the one of the outputs from the sample directory. It is actually a live search query displayed in JSON string.

In C#, each object is contracted with an IJSONObject interface. That interface has a single WriteObject Method that does the JavScript representation of the actual object.

Here is a sample implementation for a result type object.

public JSONObject WriteObject()
{   
    JSONNumber<int> jTotal = new JSONNumber<int>("Total", m_Total);
    JSONNumber<int> jOffset = new JSONNumber<int>("Offset", m_Offset); 
 
    List<JSONObject> ResultObjects = new List<JSONObject>(m_Results.Count);
    foreach (SearchResult r in m_Results)
    {
        ResultObjects.Add(r.WriteObject());
    } 
 
    JSONArray jResults = new JSONArray("Result_List", ResultObjects); 
 
    JSONObject js = new JSONObject("LiveResults", jTotal, jOffset, jResults);
    return js;
}

Another representation of a result by using different JSON types.

public JSONObject WriteObject()
       {    
           JSONString jDescription = new JSONString("Description", m_Description);
           JSONString jTitle = new JSONString("Title", m_Title);
           JSONString jURL= new JSONString("URL", m_URL); 
 
           JSONObject js = new JSONObject("Result", jDescription, jTitle, jURL);
           return js;
       }

I liked the way it creates JSON object out of an object. No reflection, no dynamic code emit, which means it should have no problems for busy heavy servers.  On the other hand a JSONReflector and a JSONParser could be implemented using the same class library.