public static OperationResult <bool> DeleteEmptyFolders(DirectoryInfo processingFolder, ILogger logger) { var result = new OperationResult <bool>(); try { result.IsSuccess = FolderPathHelper.DeleteEmptyFolders(processingFolder); } catch (Exception ex) { logger.LogError(ex, string.Format("Error Deleting Empty Folder [{0}] Error [{1}]", processingFolder.FullName, ex.Serialize())); } return(result); }
public void Inspect(bool doCopy, bool isReadOnly, string directoryToInspect, string destination, bool dontAppendSubFolder, bool dontDeleteEmptyFolders, bool dontRunPreScripts) { Configuration.Inspector.IsInReadOnlyMode = isReadOnly; Configuration.Inspector.DoCopyFiles = doCopy; var artistsFound = new List <string>(); var releasesFound = new List <string>(); var mp3FilesFoundCount = 0; Trace.Listeners.Add(new LoggingTraceListener()); Console.BackgroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine($"✨ Inspector Start, UTC [{DateTime.UtcNow.ToString("s")}]"); Console.ResetColor(); string scriptResult = null; // Run PreInspect script if (dontRunPreScripts) { Console.BackgroundColor = ConsoleColor.Blue; Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"Skipping PreInspectScript."); Console.ResetColor(); } else { scriptResult = RunScript(Configuration.Processing.PreInspectScript, doCopy, isReadOnly, directoryToInspect, destination); if (!string.IsNullOrEmpty(scriptResult)) { Console.BackgroundColor = ConsoleColor.Blue; Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"PreInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}"); Console.ResetColor(); } } // Create a new destination subfolder for each Inspector run by Current timestamp var dest = Path.Combine(destination, DateTime.UtcNow.ToString("yyyyMMddHHmm")); if (isReadOnly || dontAppendSubFolder) { dest = destination; } // Get all the directorys in the directory var directoryDirectories = Directory.GetDirectories(directoryToInspect, "*.*", SearchOption.AllDirectories); var directories = new List <string> { directoryToInspect }; directories.AddRange(directoryDirectories); directories.Remove(dest); var inspectedImagesInDirectories = new List <string>(); try { var createdDestinationFolder = false; var sw = Stopwatch.StartNew(); foreach (var directory in directories.OrderBy(x => x)) { var directoryInfo = new DirectoryInfo(directory); Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine($"╔ 📂 Inspecting [{directory}]"); Console.ResetColor(); Console.WriteLine("╠╦════════════════════════╣"); // Get all the MP3 files in 'directory' var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly); if (files != null && files.Any()) { if (!isReadOnly && !createdDestinationFolder && !Directory.Exists(dest)) { Directory.CreateDirectory(dest); createdDestinationFolder = true; } // Run directory plugins against current directory foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin) .OrderBy(x => x.Order)) { Console.WriteLine($"╠╬═ Running Directory Plugin {plugin.Description}"); var pluginResult = plugin.Process(directoryInfo); if (!pluginResult.IsSuccess) { Console.WriteLine( $"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]"); return; } if (!string.IsNullOrEmpty(pluginResult.Data)) { Console.WriteLine($"╠╣ Directory Plugin Message: {pluginResult.Data}"); } } Console.WriteLine("╠╝"); Console.WriteLine($"╟─ Found [{files.Length}] mp3 Files"); var fileMetaDatas = new List <AudioMetaData>(); var fileInfos = new List <FileInfo>(); // Inspect the found MP3 files in 'directory' foreach (var file in files) { mp3FilesFoundCount++; var fileInfo = new FileInfo(file); Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WriteLine($"╟─ 🎵 Inspecting [{fileInfo.FullName}]"); var tagLib = TagsHelper.MetaDataForFile(fileInfo.FullName, true); Console.ForegroundColor = ConsoleColor.Cyan; if (!tagLib?.IsSuccess ?? false) { Console.ForegroundColor = ConsoleColor.DarkYellow; } Console.WriteLine($"╟ (Pre ) : {tagLib.Data}"); Console.ResetColor(); tagLib.Data.Filename = fileInfo.FullName; var originalMetaData = tagLib.Data.Adapt <AudioMetaData>(); if (!originalMetaData.IsValid) { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine( $"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}"); Console.WriteLine($"╟ [{JsonConvert.SerializeObject(tagLib, Newtonsoft.Json.Formatting.Indented)}]"); Console.ResetColor(); } var pluginMetaData = tagLib.Data; // Run all file plugins against the MP3 file modifying the MetaData foreach (var plugin in FilePlugins.OrderBy(x => x.Order)) { Console.WriteLine($"╟┤ Running File Plugin {plugin.Description}"); OperationResult <AudioMetaData> pluginResult = null; pluginResult = plugin.Process(pluginMetaData); if (!pluginResult.IsSuccess) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine( $"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]"); Console.ResetColor(); return; } pluginMetaData = pluginResult.Data; } if (!pluginMetaData.IsValid) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine( $"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}"); Console.ResetColor(); return; } // See if the MetaData from the Plugins is different from the original if (originalMetaData != null && pluginMetaData != null) { var differences = Comparer.Compare(originalMetaData, pluginMetaData); if (differences.Any()) { var skipDifferences = new List <string> { "AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists" }; var differencesDescription = $"{Environment.NewLine}"; foreach (var difference in differences) { if (skipDifferences.Contains(difference.Name)) { continue; } differencesDescription += $"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}"; } Console.Write($"╟ ≡ != ID3 Tag Modified: {differencesDescription}"); if (!isReadOnly) { if (!TagsHelper.WriteTags(pluginMetaData, pluginMetaData.Filename)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("📛 WriteTags Failed"); Console.ResetColor(); return; } } else { Console.WriteLine("╟ 🔒 Read Only Mode: Not Modifying File ID3 Tags."); } } else { Console.WriteLine("╟ ≡ == ID3 Tag NOT Modified"); } } else { var oBad = originalMetaData == null; var pBad = pluginMetaData == null; Console.WriteLine( $"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : "")} {(pBad ? "Post MetaData is Invalid" : "")}"); } if (!pluginMetaData.IsValid) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine( $"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}"); Console.ResetColor(); } else { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine($"╟ (Post) : {pluginMetaData}"); Console.ResetColor(); var artistToken = ArtistInspectorToken(tagLib.Data); if (!artistsFound.Contains(artistToken)) { artistsFound.Add(artistToken); } var releaseToken = ReleaseInspectorToken(tagLib.Data); if (!releasesFound.Contains(releaseToken)) { releasesFound.Add(releaseToken); } var newFileName = $"CD{(tagLib.Data.Disc ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000")}_{tagLib.Data.TrackNumber.Value.ToString("0000")}.mp3"; // Artist sub folder is created to hold Releases for Artist and Artist Images var artistSubDirectory = directory == dest ? fileInfo.DirectoryName : Path.Combine(dest, artistToken); // Each release is put into a subfolder into the current run Inspector folder to hold MP3 Files and Release Images var subDirectory = directory == dest ? fileInfo.DirectoryName : Path.Combine(dest, artistToken, releaseToken); if (!isReadOnly && !Directory.Exists(subDirectory)) { Directory.CreateDirectory(subDirectory); } // Inspect images if (!inspectedImagesInDirectories.Contains(directoryInfo.FullName)) { // Get all artist images and move to artist folder var foundArtistImages = new List <FileInfo>(); foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Artist, SearchOption.TopDirectoryOnly)); foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent, tagLib.Data.Artist, SearchOption.TopDirectoryOnly)); foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory( directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly)); foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory( directoryInfo.Parent, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly)); foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Artist, SearchOption.TopDirectoryOnly)); foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly)); foreach (var artistImage in foundArtistImages) { InspectImage(isReadOnly, doCopy, dest, artistSubDirectory, artistImage); } // Get all release images and move to release folder var foundReleaseImages = new List <FileInfo>(); foundReleaseImages.AddRange( ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release)); foundReleaseImages.AddRange( ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release)); foundReleaseImages.AddRange( ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ReleaseSecondary)); foreach (var foundReleaseImage in foundReleaseImages) { InspectImage(isReadOnly, doCopy, dest, subDirectory, foundReleaseImage); } inspectedImagesInDirectories.Add(directoryInfo.FullName); } // If enabled move MP3 to new folder var newPath = Path.Combine(dest, subDirectory, newFileName.ToFileNameFriendly()); if (isReadOnly) { Console.WriteLine( $"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]"); } else { if (!doCopy) { if (fileInfo.FullName != newPath) { if (File.Exists(newPath)) { File.Delete(newPath); } fileInfo.MoveTo(newPath); } } else { fileInfo.CopyTo(newPath, true); } Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine($"╠═ 🚛 {(doCopy ? "Copied" : "Moved")} MP3 File to [{newPath}]"); Console.ResetColor(); } Console.WriteLine("╠════════════════════════╣"); } } } } foreach (var directory in directories.OrderBy(x => x)) { var directoryInfo = new DirectoryInfo(directory); Console.WriteLine($"╠╬═ Post-Processing Directory [{directoryInfo.FullName}] "); // Run post-processing directory plugins against current directory foreach (var plugin in DirectoryPlugins.Where(x => x.IsPostProcessingPlugin).OrderBy(x => x.Order)) { Console.WriteLine($"╠╬═ Running Post-Processing Directory Plugin {plugin.Description}"); var pluginResult = plugin.Process(directoryInfo); if (!pluginResult.IsSuccess) { Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]"); return; } if (!string.IsNullOrEmpty(pluginResult.Data)) { Console.WriteLine($"╠╣ Directory Plugin Message: {pluginResult.Data}"); } } } Console.WriteLine("╠╝"); sw.Stop(); Console.WriteLine( $"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count()}, Releases {releasesFound.Count()}, MP3s {mp3FilesFoundCount} ═╝"); } catch (Exception ex) { Logger.LogError(ex); Console.WriteLine("📛 Exception: " + ex); } if (!dontDeleteEmptyFolders) { var delEmptyFolderIn = new DirectoryInfo(directoryToInspect); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"❌ Deleting Empty folders in [{delEmptyFolderIn.FullName}]"); Console.ResetColor(); FolderPathHelper.DeleteEmptyFolders(delEmptyFolderIn); } else { Console.WriteLine("🔒 Read Only Mode: Not deleting empty folders."); } // Run PreInspect script scriptResult = RunScript(Configuration.Processing.PostInspectScript, doCopy, isReadOnly, directoryToInspect, destination); if (!string.IsNullOrEmpty(scriptResult)) { Console.BackgroundColor = ConsoleColor.Blue; Console.ForegroundColor = ConsoleColor.White; Console.WriteLine( $"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}"); Console.ResetColor(); } }