ViewModel for a MediaDBScrobble.
Inheritance: Caliburn.Micro.PropertyChangedBase
        /// <summary>
        /// Parses the windows media player database.
        /// </summary>
        private async void ParseWMPDatabase()
        {
            EnableControls = false;

            try
            {
                await Task.Run(() =>
                {
                    OnStatusUpdated("Parsing Windows Media Player library...");
                    using (WMP wmp = new WMP())
                    {
                        // todo: this can be better
                        var scrobbles   = wmp.GetMusicLibrary();
                        var scrobbleVMs = new List <MediaDBScrobbleViewModel>();
                        foreach (var scrobble in scrobbles)
                        {
                            var vm = new MediaDBScrobbleViewModel(scrobble);
                            vm.ToScrobbleChanged += ToScrobbleChanged;
                            scrobbleVMs.Add(vm);
                        }

                        ParsedScrobbles = new ObservableCollection <MediaDBScrobbleViewModel>(scrobbleVMs);
                    }
                    OnStatusUpdated("Successfully parsed Windows Media Player library");
                });
            }
            catch (Exception ex)
            {
                OnStatusUpdated("Fatal error while parsing Windows Media Player library. Error: " + ex.Message);
            }
            finally
            {
                EnableControls = true;
            }
        }
    /// <summary>
    /// Parses the windows media player database.
    /// </summary>
    private async void ParseWMPDatabase()
    {
      EnableControls = false;

      await Task.Run(() =>
      {
        OnStatusUpdated("Parsing Windows Media Player library...");
        using (WMP wmp = new WMP())
        {
          // todo: this can be better
          var scrobbles = wmp.GetMusicLibrary();
          var scrobbleVMs = new List<MediaDBScrobbleViewModel>();
          foreach (var scrobble in scrobbles)
          {
            var vm = new MediaDBScrobbleViewModel(scrobble);
            vm.ToScrobbleChanged += ToScrobbleChanged;
            scrobbleVMs.Add(vm);
          }

          ParsedScrobbles = new ObservableCollection<MediaDBScrobbleViewModel>(scrobbleVMs);
        }
        OnStatusUpdated("Successfully parsed Windows Media Player library");
      });

      EnableControls = true;
    }
        /// <summary>
        /// Parse the <see cref="DBFilePath"/>.
        /// A lot of media players use the same xml format.
        /// </summary>
        private async void ParseItunesConformXML()
        {
            EnableControls = false;

            XmlDocument xmlDocument = new XmlDocument();

            try
            {
                xmlDocument.Load(DBFilePath);
            }
            catch (Exception ex)
            {
                EnableControls = true;
                OnStatusUpdated("Could not load database file: " + ex.Message);
                return;
            }

            // node that points to all tracks
            XmlNode trackDictNode = null;

            try
            {
                trackDictNode = xmlDocument.ChildNodes[2].ChildNodes[0].ChildNodes.OfType <XmlNode>().First(i => i.Name == "dict");
                if (trackDictNode == null)
                {
                    throw new Exception("Could not find 'Tracks' node in xml file");
                }
            }
            catch (Exception ex)
            {
                EnableControls = true;
                OnStatusUpdated("Error parsing database file: " + ex.Message);
                return;
            }

            List <MediaDBScrobbleViewModel> scrobbles  = new List <MediaDBScrobbleViewModel>();
            Dictionary <XmlNode, string>    errorNodes = new Dictionary <XmlNode, string>();

            int count     = 1;
            var dictNodes = trackDictNode.ChildNodes.OfType <XmlNode>().Where(i => i.Name == "dict");

            foreach (XmlNode trackNode in dictNodes)
            {
                await Task.Run(() =>
                {
                    try
                    {
                        var xmlNodes        = trackNode.ChildNodes.OfType <XmlNode>();
                        int playCount       = int.Parse(xmlNodes.First(i => i.InnerText == "Play Count").NextSibling.InnerText);
                        string trackName    = xmlNodes.First(i => i.InnerText == "Name").NextSibling.InnerText;
                        string artistName   = xmlNodes.First(i => i.InnerText == "Artist").NextSibling.InnerText;
                        string albumName    = xmlNodes.FirstOrDefault(i => i.InnerText == "Album")?.NextSibling.InnerText;
                        string albumArtist  = xmlNodes.FirstOrDefault(i => i.InnerText == "Album Artist")?.NextSibling.InnerText;
                        TimeSpan duration   = TimeSpan.FromMilliseconds(int.Parse(xmlNodes.FirstOrDefault(i => i.InnerText == "Total Time")?.NextSibling.InnerText));
                        DateTime lastPlayed = DateTime.Parse(xmlNodes.FirstOrDefault(i => i.InnerText == "Play Date UTC")?.NextSibling.InnerText);

                        MediaDBScrobbleViewModel vm = new MediaDBScrobbleViewModel(new MediaDBScrobble(playCount, lastPlayed, trackName, artistName, albumName, albumArtist, duration));
                        vm.ToScrobbleChanged       += ToScrobbleChanged;
                        scrobbles.Add(vm);
                    }
                    catch (Exception ex)
                    {
                        // corrupted or something, log and continue.
                        errorNodes.Add(trackNode, ex.Message);
                    }
                    finally
                    {
                        OnStatusUpdated("Parsing database file... " + count++ + " / " + dictNodes.Count());
                    }
                });
            }

            OnStatusUpdated("Successfully parsed database file");
            ParsedScrobbles = new ObservableCollection <MediaDBScrobbleViewModel>(scrobbles);
            EnableControls  = true;
        }
    /// <summary>
    /// Parse the <see cref="DBFilePath"/>.
    /// A lot of media players use the same xml format.
    /// </summary>
    private async void ParseItunesConformXML()
    {
      EnableControls = false;

      XmlDocument xmlDocument = new XmlDocument();
      try
      {
        xmlDocument.Load(DBFilePath);
      }
      catch (Exception ex)
      {
        EnableControls = true;
        OnStatusUpdated("Could not load database file: " + ex.Message);
        return;
      }

      // node that points to all tracks
      XmlNode trackDictNode = null;
      try
      {
        trackDictNode = xmlDocument.ChildNodes[2].ChildNodes[0].ChildNodes.OfType<XmlNode>().First(i => i.Name == "dict");
        if (trackDictNode == null)
          throw new Exception("Could not find 'Tracks' node in xml file");
      }
      catch (Exception)
      {
        EnableControls = true;
        OnStatusUpdated("Could not find 'Tracks' node in xml file");
        return;
      }

      List<MediaDBScrobbleViewModel> scrobbles = new List<MediaDBScrobbleViewModel>();
      Dictionary<XmlNode, string> errorNodes = new Dictionary<XmlNode, string>();

      int count = 1;
      var dictNodes = trackDictNode.ChildNodes.OfType<XmlNode>().Where(i => i.Name == "dict");
      foreach (XmlNode trackNode in dictNodes)
      {
        await Task.Run(() =>
        {
          try
          {
            var xmlNodes = trackNode.ChildNodes.OfType<XmlNode>();
            int playCount = int.Parse(xmlNodes.First(i => i.InnerText == "Play Count").NextSibling.InnerText);
            string trackName = xmlNodes.First(i => i.InnerText == "Name").NextSibling.InnerText;
            string artistName = xmlNodes.First(i => i.InnerText == "Artist").NextSibling.InnerText;
            string albumName = xmlNodes.FirstOrDefault(i => i.InnerText == "Album")?.NextSibling.InnerText;
            DateTime lastPlayed = DateTime.Parse(xmlNodes.FirstOrDefault(i => i.InnerText == "Play Date UTC")?.NextSibling.InnerText);


            MediaDBScrobbleViewModel vm = new MediaDBScrobbleViewModel(new MediaDBScrobble(trackName, artistName, albumName, playCount, lastPlayed));
            vm.ToScrobbleChanged += ToScrobbleChanged;
            scrobbles.Add(vm);
          }
          catch (Exception ex)
          {
            // todo: corrupted or something, log and continue.
            //errorNodes.Add(trackNode, ex.Message);
          }
          finally
          {
            OnStatusUpdated("Parsing database file... " + count + " / " + dictNodes.Count());
            count++;
          }
        });
      }

      OnStatusUpdated("Successfully parsed database file");
      ParsedScrobbles = new ObservableCollection<MediaDBScrobbleViewModel>(scrobbles);
      EnableControls = true;
    }