Click here to Skip to main content
15,881,204 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.1K   2.4K   184  
An article describing the development of a non-trivial C#/.NET application to fetch lyrics for songs.
/*
 * LyricsFetcher - Handle the fetching of lyrics for a single song
 *
 * Author: Phillip Piper
 * Date: 2009-02-07 11:15 AM
 *
 * Change log:
 * 2009-02-071  JPP  Initial version
 */

using System;
using System.Collections.Generic;

namespace LyricsFetcher
{
    /// <summary>
    /// What is the status of the fetch operation?
    /// </summary>
    public enum LyricsFetchStatus
    {
        Undefined = 0,
        NotFound,
        Waiting,
        Fetching,
        SourceDone,
        Done,
        Cancelled
    }

    /// <summary>
    /// The information available in a FetchStatusEvent
    /// </summary>
    public class LyricsFetchStatusEventArgs : EventArgs
    {
        /// <summary>
        /// What is the fetch status of this song?
        /// </summary>
        public LyricsFetchStatus Status = LyricsFetchStatus.Undefined;
        
        /// <summary>
        /// What song is the event for?
        /// </summary>
        public Song Song;
        
        /// <summary>
        /// What lyrics source was involved?
        /// </summary>
        public ILyricsSource LyricsSource;

        /// <summary>
        /// Were the lyrics actually found?
        /// </summary>
        /// <remarks>
        /// This is only valid when Status == FetchStatus.SourceDone
        /// </remarks>
        public bool LyricsFound;
        
        /// <summary>
        /// How many milliseconds elapsed in searching the given source
        /// </summary>
        public int ElapsedTime;

        /// <summary>
        /// What were the lyrics
        /// </summary>
        /// <remarks>
        /// This is only valid when Status == FetchStatus.SourceDone
        /// </remarks>
        public string Lyrics;
    }

    /// <summary>
    /// A LyricsFetcher handles a single attempt to fetch the lyrics of a given
    /// song. It is designed to be run as a background task, using FetchSongLyrics
    /// as the thread entry point. Progress, success and failure are all reported
    /// through the StatusEvent event.
    /// </summary>
    public class LyricsFetcher
    {
        /// <summary>
        /// Get or set where this fetcher look to find its lyrics?
        /// </summary>
        public IList<ILyricsSource> Sources
        {
            get { return this.sources; }
            set { this.sources = value; }
        }
        
        private IList<ILyricsSource> sources = new List<ILyricsSource>();

        /// <summary>
        /// This the main thread entry point
        /// </summary>
        /// <param name="song"></param>
        public void FetchSongLyrics(object param)
        {
            Song song = (Song)param;

            this.StartFetch(song);
            string lyrics = this.DoFetch(song);
            this.FinishFetch(lyrics);
        }

        private void StartFetch(Song song)
        {
            this.args.Song = song;
        }

        private string DoFetch(Song song)
        {
            string lyrics = String.Empty;

            foreach (ILyricsSource source in this.Sources) {
                this.StartSource(source);

                int startTickCount = Environment.TickCount;
                lyrics = source.GetLyrics(song);
                this.FinishSource(source, lyrics, Environment.TickCount - startTickCount);

                if (lyrics != String.Empty)
                    return lyrics;
            }

            return String.Empty;
        }

        private void StartSource(ILyricsSource source)
        {
            this.args.Status = LyricsFetchStatus.Fetching;
            this.args.LyricsSource = source;
            this.OnStatusEvent(args);
        }

        private void FinishSource(ILyricsSource source, string lyrics, int elapsedTime)
        {
            this.args.Status = LyricsFetchStatus.SourceDone;
            this.args.LyricsSource = source;
            this.args.Lyrics = lyrics;
            this.args.ElapsedTime = elapsedTime;
            this.OnStatusEvent(args);
        }

        private void FinishFetch(string lyrics)
        {
            this.args.Status = LyricsFetchStatus.Done;
            this.args.Lyrics = lyrics;
            this.OnStatusEvent(args);
        }

        #region Events

        /// <summary>
        /// Signal that the fetch status may have changed
        /// </summary>
        public event EventHandler<LyricsFetchStatusEventArgs> StatusEvent;

        protected virtual void OnStatusEvent(LyricsFetchStatusEventArgs args)
        {
            if (this.StatusEvent != null)
                this.StatusEvent(this, args);
        }

        #endregion

        #region Private variables

        private LyricsFetchStatusEventArgs args = new LyricsFetchStatusEventArgs();

        #endregion
    }
}

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