// Invoke the Changed event; called whenever list changes
 protected virtual void OnDatabaseReorgChanged(DatabaseReorgEventArgs e)
 {
   if (DatabaseReorgChanged != null)
   {
     DatabaseReorgChanged(this, e);
   }
 }
    /// <summary>
    /// Scan the folders in the selected shares for music files to be added to the database
    /// </summary>
    private void AddUpdateFiles()
    {
      DatabaseReorgEventArgs MyArgs = new DatabaseReorgEventArgs();
      string strSQL;

      _processCount = 0;
      _songsAdded = 0;
      _songsUpdated = 0;
      _songsSkipped = 0;

      int allFilesCount = 0;

      foreach (string Share in _shares)
      {
        //dummy call to stop lots of watchers being created unnecessarily
        Util.Utils.FileExistsInCache(Path.Combine(Share, "folder.jpg"));
        // Get all the files for the given Share / Path
        try
        {
          foreach (FileInformation file in GetFilesRecursive(new DirectoryInfo(Share)))
          {
            allFilesCount++;

            if (allFilesCount % 1000 == 0)
            {
              Log.Info("MusicDBReorg: Procesing file {0}", allFilesCount);
            }

            MyArgs.progress = 4;
            MyArgs.phase = String.Format("Processing file {0}", allFilesCount);
            OnDatabaseReorgChanged(MyArgs);

            if (!CheckFileForInclusion(file))
            {
              continue;
            }

            _processCount++;

            AddUpdateSong(file.Name);
          }
        }
        catch (Exception ex)
        {
          Log.Error("MusicDBReorg: Exception accessing file or folder: {0}", ex.Message);
        }
      }

      // Now we will remove the CUE data file from the database, since we will add Fake Tracks in the next step
      foreach (string cueFile in cueFiles)
      {
        try
        {
          CueSheet cueSheet = new CueSheet(cueFile);
          string cuePath = Path.GetDirectoryName(cueFile);
          string cueDataFile = cuePath + "\\" + cueSheet.Tracks[0].DataFile.Filename;
          DatabaseUtility.RemoveInvalidChars(ref cueDataFile);
          strSQL = String.Format("delete from tracks where strPath='{0}'", cueDataFile);
          try
          {
            DirectExecute(strSQL);
          }
          catch (Exception ex)
          {
            Log.Error("Error deleting song from Database: {0}", ex.Message);
          }
        }
        catch (Exception ex)
        {
          Log.Error("Exception Processing CUE File: {0}: {1}", cueFile, ex.Message);
        }
      }

      try
      {
        // Apply CUE Filter
        List<string> cueFileFakeTracks = new List<string>();
        cueFileFakeTracks =
          (List<string>)CueUtil.CUEFileListFilterList<string>(cueFiles, CueUtil.CUE_TRACK_FILE_STRING_BUILDER);

        // and add them also to the Hashtable, so that they don't get deleted in the next step
        foreach (string song in cueFileFakeTracks)
        {
          _processCount++;
          AddUpdateSong(song);
          allFiles.Add(song, false);
        }
      }
      catch (Exception ex)
      {
        Log.Error("Error processing CUE files: {0}", ex.Message);
      }

      _resetEvent.Set();
    }
    /// <summary>
    /// Remove songs, which are not existing anymore, because they have been moved, deleted.
    /// </summary>
    /// <returns></returns>
    private int DeleteNonExistingSongs()
    {
      SQLiteResultSet results;
      strSQL = String.Format("select idTrack, strPath from tracks");
      try
      {
        results = DirectExecute(strSQL);
        if (results == null)
        {
          return (int)Errors.ERROR_REORG_SONGS;
        }
      }
      catch (Exception ex)
      {
        Log.Error("Musicdatabasereorg: Unable to retrieve songs from database in DeleteNonExistingSongs() {0}",
                  ex.Message);
        return (int)Errors.ERROR_REORG_SONGS;
      }
      int removed = 0;
      Log.Info("Musicdatabasereorg: starting song cleanup for {0} songs", (int)results.Rows.Count);
      for (int i = 0; i < results.Rows.Count; ++i)
      {
        string strFileName = DatabaseUtility.Get(results, i, "tracks.strPath");

        if (!allFiles.Contains(strFileName))
        {
          /// song doesn't exist anymore, delete it
          /// We don't care about foreign keys at this moment. We'll just change this later.
          removed++;
          DeleteSong(strFileName, false);
        }
        if ((i % 10) == 0)
        {
          DatabaseReorgEventArgs MyArgs = new DatabaseReorgEventArgs();
          MyArgs.progress = 4;
          MyArgs.phase = String.Format("Removing non existing songs:{0}/{1} checked, {2} removed", i, results.Rows.Count,
                                       removed);
          OnDatabaseReorgChanged(MyArgs);
        }
      } //for (int i=0; i < results.Rows.Count;++i)
      Log.Info("Musicdatabasereorg: DeleteNonExistingSongs completed. Removed {0} non-existing songs", removed);
      return (int)Errors.ERROR_OK;
    }
    /// <summary>
    /// This method is called directly from the Config dialog and should use all settings,
    /// which may have changed in the Config GUI
    /// </summary>
    /// <param name="shares"></param>
    /// <param name="setting"></param>
    /// <returns></returns>
    public int MusicDatabaseReorg(ArrayList shares, MusicDatabaseSettings setting)
    {
      // Get the values from the Setting Object, which we received from the Config
      using (Settings xmlreader = new MPSettings())
      {
        _updateSinceLastImport = xmlreader.GetValueAsBool("musicfiles", "updateSinceLastImport", false);
        _excludeHiddenFiles = xmlreader.GetValueAsBool("musicfiles", "excludeHiddenFiles", false);
      }
      if (setting != null)
      {
        _createMissingFolderThumbs = setting.CreateMissingFolderThumb;
        _extractEmbededCoverArt = setting.ExtractEmbeddedCoverArt;
        _stripArtistPrefixes = setting.StripArtistPrefixes;
        _treatFolderAsAlbum = setting.TreatFolderAsAlbum;
        _useFolderThumbs = setting.UseFolderThumbs;
        _useAllImages = setting.UseAllImages;
        _createArtistPreviews = setting.CreateArtistPreviews;
        _createGenrePreviews = setting.CreateGenrePreviews;
        _updateSinceLastImport = setting.UseLastImportDate;
        _dateAddedValue = setting.DateAddedValue;
        //_excludeHiddenFiles = setting.ExcludeHiddenFiles; <-- no GUI setting yet; use xml file to specify this
      }

      if (!_updateSinceLastImport && !_singleFolderScan)
      {
        _lastImport = DateTime.MinValue;
      }

      if (shares == null)
      {
        LoadShares();
      }
      else
      {
        _shares = (ArrayList)shares.Clone();
      }
      DatabaseReorgEventArgs MyArgs = new DatabaseReorgEventArgs();

      DateTime startTime = DateTime.UtcNow;

      try
      {
        if (_singleFolderScan)
        {
          Log.Info("Musicdatabasereorg: Importing Music for folder: {0}", _shares[0].ToString());
        }
        else
        {
          Log.Info("Musicdatabasereorg: Beginning music database reorganization...");
          Log.Info("Musicdatabasereorg: Last import done at {0}", _lastImport.ToString());
        }

        BeginTransaction();

        // When starting a complete rescan, we cleanup the foreign keys
        if (_lastImport == DateTime.MinValue && !_singleFolderScan)
        {
          MyArgs.progress = 2;
          MyArgs.phase = "Cleaning up Artists, AlbumArtists and Genres";
          OnDatabaseReorgChanged(MyArgs);
          Log.Info("Musicdatabasereorg: Cleaning up Artists, AlbumArtists and Genres");
          CleanupForeignKeys();
        }

        // Add missing files (example: You downloaded some new files)
        MyArgs.progress = 3;
        MyArgs.phase = "Scanning new files";
        OnDatabaseReorgChanged(MyArgs);
        Log.Info("Musicdatabasereorg: Scanning for music files");

        // Start the Scanning and Update Thread
        musicFolders = new List<string>(4000);
        cueFiles = new List<string>(500);
        allFiles = new Hashtable(100000);

        _resetEvent = new AutoResetEvent(false);
        _scanThread = new Thread(AddUpdateFiles);
        _scanThread.Start();

        // Wait for the Scan and Update Thread to finish, before continuing
        _resetEvent.WaitOne();

        Log.Info("Musicdatabasereorg: Total Songs: {0}. {1} added / {2} updated / {3} skipped", _processCount,
                 _songsAdded, _songsUpdated, _songsSkipped);

        DateTime stopTime = DateTime.UtcNow;
        TimeSpan ts = stopTime - startTime;
        float fSecsPerTrack = ((float)ts.TotalSeconds / (float)_processCount);
        string trackPerSecSummary = "";

        if (_processCount > 0)
        {
          trackPerSecSummary = string.Format(" ({0} seconds per track)", fSecsPerTrack);
        }

        Log.Info(
          "Musicdatabasereorg: Processed {0} tracks in: {1:d2}:{2:d2}:{3:d2}{4}", _processCount, ts.Hours, ts.Minutes,
          ts.Seconds, trackPerSecSummary);


        if (!_singleFolderScan)
        {
          // Delete files that don't exist anymore (example: you deleted files from the Windows Explorer)
          Log.Info("Musicdatabasereorg: Removing non existing songs from the database");
          MyArgs.progress = 80;
          MyArgs.phase = "Removing non existing songs";
          OnDatabaseReorgChanged(MyArgs);
          DeleteNonExistingSongs();
        }

        if (_useFolderThumbs)
        {
          Log.Info("Musicdatabasereorg: Create Folder Thumbs");
          CreateFolderThumbs(85, 90, _shares);
        }

        if (_createArtistPreviews)
        {
          Log.Info("Musicdatabasereorg: Create Artist Thumbs");
          CreateArtistThumbs(90, 92);
        }

        if (_createGenrePreviews)
        {
          Log.Info("Musicdatabasereorg: Create Genre Thumbs");
          CreateGenreThumbs(93, 94);
        }

        if (_createMissingFolderThumbs)
        {
          // implement sth like that:
          // Util.Picture.CreateThumbnail(aThumbLocation, folderThumb, (int)Thumbs.ThumbLargeResolution, (int)Thumbs.ThumbLargeResolution, 0, Thumbs.SpeedThumbsLarge);
        }

        if (!_singleFolderScan)
        {
          MyArgs.progress = 95;
          MyArgs.phase = "Cleanup non-existing Artists, AlbumArtists and Genres";
          CleanupMultipleEntryTables();
        }
      }
      catch (Exception ex)
      {
        Log.Error("Musicdatabasereorg: Unhandled error {0} - scan aborted!\n{1}\n{2}", ex.Message, ex.Source,
                  ex.StackTrace);

        RollbackTransaction();
        _singleFolderScan = false;
        return (int)Errors.ERROR_CANCEL;
      }
      finally
      {
        MyArgs.progress = 96;
        MyArgs.phase = "Finishing";
        OnDatabaseReorgChanged(MyArgs);
        CommitTransaction();

        MyArgs.progress = 98;
        MyArgs.phase = "Compressing the database";
        OnDatabaseReorgChanged(MyArgs);
        Compress();

        MyArgs.progress = 100;
        MyArgs.phase = string.Format("Rescan completed. Total {0} Added {1} / Updated {2} / Skipped {3}", _processCount,
                                     _songsAdded, _songsUpdated, _songsSkipped);
        OnDatabaseReorgChanged(MyArgs);

        Log.Info("Musicdatabasereorg: Finished Reorganisation of the Database");

        // Save the time of the reorg, to be able to skip the files not updated / added the next time
        if (!_singleFolderScan)
        {
          using (Settings xmlreader = new MPSettings())
          {
            xmlreader.SetValue("musicfiles", "lastImport",
                               startTime.ToString("yyyy-M-d H:m:s", CultureInfo.InvariantCulture));
          }
        }

        GC.Collect();
      }
      _singleFolderScan = false;
      return (int)Errors.ERROR_OK;
    }
    private void CreateFolderThumbs(int aProgressStart, int aProgressEnd, ArrayList aShareList)
    {
      DatabaseReorgEventArgs MyFolderArgs = new DatabaseReorgEventArgs();
      foreach (string sharePath in aShareList)
      {
        try
        {
          int i = 0;
          foreach (string coverPath in musicFolders)
          {
            try
            {
              //string displayPath = Path.GetDirectoryName(coverPath);
              //displayPath = displayPath.Remove(0, displayPath.LastIndexOf('\\'));
              MyFolderArgs.phase = string.Format("Caching folder thumbs: {0}/{1}", Convert.ToString(i + 1),
                                                 Convert.ToString(musicFolders.Count));
              // range = 80-89
              int folderProgress = aProgressStart + (((i + 1) / musicFolders.Count) * (aProgressEnd - aProgressStart));
              MyFolderArgs.progress = folderProgress;
              OnDatabaseReorgChanged(MyFolderArgs);

              bool foundCover = false;
              string sharefolderThumb;
              // We add the slash to be able to use TryEverythingToGetFolderThumbByFilename and GetLocalFolderThumb
              string currentPath = string.Format("{0}\\", coverPath);
              string localFolderThumb = Util.Utils.GetLocalFolderThumb(currentPath);
              string localFolderLThumb = Util.Utils.ConvertToLargeCoverArt(localFolderThumb);

              if (_useAllImages)
              {
                sharefolderThumb = Util.Utils.TryEverythingToGetFolderThumbByFilename(currentPath, true);
                if (!string.IsNullOrEmpty(sharefolderThumb))
                {
                  foundCover = true;
                }
              }
              else
              {
                sharefolderThumb = Util.Utils.GetFolderThumb(currentPath);
                if (Util.Utils.FileExistsInCache(sharefolderThumb))
                {
                  foundCover = true;
                }
              }

              if (foundCover)
              {
                if (
                  !Util.Picture.CreateThumbnail(sharefolderThumb, localFolderThumb, (int)Thumbs.ThumbResolution,
                                                (int)Thumbs.ThumbResolution, 0, Thumbs.SpeedThumbsSmall))
                {
                  Log.Info("MusicDatabase: Could not cache folder thumb from folder {0}", sharePath);
                }
                if (
                  !Util.Picture.CreateThumbnail(sharefolderThumb, localFolderLThumb, (int)Thumbs.ThumbLargeResolution,
                                                (int)Thumbs.ThumbLargeResolution, 0, Thumbs.SpeedThumbsLarge))
                {
                  Log.Info("MusicDatabase: Could not cache large folder thumb from folder {0}", sharePath);
                }
              }
            }
            catch (Exception ex2)
            {
              Log.Error("MusicDatabase: Error caching folder thumb of {0} - {1}", coverPath, ex2.Message);
            }
            i++;
          }
        }
        catch (Exception ex)
        {
          Log.Error("MusicDatabase: Error caching folder thumbs - {0}", ex.Message);
        }
      }
    }
    private void CreateGenreThumbs(int aProgressStart, int aProgressEnd)
    {
      DatabaseReorgEventArgs MyGenreArgs = new DatabaseReorgEventArgs();
      ArrayList allGenres = new ArrayList();
      List<Song> groupedGenreSongs = new List<Song>();
      List<String> imageTracks = new List<string>();

      if (GetGenres(ref allGenres))
      {
        for (int i = 0; i < allGenres.Count; i++)
        {
          string curGenre = allGenres[i].ToString();
          if (!string.IsNullOrEmpty(curGenre) && curGenre != "unknown")
          {
            MyGenreArgs.phase = string.Format("Creating genre preview thumbs: {1}/{2} - {0}", curGenre,
                                              Convert.ToString(i + 1), Convert.ToString(allGenres.Count));
            int genreProgress = aProgressStart + (((i + 1) / allGenres.Count) * (aProgressEnd - aProgressStart));
            MyGenreArgs.progress = genreProgress;
            OnDatabaseReorgChanged(MyGenreArgs);

            groupedGenreSongs.Clear();
            imageTracks.Clear();
            string genreThumbPath = Util.Utils.GetCoverArtName(Thumbs.MusicGenre, curGenre);
            if (!Util.Utils.FileExistsInCache(genreThumbPath))
            {
              if (GetSongsByGenre(curGenre, ref groupedGenreSongs, true))
              {
                for (int j = 0; j < groupedGenreSongs.Count; j++)
                {
                  bool foundDup = false;
                  string coverArt = Util.Utils.TryEverythingToGetFolderThumbByFilename(groupedGenreSongs[j].FileName,
                                                                                       true);
                  if (!string.IsNullOrEmpty(coverArt))
                  {
                    foreach (string dupCheck in imageTracks)
                    {
                      if (dupCheck == coverArt)
                      {
                        foundDup = true;
                      }
                    }
                    if (!foundDup)
                    {
                      imageTracks.Add(coverArt);
                    }
                  }
                  // we need a maximum of 4 covers for the preview
                  if (imageTracks.Count >= 4)
                  {
                    break;
                  }
                }

                if (Util.Utils.CreateFolderPreviewThumb(imageTracks, genreThumbPath))
                {
                  Log.Info("MusicDatabase: Added genre thumb for {0}", curGenre);
                }
              }
            }
          }
        } // for all genres
      }
    }
Example #7
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 /// 
 private void SetStatus(object sender, DatabaseReorgEventArgs e)
 {
   fileLabel.Text = e.phase;
   Application.DoEvents();
 }
 private void SetStatus(object sender, DatabaseReorgEventArgs e)
 {
   GUIPropertyManager.SetProperty("#scanstatus", e.phase);
 }
Example #9
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 /// 
 private void SetStatus(object sender, DatabaseReorgEventArgs e)
 {
   _scanThread.ReportProgress(e.progress, e.phase);
 }
 private void SetPercentDonebyEvent(object sender, DatabaseReorgEventArgs e)
 {
   GUIDialogProgress pDlgProgress =
     (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);
   if (null == pDlgProgress)
   {
     return;
   }
   pDlgProgress.SetPercentage(e.progress);
   pDlgProgress.SetLine(1, e.phase);
   pDlgProgress.Progress();
 }
Example #11
0
 /// <summary>
 /// When the Reorg is run from inside the GUI Settings, we are notified here and prevent shutdown, while the import is running 
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void ReorgStatusChange(object sender, DatabaseReorgEventArgs e)
 {
   switch (e.progress)
   {
     case 2:
       _reorgRunning = true;
       break;
     case 100:
       _reorgRunning = false;
       break;
     default:
       break;
   }
 }