public void ParseYearShouldBeNinteenEightyThree(string year) { var dn = ID3TagsHelper.ParseYear(year); Assert.NotNull(dn); Assert.Equal((short)1983, dn); }
public void FindTotalDiscsShouldBeTen() { var three = new List <AudioMetaData> { new AudioMetaData { Filename = @"C:\roadiedevroot\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3" }, new AudioMetaData { Filename = @"C:\roadiedevroot\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 02\02 - Not A Depth Charge.mp3" }, new AudioMetaData { Filename = @"C:\roadiedevroot\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 04\01 - First.mp3" }, new AudioMetaData { Filename = @"C:\roadiedevroot\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 06\02 - Second.mp3" }, new AudioMetaData { Filename = @"C:\roadiedevroot\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 10\01 - Depth Charge.mp3" } }; var n = ID3TagsHelper.DetermineTotalDiscNumbers(three); Assert.Equal(10, n); }
public void ParseDiscNumberGood(string discNumber) { var dn = ID3TagsHelper.ParseDiscNumber(discNumber); Assert.NotNull(dn); Assert.True(dn > 0); }
public void ParseTotalTrackNumberShouldBeFive(string trackNumber) { var dn = ID3TagsHelper.ParseTotalTrackNumber(trackNumber); Assert.NotNull(dn); Assert.Equal(5, dn.Value); }
public void Find_Total_Discs_Should_Be_One() { var three = new List <AudioMetaData> { new AudioMetaData { Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\01 - Depth Charge.mp3" }, new AudioMetaData { Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\02 - Not A Depth Charge.mp3" } }; var n = ID3TagsHelper.DetermineTotalDiscNumbers(three); Assert.Equal(1, n); three = new List <AudioMetaData> { new AudioMetaData { Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD1\01 - Depth Charge.mp3" }, new AudioMetaData { Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD1\02 - Not A Depth Charge.mp3" } }; n = ID3TagsHelper.DetermineTotalDiscNumbers(three); Assert.Equal(1, n); }
public void Find_Disc_Number_Should_Be_One(string filename) { var n = ID3TagsHelper.DetermineDiscNumber(new AudioMetaData { Filename = filename }); Assert.Equal(1, n); }
public bool WriteTags(AudioMetaData metaData, FileInfo fileInfo) { if (Configuration.Processing.DoSaveEditsToTags) { return(ID3TagsHelper.WriteTags(metaData, fileInfo.FullName)); } return(false); }
public void FindDiscNumberShouldBeTwo(string filename) { var n = ID3TagsHelper.DetermineDiscNumber(new AudioMetaData { Filename = filename }); Assert.Equal(2, n); }
public void Find_Total_Discs_Should_Be_Two() { var three = new List <AudioMetaData> { new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3" }, new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\02 - Not A Depth Charge.mp3" }, new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - First.mp3" }, new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 02\02 - Second.mp3" }, new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3" } }; var n = ID3TagsHelper.DetermineTotalDiscNumbers(three); Assert.Equal(2, n); three = new List <AudioMetaData> { new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD0\01 - Depth Charge.mp3" }, new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD2\02 - Not A Depth Charge.mp3" } }; n = ID3TagsHelper.DetermineTotalDiscNumbers(three); Assert.Equal(2, n); three = new List <AudioMetaData> { new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 1\01 - Depth Charge.mp3" }, new AudioMetaData { Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 2\02 - Not A Depth Charge.mp3" } }; n = ID3TagsHelper.DetermineTotalDiscNumbers(three); Assert.Equal(2, n); }
public override OperationResult <AudioMetaData> Process(AudioMetaData metaData) { var result = new OperationResult <AudioMetaData>(); var metaDatasForFilesInFolder = GetAudioMetaDatasForDirectory(metaData.FileInfo.Directory); metaData.TrackNumber = (metaData.TrackNumber ?? 0) > 0 ? metaData.TrackNumber : ID3TagsHelper.DetermineTrackNumber(metaData.FileInfo.Name); metaData.TotalTrackNumbers = ID3TagsHelper.DetermineTotalTrackNumbers(metaData.Filename) ?? metaDatasForFilesInFolder.Count(); metaData.Disc = ID3TagsHelper.DetermineDiscNumber(metaData); metaData.TotalDiscCount = ID3TagsHelper.DetermineTotalDiscNumbers(metaDatasForFilesInFolder); result.Data = metaData; result.IsSuccess = true; return(result); }
public void ReadTotalTrackNumbersFromM3u_Should_Be_Fourteen() { var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\m3u4"; var directory = new DirectoryInfo(cuesDir); if (directory.Exists) { foreach (var file in Directory.GetFiles(cuesDir)) { var t = ID3TagsHelper.DetermineTotalTrackNumbers(file); Assert.Equal(14, t.Value); } } else { Assert.True(true); } }
public void ReadTotalTrackNumbersFromSfvShouldBeEleven() { var sfvDir = @"C:\roadie_dev_root\test_cue_and_playlists\sfv1"; var directory = new DirectoryInfo(sfvDir); if (directory.Exists) { foreach (var file in Directory.GetFiles(sfvDir)) { var t = ID3TagsHelper.DetermineTotalTrackNumbers(file); Assert.Equal(11, t.Value); } } else { Assert.True(true); } }
private AudioMetaData ParseFromTags(FileInfo fileInfo) { try { var metaDataFromFile = ID3TagsHelper.MetaDataForFile(fileInfo.FullName); if (metaDataFromFile.IsSuccess) { return(metaDataFromFile.Data); } } catch (Exception ex) { Logger.LogError(ex, string.Format("Error With ID3TagsHelper.MetaDataForFile From File [{0}]", fileInfo.FullName)); } return(new AudioMetaData { Filename = fileInfo.FullName }); }
public Inspector() { Console.WriteLine("Roadie Media Inspector"); MessageLogger = new EventMessageLogger(); MessageLogger.Messages += MessageLogger_Messages; var settings = new RoadieSettings(); IConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddJsonFile("appsettings.json", false); IConfiguration configuration = configurationBuilder.Build(); configuration.GetSection("RoadieSettings").Bind(settings); settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection"); Configuration = settings; CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4))); TagsHelper = new ID3TagsHelper(Configuration, CacheManager, Logger); }
public override OperationResult <IEnumerable <AudioMetaData> > Process(IEnumerable <AudioMetaData> metaDatas) { var result = new OperationResult <IEnumerable <AudioMetaData> >(); var totalNumberOfMedia = ID3TagsHelper.DetermineTotalDiscNumbers(metaDatas); var folders = metaDatas.GroupBy(x => x.FileInfo.DirectoryName); foreach (var folder in folders) { short looper = 0; foreach (var metaData in folder) { looper++; metaData.TrackNumber = looper; metaData.TotalTrackNumbers = ID3TagsHelper.DetermineTotalTrackNumbers(metaData.Filename) ?? folder.Count(); metaData.Disk = ID3TagsHelper.DetermineDiscNumber(metaData); metaData.TotalDiscCount = totalNumberOfMedia; } } result.Data = metaDatas; result.IsSuccess = true; return(result); }
public AdminService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext, data.IRoadieDbContext context, ICacheManager cacheManager, ILogger <ArtistService> logger, IHubContext <ScanActivityHub> scanActivityHub ) : base(configuration, httpEncoder, context, cacheManager, logger, httpContext) { ScanActivityHub = scanActivityHub; EventMessageLogger = new EventMessageLogger(); EventMessageLogger.Messages += EventMessageLogger_Messages; MusicBrainzProvider = new MusicBrainzProvider(configuration, cacheManager, MessageLogger); LastFmHelper = new LastFmHelper(configuration, cacheManager, MessageLogger, context, httpEncoder); FileNameHelper = new FileNameHelper(configuration, cacheManager, MessageLogger); ID3TagsHelper = new ID3TagsHelper(configuration, cacheManager, MessageLogger); ArtistLookupEngine = new ArtistLookupEngine(configuration, httpEncoder, context, cacheManager, MessageLogger); LabelLookupEngine = new LabelLookupEngine(configuration, httpEncoder, context, cacheManager, MessageLogger); ReleaseLookupEngine = new ReleaseLookupEngine(configuration, httpEncoder, context, cacheManager, MessageLogger, ArtistLookupEngine, LabelLookupEngine); ImageFactory = new ImageFactory(configuration, httpEncoder, context, cacheManager, MessageLogger, ArtistLookupEngine, ReleaseLookupEngine); LabelFactory = new LabelFactory(configuration, httpEncoder, context, cacheManager, MessageLogger, ArtistLookupEngine, ReleaseLookupEngine); AudioMetaDataHelper = new AudioMetaDataHelper(configuration, httpEncoder, context, MusicBrainzProvider, LastFmHelper, cacheManager, MessageLogger, ArtistLookupEngine, ImageFactory, FileNameHelper, ID3TagsHelper); ReleaseFactory = new ReleaseFactory(configuration, httpEncoder, context, cacheManager, MessageLogger, ArtistLookupEngine, LabelFactory, AudioMetaDataHelper, ReleaseLookupEngine); ArtistFactory = new ArtistFactory(configuration, httpEncoder, context, cacheManager, MessageLogger, ArtistLookupEngine, ReleaseFactory, ImageFactory, ReleaseLookupEngine, AudioMetaDataHelper); }
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(); } }
public void ParseTrackNumberShouldBeNull(string trackNumber) { var dn = ID3TagsHelper.ParseTrackNumber(trackNumber); Assert.Null(dn); }
public void ParseDiscNumberBad(string discNumber) { var dn = ID3TagsHelper.ParseDiscNumber(discNumber); Assert.Null(dn); }
public async Task <OperationResult <Data.Release> > PerformMetaDataProvidersReleaseSearch(AudioMetaData metaData, string artistFolder = null, int?submissionId = null) { SimpleContract.Requires <ArgumentNullException>(metaData != null, "Invalid MetaData"); var sw = new Stopwatch(); sw.Start(); var result = new Data.Release { Title = metaData.Release.ToTitleCase(false), TrackCount = (short)(metaData.TotalTrackNumbers ?? 0), ReleaseDate = SafeParser.ToDateTime(metaData.Year), SubmissionId = submissionId }; var resultsExceptions = new List <Exception>(); var releaseGenres = new List <string>(); // Add any Genre found in the given MetaData if (metaData.Genres != null) { releaseGenres.AddRange(metaData.Genres); } var releaseLabels = new List <ReleaseLabelSearchResult>(); var releaseMedias = new List <ReleaseMediaSearchResult>(); var releaseImageUrls = new List <string>(); var dontDoMetaDataProvidersSearchArtists = this.Configuration.DontDoMetaDataProvidersSearchArtists; if (!dontDoMetaDataProvidersSearchArtists.Any(x => x.Equals(metaData.Artist, StringComparison.OrdinalIgnoreCase))) { try { #region ITunes if (this.ITunesReleaseSearchEngine.IsEnabled) { this.Logger.LogTrace("ITunesReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title); var iTunesResult = await this.ITunesReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1); if (iTunesResult.IsSuccess) { var i = iTunesResult.Data.First(); if (i.AlternateNames != null) { result.AlternateNames = result.AlternateNames.AddToDelimitedList(i.AlternateNames); } if (i.Tags != null) { result.Tags = result.Tags.AddToDelimitedList(i.Tags); } if (i.Urls != null) { result.URLs = result.URLs.AddToDelimitedList(i.Urls); } if (i.ImageUrls != null) { releaseImageUrls.AddRange(i.ImageUrls); } if (i.ReleaseGenres != null) { releaseGenres.AddRange(i.ReleaseGenres); } result.CopyTo(new Data.Release { ReleaseDate = result.ReleaseDate ?? i.ReleaseDate, AmgId = i.AmgId, Profile = i.Profile, ITunesId = i.iTunesId, Title = result.Title ?? i.ReleaseTitle, Thumbnail = i.ReleaseThumbnailUrl != null ? WebHelper.BytesForImageUrl(i.ReleaseThumbnailUrl) : null, ReleaseType = result.ReleaseType == ReleaseType.Unknown ? SafeParser.ToEnum <ReleaseType>(i.ReleaseType) : result.ReleaseType }); if (i.ReleaseLabel != null) { releaseLabels.AddRange(i.ReleaseLabel); } if (i.ReleaseMedia != null) { releaseMedias.AddRange(i.ReleaseMedia); } } if (iTunesResult.Errors != null) { resultsExceptions.AddRange(iTunesResult.Errors); } } #endregion ITunes #region MusicBrainz if (this.MusicBrainzReleaseSearchEngine.IsEnabled) { this.Logger.LogTrace("MusicBrainzReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title); var mbResult = await this.MusicBrainzReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1); if (mbResult.IsSuccess) { var mb = mbResult.Data.First(); if (mb.AlternateNames != null) { result.AlternateNames = result.AlternateNames.AddToDelimitedList(mb.AlternateNames); } if (mb.Tags != null) { result.Tags = result.Tags.AddToDelimitedList(mb.Tags); } if (mb.Urls != null) { result.URLs = result.URLs.AddToDelimitedList(mb.Urls); } if (mb.ImageUrls != null) { releaseImageUrls.AddRange(mb.ImageUrls); } if (mb.ReleaseGenres != null) { releaseGenres.AddRange(mb.ReleaseGenres); } if (!string.IsNullOrEmpty(mb.ReleaseTitle) && !mb.ReleaseTitle.Equals(result.Title, StringComparison.OrdinalIgnoreCase)) { result.AlternateNames.AddToDelimitedList(new string[] { mb.ReleaseTitle }); } result.CopyTo(new Data.Release { ReleaseDate = result.ReleaseDate ?? mb.ReleaseDate, AmgId = mb.AmgId, Profile = mb.Profile, TrackCount = mb.ReleaseMedia != null ? (short)mb.ReleaseMedia.Sum(x => x.TrackCount) : (short)0, MusicBrainzId = mb.MusicBrainzId, ITunesId = mb.iTunesId, Title = result.Title ?? mb.ReleaseTitle, Thumbnail = mb.ReleaseThumbnailUrl != null ? WebHelper.BytesForImageUrl(mb.ReleaseThumbnailUrl) : null, ReleaseType = result.ReleaseType == ReleaseType.Unknown ? SafeParser.ToEnum <ReleaseType>(mb.ReleaseType) : result.ReleaseType }); if (mb.ReleaseLabel != null) { releaseLabels.AddRange(mb.ReleaseLabel); } if (mb.ReleaseMedia != null) { releaseMedias.AddRange(mb.ReleaseMedia); } } if (mbResult.Errors != null) { resultsExceptions.AddRange(mbResult.Errors); } } #endregion MusicBrainz #region LastFm if (this.LastFmReleaseSearchEngine.IsEnabled) { this.Logger.LogTrace("LastFmReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title); var lastFmResult = await this.LastFmReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1); if (lastFmResult.IsSuccess) { var l = lastFmResult.Data.First(); if (l.AlternateNames != null) { result.AlternateNames = result.AlternateNames.AddToDelimitedList(l.AlternateNames); } if (l.Tags != null) { result.Tags = result.Tags.AddToDelimitedList(l.Tags); } if (l.Urls != null) { result.URLs = result.URLs.AddToDelimitedList(l.Urls); } if (l.ImageUrls != null) { releaseImageUrls.AddRange(l.ImageUrls); } if (l.ReleaseGenres != null) { releaseGenres.AddRange(l.ReleaseGenres); } if (!string.IsNullOrEmpty(l.ReleaseTitle) && !l.ReleaseTitle.Equals(result.Title, StringComparison.OrdinalIgnoreCase)) { result.AlternateNames.AddToDelimitedList(new string[] { l.ReleaseTitle }); } result.CopyTo(new Data.Release { ReleaseDate = result.ReleaseDate ?? l.ReleaseDate, AmgId = l.AmgId, Profile = l.Profile, LastFMId = l.LastFMId, LastFMSummary = l.LastFMSummary, MusicBrainzId = l.MusicBrainzId, ITunesId = l.iTunesId, Title = result.Title ?? l.ReleaseTitle, Thumbnail = l.ReleaseThumbnailUrl != null ? WebHelper.BytesForImageUrl(l.ReleaseThumbnailUrl) : null, ReleaseType = result.ReleaseType == ReleaseType.Unknown ? SafeParser.ToEnum <ReleaseType>(l.ReleaseType) : result.ReleaseType }); if (l.ReleaseLabel != null) { releaseLabels.AddRange(l.ReleaseLabel); } if (l.ReleaseMedia != null) { releaseMedias.AddRange(l.ReleaseMedia); } } if (lastFmResult.Errors != null) { resultsExceptions.AddRange(lastFmResult.Errors); } } #endregion LastFm #region Spotify if (this.SpotifyReleaseSearchEngine.IsEnabled) { this.Logger.LogTrace("SpotifyReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title); var spotifyResult = await this.SpotifyReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1); if (spotifyResult.IsSuccess) { var s = spotifyResult.Data.First(); if (s.Tags != null) { result.Tags = result.Tags.AddToDelimitedList(s.Tags); } if (s.Urls != null) { result.URLs = result.URLs.AddToDelimitedList(s.Urls); } if (s.ImageUrls != null) { releaseImageUrls.AddRange(s.ImageUrls); } if (s.ReleaseGenres != null) { releaseGenres.AddRange(s.ReleaseGenres); } if (!string.IsNullOrEmpty(s.ReleaseTitle) && !s.ReleaseTitle.Equals(result.Title, StringComparison.OrdinalIgnoreCase)) { result.AlternateNames.AddToDelimitedList(new string[] { s.ReleaseTitle }); } result.CopyTo(new Data.Release { ReleaseDate = result.ReleaseDate ?? s.ReleaseDate, AmgId = s.AmgId, Profile = this.HttpEncoder.HtmlEncode(s.Profile), SpotifyId = s.SpotifyId, MusicBrainzId = s.MusicBrainzId, ITunesId = s.iTunesId, Title = result.Title ?? s.ReleaseTitle, Thumbnail = s.ReleaseThumbnailUrl != null ? WebHelper.BytesForImageUrl(s.ReleaseThumbnailUrl) : null, ReleaseType = result.ReleaseType == ReleaseType.Unknown ? SafeParser.ToEnum <ReleaseType>(s.ReleaseType) : result.ReleaseType }); if (s.ReleaseLabel != null) { releaseLabels.AddRange(s.ReleaseLabel); } if (s.ReleaseMedia != null) { releaseMedias.AddRange(s.ReleaseMedia); } } if (spotifyResult.Errors != null) { resultsExceptions.AddRange(spotifyResult.Errors); } } #endregion Spotify #region Discogs if (this.DiscogsReleaseSearchEngine.IsEnabled) { this.Logger.LogTrace("DiscogsReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title); var discogsResult = await this.DiscogsReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1); if (discogsResult.IsSuccess) { var d = discogsResult.Data.First(); if (d.Urls != null) { result.URLs = result.URLs.AddToDelimitedList(d.Urls); } if (d.ImageUrls != null) { releaseImageUrls.AddRange(d.ImageUrls); } if (d.AlternateNames != null) { result.AlternateNames = result.AlternateNames.AddToDelimitedList(d.AlternateNames); } if (!string.IsNullOrEmpty(d.ReleaseTitle) && !d.ReleaseTitle.Equals(result.Title, StringComparison.OrdinalIgnoreCase)) { result.AlternateNames.AddToDelimitedList(new string[] { d.ReleaseTitle }); } result.CopyTo(new Data.Release { Profile = this.HttpEncoder.HtmlEncode(d.Profile), DiscogsId = d.DiscogsId, Title = result.Title ?? d.ReleaseTitle, Thumbnail = d.ReleaseThumbnailUrl != null ? WebHelper.BytesForImageUrl(d.ReleaseThumbnailUrl) : null, ReleaseType = result.ReleaseType == ReleaseType.Unknown ? SafeParser.ToEnum <ReleaseType>(d.ReleaseType) : result.ReleaseType }); if (d.ReleaseLabel != null) { releaseLabels.AddRange(d.ReleaseLabel); } if (d.ReleaseMedia != null) { releaseMedias.AddRange(d.ReleaseMedia); } } if (discogsResult.Errors != null) { resultsExceptions.AddRange(discogsResult.Errors); } } #endregion Discogs } catch (Exception ex) { this.Logger.LogError(ex); } this.Logger.LogTrace("Metadata Providers Search Complete. [{0}]", sw.ElapsedMilliseconds); } else { this.Logger.LogTrace("Skipped Metadata Providers Search, DontDoMetaDataProvidersSearchArtists set for Artist [{0}].", metaData.Artist); } if (result.AlternateNames != null) { result.AlternateNames = string.Join("|", result.AlternateNames.ToListFromDelimited().Distinct().OrderBy(x => x)); } if (result.URLs != null) { result.URLs = string.Join("|", result.URLs.ToListFromDelimited().Distinct().OrderBy(x => x)); } if (result.Tags != null) { result.Tags = string.Join("|", result.Tags.ToListFromDelimited().Distinct().OrderBy(x => x)); } if (releaseGenres.Any()) { result.Genres = new List <ReleaseGenre>(); foreach (var releaseGenre in releaseGenres.Where(x => !string.IsNullOrEmpty(x)).GroupBy(x => x).Select(x => x.First())) { var rg = releaseGenre.Trim(); if (!string.IsNullOrEmpty(rg)) { foreach (var g in ID3TagsHelper.SplitGenre(rg)) { result.Genres.Add(new Data.ReleaseGenre { Genre = (this.DbContext.Genres.Where(x => x.Name.ToLower() == g.ToLower()).FirstOrDefault() ?? new Data.Genre { Name = g }) }); } } } ; } if (releaseImageUrls.Any()) { var imageBag = new ConcurrentBag <Data.Image>(); var i = releaseImageUrls.Select(async url => { imageBag.Add(await WebHelper.GetImageFromUrlAsync(url)); }); await Task.WhenAll(i); // If the release has images merge any fetched images var existingImages = result.Images != null?result.Images.ToList() : new List <Data.Image>(); existingImages.AddRange(imageBag.ToList()); // Now set release images to be unique image based on image hash result.Images = existingImages.Where(x => x != null && x.Bytes != null).GroupBy(x => x.Signature).Select(x => x.First()).Take(this.Configuration.Processing.MaximumReleaseImagesToAdd).ToList(); if (result.Thumbnail == null && result.Images != null) { result.Thumbnail = result.Images.First().Bytes; } } if (releaseLabels.Any()) { result.Labels = releaseLabels.GroupBy(x => x.CatalogNumber).Select(x => x.First()).Select(x => new Data.ReleaseLabel { CatalogNumber = x.CatalogNumber, BeginDate = x.BeginDate, EndDate = x.EndDate, Status = Statuses.New, Label = new Data.Label { Name = x.Label.LabelName, SortName = x.Label.LabelSortName, MusicBrainzId = x.Label.MusicBrainzId, BeginDate = x.Label.StartDate, EndDate = x.Label.EndDate, ImageUrl = x.Label.LabelImageUrl, AlternateNames = x.Label.AlternateNames.ToDelimitedList(), URLs = x.Label.Urls.ToDelimitedList(), Status = Statuses.New } }).ToList(); } if (releaseMedias.Any()) { var resultReleaseMedias = new List <Data.ReleaseMedia>(); foreach (var releaseMedia in releaseMedias.GroupBy(x => x.ReleaseMediaNumber).Select(x => x.First())) { var rm = new Data.ReleaseMedia { MediaNumber = releaseMedia.ReleaseMediaNumber ?? 0, SubTitle = releaseMedia.ReleaseMediaSubTitle, TrackCount = releaseMedia.TrackCount ?? 0, Status = Statuses.New }; var rmTracks = new List <Data.Track>(); foreach (var releaseTrack in releaseMedias.Where(x => x.ReleaseMediaNumber == releaseMedia.ReleaseMediaNumber) .SelectMany(x => x.Tracks) .Where(x => x.TrackNumber.HasValue) .OrderBy(x => x.TrackNumber)) { var foundTrack = true; var rmTrack = rmTracks.FirstOrDefault(x => x.TrackNumber == releaseTrack.TrackNumber.Value); if (rmTrack == null) { Data.Artist trackArtist = null; if (releaseTrack.Artist != null) { trackArtist = new Data.Artist { Name = releaseTrack.Artist.ArtistName, SpotifyId = releaseTrack.Artist.SpotifyId, ArtistType = releaseTrack.Artist.ArtistType }; } rmTrack = new Data.Track { TrackArtist = trackArtist, TrackArtists = releaseTrack.Artists, TrackNumber = releaseTrack.TrackNumber.Value, MusicBrainzId = releaseTrack.MusicBrainzId, SpotifyId = releaseTrack.SpotifyId, AmgId = releaseTrack.AmgId, Title = releaseTrack.Title, AlternateNames = releaseTrack.AlternateNames.ToDelimitedList(), Duration = releaseTrack.Duration, Tags = releaseTrack.Tags.ToDelimitedList(), ISRC = releaseTrack.ISRC, LastFMId = releaseTrack.LastFMId, Status = Statuses.New }; foundTrack = false; } rmTrack.Duration = rmTrack.Duration ?? releaseTrack.Duration; rmTrack.MusicBrainzId = rmTrack.MusicBrainzId ?? releaseTrack.MusicBrainzId; rmTrack.SpotifyId = rmTrack.SpotifyId ?? releaseTrack.SpotifyId; rmTrack.AmgId = rmTrack.AmgId ?? releaseTrack.AmgId; rmTrack.Title = rmTrack.Title ?? releaseTrack.Title; rmTrack.Duration = releaseTrack.Duration; rmTrack.Tags = rmTrack.Tags == null?releaseTrack.Tags.ToDelimitedList() : rmTrack.Tags.AddToDelimitedList(releaseTrack.Tags); rmTrack.AlternateNames = rmTrack.AlternateNames == null?releaseTrack.AlternateNames.ToDelimitedList() : rmTrack.AlternateNames.AddToDelimitedList(releaseTrack.AlternateNames); rmTrack.ISRC = rmTrack.ISRC ?? releaseTrack.ISRC; rmTrack.LastFMId = rmTrack.LastFMId ?? releaseTrack.LastFMId; if (!foundTrack) { rmTracks.Add(rmTrack); } } rm.Tracks = rmTracks; rm.TrackCount = (short)rmTracks.Count(); resultReleaseMedias.Add(rm); } result.Medias = resultReleaseMedias; result.TrackCount = (short)releaseMedias.SelectMany(x => x.Tracks).Count(); } if (metaData.Images != null && metaData.Images.Any()) { var image = metaData.Images.FirstOrDefault(x => x.Type == AudioMetaDataImageType.FrontCover); if (image == null) { image = metaData.Images.FirstOrDefault(); } // If there is an image on the metadata file itself then that over-rides metadata providers. if (image != null) { result.Thumbnail = image.Data; } } if (!string.IsNullOrEmpty(artistFolder)) { // If any file exist for cover that over-rides whatever if found in metadata providers. var releaseFolder = new DirectoryInfo(result.ReleaseFileFolder(artistFolder)); if (releaseFolder.Exists) { string coverFileName = null; var cover = ImageHelper.FindImageTypeInDirectory(releaseFolder, ImageType.Release); if (!cover.Any()) { // See if cover exist by filename var imageFilesInFolder = ImageHelper.ImageFilesInFolder(releaseFolder.FullName, SearchOption.AllDirectories); if (imageFilesInFolder != null && imageFilesInFolder.Any()) { var imageCoverByReleaseName = imageFilesInFolder.FirstOrDefault(x => x == result.Title || x == result.Title.ToFileNameFriendly()); if (imageCoverByReleaseName != null) { coverFileName = imageCoverByReleaseName; } } } else if (cover.Any()) { coverFileName = cover.First().FullName; } if (!string.IsNullOrEmpty(coverFileName)) { // Read image and convert to jpeg result.Thumbnail = File.ReadAllBytes(coverFileName); this.Logger.LogDebug("Using Release Cover File [{0}]", coverFileName); } } } if (result.Thumbnail != null) { result.Thumbnail = ImageHelper.ResizeImage(result.Thumbnail, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height); result.Thumbnail = ImageHelper.ConvertToJpegFormat(result.Thumbnail); if (result.Thumbnail.Length >= ImageHelper.MaximumThumbnailByteSize) { Logger.LogWarning($"Release Thumbnail larger than maximum size after resizing to [{ this.Configuration.ThumbnailImageSize.Width }x{ this.Configuration.ThumbnailImageSize.Height}] Thumbnail Size [{ result.Thumbnail.Length }]"); result.Thumbnail = null; } } sw.Stop(); return(new OperationResult <Data.Release> { Data = result, IsSuccess = result != null, Errors = resultsExceptions, OperationTime = sw.ElapsedMilliseconds }); }
public void ParseYearShouldBeBad(string year) { var dn = ID3TagsHelper.ParseYear(year); Assert.Null(dn); }
public void Inspect(bool doCopy, string folder, string destination) { // Get all the directorys in the directory var folderDirectories = Directory.GetDirectories(folder, "*.*", SearchOption.AllDirectories); var directories = new List <string> { folder }; directories.AddRange(folderDirectories); foreach (var directory in directories) { Console.WriteLine($"╔ ░▒▓ Inspecting [{ directory }] ▓▒░"); Console.WriteLine("╠═╗"); // Get all the MP3 files in the folder var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly); if (files == null || !files.Any()) { continue; } Console.WriteLine($"Found [{ files.Length }] mp3 Files"); Console.WriteLine("╠═╣"); // Get audiometadata and output details including weight/validity foreach (var file in files) { var tagLib = this.TagsHelper.MetaDataForFile(file); Console.WriteLine(tagLib.Data); } Console.WriteLine("╠═╣"); List <AudioMetaData> fileMetaDatas = new List <AudioMetaData>(); List <FileInfo> fileInfos = new List <FileInfo>(); foreach (var file in files) { var fileInfo = new FileInfo(file); var tagLib = this.TagsHelper.MetaDataForFile(fileInfo.FullName); var artistToken = ArtistInspectorToken(tagLib.Data); var releaseToken = ReleaseInspectorToken(tagLib.Data); var newFileName = $"{artistToken}_{releaseToken}_CD{ (tagLib.Data.Disk ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000") }_{ tagLib.Data.TrackNumber.Value.ToString("0000") }.mp3"; var subFolder = folder == destination ? fileInfo.DirectoryName : destination; var newPath = Path.Combine(destination, subFolder, newFileName.ToFileNameFriendly()); if (!doCopy) { if (fileInfo.FullName != newPath) { if (File.Exists(newPath)) { File.Delete(newPath); } fileInfo.MoveTo(newPath); } } else { fileInfo.CopyTo(newPath, true); } tagLib.Data.Filename = fileInfo.FullName; fileMetaDatas.Add(tagLib.Data); fileInfos.Add(fileInfo); } // Perform InspectorPlugins IEnumerable <AudioMetaData> pluginMetaData = fileMetaDatas.OrderBy(x => x.Filename); foreach (var plugin in this.Plugins.OrderBy(x => x.Order)) { Console.WriteLine($"╟ Running Plugin { plugin.Description }"); OperationResult <IEnumerable <AudioMetaData> > pluginResult = null; try { pluginResult = plugin.Process(pluginMetaData); } catch (Exception ex) { Console.WriteLine($"Plugin Error: [{ ex.ToString() }]"); } if (!pluginResult.IsSuccess) { Console.WriteLine($"Plugin Failed. Error [{ JsonConvert.SerializeObject(pluginResult)}]"); } pluginMetaData = pluginResult.Data; } // Save all plugin modifications to the MetaData foreach (var metadata in pluginMetaData) { this.TagsHelper.WriteTags(metadata, metadata.Filename); } Console.WriteLine("╠═╣"); // Get audiometadata and output details including weight/validity foreach (var fileInfo in fileInfos) { var tagLib = this.TagsHelper.MetaDataForFile(fileInfo.FullName); if (!tagLib.IsSuccess || !tagLib.Data.IsValid) { Console.WriteLine($"■■ INVALID: {tagLib.Data }"); } else { Console.WriteLine(tagLib.Data); } } Console.WriteLine("╚═╝"); } }
public void DetermineTrackNumber(string filename) { var tn = ID3TagsHelper.DetermineTrackNumber(filename); Assert.True(tn > 0); }