Click here to Skip to main content
15,896,111 members
Articles / Programming Languages / C#

LyricsFetcher - The Easiest Way to Find Lyrics for your Songs

Rate me:
Please Sign up or sign in to vote.
4.93/5 (82 votes)
29 Oct 2009GPL325 min read 201.8K   2.4K   184  
An article describing the development of a non-trivial C#/.NET application to fetch lyrics for songs.
/*
 * This file holds the class implementations necessary to interact with iTunes.
 *
 * Author: Phillip Piper
 * Date: 2009-03-14 8:28 AM
 *
 * CHANGE LOG:
 * 2009-03-14 JPP  Separated from iTunesLibrary.cs
 */

using System;
using System.Runtime.InteropServices;
using iTunesLib;

namespace LyricsFetcher
{

    /// <summary>
    /// This class implements a Song object based on iTunes track
    /// </summary>
    public class ITunesSong : Song
    {
        /// <summary>
        /// Build a Song from the information available in the iTunes xml file
        /// </summary>
        /// <param name="title"></param>
        /// <param name="artist"></param>
        /// <param name="album"></param>
        /// <param name="genre"></param>
        /// <param name="persistentId"></param>
        public ITunesSong(string title, string artist, string album, string genre, string persistentId) :
            base(title, artist, album, genre) {
            this.persistentIdHigh = Convert.ToInt32(persistentId.Substring(0, 8), 16);
            this.persistentIdLow = Convert.ToInt32(persistentId.Substring(8, 8), 16);
        }

        /// <summary>
        /// Build a Song from a given iTunes Track object
        /// </summary>
        /// <param name="track"></param>
        public ITunesSong(IITTrack track) :
            base(track.Name, track.Artist, track.Album, track.Genre) {
            track.GetITObjectIDs(out this.sourceId, out this.playlistId, out this.trackId, out this.databaseId);
        }

        /// <summary>
        /// Get the IITrack com object that is this song in the iTunes library
        /// </summary>
        public IITTrack Track {
            get {
                // If we don't have a database id, we must have persistent ids. In that case
                // we get the object from its persistent ids, and the fetch the full four ids.
                // Getting an object by its ids is about 4x faster than fetch it by persistent ids
                if (this.databaseId == -1) {
                    IITTrack track = ITunes.Instance.GetTrackByPersistentIds(this.persistentIdHigh, this.persistentIdLow);
                    if (track != null)
                        track.GetITObjectIDs(out this.sourceId, out this.playlistId, out this.trackId, out this.databaseId);
                    return track;
                } else {
                    return ITunes.Instance.GetObjectByIds(this.sourceId,
                        this.playlistId, this.trackId, this.databaseId) as IITTrack;
                }
            }
        }

        /// <summary>
        /// Read the lyrics for this song from their underlying source.
        /// </summary>
        /// <remarks>This normally has to open and read the underlying media
        /// file, so this is a slow operation.</remarks>
        public override void GetLyrics() {
            IITFileOrCDTrack fileTrack = this.Track as IITFileOrCDTrack;
            if (fileTrack != null) {
                try {
                    this.Lyrics = fileTrack.Lyrics;
                }
                catch (COMException) {
                    // If the file is corrupt, missing or just plain obstinate, this can fail.
                }
            }
        }

        /// <summary>
        /// Write any changes to this song out to the music library.
        /// </summary>
        public override void Commit() {
            IITTrack track = this.Track;
            if (track == null)
                return;

            try {
                if (this.Title != null && track.Name != this.Title)
                    track.Name = this.Title;
                if (this.Artist != null && track.Artist != this.Artist)
                    track.Artist = this.Artist;
                if (this.Album != null && track.Album != this.Album)
                    track.Album = this.Album;
                if (this.Genre != null && track.Genre != this.Genre)
                    track.Genre = this.Genre;

                IITFileOrCDTrack fileTrack = track as IITFileOrCDTrack;
                if (fileTrack != null && this.Lyrics != null)
                    fileTrack.Lyrics = this.Lyrics;
            }
            catch (COMException) {
                // There are quite a few reasons why these might fail. If the track
                // is locked, or the underlying file has been deleted/moved.
                // There is nothing we can do if this fails.
            }
        }

        // If we have read this song from the XML, these are used to temporarily identify the
        // song in the library. The first time we need the IITrack object, these will be translated
        // to the other 4-tuple of ids.
        private int persistentIdHigh;
        private int persistentIdLow;

        // This 4-tuple uniquely identifies a track within a music library. Their values are not
        // persistent.
        private int sourceId;
        private int playlistId;
        private int trackId;
        private int databaseId = -1;
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Team Leader
Australia Australia
Phillip has been playing with computers since the Apple II was the hottest home computer available. He learned the fine art of C programming and Guru meditation on the Amiga.

C# and Python are his languages of choice. Smalltalk is his mentor for simplicity and beauty. C++ is to programming what drills are to visits to the dentist.

He worked for longer than he cares to remember as Lead Programmer and System Architect of the Objective document management system. (www.objective.com)

He has lived for 10 years in northern Mozambique, teaching in villages.

He has developed high volume trading software, low volume FX trading software, and is currently working for Atlassian on HipChat.

Comments and Discussions