// 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 } }
/// <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); }
/// <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(); }
/// <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; } }