Archive for the ‘javascript’ Category.

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.

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.