Exemplo n.º 1
0
INFO_RET CMusicInfoScanner::ScanTags(const CFileItemList& items, CFileItemList& scannedItems)
{
  std::vector<std::string> regexps = g_advancedSettings.m_audioExcludeFromScanRegExps;

  for (int i = 0; i < items.Size(); ++i)
  {
    if (m_bStop)
      return INFO_CANCELLED;

    CFileItemPtr pItem = items[i];

    if (CUtil::ExcludeFileOrFolder(pItem->GetPath(), regexps))
      continue;

    if (pItem->m_bIsFolder || pItem->IsPlayList() || pItem->IsPicture() || pItem->IsLyrics())
      continue;

    m_currentItem++;

    CMusicInfoTag& tag = *pItem->GetMusicInfoTag();
    if (!tag.Loaded())
    {
      std::unique_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(*pItem));
      if (NULL != pLoader.get())
        pLoader->Load(pItem->GetPath(), tag);
    }

    if (m_handle && m_itemCount>0)
      m_handle->SetPercentage(m_currentItem / (float)m_itemCount * 100);

    if (!tag.Loaded() && !pItem->HasCueDocument())
    {
      CLog::Log(LOGDEBUG, "%s - No tag found for: %s", __FUNCTION__, pItem->GetPath().c_str());
      continue;
    }
    else
    {
      if (!tag.GetCueSheet().empty())
        pItem->LoadEmbeddedCue();
    }

    if (pItem->HasCueDocument())
      pItem->LoadTracksFromCueDocument(scannedItems);
    else
      scannedItems.Add(pItem);
  }
  return INFO_ADDED;
}
Exemplo n.º 2
0
/// \brief Retrieve tag information for \e m_vecItems
void CGUIWindowMusicBase::RetrieveMusicInfo()
{
    unsigned int startTick = XbmcThreads::SystemClockMillis();

    OnRetrieveMusicInfo(*m_vecItems);

    // \todo Scan for multitrack items here...
    vector<string> itemsForRemove;
    CFileItemList itemsForAdd;
    for (int i = 0; i < m_vecItems->Size(); ++i)
    {
        CFileItemPtr pItem = (*m_vecItems)[i];
        if (pItem->m_bIsFolder || pItem->IsPlayList() || pItem->IsPicture() || pItem->IsLyrics())
            continue;

        CMusicInfoTag& tag = *pItem->GetMusicInfoTag();
        if (tag.Loaded() && !tag.GetCueSheet().empty())
            pItem->LoadEmbeddedCue();

        if (pItem->HasCueDocument()
                && pItem->LoadTracksFromCueDocument(itemsForAdd))
        {
            itemsForRemove.push_back(pItem->GetPath());
        }
    }
    for (size_t i = 0; i < itemsForRemove.size(); ++i)
    {
        for (int j = 0; j < m_vecItems->Size(); ++j)
        {
            if ((*m_vecItems)[j]->GetPath() == itemsForRemove[i])
            {
                m_vecItems->Remove(j);
                break;
            }
        }
    }
    m_vecItems->Append(itemsForAdd);

    CLog::Log(LOGDEBUG, "RetrieveMusicInfo() took %u msec",
              XbmcThreads::SystemClockMillis() - startTick);
}
Exemplo n.º 3
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();
}
Exemplo n.º 4
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();
}