context: // Type: FanartHandler.Scraper
  // Assembly: FanartHandler, Version=4.0.3.0, Culture=neutral, PublicKeyToken=null
  // MVID: 073E8D78-B6AE-4F86-BDE9-3E09A337833B
  
  extern alias FHNLog;
  
  using FHNLog.NLog;
  
  using MediaPortal.ExtensionMethods;
  
  using Newtonsoft.Json;
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Drawing.Imaging;
  using System.Globalization;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Runtime.CompilerServices;
  using System.Text.RegularExpressions;
  using System.Web;
  using System.Xml;
  using System.Xml.Linq;
  using System.Xml.XPath;
  
  namespace FanartHandler
  {
    internal class Scraper
    {
      private static readonly Logger logger = LogManager.GetCurrentClassLogger();
      private ArrayList alSearchResults;
  
      private static Regex[] StackRegExpressions = null;
      // private static bool _getLastfmCover = true;
      private static string DefUserAgent = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36";
      
      // TODO
      // http://photography.nationalgeographic.com/photography/photo-of-the-day
      // https://www.nasa.gov/multimedia/imagegallery/iotd.html
      //
                                
      static Scraper()
      {
      }
  
      #region Thumbnails Image
      public static Image CreateNonIndexedImage(string path)
      {
        try
        {
          using (var image = Utils.LoadImageFastFromFile(path))
          {
            var bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
            using (var graphics = Graphics.FromImage(bitmap))
              graphics.DrawImageUnscaled(image, 0, 0);
            return bitmap;
          }
        }
        catch (Exception ex)
        {
          logger.Error("CreateNonIndexedImage: " + ex);
        }
        return null;
      }
  
      private bool ReplaceOldThumbnails(string filenameOld, string filenameNew, bool forceDelete)
      {
        #region Force Delete
        if (forceDelete)
        {
          try
          {
            File.SetAttributes(filenameOld, FileAttributes.Normal);
            MediaPortal.Util.Utils.FileDelete(filenameOld);
            return true;
          }
          catch (Exception ex)
          {
            logger.Error("ReplaceOldThumbnails: Deleting old thumbnail: " + filenameOld);
            logger.Error(ex);
          }
          return false; 
        }
        #endregion
  
        #region Not Force Delete
        bool doReplace = true;
  
        var image1 = (Image) null;
        var image2 = (Image) null;
        var num1 = 0.0;
        var num2 = 0.0;
        var num3 = 0.0;
        var num4 = 0.0;
  
        try
        {
          image1 = CreateNonIndexedImage(filenameOld);
          image2 = CreateNonIndexedImage(filenameNew);
  
          num1 = image1.Width;
          num2 = image1.Height;
          num3 = image2.Width;
          num4 = image2.Height;
        }
        catch (Exception ex)
        {
          doReplace = false;
          logger.Error("ReplaceOldThumbnails: Get image information: " + filenameOld + " / " + filenameNew);
          logger.Error(ex);
        }
        finally
        {
          ObjectMethods.SafeDispose(image1);
          ObjectMethods.SafeDispose(image2);
        }
  
        try
        {
          if ((num1 < num3 || num2 < num4) || num1 != num2)
          {
            File.SetAttributes(filenameOld, FileAttributes.Normal);
            MediaPortal.Util.Utils.FileDelete(filenameOld);
          }
          else
          {
            doReplace = false;
          }
        }
        catch (Exception ex)
        {
          doReplace = false;
          logger.Error("ReplaceOldThumbnails: Deleting old thumbnail: " + filenameOld);
          logger.Error(ex);
        }
        return doReplace;
        #endregion
      }
  
      public bool CreateThumbnail(string aInputFilename, bool bigThumb, Utils.Category category)
      {
        int templateWidth = 100;
        int templateHeight = 100;
        double aRatio = 1.0;
  
        if (category != Utils.Category.MusicAlbum && category != Utils.Category.MusicArtist)
        {
          templateWidth = 150;
          templateHeight = 200;
          aRatio = (double) templateHeight / (double) templateWidth;
        }
  
        string iText = string.Empty;
        string NewFile = string.Empty;
  
        #region ThumbsQuality
        switch (MediaPortal.Util.Thumbs.Quality)
        {
          case MediaPortal.Util.Thumbs.ThumbQuality.fastest:
            // templateWidth = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.small : (int) MediaPortal.Util.Thumbs.LargeThumbSize.small;
            templateHeight = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.small : (int) MediaPortal.Util.Thumbs.LargeThumbSize.small;
            iText = "fastest";
            break;
  
          case MediaPortal.Util.Thumbs.ThumbQuality.fast:
            // templateWidth = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.small : (int) MediaPortal.Util.Thumbs.LargeThumbSize.small;
            templateHeight = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.small : (int) MediaPortal.Util.Thumbs.LargeThumbSize.small;
            iText = "fast";
            break;
  
          case MediaPortal.Util.Thumbs.ThumbQuality.average:
            // templateWidth = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.average : (int) MediaPortal.Util.Thumbs.LargeThumbSize.average;
            templateHeight = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.average : (int) MediaPortal.Util.Thumbs.LargeThumbSize.average;
            iText = "average";
            break;
  
          case MediaPortal.Util.Thumbs.ThumbQuality.higher:
            // templateWidth = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.average : (int) MediaPortal.Util.Thumbs.LargeThumbSize.average;
            templateHeight = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.average : (int) MediaPortal.Util.Thumbs.LargeThumbSize.average;
            iText = "high quality";
            break;
  
          case MediaPortal.Util.Thumbs.ThumbQuality.highest:
            // templateWidth = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.large : (int) MediaPortal.Util.Thumbs.LargeThumbSize.large;
            templateHeight = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.large : (int) MediaPortal.Util.Thumbs.LargeThumbSize.large;
            iText = "highest quality";
            break;
  
          case MediaPortal.Util.Thumbs.ThumbQuality.uhd:
            // templateWidth = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.uhd : (int) MediaPortal.Util.Thumbs.LargeThumbSize.uhd;
            templateHeight = (!bigThumb) ? (int) MediaPortal.Util.Thumbs.ThumbSize.uhd : (int) MediaPortal.Util.Thumbs.LargeThumbSize.uhd;
            iText = "UHD quality";
            break;
  
          default:
            // templateWidth = (!bigThumb) ? (int) templateWidth : 500;
            templateHeight = (!bigThumb) ? (int) templateWidth : 500;
            iText = "default";
            break;
        }
        // templateHeight = templateWidth;
        templateWidth = (int) Math.Round((double) templateHeight / aRatio);
  
        logger.Debug("CreateThumbnail: " + ((bigThumb) ? "Big" : string.Empty) + "Thumbs mode: " + iText + " size (WxH): " + templateWidth + "x" + templateHeight);
        #endregion
  
        #region HighDefThumbnails
        if (bigThumb && Utils.UseHighDefThumbnails)
        {
          var SourceBitmap = (Bitmap) null;
          try
          {
            SourceBitmap = (Bitmap) Utils.LoadImageFastFromFile(aInputFilename);
            if (SourceBitmap != null)
            {
              if ((SourceBitmap.Width > templateWidth) || (SourceBitmap.Height > templateHeight))
              {
                if (templateWidth == templateHeight)
                {
                  templateWidth  = (SourceBitmap.Width > SourceBitmap.Height) ? (int) SourceBitmap.Width : (int) SourceBitmap.Height;
                  templateHeight = templateWidth;
                }
                else
                {
                  templateWidth  = (int) SourceBitmap.Width;
                  templateHeight = (int) SourceBitmap.Height;
                }
                logger.Debug("CreateThumbnail: " + ((bigThumb) ? "Big" : string.Empty) + "Thumbs mode: overrided size (WxH): " + templateWidth + "x" + templateHeight);
              }
            }
          }
          finally
          {
            if (SourceBitmap != null)
              ObjectMethods.SafeDispose(SourceBitmap);
            SourceBitmap = null;
          }
        }
        #endregion
  
        NewFile = aInputFilename.Substring(0, aInputFilename.IndexOf("_tmp.jpg", StringComparison.CurrentCulture)) + ((bigThumb) ? "L" : string.Empty) + ".jpg";
        try
        {
          return CropImage(aInputFilename, templateWidth, templateHeight, NewFile);
        }
        catch (Exception ex)
        {
          logger.Error("CreateThumbnail:");
          logger.Error(ex);
          return false;
        }
      }
  
      public bool CropImage(string OriginalFile, int templateWidth, int templateHeight, string NewFile)
      {
        var image1 = (Image) null;
        var image2 = (Image) null;
        var graphics1 = (Graphics) null;
        var image3 = (Image) null;
        var graphics2 = (Graphics) null;
  
        try
        {
          image1 = Utils.LoadImageFastFromFile(OriginalFile);
          var num1 = double.Parse(templateWidth.ToString()) / templateHeight;
          var num2 = double.Parse(image1.Width.ToString()) / image1.Height;
          if (num1 == num2)
          {
            image2 = new Bitmap(templateWidth, templateHeight);
            graphics1 = Graphics.FromImage(image2);
            graphics1.InterpolationMode = InterpolationMode.High;
            graphics1.SmoothingMode = SmoothingMode.HighQuality;
            graphics1.Clear(Color.White);
            graphics1.DrawImage(image1, new Rectangle(0, 0, templateWidth, templateHeight), new Rectangle(0, 0, image1.Width, image1.Height), GraphicsUnit.Pixel);
            image2.Save(NewFile, ImageFormat.Jpeg);
          }
          else
          {
            var srcRect = new Rectangle(0, 0, 0, 0);
            var destRect = new Rectangle(0, 0, 0, 0);
            if (num1 > num2)
            {
              image3 = new Bitmap(image1.Width, int.Parse(Math.Floor(image1.Width / num1).ToString()));
              graphics2 = Graphics.FromImage(image3);
              srcRect.X = 0;
              srcRect.Y = 0;
              srcRect.Width = image1.Width;
              srcRect.Height = int.Parse(Math.Floor(image1.Width / num1).ToString());
              destRect.X = 0;
              destRect.Y = 0;
              destRect.Width = image1.Width;
              destRect.Height = int.Parse(Math.Floor(image1.Width / num1).ToString());
            }
            else
            {
              image3 = new Bitmap(int.Parse(Math.Floor(image1.Height * num1).ToString()), image1.Height);
              graphics2 = Graphics.FromImage(image3);
              srcRect.X = int.Parse(Math.Floor((image1.Width - image1.Height * num1) / 2.0).ToString());
              srcRect.Y = 0;
              srcRect.Width = int.Parse(Math.Floor(image1.Height * num1).ToString());
              srcRect.Height = image1.Height;
              destRect.X = 0;
              destRect.Y = 0;
              destRect.Width = int.Parse(Math.Floor(image1.Height * num1).ToString());
              destRect.Height = image1.Height;
            }
            graphics2.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics2.SmoothingMode = SmoothingMode.HighQuality;
            graphics2.DrawImage(image1, destRect, srcRect, GraphicsUnit.Pixel);
            image2 = new Bitmap(templateWidth, templateHeight);
            graphics1 = Graphics.FromImage(image2);
            graphics1.InterpolationMode = InterpolationMode.High;
            graphics1.SmoothingMode = SmoothingMode.HighQuality;
            graphics1.Clear(Color.White);
            graphics1.DrawImage(image3, new Rectangle(0, 0, templateWidth, templateHeight), new Rectangle(0, 0, image3.Width, image3.Height), GraphicsUnit.Pixel);
            image2.Save(NewFile, ImageFormat.Jpeg);
          }
          File.SetAttributes(NewFile, File.GetAttributes(NewFile) | FileAttributes.Hidden);
        }
        catch (Exception ex)
        {
          logger.Error("CropImage: " + ex);
        }
        finally
        {
          ObjectMethods.SafeDispose(image2);
          ObjectMethods.SafeDispose(graphics1);
          if (graphics2 != null)
            graphics2.Dispose();
          if (image3 != null)
            image3.Dispose();
          if (image1 != null)
            image1.Dispose();
        }
        return true;
      }
      #endregion
  
      private string CommonGetMusicBrainzID(string artist, string album)
      {
        string res = Utils.DBm.GetDBMusicBrainzID(Utils.GetArtist(artist), (string.IsNullOrEmpty(album)) ? null : Utils.GetAlbum(album));
        if (Utils.IsMBID(res))
        {
          logger.Debug("Common: MusicBrainz DB ID: " + res);
          return res;
        }
  
        if (res.Trim().Equals("<none>", StringComparison.CurrentCulture))
        {
          logger.Debug("Common: MusicBrainz DB ID: Disabled");
          return string.Empty;
        }
  
        string[] providers;
        if (string.IsNullOrEmpty(album))
        {
          providers = Utils.MBIDArtistProviders.ToArray();
        }
        else
        {
          providers = Utils.MBIDAlbumProviders.ToArray();
        }
  
        if (providers.Count() == 0)
        {
          logger.Debug("Common: MusicBrainz DB ID: The list of providers is empty.");
          return string.Empty;
        }
  
        foreach (string provider in providers)
        {
          // logger.Debug("*** MusicBrainz DB ID: Current Provider: {0}", provider);
          if (provider.Equals(Utils.MBIDProvider.TheAudioDB.ToString(), StringComparison.InvariantCultureIgnoreCase))
          {
            res = TheAudioDBGetMusicBrainzID(artist, album);
            if (!string.IsNullOrEmpty(res))
            {
              return res;
            }
            continue;
          }
          if (provider.Equals(Utils.MBIDProvider.LastFM.ToString(), StringComparison.InvariantCultureIgnoreCase))
          {
            res = LastFMGetMusicBrainzID(artist, album);
            if (!string.IsNullOrEmpty(res))
            {
              return res;
            }
            continue;
          }
          if (provider.Equals(Utils.MBIDProvider.MusicBrainz.ToString(), StringComparison.InvariantCultureIgnoreCase))
          {
            res = GetMusicBrainzID(artist, album);
            if (!string.IsNullOrEmpty(res))
            {
              return res;
            }
            continue;
          }
        }
        return string.Empty;
      }
  
      private string CommonGetMusicBrainzID(string artist)
      {
        return CommonGetMusicBrainzID(artist, null);
      }
  
      #region MusicBrainz
      // Begin: Extract MusicBrainz ID
      public string ExtractMID(string AInputString)
      {
        const string URLRE = @"id=\""(.+?)\""";
        var Result = string.Empty;         
  
        if (string.IsNullOrEmpty(AInputString))
        {
          logger.Debug("MusicBrainz: Extract ID: Input empty");
          return Result;
        }
  
        if (Utils.AdvancedDebug)
        {
          logger.Debug("*** ExtractMID: XML: {0}", AInputString);
        }
  
        Regex ru = new Regex(URLRE,RegexOptions.IgnoreCase);
        MatchCollection mcu = ru.Matches(AInputString);
        foreach(Match mu in mcu)
        {
          Result = mu.Groups[1].Value.ToString();
          if (Utils.AdvancedDebug)
          {
            logger.Debug("*** ExtractMID: Match: {0}", Result);
          }
          if (Utils.IsMBID(Result))
          {
            logger.Debug("MusicBrainz: Extract ID: " + Result);
            break;
          }
        }
        if (!Utils.IsMBID(Result))
        {
          Result = string.Empty;
        }
        if (string.IsNullOrEmpty(Result))
        {
          logger.Debug("MusicBrainz: Extract ID: Empty");
        }
        return Result;
      }
  
      private string ExtractReleaseMID(string AInputString)
      {
        const string URLRE = @"release.id=\""(.+?)\""";
        var Result = string.Empty;         
  
        if (string.IsNullOrEmpty(AInputString))
        {
          logger.Debug("MusicBrainz: Extract Release ID: Input empty");
          return Result;
        }
  
        Regex ru = new Regex(URLRE,RegexOptions.IgnoreCase);
        MatchCollection mcu = ru.Matches(AInputString);
        foreach(Match mu in mcu)
        {
          Result = mu.Groups[1].Value.ToString();
          if (Result.Length > 10)
          {
            logger.Debug("MusicBrainz: Extract Release ID: " + Result);
            break;
          }
        }
        if (!Utils.IsMBID(Result))
        {
          Result = string.Empty;
        }
        if (string.IsNullOrEmpty(Result))
        {
          logger.Debug("MusicBrainz: Extract Release ID: Empty");
        }
        return Result;
      }
  
      private bool ExtractMusicBrainzLabel(string html, out string label, out string lmbid)
      {
        const string URLRE = @"label.id=\""(.+?)\"".+?name>(.+?)<";
        bool Result = false;
  
        label = string.Empty;
        lmbid = string.Empty;
  
        if (string.IsNullOrEmpty(html))
        {
          logger.Debug("MusicBrainz: Extract Label ID: Input empty");
          return Result;
        }
  
        Regex ru = new Regex(URLRE,RegexOptions.IgnoreCase);
        MatchCollection mcu = ru.Matches(html);
        foreach(Match mu in mcu)
        {
          lmbid = mu.Groups[1].Value.ToString();
          label = mu.Groups[2].Value.ToString();
          if (lmbid.Length > 10 && !label.Equals("[no label]",StringComparison.CurrentCultureIgnoreCase))
          {
            logger.Debug("MusicBrainz: Extract Label ID: " + lmbid + " - " + label);
            Result = true;
            break;
          }
        }
        if (!Result)
        {
          label = string.Empty;
          lmbid = string.Empty;
  
          // logger.Debug("MusicBrainz: Extract Label ID: Empty");
        }
        return Result;
      }
      // End: Extract MusicBrainz ID
  
      // Begin: GetMusicBrainzID
      private string GetMusicBrainzID(string artist)
      {
        return GetMusicBrainzID(artist, null);
      }
  
      private string GetMusicBrainzID(string artist, string album)
      {
        var html = GetMusicBrainzXML(artist, album);
        return ExtractMID(html);
      }
      // End: GetMusicBrainzID
  
      // Begin: GetMisicBrainzLabel
      private string GetMisicBrainzLabel(string artist, string album)
      {
        if (Utils.AdvancedDebug)
        {
          logger.Debug("*** GetMisicBrainzLabel: [{0}] [{1}]", artist, album);
        }
        // return GetMisicBrainzLabel(GetMusicBrainzID(artist, album));
        return GetMisicBrainzLabel(CommonGetMusicBrainzID(artist, album));
      }
  
      private string GetMisicBrainzLabel(string mbid)
      {
        if (string.IsNullOrEmpty(mbid))
        {
          return string.Empty;
        }
  
        string html = GetMusicBrainzAlbumXML(mbid, false);
        string rmbid = ExtractReleaseMID(html);
        html = GetMusicBrainzAlbumXML(rmbid, true);
  
        string label = string.Empty;
        string lmbid = string.Empty;
        if (ExtractMusicBrainzLabel(html, out label, out lmbid))
        {
          return lmbid + "|" + label;
        }
        return string.Empty;
      }
      // End: GetMisicBrainzLabel
  
      // Begin: GetMusicBrainzXML
      private string GetMusicBrainzXML(string artist, string album)
      {
        if (string.IsNullOrEmpty(artist))
        {
          return string.Empty;
        }
  
        const string MBURL     = "http://www.musicbrainz.org/ws/2/{0}/?query={1}:{2} {3} {4}:{5}";
        string URL = string.Empty;
  
        string artistMBID = string.Empty;
        if (!string.IsNullOrEmpty(album))
        {
          // Get from DB stored Artist MBID for Album
          string res = Utils.DBm.GetDBMusicBrainzID(Utils.GetArtist(artist), null);
          if (Utils.IsMBID(res))
          {
            artistMBID = res;
          }
        }
  
        // Search MBID for Artist
        if (string.IsNullOrEmpty(album))
        {
          logger.Debug("MusicBrainz: Trying to find MusicBrainz ID for Artist: {0}.", artist);
          URL = String.Format(MBURL, "artist", "artist", @"""" + HttpUtility.UrlEncode(artist) + @"""", "OR", "alias", @"""" + HttpUtility.UrlEncode(artist) + @"""");
        }
        else
        {
          // Search MBID for Album
          if (string.IsNullOrEmpty(artistMBID))
          {
            // By Artist name - Album
            logger.Debug("MusicBrainz: Trying to find MusicBrainz ID for Album: {0} - {1}.", artist, album);
            URL = String.Format(MBURL, "release-group", "artist", @"""" + HttpUtility.UrlEncode(artist) + @"""", "AND", "release", @"""" + HttpUtility.UrlEncode(album) + @"""");
          }
          else
          {
            // By Artist MBID - Album
            logger.Debug("MusicBrainz: Trying to find MusicBrainz ID for Album: {0}:{1} - {2}.", artistMBID, artist, album);
            URL = String.Format(MBURL, "release-group", "arid", HttpUtility.UrlEncode(artistMBID), "AND", "release", @"""" + HttpUtility.UrlEncode(album) + @"""");
          }
        }
  
        if (Utils.AdvancedDebug)
        {
          logger.Debug("*** GetMusicBrainzXML: Artist: {0}, Album: {1}, URL: {2}", artist, string.IsNullOrEmpty(album) ? "-" : album, URL);
        }
  
        var html = string.Empty;
        GetHtml(URL, out html);
        return html;
      }
  
      private string GetMusicBrainzAlbumXML(string mbid, bool release)
      {
        if (string.IsNullOrEmpty(mbid))
        {
          return string.Empty;
        }
  
        string MBURL = "http://www.musicbrainz.org/ws/2/release" + (!release ? "-group" : "") + "/?query=r" + (release ? "e" : "g") + "id:";
  
        var URL  = MBURL + HttpUtility.UrlEncode(mbid);
        var html = string.Empty;
        GetHtml(URL, out html);
        return html;
      }
      // End: GetMusicBrainzXML
      #endregion
  
      #region ReportProgress
      public void ReportProgress(bool reportProgress, bool externalAccess, double Total = 0.0)
      {
        if (!reportProgress && !externalAccess)
        {
          if (Total > 0.0)
          {
              Utils.DBm.TotArtistsBeingScraped = Total;
              Utils.DBm.CurrArtistsBeingScraped = 0.0;
              if (FanartHandlerSetup.Fh.MyScraperNowWorker != null && FanartHandlerSetup.Fh.MyScraperNowWorker.Work)
              {
                FanartHandlerSetup.Fh.MyScraperNowWorker.ReportProgress(0, Utils.Progress.Start);
              }
          }
          else
          {
              ++Utils.DBm.CurrArtistsBeingScraped;
              if (Utils.DBm.CurrArtistsBeingScraped > Utils.DBm.TotArtistsBeingScraped)
              {
                Utils.DBm.TotArtistsBeingScraped = Utils.DBm.CurrArtistsBeingScraped;
              }
              if (Utils.DBm.TotArtistsBeingScraped > 0.0 && FanartHandlerSetup.Fh.MyScraperNowWorker != null && FanartHandlerSetup.Fh.MyScraperNowWorker.Work)
              {
                FanartHandlerSetup.Fh.MyScraperNowWorker.ReportProgress(Utils.Percent(Utils.DBm.CurrArtistsBeingScraped, Utils.DBm.TotArtistsBeingScraped), Utils.Progress.Progress);
              }
          }
        }
      }
      #endregion
  
      #region Artist Backdrops/Thumbs  
      // Begin: GetArtistFanart (Fanart.TV, htBackdrops)
      public int GetArtistFanart(FanartArtist key, int iMax, bool reportProgress, bool doTriggerRefresh, bool externalAccess, bool doScrapeFanart)
      {
        return GetArtistFanart(key, iMax, reportProgress, doTriggerRefresh, externalAccess, doScrapeFanart, Utils.WhatDownload.All);
      }
  
      public int GetArtistFanart(FanartArtist key, bool reportProgress, bool doTriggerRefresh, bool externalAccess, bool doScrapeFanart, Utils.WhatDownload whatDownload)
      {
        return GetArtistFanart(key, 1, reportProgress, doTriggerRefresh, externalAccess, doScrapeFanart, whatDownload);
      }
  
      public int GetArtistFanart(FanartArtist key, int iMax, bool reportProgress, bool doTriggerRefresh, bool externalAccess, bool doScrapeFanart, Utils.WhatDownload whatDownload)
      {
        if (whatDownload == Utils.WhatDownload.None)
        {
          return 0;
        }
        if (!doScrapeFanart)
        {
          return 0;
        }
        if (key.IsEmpty)
        {
          return 0;
        }
        
        var res = 0;
        var flag = true;
  
        logger.Debug("--- Fanart --- " + key.Artist + " ---");
        logger.Debug("Trying to find " + (whatDownload == Utils.WhatDownload.OnlyFanart ? "Art from Fanart.tv" : "Fanart") + " for Artist: " + key.Artist);
  
        if (Utils.DBm.TotArtistsBeingScraped == 0.0)
          ReportProgress(reportProgress, externalAccess, 8.0);
        
        // *** MusicBrainzID
        key.Id = CommonGetMusicBrainzID(key.Artist);
        if (string.IsNullOrEmpty(key.Id))
        {
          // *** Get MBID & Search result from htBackdrop
          if (alSearchResults == null)
          {
            flag = GethtBackdropsSearchResult(key.Artist, "1,5");
          }
          if (flag)
          {
            if (alSearchResults != null)
            {
              if ((alSearchResults.Count > 0) && string.IsNullOrEmpty(key.Id))
              {
                key.Id = ((SearchResults)alSearchResults[0]).MBID;
              }
            }
          }
        }
  
        ReportProgress(reportProgress, externalAccess);
        while (true)
        {
          // *** Fanart.TV
          if (!string.IsNullOrEmpty(key.Id))
          {
            res = FanartTVGetPictures(key, doTriggerRefresh, externalAccess, doScrapeFanart, whatDownload, Utils.Category.MusicFanart, Utils.SubCategory.MusicFanartScraped);
          }
          Utils.DBm.InsertDummyItem(key, res, Utils.Category.FanartTV, Utils.SubCategory.FanartTVArtist);
  
          ReportProgress(reportProgress, externalAccess);
          if (Utils.DBm.StopScraper)
          {
            break;
          }
          if (whatDownload == Utils.WhatDownload.OnlyFanart)
          {
            break;
          }
  
          // ** Get MBID & Search result from htBackdrop
          if (alSearchResults == null)
          {
            flag = GethtBackdropsSearchResult(key.Artist, "1,5");
          }
          if (flag)
          {
            if (alSearchResults != null)
            {
              if ((alSearchResults.Count > 0) && string.IsNullOrEmpty(key.Id))
              {
                key.Id = ((SearchResults)alSearchResults[0]).MBID;
              }
            }
          }
          ReportProgress(reportProgress, externalAccess);
  
          // *** htBackdrops
          if ((res == 0) || (res < iMax))
          {
            if (flag)
              res = HtBackdropGetFanart(key.Artist, iMax, doTriggerRefresh, externalAccess, doScrapeFanart);
          }
          ReportProgress(reportProgress, externalAccess);
          if (Utils.DBm.StopScraper)
            break;
  
          // *** TheAudioDB
          if ((res == 0) || (res < iMax))
          {
            res = TheAudioDBGetPictures(Utils.Category.MusicFanart, Utils.SubCategory.MusicFanartScraped, key, iMax, doTriggerRefresh, externalAccess, doScrapeFanart);
          }
          ReportProgress(reportProgress, externalAccess);
          if (Utils.DBm.StopScraper)
            break;
  
          // *** Dummy
          if (res == 0)
          {
            if (alSearchResults != null) 
            {
              if ((alSearchResults.Count > 0) && string.IsNullOrEmpty(key.Id))
              {
                key.Id = ((SearchResults) alSearchResults[0]).MBID;
              }
            }
            Utils.DBm.InsertDummyItem(key, Utils.Category.MusicFanart, Utils.SubCategory.MusicFanartScraped);
          }
          ReportProgress(reportProgress, externalAccess);
          if (Utils.DBm.StopScraper)
            break;
  
          // *** Get Thumbs for Artist
          if (Utils.ScrapeThumbnails)
          {
            GetArtistThumbs(key, true);
          }
          ReportProgress(reportProgress, externalAccess);
          break;
        } // while
        //
        if (alSearchResults != null)
        {
          alSearchResults.Clear();
          ObjectMethods.SafeDispose(alSearchResults);
        }
        alSearchResults = null;
        //
        ReportProgress(reportProgress, externalAccess);
        return res;
      }
      // End: GetArtistFanart
  
      // Begin: GetArtistThumbs (Fanart.TV, htBackdrops, Last.FM)
      public int GetArtistThumbs(FanartArtist key, bool onlyMissing)
      {
        var res = 0;
        var flag = true;
  
        if (key.IsEmpty)
        {
          return 0;
        }
  
        if (!Utils.ScrapeThumbnails)
        {
          logger.Debug("Artist Thumbnails - Disabled.");
          return res;
        }
  
        if (Utils.DBm.HasArtistThumb(key.DBArtist) && onlyMissing)
          return 1;
  
        logger.Debug("--- Thumb --- " + key.Artist + " ---");
        logger.Debug("Trying to find Thumbs for Artist: " + key.Artist);
  
        // *** MusicBrainzID
        key.Id = CommonGetMusicBrainzID(key.Artist);
        if (string.IsNullOrEmpty(key.Id))
        {
          // *** Get MBID & Search result from htBackdrop
          if (alSearchResults == null)
          {
            flag = GethtBackdropsSearchResult(key.Artist,"5");
          }
        }
        if (flag)
        {
          if (alSearchResults != null)
          {
            if ((alSearchResults.Count > 0) && string.IsNullOrEmpty(key.Id))
            {
              key.Id = ((SearchResults)alSearchResults[0]).MBID;
            }
          }
        }
        //
        while (true)
        {
          // *** Fanart.TV
          if (!string.IsNullOrEmpty(key.Id))
          {
            res = FanartTVGetPictures(key, Utils.WhatDownload.All, Utils.Category.MusicArtist, Utils.SubCategory.MusicArtistThumbScraped);
          }
          if (Utils.DBm.StopScraper)
            break;
  
          // ** Get MBID & Search result from htBackdrop
          if (alSearchResults == null)
            flag = GethtBackdropsSearchResult(key.Artist,"5");
          if (flag)
          {
            if (alSearchResults != null)
            {
              if ((alSearchResults.Count > 0) && string.IsNullOrEmpty(key.Id))
              {
                key.Id = ((SearchResults)alSearchResults[0]).MBID;
              }
            }
          }
          // *** htBackdrops
          if (res == 0)
          {
            if (flag)
              res = HtBackdropGetThumbsImages(key.Artist, onlyMissing);
          }
          if (Utils.DBm.StopScraper)
            break;
  
          // *** TheAudioDB
          if (res == 0)
          {
            res = TheAudioDBGetPictures(Utils.Category.MusicArtist, Utils.SubCategory.MusicArtistThumbScraped, key, 1, false, false, true);
          }
          if (Utils.DBm.StopScraper)
            break;
  
          // *** Last.FM
          if (res == 0) 
          {
            res = LastFMGetTumbnails(Utils.Category.MusicArtist, Utils.SubCategory.MusicArtistThumbScraped, key, false);
          }
          break;
        } // while
  
        // *** Dummy
        if (res == 0)
        {
          if (alSearchResults != null) 
          {
            if ((alSearchResults.Count > 0) && string.IsNullOrEmpty(key.Id))
            {
              key.Id = ((SearchResults) alSearchResults[0]).MBID;
            }
          }
          Utils.DBm.InsertDummyItem(key, Utils.Category.MusicArtist, Utils.SubCategory.MusicArtistThumbScraped);
        }
        // 
        if (alSearchResults != null)
        {
          alSearchResults.Clear();
          ObjectMethods.SafeDispose(alSearchResults);
        }
        alSearchResults = null;
        //
        return res;
      }
      // End: GetArtistThumbs
  
      // Begin: GetArtistAlbumThumbs (Fanart.TV, htBackdrops, Last.FM)
      public int GetArtistAlbumThumbs(FanartAlbum key, bool onlyMissing, bool externalAccess)
      {
        return GetArtistAlbumThumbs(key, onlyMissing, externalAccess, Utils.WhatDownload.All);
      }
  
      public int GetArtistAlbumThumbs(FanartAlbum key, bool onlyMissing, bool externalAccess, Utils.WhatDownload whatDownload)
      {
        if (whatDownload == Utils.WhatDownload.None)
        {
          return 0;
        }
        if (key.IsEmpty)
        {
          return 0;
        }
  
        var res = 0;
  
        if (whatDownload != Utils.WhatDownload.OnlyFanart)
        {
          if (!Utils.ScrapeThumbnailsAlbum)
          {
            logger.Debug("Artist/Album Thumbnails - Disabled.");
            return res;
          }
          if (Utils.DBm.HasAlbumThumb(key.DBArtist, key.DBAlbum) && onlyMissing)
            return 1;
        }
        logger.Debug("--- Thumb --- " + key.Artist + " - " + key.Album + " ---");
        logger.Debug("Trying to find " + (whatDownload == Utils.WhatDownload.OnlyFanart ? "Art from Fanart.tv" : "Thumbs") + " for Artist/Album: " + key.Artist + " - " + key.Album);
  
        // *** MusicBrainzID
        key.Id = CommonGetMusicBrainzID(key.Artist, key.Album);
        while (true)
        {
          // *** Fanart.TV
          if (!string.IsNullOrEmpty(key.Id))
          {
            res = FanartTVGetPictures(key, false, externalAccess, true, whatDownload, Utils.Category.MusicAlbum, Utils.SubCategory.MusicAlbumThumbScraped);
          }
          Utils.DBm.InsertDummyItem(key, res, Utils.Category.FanartTV, Utils.SubCategory.FanartTVAlbum);
  
          if (Utils.StopScraper)
          {
            break;
          }
          if (whatDownload == Utils.WhatDownload.OnlyFanart)
          {
            break;
          }
  
          // *** TheAudioDB
          if (res == 0)
          {
            res = TheAudioDBGetPictures(Utils.Category.MusicAlbum, Utils.SubCategory.MusicAlbumThumbScraped, key, 1, false, externalAccess, true);
          }
          if (Utils.StopScraper)
            break;
  
          // *** Last.FM
          if (res == 0) 
          {
            res = LastFMGetTumbnails(Utils.Category.MusicAlbum, Utils.SubCategory.MusicAlbumThumbScraped, key, externalAccess);
          }
          if (Utils.StopScraper)
            break;
  
          // *** CoverArtArchive.org
          if (res == 0 && !string.IsNullOrEmpty(key.Id)) 
          {
            res = CoverartArchiveGetTumbnails(Utils.Category.MusicAlbum, Utils.SubCategory.MusicAlbumThumbScraped, key, externalAccess);
          }
          break;
        } // while
  
        // *** Dummy
        if (res == 0)
        {
          Utils.DBm.InsertDummyItem(key, Utils.Category.MusicAlbum, Utils.SubCategory.MusicAlbumThumbScraped);
        }
  
        // *** Label for Album
        if (!string.IsNullOrEmpty(key.Id))
        {
          AddLabelForAlbum(key.Id);
        }
        return res;
      }
      // End: GetArtistAlbumThumbs
  
      // Begin: GetArtistAlbumLabels
      public int GetArtistAlbumLabels(FanartAlbum key)
      {
        if (!Utils.MusicLabelDownload)
        {
          logger.Debug("Record Labels Download - Disabled.");
          return 0;
        }
  
        if (key.IsEmpty && key.RecordLabel.IsEmpty)
        {
          return 0;
        }
  
        if (!key.RecordLabel.HasMBID && !key.HasMBID)
        {
          key.Id = Utils.DBm.GetDBMusicBrainzID(key.DBArtist, key.DBAlbum);
          if (!key.HasMBID)
          {
            return 0;
          }
        }
  
        if (!key.RecordLabel.HasMBID)
        {
          key.RecordLabel.SetRecordLabelFromDB(Utils.DBm.GetLabelIdNameForAlbum(key.Id));
        }
        if (!key.RecordLabel.HasMBID)
        {
          return 0;
        }
  
        int res = 0;
  
        res = FanartTVGetPictures(key, Utils.WhatDownload.All, Utils.Category.FanartTV, Utils.SubCategory.FanartTVRecordLabels, Utils.FanartTV.MusicLabel);
  
        return res;
      }
      // End: GetArtistAlbumLabels
  
      // Begin: GetArtistInfo
      public FanartArtistInfo GetArtistInfo(FanartArtist key)
      {
        FanartArtistInfo fa = new FanartArtistInfo();
        if (!Utils.GetArtistInfo)
        {
          logger.Debug("Artist Info - Disabled.");
          return fa;
        }
  
        if (key.IsEmpty)
        {
          return fa;
        }
  
        var far = TheAudioDBGetInfo(Utils.Info.Artist, key);
        if (far != null)
        {
          return (FanartArtistInfo)far;
        }
        return fa;
      }
      // End: GetArtistInfo
  
      // Begin: GetAlbumInfo 
      public FanartAlbumInfo GetAlbumInfo(FanartAlbum key)
      {
        FanartAlbumInfo fa = new FanartAlbumInfo();
        if (!Utils.GetAlbumInfo)
        {
          logger.Debug("Album Info - Disabled.");
          return fa;
        }
  
        if (key.IsEmpty)
        {
          return fa;
        }
  
        var far = TheAudioDBGetInfo(Utils.Info.Album, key);
        if (far != null)
        {
          return (FanartAlbumInfo)far;
        }
        return fa;
      }
      // End: GetAlbumInfo
      #endregion
  
      #region Movies fanart
      public int GetMoviesFanart(FanartMovie key)
      {
        return GetMoviesFanart(key, Utils.WhatDownload.All);
      }
  
      public int GetMoviesFanart(FanartMovie key, Utils.WhatDownload whatDownload)
      {
        if (whatDownload == Utils.WhatDownload.None)
        {
          return 0;
        }
        if (key.IsEmpty)
        {
          return 0;
        }
  
        var res = 0;
  
        logger.Debug("--- Movie --- " + key.Id + " - " + key.IMDBId + " - " + key.Title + " ---");
        logger.Debug("Trying to find " + (whatDownload == Utils.WhatDownload.OnlyFanart ? "Art from Fanart.tv" : "Art") + " for Movie: " + key.Id + " - " + key.IMDBId + " - " + key.Title);
  
        if (whatDownload != Utils.WhatDownload.OnlyFanart && Utils.TheMovieDBMovieNeedDownload)
        {
          TheMovieDBClass.TheMovieDBDetails movieDB = TheMovieDBGetInfo(Utils.Category.Movie, Utils.SubCategory.MovieScraped, key);
          if (movieDB != null)
          {
            res = res + TheMovieDBGetFanart(Utils.Category.Movie, Utils.SubCategory.MovieScraped, key, movieDB, whatDownload);
          }
        }
  
        res = res + FanartTVGetPictures(key, whatDownload, Utils.Category.Movie, Utils.SubCategory.MovieScraped);
        Utils.DBm.InsertDummyItem(key, res, Utils.Category.FanartTV, Utils.SubCategory.FanartTVMovie);
  
        if (whatDownload != Utils.WhatDownload.OnlyFanart && res == 0)
        {
          Utils.DBm.InsertDummyItem(key, Utils.Category.Movie, Utils.SubCategory.MovieScraped);
        }
  
        return res;
      }
      #endregion
  
      #region Movies Collections
      public int GetMovieCollectionsFanart(FanartMovieCollection key)
      {
        return GetMovieCollectionsFanart(key, Utils.WhatDownload.All);
      }
  
      public int GetMovieCollectionsFanart(FanartMovieCollection key, Utils.WhatDownload whatDownload)
      {
        if (whatDownload == Utils.WhatDownload.None)
        {
          return 0;
        }
        if (!Utils.TheMovieDBMoviesCollectionNeedDownload && !Utils.FanartTVNeedDownloadMoviesCollection)
        {
          return 0;
        }
        if (!key.HasTitle)
        {
          return 0;
        }
  
        if (key.IsEmpty)
        {
          Utils.DBm.GetCollection(ref key);
        }
  
        TheMovieDBClass.TheMovieDBDetails movieDB = null; 
        if (key.IsEmpty || Utils.TheMovieDBMoviesCollectionNeedDownload)
        {
          movieDB = TheMovieDBGetInfo(Utils.Category.Movie, Utils.SubCategory.MovieCollection, key);
          if (movieDB != null)
          {
            key.Id = ((TheMovieDBClass.CollectionDetails)movieDB).id.ToString();
          }
          Utils.DBm.AddCollection(key);
        }
  
        int res = 0;
  
        if (!key.IsEmpty)
        {
          logger.Debug("--- Movie (Collection) --- " + key.Id + " - " + key.Title + " ---");
          logger.Debug("Trying to find " + (whatDownload == Utils.WhatDownload.OnlyFanart ? "Art from Fanart.tv" : "Art") + " for Movie (Collection): " + key.Id + " - " + key.Title);
          if (Utils.TheMovieDBMoviesCollectionNeedDownload)
          {
            res = res + TheMovieDBGetFanart(Utils.Category.Movie, Utils.SubCategory.MovieCollection, key, movieDB, whatDownload);
          }
          if (Utils.FanartTVNeedDownloadMoviesCollection)
          {
            res = FanartTVGetPictures(key, whatDownload, Utils.Category.Movie, Utils.SubCategory.MovieCollection);
          }
        }
        Utils.DBm.UpdateCollectionTimeStamp(key);
  
        return res;
      }
      #endregion
  
      #region Movies Animated
      public int GetMoviesAnimated(FanartMovie key)
      {
        if (!Utils.UseAnimated || !Utils.AnimatedNeedDownloadMovies)
        {
          return 0;
        }
  
        if (key.IsEmpty)
        {
          return 0;
        }
  
        var num = 0;
  
        Utils.AnimatedLoad(); 
  
        if (Utils.AnimatedMoviesPosterDownload)
        {
          var res = 0;
          logger.Debug("--- Movie --- " + key.Id + " - " + key.IMDBId + " - " + key.Title + " ---");
          logger.Debug("Trying to find Animated Poster for Movie: " + key.Id + " - " + key.IMDBId + " - " + key.Title);
          res = GetAnimatedPictures(Utils.Animated.MoviesPoster, key);
          Utils.DBm.InsertDummyItem(key, Utils.Category.Animated, Utils.SubCategory.AnimatedMovie, Utils.Animated.MoviesPoster);
          num = res;
        }
  
        if (Utils.AnimatedMoviesBackgroundDownload)
        {
          var res = 0;
          logger.Debug("--- Movie --- " + key.Id + " - " + key.IMDBId + " - " + key.Title + " ---");
          logger.Debug("Trying to find Animated Background for Movie: " + key.Id + " - " + key.IMDBId + " - " + key.Title);
          res = GetAnimatedPictures(Utils.Animated.MoviesBackground, key);
          Utils.DBm.InsertDummyItem(key, Utils.Category.Animated, Utils.SubCategory.AnimatedMovie, Utils.Animated.MoviesBackground);
          num += res;
        }
  
        Utils.AnimatedUnLoad();
  
        return num;
      }
      #endregion
  
      #region Series fanart
      public int GetSeriesFanart(FanartTVSeries key)
      {
        return GetSeriesFanart(key, Utils.WhatDownload.All);
      }
  
      public int GetSeriesFanart(FanartTVSeries key, Utils.WhatDownload whatDownload)
      {
        if (whatDownload == Utils.WhatDownload.None)
        {
          return 0;
        }
        if (key.IsEmpty)
        {
          return 0;
        }
  
        var res = 0;
  
        logger.Debug("--- Series --- " + key.Id + " - " + key.Name + " [" + key.Seasons + "] ---");
        logger.Debug("Trying to find " + (whatDownload == Utils.WhatDownload.OnlyFanart ? "Art from Fanart.tv" : "Art") + " for Series: " + key.Id + " - " + key.Name + " - " + key.Seasons);
        res = FanartTVGetPictures(key, whatDownload, Utils.Category.TVSeries, Utils.SubCategory.TVSeriesScraped);
        Utils.DBm.InsertDummyItem(key, res, Utils.Category.FanartTV, Utils.SubCategory.FanartTVSeries);
  
        if (whatDownload != Utils.WhatDownload.OnlyFanart && res == 0)
        {
          Utils.DBm.InsertDummyItem(key, Utils.Category.TVSeries, Utils.SubCategory.TVSeriesScraped);
        }
  
        return res;
      }
      #endregion
  
      #region htBackdrops
      // Begin: GetNodeInfo
      private void GetNodeInfo(XPathNavigator nav1)
      {
        if (nav1 != null && nav1.Name != null && nav1.Name.ToString(CultureInfo.CurrentCulture).Equals("images", StringComparison.CurrentCulture))
        {
          using (var xmlReader = nav1.ReadSubtree())
          {
            var searchResults = new SearchResults();
            while (xmlReader.Read())
            {
              if (xmlReader.NodeType == XmlNodeType.Element)
              {
                switch (xmlReader.Name)
                {
                  case "id":
                    searchResults = new SearchResults();
                    searchResults.Id = xmlReader.ReadString();
                    continue;
                  case "album":
                    searchResults.Album = xmlReader.ReadString();
                    continue;
                  case "title":
                    searchResults.Title = xmlReader.ReadString();
                    continue;
                  case "alias":
                    searchResults.AddAlias(xmlReader.ReadString());
                    continue;
                  case "mbid":
                    searchResults.MBID = xmlReader.ReadString();
                    continue;
                  case "votes":
                    alSearchResults.Add(searchResults);
                    continue;
                  default:
                    continue;
                }
              }
            }
          }
        }
        if (nav1 != null && nav1.HasChildren)
        {
          nav1.MoveToFirstChild();
          while (nav1.MoveToNext())
          {
            GetNodeInfo(nav1);
            nav1.MoveToParent();
          }
        }
        else
        {
          if (nav1 == null || !nav1.MoveToNext())
            return;
          GetNodeInfo(nav1);
        }
      }
      // End: GetNodeInfo
  
      // Begin: GethtBackdropsSearchResult
      private bool GethtBackdropsSearchResult(string str, string type)
      {
        if (!Utils.UseHtBackdrops)
          return false;
  
        var xml = string.Empty;
        var xmlDocument = (XmlDocument) null;
        var nav1 = (XPathNavigator) null;
        var res = false;
  
        if (GetHtml("http://htbackdrops.org/api/"+ApiKeyhtBackdrops+"/searchXML?keywords=" + HttpUtility.UrlEncode(str) + "&aid="+ type + "&default_operator=and" + "&inc=keywords,mb_aliases", out xml))
        {
          try
          {
            if (!string.IsNullOrWhiteSpace(xml))
            {
              xmlDocument = new XmlDocument();
              alSearchResults = new ArrayList();
  
              xmlDocument.LoadXml(xml);
              nav1 = xmlDocument.CreateNavigator();
              nav1.MoveToRoot();
              if (nav1.HasChildren)
              {
                nav1.MoveToFirstChild();
                GetNodeInfo(nav1);
              }
              res = alSearchResults.Count > 0;
            }
          }
          catch (Exception ex)
          {
            if (alSearchResults != null)
            {
              alSearchResults.Clear();
              ObjectMethods.SafeDispose(alSearchResults);
            }
            alSearchResults = null;
  
            logger.Error("GethtBackdropsSearchResult:");
            logger.Error(ex);
            res = false;
          }
          finally
          {
            ObjectMethods.SafeDispose(xmlDocument);
            ObjectMethods.SafeDispose(nav1);
          }
        }
        return res;
      }
      // End: GethtBackdropsSearchResult
  
      public int HtBackdropGetFanart(string artist, int MaxPictures, bool doTriggerRefresh, bool externalAccess, bool doScrapeFanart)
      {
        if (!Utils.UseHtBackdrops)
          return 0;
  
        int iMax = MaxPictures;
  
        try
        {
          var dbartist = Utils.GetArtist(artist);
          if (string.IsNullOrEmpty(dbartist))
          {
            logger.Debug("HtBackdrops: GetFanart - Artist - Empty.");
            return 0;
          }
  
          iMax = Utils.DBm.GetNumberOfFanartImages(Utils.Category.MusicFanart, dbartist, iMax);
          if (iMax <= 0)
          {
            return MaxPictures;
          }
  
          if ((!Utils.DBm.StopScraper) && (doScrapeFanart))
          {
            var filename = string.Empty;
  
            var num = 0;
            if (alSearchResults != null)
            {
              logger.Debug("HtBackdrops: Trying to find fanart for Artist: " + artist + ".");
  
              var index = 0;
              while (index < alSearchResults.Count && !Utils.DBm.StopScraper)
              {
                var findartist = Utils.GetArtist(Utils.RemoveResolutionFromFileName(((SearchResults) alSearchResults[index]).Title));
                if (Utils.IsMatch(dbartist, findartist, ((SearchResults) alSearchResults[index]).Alias))
                {
                  string sourceFilename;
                  string mbid = ((SearchResults) alSearchResults[index]).MBID;
                  if (num < iMax)
                  {
                    if (((SearchResults) alSearchResults[index]).Album.Equals("1", StringComparison.CurrentCulture))
                    {
                      logger.Debug("HtBackdrops: Found fanart for Artist: " + artist + ". MBID: "+mbid);
                      sourceFilename = "http://htbackdrops.org/api/"+ApiKeyhtBackdrops+"/download/" + ((SearchResults) alSearchResults[index]).Id + "/fullsize";
                      if (!Utils.DBm.SourceImageExist(dbartist, null, sourceFilename, null, mbid, ((SearchResults) alSearchResults[index]).Id, Utils.Category.MusicFanart, Utils.SubCategory.MusicFanartScraped, Utils.Provider.HtBackdrops))
                      {
                        if (DownloadImage(new FanartArtist(mbid, dbartist), ((SearchResults) alSearchResults[index]).Id, sourceFilename, Utils.Provider.HtBackdrops,
                                          ref filename, 
                                          Utils.Category.MusicFanart, Utils.SubCategory.MusicFanartScraped))
                        {
                          checked { ++num; }
                          Utils.DBm.LoadFanart(dbartist, null, mbid, ((SearchResults)alSearchResults[index]).Id, filename, sourceFilename, Utils.Category.MusicFanart, Utils.SubCategory.MusicFanartScraped, Utils.Provider.HtBackdrops);
                          if (FanartHandlerSetup.Fh.MyScraperNowWorker != null && doTriggerRefresh && !externalAccess)
                          {
                            FanartHandlerSetup.Fh.MyScraperNowWorker.TriggerRefresh = true;
                            // doTriggerRefresh = false;
                          }
                          ExternalAccess.InvokeScraperCompleted(Utils.Category.MusicFanart.ToString(), Utils.SubCategory.MusicFanartScraped.ToString(), dbartist);
                        }
                      }
                      else
                        logger.Debug("HtBackdrops: Will not download fanart image as it already exist an image in your fanart database with this source image name.");
                    }
                  }
                  else
                  {
                    num = iMax;
                  }
                  if (Utils.DBm.StopScraper)
                    break;
                }
                checked { ++index; }
              } // while (index < alSearchResults.Count && !Utils.DBm.StopScraper)
            } // if (alSearchResults != null)
            logger.Debug("HtBackdrops: Find fanart for Artist: " + artist + " complete. Found: " + num + " pictures.");
            return num;
          }
        }
        catch (Exception ex)
        {
          logger.Error("HtBackdrops: GetFanart:");
          logger.Error(ex);
        }
        return 0;
      }
  
      public int HtBackdropGetThumbsImages(string artist, bool onlyMissing)
      {
        if (!Utils.UseHtBackdrops)
          return 0;
  
        int num = 0;
        try
        {
          var dbartist = Utils.GetArtist(artist);
          if (string.IsNullOrEmpty(dbartist))
          {
            logger.Debug("HtBackdrops: GetTumbnails - Artist - Empty.");
            return 0;
          }
  
          num = Utils.DBm.HasArtistThumb(dbartist) ? 1 : 0;
          if ((!Utils.DBm.StopScraper) && (!Utils.DBm.HasArtistThumb(dbartist) || !onlyMissing))
          {
            var filename = string.Empty;
            if (alSearchResults != null)
            {
              logger.Debug("HtBackdrops: Trying to find thumbnail for Artist: " + artist + ".");
              num = 0;
              var index = 0;
              while (index < alSearchResults.Count && !Utils.DBm.StopScraper)
              {
                var findartist = Utils.GetArtist(Utils.RemoveResolutionFromFileName(((SearchResults) alSearchResults[index]).Title));
                if (Utils.IsMatch(dbartist, findartist, ((SearchResults) alSearchResults[index]).Alias))
                {
                  if (!Utils.DBm.StopScraper)
                  {
                    if (((SearchResults) alSearchResults[index]).Album.Equals("5", StringComparison.CurrentCulture))
                    {
                      string mbid = ((SearchResults) alSearchResults[index]).MBID;
                      logger.Debug("HtBackdrops: Found thumbnail for Artist: " + artist + ". MBID: "+mbid);
                      var sourceFilename = "http://htbackdrops.org/api/"+ApiKeyhtBackdrops+"/download/" + ((SearchResults) alSearchResults[index]).Id + "/fullsize";
                      if (DownloadImage(new FanartArtist(mbid, artist), sourceFilename, Utils.Provider.HtBackdrops,
                                        ref filename, 
                                        Utils.Category.MusicArtist, Utils.SubCategory.MusicArtistThumbScraped))
                      {
                        checked { ++num; }
                        Utils.DBm.LoadFanart(dbartist, null, mbid, null, filename, sourceFilename, Utils.Category.MusicArtist, Utils.SubCategory.MusicArtistThumbScraped, Utils.Provider.HtBackdrops);
                        ExternalAccess.InvokeScraperCompleted(Utils.Category.MusicArtist.ToString(), Utils.SubCategory.MusicArtistThumbScraped.ToString(), dbartist);
                        break;
                      }
                    }
                  }
                  else
                    break;
                }
                checked { ++index; }
              }
            }
            logger.Debug("HtBackdrops: Find thumbnail for Artist: " + artist + " complete. Found: "+num+" pictures.");
          }
        }
        catch (Exception ex)
        {
          logger.Error("HtBackdrops: GetThumbsImages:");
          logger.Error(ex);
        }
        return num;
      }
      #endregion
  
      #region Last.FM
      public static void RemoveStackEndings(ref string strFileName)
      {
        if (string.IsNullOrEmpty(strFileName)) 
          return;
  
        var stackReg = StackExpression();
        for (var i = 0; i < stackReg.Length; i++)
        {
          // See if we can find the special patterns in both filenames
          //if (Regex.IsMatch(strFileName, pattern[i], RegexOptions.IgnoreCase))
          if (stackReg[i].IsMatch(strFileName))
          {
            strFileName = stackReg[i].Replace(strFileName, string.Empty);
            //Regex.Replace(strFileName, pattern[i], string.Empty, RegexOptions.IgnoreCase);
          }
        }
      }
  
      public static Regex[] StackExpression()
      {
        // Patterns that are used for matching
        // 1st pattern matches [x-y] for example [1-2] which is disc 1 of 2 total
        // 2nd pattern matches ?cd?## and ?disc?## for example -cd2 which is cd 2.
        //     ? is -_+ or space (second ? is optional), ## is 1 or 2 digits
        //
        // Chemelli: added "+" as separator to allow IMDB scripts usage of this function
        //
        if (StackRegExpressions != null) return StackRegExpressions;
        string[] pattern = {
                             "\\s*\\[(?<digit>[0-9]{1,2})-[0-9]{1,2}\\]",
                             "\\s*[-_+ ]\\({0,1}(cd|dis[ck]|part|dvd)[-_+ ]{0,1}(?<digit>[0-9]{1,2})\\){0,1}"
                           };
  
        StackRegExpressions = new Regex[]
                                {
                                  new Regex(pattern[0], RegexOptions.Compiled | RegexOptions.IgnoreCase),
                                  new Regex(pattern[1], RegexOptions.Compiled | RegexOptions.IgnoreCase)
                                };
        return StackRegExpressions;
      }
  
      public static bool ShouldStack(string strFile1, string strFile2)
      {
        if (string.IsNullOrEmpty(strFile1)) return false;
        if (string.IsNullOrEmpty(strFile2)) return false;
  
        try
        {
          var stackReg = StackExpression();
  
          // Strip the extensions and make everything lowercase
          var strFileName1 = Path.GetFileNameWithoutExtension(strFile1).ToLowerInvariant();
          var strFileName2 = Path.GetFileNameWithoutExtension(strFile2).ToLowerInvariant();
  
          // Check all the patterns
          for (var i = 0; i < stackReg.Length; i++)
          {
            // See if we can find the special patterns in both filenames
            //if (Regex.IsMatch(strFileName1, pattern[i], RegexOptions.IgnoreCase) &&
            //    Regex.IsMatch(strFileName2, pattern[i], RegexOptions.IgnoreCase))
            if (stackReg[i].IsMatch(strFileName1) && stackReg[i].IsMatch(strFileName2))
            {
              // Both strings had the special pattern. Now see if the filenames are the same.
              // Do this by removing the special pattern and compare the remains.
              //if (Regex.Replace(strFileName1, pattern[i], string.Empty, RegexOptions.IgnoreCase)
              //    == Regex.Replace(strFileName2, pattern[i], string.Empty, RegexOptions.IgnoreCase))
              if (stackReg[i].Replace(strFileName1, string.Empty) == stackReg[i].Replace(strFileName2, string.Empty))
              {
                // It was a match so stack it
                return true;
              }
            }
          }
        }
        catch (Exception) { }
  
        // No matches were found, so no stacking
        return false;
      }
  
      [MethodImpl(MethodImplOptions.Synchronized)]
      private static string removeInvalidChars(string inputString_)
      {
        var cleanString = inputString_;
        var dotIndex = 0;
  
        try
        {
          // remove CD1, CD2, CDn from Tracks
          if (ShouldStack(cleanString, cleanString))
          {
            RemoveStackEndings(ref cleanString);
          }
          // remove [DJ Spacko MIX (2000)]
          dotIndex = cleanString.IndexOf("[");
          if (dotIndex > 0) {
            cleanString = cleanString.Remove(dotIndex);
          }
          dotIndex = cleanString.IndexOf("(");
          if (dotIndex > 0) {
            cleanString = cleanString.Remove(dotIndex);
          }
          // dotIndex = cleanString.IndexOf("feat.");
          // if (dotIndex > 0) {
          //   cleanString = cleanString.Remove(dotIndex);
          // }
  
          // TODO: build REGEX here
          // replace our artist concatenation
          // cleanString = cleanString.Replace("|", "&");
          if (cleanString.Contains("|")) {
            cleanString = cleanString.Remove(cleanString.IndexOf("|"));
          }
          // substitute "&" with "and" <-- as long as needed
          //      cleanString = cleanString.Replace("&", " and ");
          // make sure there's only one space
          //      cleanString = cleanString.Replace("  ", " ");
          // substitute "/" with "+"
          //      cleanString = cleanString.Replace(@"/", "+");
          // clean soundtracks
          cleanString = cleanString.Replace("OST ", " ");
          cleanString = cleanString.Replace("Soundtrack - ", " ");
  
          if (cleanString.EndsWith("Soundtrack")) {
            cleanString = cleanString.Remove(cleanString.IndexOf("Soundtrack"));
          }
          if (cleanString.EndsWith("OST")) {
            cleanString = cleanString.Remove(cleanString.IndexOf("OST"));
          }
          if (cleanString.EndsWith(" EP")) {
            cleanString = cleanString.Remove(cleanString.IndexOf(" EP"));
          }
          if (cleanString.EndsWith(" (EP)")) {
            cleanString = cleanString.Remove(cleanString.IndexOf(" (EP)"));
          }
        }
        catch (Exception ex)
        {
          logger.Warn("AudioscrobblerBase: Removal of invalid chars failed - {0}", ex.Message);
        }
  
        return cleanString.Trim();
      }
  
      [MethodImpl(MethodImplOptions.Synchronized)]
      private static string removeEndingChars(string inputString_)
      {
        try
        {
          // build a clean end
          inputString_.TrimEnd(new char[] { '-', '+', ' ' });
        }
        catch (Exception ex)
        {
          logger.Error("AudioscrobblerBase: Error removing ending chars - {0}", ex.Message);
        }
        return inputString_;
      }
  
      [MethodImpl(MethodImplOptions.Synchronized)]
      public static string getValidURLLastFMString(string lastFMString)
      {
        var outString = string.Empty;
        var urlString = HttpUtility.UrlEncode(lastFMString);
  
        try
        {
          outString = removeInvalidChars(lastFMString);
  
          if (!string.IsNullOrEmpty(outString)) {
            urlString = HttpUtility.UrlEncode(removeEndingChars(outString));
          }
  
          outString = urlString;
  
          // add chars here which need to be followed by "+" to be recognized correctly by last.fm
          // consider some special cases like R.E.M. / D.D.E. / P.O.D etc
          var invalidSingleChars = new List<Char>();
          // invalidSingleChars.Add('.');
          // invalidSingleChars.Add(',');
  
          foreach (var singleChar in invalidSingleChars)
          {
            // do not loop unless needed
  
gt:           if (urlString.IndexOf(singleChar) > 0) {