iTunes COM API in C#

I decided that I would post a little guide to some of the things that I have learned in using the iTunes COM API in C#. It's not very well documented, and I though I could help.

Initialization:

First, you have to add a Reference and Using

Right click on References, and click "Add Refrence"

Switch to the COM tab and find "iTunes *.** Type Library, and click add.

At the top of your code, add "Using iTunesLib"

Finally, add these two lines of code under the class of the form, outside of any function:

delegate void Router(object arg);
iTunesApp app = new iTunesAppClass();

The Router helps in handling the iTunes Events, and "app" is what you will use to do anything with iTunes.

Events:

You'll need to attach at least one event for a program that controls iTunes, to see when something changes in iTunes, and here is some code for that:

app.OnPlayerPlayEvent += new _IiTunesEvents_OnPlayerPlayEventEventHandler(delegate(object o)
  {
      this.Invoke(new Router(app_OnPlayerPlayEvent), o);
  });

This should be put under InitializeComponent(), and will call app_OnPlayerPlayEvent when it is activated.

**Controls:

**These are pretty simple, just call them to control iTunes:

app.Play();

app.Pause();

app.NextTrack();

app.PreviousTrack();

app.Stop():

There are a few others, but these are the big ones.

**Track Information:

**iTunes provides pretty much all of the information about a playing track, there is a lot more than I mention here, I reccomend experimentation.

IITTrack track = app.CurrentTrack;

Albumlbl.Text = track.Album;

Artistlbl.Text = track.Artist;

Tracklbl.Text = track.Name;

These will populate the labels with the track (at the time) that is playing or paused. It must be refreshed to update the information.

IITArtworkCollection Art1 = track.Artwork;

IITArtwork Art2 = Art1[1];

Art2.SaveArtworkToFile("c:\\temp\\Album.jpg");

Stream r = File.Open("c:\\temp\\Album.jpg", FileMode.Open);

Image temp = Image.FromStream(r);

r.Close();

pictureBox1.Image = temp;

SetImage(pictureBox1);

This is a big one, it will allow you to put the Album Art of the currently playing track in a Picture Box. I recommend checking the Art1[] or doing this in a Try...Catch to avoid errors when a song does not have art. You will also need these, also, for resizing:

Original Link

public Size GenerateImageDimensions(int currW, int currH, int destW, int destH)
{
    //double to hold the final multiplier to use when scaling the image
    double multiplier = 0;
    //string for holding layout
    string layout;
    //determine if it's Portrait or Landscape
    
    if (currH > currW) layout = "portrait";
    else layout = "landscape";
    
    switch (layout.ToLower())
    {
        case "portrait":
            //calculate multiplier on heights
            if (destH > destW)
            {
                multiplier = (double)destW / (double)currW;
            }
            else
            {
                multiplier = (double)destH / (double)currH;
            }
            break;
        case "landscape":
            //calculate multiplier on widths
            if (destH > destW)
            {
                multiplier = (double)destW / (double)currW;
            }
            else
            {
                multiplier = (double)destH / (double)currH;
            }
            break;
    }
    //return the new image dimensions
    return new Size((int)(currW * multiplier), (int)(currH * multiplier));
}
//Resize the image
private void SetImage(PictureBox pb)
{
    try
    {
        //create a temp image
        Image img = pb.Image;

        //calculate the size of the image
        Size imgSize = GenerateImageDimensions(img.Width, img.Height, this.pictureBox1.Width, this.pictureBox1.Height);

        //create a new Bitmap with the proper dimensions
        Bitmap finalImg = new Bitmap(img, imgSize.Width, imgSize.Height);

        //create a new Graphics object from the image
        Graphics gfx = Graphics.FromImage(img);

        //clean up the image (take care of any image loss from resizing)
        gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;

        //empty the PictureBox
        pb.Image = null;

        //center the new image
        pb.SizeMode = PictureBoxSizeMode.CenterImage;

        //set the new image
        pb.Image = finalImg;
    }
    catch (System.Exception e)
    {
        //MessageBox.Show(e.Message);
    }
}

Another thing that you can do is a progress bar for Track Time. I have Timer1 set for 1 second intervals. This is not totally tested, your mileage may vary:

void Timer1Tick(object sender, EventArgs e)
{
    IITTrack track = app.CurrentTrack;
    progress.Maximum = track.Duration;
    progress.Value = app.PlayerPosition;
    if (track.Duration != oldtrack)
    {
        if (track.Name != oldname)
        {
            NewSong();
        }
        else
        {
            oldname = track.Name;
        }
    }
    else
    {
        oldtrack = track.Duration;
    }
}

REST Album Art and Lyrics

Finally, I have these few functions that will use Amazon and LyricWiki to find Album Art and Lyrics of a playing song. I would recommend running them in a BackgroundWorker, to prevent a program from locking up.

Lyrics:

private static string GetLyrics(string Artist, string Title)
{
    StringBuilder lyric = new StringBuilder();  //Build a new string
    lyric.Append("http://lyricwiki.org/api.php?func=getSong&artist="); //Add base URL
    lyric.Append(Artist);
    lyric.Append("&song=");
    lyric.Append(Title);
    lyric.Append("&fmt=xml");
    WebRequest requestlyr = WebRequest.Create(lyric.ToString()); //prepare web request
    StreamReader responseStreamlyr = new StreamReader(requestlyr.GetResponse().GetResponseStream()); //prepare responese holder
    string responselyr = responseStreamlyr.ReadToEnd(); //fill up response
    responseStreamlyr.Close(); //Close stream
    string lyrics = XmlParse_general(responselyr.ToString(), "lyrics"); //parse the XML
    return lyrics;
}

private static string XmlParse_general(string Url, string type)    //XML parse Function
{
    XmlTextReader xmlrt1 = new XmlTextReader(new StringReader(Url));
    while (xmlrt1.Read())
    {
        //Trace.Write("Node Type", xmlrt1.NodeType.ToString());
        string strNodeType = xmlrt1.NodeType.ToString();
        string strName = xmlrt1.Name;
        if (strNodeType == "Element" && strName == type)
        {
            xmlrt1.Read();
            return xmlrt1.Value; //Return output
        }
    } 
    return "";
}

Album Art:

private string AlbumURL(string artist, string album)

{
    StringBuilder art = new StringBuilder();  //Build a new string
    art.Append("http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&Version=2005-03-23&Operation=ItemSearch&ContentType=text%2Fxml&SubscriptionId=09XAA8GD0PQVCC8KR5G2&SearchIndex=Music&Artist=");   //Add base URL

    art.Append(artist);
    art.Append("&Keywords=");
    art.Append(album);
    art.Append("&ResponseGroup=Images");
    WebRequest requestart = WebRequest.Create(art.ToString()); //prepare web request

    StreamReader responseStreamart = new StreamReader(requestart.GetResponse().GetResponseStream()); //prepare responese holder
    string responseart = responseStreamart.ReadToEnd(); //fill up response
    responseStreamart.Close(); //Close stream
    string url = XML_image(responseart.ToString()); //parse the XML
    return url;
}

private static string XML_image(string xml)
{
    XmlTextReader reader = new XmlTextReader(new StringReader(xml));
    reader.ReadToFollowing("LargeImage");
    reader.ReadToFollowing("URL");
    reader.Read();
    return reader.Value;
}

If anyone has any questions or needs help getting these going, especially the REST functions, or has any suggested improvements, contact me, I'd be glad to help.

Goodbye, and Good Luck!


blog comments powered by Disqus