Esempio n. 1
0
void CGUIWindowMusicInfo::SetSongs(const VECSONGS &songs)
{
  m_albumSongs->Clear();
  for (unsigned int i = 0; i < songs.size(); i++)
  {
    const CSong& song = songs[i];
    CFileItem *item = new CFileItem(song);
    m_albumSongs->Add(item);
  }
}
Esempio n. 2
0
void CGUIDialogMusicInfo::SetSongs(const VECSONGS &songs) const
{
  m_albumSongs->Clear();
  CMusicThumbLoader loader;
  for (unsigned int i = 0; i < songs.size(); i++)
  {
    const CSong& song = songs[i];
    CFileItemPtr item(new CFileItem(song));
    // Load the song art and related artist(s) (that may be different from album artist) art
    loader.LoadItem(item.get());
    m_albumSongs->Add(item);
  }
}
Esempio n. 3
0
bool CMusicInfoScanner::HasSingleAlbum(const VECSONGS &songs, CStdString &album, CStdString &artist)
{
  // check how many unique albums are in this path, and if there's only one, and it has a thumb
  // then cache the thumb as the folder thumb
  for (unsigned int i = 0; i < songs.size(); i++)
  {
    const CSong &song = songs[i];
    // don't bother with empty album tags - they're treated as singles, and there's no way to determine
    // whether more than one track in the folder is supposed to mean they belong to an "album"
    if (song.strAlbum.IsEmpty())
      return false;

    CStdString albumArtist = song.strAlbumArtist.IsEmpty() ? song.strArtist : song.strAlbumArtist;

    if (!album.IsEmpty() && (album != song.strAlbum || artist != albumArtist))
      return false; // have more than one album

    album = song.strAlbum;
    artist = albumArtist;
  }
  return !album.IsEmpty();
}
Esempio n. 4
0
bool CMusicInfoScanner::HasSingleAlbum(const VECSONGS &songs, CStdString &album, CStdString &artist)
{
  // check how many unique albums are in this path, and if there's only one, and it has a thumb
  // then cache the thumb as the folder thumb
  for (unsigned int i = 0; i < songs.size(); i++)
  {
    const CSong &song = songs[i];
    // don't bother with empty album tags - they're unlikely to have an embedded thumb anyway,
    // and if one is not tagged correctly, how can we know whether there is only one album?
    if (song.strAlbum.IsEmpty())
      return false;

    CStdString albumArtist = song.strAlbumArtist.IsEmpty() ? song.strArtist : song.strAlbumArtist;

    if (!album.IsEmpty() && (album != song.strAlbum || artist != albumArtist))
      return false; // have more than one album

    album = song.strAlbum;
    artist = albumArtist;
  }
  return !album.IsEmpty();
}
Esempio n. 5
0
int CMusicInfoScanner::RetrieveMusicInfo(CFileItemList& items, const CStdString& strDirectory)
{
  CSongMap songsMap;

  // get all information for all files in current directory from database, and remove them
  if (m_musicDatabase.RemoveSongsFromPath(strDirectory, songsMap))
    m_needsCleanup = true;

  VECSONGS songsToAdd;

  CStdStringArray regexps = g_advancedSettings.m_audioExcludeFromScanRegExps;

  // for every file found, but skip folder
  for (int i = 0; i < items.Size(); ++i)
  {
    CFileItemPtr pItem = items[i];
    CStdString strExtension;
    URIUtils::GetExtension(pItem->GetPath(), strExtension);

    if (m_bStop)
      return 0;

    // Discard all excluded files defined by m_musicExcludeRegExps
    if (CUtil::ExcludeFileOrFolder(pItem->GetPath(), regexps))
      continue;

    // dont try reading id3tags for folders, playlists or shoutcast streams
    if (!pItem->m_bIsFolder && !pItem->IsPlayList() && !pItem->IsPicture() && !pItem->IsLyrics() )
    {
      m_currentItem++;
//      CLog::Log(LOGDEBUG, "%s - Reading tag for: %s", __FUNCTION__, pItem->GetPath().c_str());

      // grab info from the song
      CSong *dbSong = songsMap.Find(pItem->GetPath());

      CMusicInfoTag& tag = *pItem->GetMusicInfoTag();
      if (!tag.Loaded() )
      { // read the tag from a file
        auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(pItem->GetPath()));
        if (NULL != pLoader.get())
          pLoader->Load(pItem->GetPath(), tag);
      }

      // if we have the itemcount, update our
      // dialog with the progress we made
      if (m_handle && m_itemCount>0)
        m_handle->SetPercentage(m_currentItem/(float)m_itemCount*100);

      if (tag.Loaded())
      {
        CSong song(tag);

        // ensure our song has a valid filename or else it will assert in AddSong()
        if (song.strFileName.IsEmpty())
        {
          // copy filename from path in case UPnP or other tag loaders didn't specify one (FIXME?)
          song.strFileName = pItem->GetPath();

          // if we still don't have a valid filename, skip the song
          if (song.strFileName.IsEmpty())
          {
            // this shouldn't ideally happen!
            CLog::Log(LOGERROR, "Skipping song since it doesn't seem to have a filename");
            continue;
          }
        }

        song.iStartOffset = pItem->m_lStartOffset;
        song.iEndOffset = pItem->m_lEndOffset;
        song.strThumb = pItem->GetUserMusicThumb(true);
        if (dbSong)
        { // keep the db-only fields intact on rescan...
          song.iTimesPlayed = dbSong->iTimesPlayed;
          song.lastPlayed = dbSong->lastPlayed;
          song.iKaraokeNumber = dbSong->iKaraokeNumber;

          if (song.rating == '0') song.rating = dbSong->rating;
          if (song.strThumb.empty())
            song.strThumb = dbSong->strThumb;
        }
        songsToAdd.push_back(song);
//        CLog::Log(LOGDEBUG, "%s - Tag loaded for: %s", __FUNCTION__, pItem->GetPath().c_str());
      }
      else
        CLog::Log(LOGDEBUG, "%s - No tag found for: %s", __FUNCTION__, pItem->GetPath().c_str());
    }
  }

  VECALBUMS albums;
  CategoriseAlbums(songsToAdd, albums);
  FindArtForAlbums(albums, items.GetPath());

  // finally, add these to the database
  m_musicDatabase.BeginTransaction();
  int numAdded = 0;
  set<int> albumsToScan;
  set<int> artistsToScan;
  for (VECALBUMS::iterator i = albums.begin(); i != albums.end(); ++i)
  {
    vector<int> songIDs;
    int idAlbum = m_musicDatabase.AddAlbum(*i, songIDs);
    numAdded += i->songs.size();
    if (m_bStop)
    {
      m_musicDatabase.RollbackTransaction();
      return numAdded;
    }

    // Build the artist & album sets
    albumsToScan.insert(idAlbum);
    for (vector<int>::iterator j = songIDs.begin(); j != songIDs.end(); ++j)
    {
      vector<int> songArtists;
      m_musicDatabase.GetArtistsBySong(*j, false, songArtists);
      artistsToScan.insert(songArtists.begin(), songArtists.end());
    }
    std::vector<int> albumArtists;
    m_musicDatabase.GetArtistsByAlbum(idAlbum, false, albumArtists);
    artistsToScan.insert(albumArtists.begin(), albumArtists.end());
  }
  m_musicDatabase.CommitTransaction();

  // Download info & artwork
  bool bCanceled;
  for (set<int>::iterator it = artistsToScan.begin(); it != artistsToScan.end(); ++it)
  {
    bCanceled = false;
    if (find(m_artistsScanned.begin(),m_artistsScanned.end(), *it) == m_artistsScanned.end())
    {
      CStdString strArtist = m_musicDatabase.GetArtistById(*it);
      m_artistsScanned.push_back(*it);
      if (!m_bStop && (m_flags & SCAN_ONLINE))
      {
        CStdString strPath;
        strPath.Format("musicdb://2/%u/", *it);

        if (!DownloadArtistInfo(strPath, strArtist, bCanceled)) // assume we want to retry
          m_artistsScanned.pop_back();
      }
      else
      {
        map<string, string> artwork = GetArtistArtwork(*it);
        m_musicDatabase.SetArtForItem(*it, "artist", artwork);
      }
    }
  }

  if (m_flags & SCAN_ONLINE)
  {
    for (set<int>::iterator it = albumsToScan.begin(); it != albumsToScan.end(); ++it)
    {
      if (m_bStop)
        return songsToAdd.size();

      CStdString strPath;
      strPath.Format("musicdb://3/%u/",*it);

      CAlbum album;
      m_musicDatabase.GetAlbumInfo(*it, album, NULL);
      bCanceled = false;
      if (find(m_albumsScanned.begin(), m_albumsScanned.end(), *it) == m_albumsScanned.end())
      {
        CMusicAlbumInfo albumInfo;
        if (DownloadAlbumInfo(strPath, StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator), album.strAlbum, bCanceled, albumInfo))
          m_albumsScanned.push_back(*it);
      }
    }
  }
  if (m_handle)
    m_handle->SetTitle(g_localizeStrings.Get(505));

  return songsToAdd.size();
}
Esempio n. 6
0
void CMusicInfoScanner::CheckForVariousArtists(VECSONGS &songsToCheck)
{
  // first, find all the album names for these songs
  map<CStdString, vector<CSong *> > albumsToAdd;
  map<CStdString, vector<CSong *> >::iterator it;
  for (unsigned int i = 0; i < songsToCheck.size(); ++i)
  {
    CSong &song = songsToCheck[i];
    if (!song.strAlbumArtist.IsEmpty()) // albumartist specified, so assume the user knows what they're doing
      continue;
    it = albumsToAdd.find(song.strAlbum);
    if (it == albumsToAdd.end())
    {
      vector<CSong *> songs;
      songs.push_back(&song);
      albumsToAdd.insert(make_pair(song.strAlbum, songs));
    }
    else
      it->second.push_back(&song);
  }
  // as an additional check for those that have multiple albums in the same folder, ignore albums
  // that have overlapping track numbers
  for (it = albumsToAdd.begin(); it != albumsToAdd.end();)
  {
    vector<CSong *> &songs = it->second;
    bool overlappingTrackNumbers(false);
    if (songs.size() > 1)
    {
      sort(songs.begin(), songs.end(), SortSongsByTrack);
      for (unsigned int i = 0; i < songs.size() - 1; i++)
      {
        CSong *song = songs[i];
        CSong *song2 = songs[i+1];
        if (song->iTrack == song2->iTrack)
        {
          overlappingTrackNumbers = true;
          break;
        }
      }
    }
    if (overlappingTrackNumbers)
    { // remove this album
      albumsToAdd.erase(it++);
    }
    else
      it++;
  }

  // ok, now run through these albums, and check whether they qualify as a "various artist" album
  // an album is considered a various artists album if the songs' primary artist differs
  // it qualifies as a "single artist with featured artists" album if the primary artist is the same, but secondary artists differ
  for (it = albumsToAdd.begin(); it != albumsToAdd.end(); it++)
  {
    const CStdString &album = it->first;
    vector<CSong *> &songs = it->second;
    if (!album.IsEmpty() && songs.size() > 1)
    {
      bool variousArtists(false);
      bool singleArtistWithFeaturedArtists(false);
      for (unsigned int i = 0; i < songs.size() - 1; i++)
      {
        CSong *song1 = songs[i];
        CSong *song2 = songs[i+1];
        CStdStringArray vecArtists1, vecArtists2;
        StringUtils::SplitString(song1->strArtist, g_advancedSettings.m_musicItemSeparator, vecArtists1);
        StringUtils::SplitString(song2->strArtist, g_advancedSettings.m_musicItemSeparator, vecArtists2);
        CStdString primaryArtist1 = vecArtists1[0]; primaryArtist1.TrimRight();
        CStdString primaryArtist2 = vecArtists2[0]; primaryArtist2.TrimRight();
        if (primaryArtist1 != primaryArtist2)
        { // primary artist differs -> a various artists album
          variousArtists = true;
          break;
        }
        else if (song1->strArtist != song2->strArtist)
        { // have more than one artist, the first artist(s) agree, but the full artist name doesn't
          // so this is likely a single-artist compilation (ie with other artists featured on some tracks) album
          singleArtistWithFeaturedArtists = true;
        }
      }
      if (variousArtists)
      { // have a various artists album - update all songs to be the various artist
        for (unsigned int i = 0; i < songs.size(); i++)
        {
          CSong *song = songs[i];
          song->strAlbumArtist = g_localizeStrings.Get(340); // Various Artists
        }
      }
      else if (singleArtistWithFeaturedArtists)
      { // have an album where all the first artists agree - make this the album artist
        CStdStringArray vecArtists;
        StringUtils::SplitString(songs[0]->strArtist, g_advancedSettings.m_musicItemSeparator, vecArtists);
        CStdString albumArtist(vecArtists[0]);
        for (unsigned int i = 0; i < songs.size(); i++)
        {
          CSong *song = songs[i];
          song->strAlbumArtist = albumArtist; // first artist of all tracks
        }
      }
    }
  }
}
Esempio n. 7
0
int CMusicInfoScanner::RetrieveMusicInfo(CFileItemList& items, const CStdString& strDirectory)
{
  CSongMap songsMap;

  // get all information for all files in current directory from database, and remove them
  if (m_musicDatabase.RemoveSongsFromPath(strDirectory, songsMap))
    m_needsCleanup = true;

  VECSONGS songsToAdd;

  CStdStringArray regexps = g_advancedSettings.m_audioExcludeFromScanRegExps;

  // for every file found, but skip folder
  for (int i = 0; i < items.Size(); ++i)
  {
    CFileItemPtr pItem = items[i];
    CStdString strExtension;
    URIUtils::GetExtension(pItem->GetPath(), strExtension);

    if (m_bStop)
      return 0;

    // Discard all excluded files defined by m_musicExcludeRegExps
    if (CUtil::ExcludeFileOrFolder(pItem->GetPath(), regexps))
      continue;

    // dont try reading id3tags for folders, playlists or shoutcast streams
    if (!pItem->m_bIsFolder && !pItem->IsPlayList() && !pItem->IsPicture() && !pItem->IsLyrics() )
    {
      m_currentItem++;
//      CLog::Log(LOGDEBUG, "%s - Reading tag for: %s", __FUNCTION__, pItem->GetPath().c_str());

      // grab info from the song
      CSong *dbSong = songsMap.Find(pItem->GetPath());

      CMusicInfoTag& tag = *pItem->GetMusicInfoTag();
      if (!tag.Loaded() )
      { // read the tag from a file
        auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(pItem->GetPath()));
        if (NULL != pLoader.get())
          pLoader->Load(pItem->GetPath(), tag);
      }

      // if we have the itemcount, notify our
      // observer with the progress we made
      if (m_pObserver && m_itemCount>0)
        m_pObserver->OnSetProgress(m_currentItem, m_itemCount);

      if (tag.Loaded())
      {
        CSong song(tag);

        // ensure our song has a valid filename or else it will assert in AddSong()
        if (song.strFileName.IsEmpty())
        {
          // copy filename from path in case UPnP or other tag loaders didn't specify one (FIXME?)
          song.strFileName = pItem->GetPath();

          // if we still don't have a valid filename, skip the song
          if (song.strFileName.IsEmpty())
          {
            // this shouldn't ideally happen!
            CLog::Log(LOGERROR, "Skipping song since it doesn't seem to have a filename");
            continue;
          }
        }

        song.iStartOffset = pItem->m_lStartOffset;
        song.iEndOffset = pItem->m_lEndOffset;
        if (dbSong)
        { // keep the db-only fields intact on rescan...
          song.iTimesPlayed = dbSong->iTimesPlayed;
          song.lastPlayed = dbSong->lastPlayed;
          song.iKaraokeNumber = dbSong->iKaraokeNumber;

          if (song.rating == '0') song.rating = dbSong->rating;
        }
        pItem->SetMusicThumb();
        song.strThumb = pItem->GetThumbnailImage();
        songsToAdd.push_back(song);
//        CLog::Log(LOGDEBUG, "%s - Tag loaded for: %s", __FUNCTION__, pItem->GetPath().c_str());
      }
      else
        CLog::Log(LOGDEBUG, "%s - No tag found for: %s", __FUNCTION__, pItem->GetPath().c_str());
    }
  }

  CheckForVariousArtists(songsToAdd);
  if (!items.HasThumbnail())
    UpdateFolderThumb(songsToAdd, items.GetPath());

  // finally, add these to the database
  set<CStdString> artistsToScan;
  set< pair<CStdString, CStdString> > albumsToScan;
  m_musicDatabase.BeginTransaction();
  for (unsigned int i = 0; i < songsToAdd.size(); ++i)
  {
    if (m_bStop)
    {
      m_musicDatabase.RollbackTransaction();
      return i;
    }
    CSong &song = songsToAdd[i];
    m_musicDatabase.AddSong(song, false);

    artistsToScan.insert(song.strArtist);
    albumsToScan.insert(make_pair(song.strAlbum, song.strArtist));
  }
  m_musicDatabase.CommitTransaction();

  bool bCanceled;
  for (set<CStdString>::iterator i = artistsToScan.begin(); i != artistsToScan.end(); ++i)
  {
    bCanceled = false;
    long iArtist = m_musicDatabase.GetArtistByName(*i);
    if (find(m_artistsScanned.begin(),m_artistsScanned.end(),iArtist) == m_artistsScanned.end())
    {
      m_artistsScanned.push_back(iArtist);
      if (!m_bStop && g_guiSettings.GetBool("musiclibrary.downloadinfo"))
      {
        CStdString strPath;
        strPath.Format("musicdb://2/%u/",iArtist);
        if (!DownloadArtistInfo(strPath,*i, bCanceled)) // assume we want to retry
          m_artistsScanned.pop_back();
      }
      else
        GetArtistArtwork(iArtist, *i);
    }
  }

  if (g_guiSettings.GetBool("musiclibrary.downloadinfo"))
  {
    for (set< pair<CStdString, CStdString> >::iterator i = albumsToScan.begin(); i != albumsToScan.end(); ++i)
    {
      if (m_bStop)
        return songsToAdd.size();

      long iAlbum = m_musicDatabase.GetAlbumByName(i->first, i->second);
      CStdString strPath;
      strPath.Format("musicdb://3/%u/",iAlbum);

      bCanceled = false;
      if (find(m_albumsScanned.begin(), m_albumsScanned.end(), iAlbum) == m_albumsScanned.end())
      {
        CMusicAlbumInfo albumInfo;
        if (DownloadAlbumInfo(strPath, i->second, i->first, bCanceled, albumInfo))
          m_albumsScanned.push_back(iAlbum);
      }
    }
  }
  if (m_pObserver)
    m_pObserver->OnStateChanged(READING_MUSIC_INFO);

  return songsToAdd.size();
}
Esempio n. 8
0
int CMusicInfoScanner::RetrieveMusicInfo(CFileItemList& items, const CStdString& strDirectory)
{
  CSongMap songsMap;

  // get all information for all files in current directory from database, and remove them
  if (m_musicDatabase.RemoveSongsFromPath(strDirectory, songsMap))
    m_needsCleanup = true;

  VECSONGS songsToAdd;
  // for every file found, but skip folder
  for (int i = 0; i < items.Size(); ++i)
  {
    CFileItem* pItem = items[i];
    CStdString strExtension;
    CUtil::GetExtension(pItem->m_strPath, strExtension);

    if (m_bStop)
      return 0;

    // dont try reading id3tags for folders, playlists or shoutcast streams
    if (!pItem->m_bIsFolder && !pItem->IsPlayList() && !pItem->IsShoutCast() && !pItem->IsPicture())
    {
      m_currentItem++;
//      CLog::Log(LOGDEBUG, "%s - Reading tag for: %s", __FUNCTION__, pItem->m_strPath.c_str());

      // grab info from the song
      CSong *dbSong = songsMap.Find(pItem->m_strPath);

      CMusicInfoTag& tag = *pItem->GetMusicInfoTag();
      if (!tag.Loaded() )
      { // read the tag from a file
        auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(pItem->m_strPath));
        if (NULL != pLoader.get())
          pLoader->Load(pItem->m_strPath, tag);
      }

      // if we have the itemcount, notify our
      // observer with the progress we made
      if (m_pObserver && m_itemCount>0)
        m_pObserver->OnSetProgress(m_currentItem, m_itemCount);

      if (tag.Loaded())
      {
        CSong song(tag);
        song.iStartOffset = pItem->m_lStartOffset;
        song.iEndOffset = pItem->m_lEndOffset;
        if (dbSong)
        { // keep the db-only fields intact on rescan...
          song.iTimesPlayed = dbSong->iTimesPlayed;
          song.lastPlayed = dbSong->lastPlayed;
          if (song.rating == '0') song.rating = dbSong->rating;
        }
        pItem->SetMusicThumb();
        song.strThumb = pItem->GetThumbnailImage();
        songsToAdd.push_back(song);
//        CLog::Log(LOGDEBUG, "%s - Tag loaded for: %s", __FUNCTION__, spItem->m_strPath.c_str());
      }
      else
        CLog::Log(LOGDEBUG, "%s - No tag found for: %s", __FUNCTION__, pItem->m_strPath.c_str());
    }
  }

  CheckForVariousArtists(songsToAdd);
  if (!items.HasThumbnail())
    UpdateFolderThumb(songsToAdd, items.m_strPath);

  // finally, add these to the database
  for (unsigned int i = 0; i < songsToAdd.size(); ++i)
  {
    if (m_bStop) return i;
    CSong &song = songsToAdd[i];
    m_musicDatabase.AddSong(song, false);
    if (!m_bStop && g_guiSettings.GetBool("musiclibrary.autoartistinfo"))
    {
      long iArtist = m_musicDatabase.GetArtistByName(song.strArtist);
      CStdString strPath;
      strPath.Format("musicdb://2/%u/",iArtist);
      if (find(m_artistsScanned.begin(),m_artistsScanned.end(),iArtist) == m_artistsScanned.end())
        if (DownloadArtistInfo(strPath,song.strArtist))
          m_artistsScanned.push_back(iArtist);

      if (m_pObserver)
        m_pObserver->OnStateChanged(READING_MUSIC_INFO);
    }
    if (!m_bStop && g_guiSettings.GetBool("musiclibrary.autoalbuminfo"))
    {
      long iAlbum = m_musicDatabase.GetAlbumByName(song.strAlbum,song.strArtist);
      CStdString strPath;
      strPath.Format("musicdb://3/%u/",iAlbum);
      
      CMusicAlbumInfo albumInfo;
      bool bCanceled;
      if (find(m_albumsScanned.begin(),m_albumsScanned.end(),iAlbum) == m_albumsScanned.end())
        if (DownloadAlbumInfo(strPath,song.strArtist,song.strAlbum,bCanceled,albumInfo))
          m_albumsScanned.push_back(iAlbum);

      if (m_pObserver)
        m_pObserver->OnStateChanged(READING_MUSIC_INFO);
    }
  }
  return songsToAdd.size();
}
Esempio n. 9
0
int CMusicInfoScanner::RetrieveMusicInfo(CFileItemList& items, const CStdString& strDirectory)
{
    CSongMap songsMap;

    // get all information for all files in current directory from database, and remove them
    if (m_musicDatabase.RemoveSongsFromPath(strDirectory, songsMap, false))
        m_needsCleanup = true;

    VECSONGS songsToAdd;

    CStdStringArray regexps = g_advancedSettings.m_audioExcludeFromScanRegExps;

    // for every file found, but skip folder
    for (int i = 0; i < items.Size(); ++i)
    {
        CFileItemPtr pItem = items[i];
        CStdString strExtension;
        URIUtils::GetExtension(pItem->GetPath(), strExtension);

        if (m_bStop)
            return 0;

        // Discard all excluded files defined by m_musicExcludeRegExps
        if (CUtil::ExcludeFileOrFolder(pItem->GetPath(), regexps))
            continue;

        if (pItem.get()->IsPFC()) {
            m_currentItem++;
            // if we have the itemcount, notify our
            // observer with the progress we made
            if (m_pObserver && m_itemCount>0)
                m_pObserver->OnSetProgress(m_currentItem, m_itemCount);

            int got = RetrievePFCSongs(pItem, songsToAdd);
            if (got > 0)
                CLog::Log(LOGDEBUG, "%s: Got songs from PFC: '%s'", __FUNCTION__, pItem.get()->GetPath().c_str());
        }

    }
// Laureon: From here!
//  CheckForVariousArtists(songsToAdd);
//  if (!items.HasThumbnail())
//    UpdateFolderThumb(songsToAdd, items.GetPath());
//
//  // finally, add these to the database
//  set<CStdString> artistsToScan;
//  set< pair<CStdString, CStdString> > albumsToScan;
//  m_musicDatabase.BeginTransaction();
//  for (unsigned int i = 0; i < songsToAdd.size(); ++i)
//  {
//    if (m_bStop)
//    {
//      m_musicDatabase.RollbackTransaction();
//      return i;
//    }
//    CSong &song = songsToAdd[i];
//    m_musicDatabase.AddSong(song, true);
//
//    artistsToScan.insert(song.strArtist);
//    albumsToScan.insert(make_pair(song.strAlbum, song.strArtist));
//  }
//  m_musicDatabase.CommitTransaction();
//
//  bool bCanceled;
//  for (set<CStdString>::iterator i = artistsToScan.begin(); i != artistsToScan.end(); ++i)
//  {
//    bCanceled = false;
//    long iArtist = m_musicDatabase.GetArtistByName(*i);
//    if (find(m_artistsScanned.begin(),m_artistsScanned.end(),iArtist) == m_artistsScanned.end())
//    {
//      m_artistsScanned.push_back(iArtist);
//      if (!m_bStop)// && g_guiSettings.GetBool("musiclibrary.downloadinfo"))
//      {
//        CStdString strPath;
//        strPath.Format("musicdb://2/%u/",iArtist);
//        if (!DownloadArtistInfo(strPath,*i, bCanceled)) // assume we want to retry
//          m_artistsScanned.pop_back();
//      }
//      else
//        GetArtistArtwork(iArtist, *i);
//    }
//  }
//
//  for (set< pair<CStdString, CStdString> >::iterator i = albumsToScan.begin(); i != albumsToScan.end(); ++i)
//  {
//    if (m_bStop)
//      return songsToAdd.size();
//
//    long iAlbum = m_musicDatabase.GetAlbumByName(i->first, i->second);
//    CStdString strPath;
//    strPath.Format("musicdb://3/%u/",iAlbum);
//
//    bCanceled = false;
//    if (find(m_albumsScanned.begin(), m_albumsScanned.end(), iAlbum) == m_albumsScanned.end())
//    {
//      CMusicAlbumInfo albumInfo;
//      if (DownloadAlbumInfo(strPath, i->second, i->first, bCanceled, albumInfo))
//        m_albumsScanned.push_back(iAlbum);
//    }
//  }
    if (m_pObserver)
        m_pObserver->OnStateChanged(READING_MUSIC_INFO);

    return songsToAdd.size();
}