public static async void LoadMetadata(Action <ApiLogMessage> logger = null) => await Task.Run(() => { List <Song> tempList = new List <Song>(); if (watcher == null) { MetadataStore.logger = logger; watcher = new FileSystemWatcher(Listener.Config.MusicBaseDir) { NotifyFilter = NotifyFilters.Size, IncludeSubdirectories = true }; watcher.Changed += OnFileChanged; watcher.EnableRaisingEvents = true; } IDeserializer deserializer = new DeserializerBuilder().Build(); foreach (string directory in Directory.EnumerateDirectories(Listener.Config.MusicBaseDir, "*", SearchOption.AllDirectories)) { foreach (string filename in Directory.EnumerateFiles(Path.Combine(Listener.Config.MusicBaseDir, directory), "*.yaml")) { try { logger?.Invoke(new ApiLogMessage( $"Loading {Path.Combine(Listener.Config.MusicBaseDir, directory, filename)}", ApiLogLevel.Debug)); FileStream inputStream = new FileStream( Path.Combine(Listener.Config.MusicBaseDir, directory, filename), FileMode.Open); Metadata result; using (StreamReader reader = new StreamReader(inputStream)) { result = deserializer.Deserialize <Metadata>(reader); } string path = Path.Combine(Listener.Config.SongFileDir ?? Listener.Config.MusicBaseDir, directory); List <Song> songs = ParseMetadata(result, path); foreach (Song song in songs) { Song duplicate = tempList.FirstOrDefault(x => x.id == song.id); if (duplicate != null) { throw new DuplicateSongException( $"ID {song.id} has been declared twice, in songs {song.title} and {duplicate.title}"); } if (File.Exists(song.path)) { tempList.AddRange(new List <Song> { song }); continue; } logger?.Invoke(new ApiLogMessage( $"Song file at {song.path} does not exist, the song will not play", ApiLogLevel.Warning)); song.path = null; } } catch (DuplicateSongException e) { logger?.Invoke(new ApiLogMessage($"Exception processing metadata file {Path.Combine(Path.Combine(Listener.Config.MusicBaseDir, directory), filename)}: {e.Message}{Environment.NewLine}{e.StackTrace}" + $"{Environment.NewLine}Cannot continue", ApiLogLevel.Critical)); break; } catch (Exception e) { logger?.Invoke(new ApiLogMessage($"Exception processing metadata file {Path.Combine(Path.Combine(Listener.Config.MusicBaseDir, directory), filename)}: {e.Message}{Environment.NewLine}{e.StackTrace}" + $"{Environment.NewLine}Inner Exception: {e.InnerException}{Environment.NewLine}Attempting to continue", ApiLogLevel.Critical)); } } } SongList = tempList; });
public static bool VerifyMetadata(bool showUnused, Action <ApiLogMessage> logger = null) { bool ret = true; IDeserializer deserializer = new DeserializerBuilder().Build(); List <string> files = new List <string>(); List <string> processed = new List <string>(); foreach (string directory in Directory.EnumerateDirectories(Listener.Config.MusicBaseDir, "*", SearchOption.AllDirectories)) { if (Listener.Config.SongFileDir != null) { if (!directory.Contains(".git") && directory.ToLowerInvariant() != "other" && !directory.ToLowerInvariant().Contains("other\\") && !directory.ToLowerInvariant().Contains("other/")) { files.AddRange(Directory .EnumerateFiles(Path.Combine(Listener.Config.SongFileDir, directory), "*") .Where(filename => !filename.EndsWith(".pos") && !filename.EndsWith("sflib") && !filename.EndsWith("sf2lib") && !filename.EndsWith(".sth")) //exclude song libraries .Select(filename => Path.Combine(Listener.Config.SongFileDir, directory, filename))); } } else if (!directory.Contains(".git") && directory.ToLowerInvariant() != "other" && !directory.ToLowerInvariant().Contains("other\\") && !directory.ToLowerInvariant().Contains("other/")) { files.AddRange(Directory .EnumerateFiles(Path.Combine(Listener.Config.MusicBaseDir, directory), "*") .Where(filename => !filename.EndsWith(".yaml") && !filename.EndsWith(".pos") && !filename.EndsWith("sflib") && !filename.EndsWith("sf2lib") && !filename.EndsWith(".sth")) .Select(filename => Path.Combine(Listener.Config.MusicBaseDir, directory, filename))); } foreach (string filename in Directory.EnumerateFiles( Path.Combine(Listener.Config.MusicBaseDir, directory), "*.yaml")) { try { FileStream inputStream = new FileStream(Path.Combine(Listener.Config.MusicBaseDir, directory, filename), FileMode.Open); Metadata result; using (StreamReader reader = new StreamReader(inputStream)) { result = deserializer.Deserialize <Metadata>(reader); } string path = Path.Combine(Listener.Config.SongFileDir ?? Listener.Config.MusicBaseDir, directory); string current = Path.Combine(Listener.Config.MusicBaseDir, directory, filename); List <Song> songs = ParseMetadata(result, path); Game game = songs.First().game; if (game.id == null) { logger?.Invoke(new ApiLogMessage($"Missing Game ID in file {current}", ApiLogLevel.Warning)); ret = false; } if (game.title == null) { logger?.Invoke(new ApiLogMessage($"Missing Game Title in file {current}", ApiLogLevel.Warning)); ret = false; } if (game.platform == null || game.platform.Length == 0) { logger?.Invoke(new ApiLogMessage($"Missing Game Platform in file {current}", ApiLogLevel.Warning)); ret = false; } if (game.year == null) { logger?.Invoke(new ApiLogMessage($"Missing Game Year in file {current}", ApiLogLevel.Warning)); ret = false; } foreach (Song song in songs) { if (song.id == null) { logger?.Invoke(new ApiLogMessage($"Missing Song ID in file {current}", ApiLogLevel.Warning)); ret = false; } if (song.title == null) { logger?.Invoke(new ApiLogMessage($"Missing Song Title in file {current}", ApiLogLevel.Warning)); ret = false; } if (song.types == null || song.types.Length == 0) { logger?.Invoke(new ApiLogMessage($"Missing Song Type in file {current}", ApiLogLevel.Warning)); ret = false; } if (song.path != null && processed.Contains(song.path)) { logger?.Invoke(new ApiLogMessage( $"Duplicate reference to song file in file {current}. Path: {song.path}", ApiLogLevel.Warning)); ret = false; } if (song.path != null && !files.Contains(song.path)) { logger?.Invoke(new ApiLogMessage( $"Song file referenced in file {current} is missing. Path: {song.path}", ApiLogLevel.Warning)); ret = false; } if (song.path == null) { logger?.Invoke(new ApiLogMessage( $"Missing Song Path in file {current}", ApiLogLevel.Warning)); ret = false; } if (song.path != null && !processed.Contains(song.path) && files.Contains(song.path)) { processed.Add(song.path); } if (song.id == null) { continue; } Song duplicate = SongList.FirstOrDefault(x => x.id == song.id); if (duplicate != null) { logger?.Invoke(new ApiLogMessage( $"ID {song.id} has been declared twice, in songs {song.title} and {duplicate.title}", ApiLogLevel.Warning)); ret = false; } SongList.Add(song); } } catch (Exception e) { logger?.Invoke(new ApiLogMessage( $"Exception encountered in file {Path.Combine(Listener.Config.MusicBaseDir, directory, filename)}:" + $"{Environment.NewLine}{e.Message}{Environment.NewLine}{e.StackTrace}{Environment.NewLine}Skipping file.", ApiLogLevel.Critical)); } } } if (!showUnused) { return(ret); } IEnumerable <string> unused = files.Where(x => !processed.Contains(x)); foreach (string path in unused) { ret = false; logger?.Invoke(new ApiLogMessage($"Song file at {path} is unused.", ApiLogLevel.Warning)); } return(ret); }