From 2bafd474a076769ab43fef07c536edd0b0e9043b Mon Sep 17 00:00:00 2001 From: Brian Bicknell Date: Tue, 18 Feb 2025 20:49:04 -0500 Subject: [PATCH] Added playlist repository logic. --- Harmonia.Core/Data/FileRepository.cs | 94 ++++++++++++++++++++++++ Harmonia.Core/Data/IRepository.cs | 8 ++ Harmonia.Core/Data/JsonFileRepository.cs | 26 +++++++ Harmonia.Core/Data/PlaylistRepository.cs | 22 ++++++ Harmonia.Core/Data/XMLFileRepository.cs | 26 +++++++ Harmonia.Core/Models/Playlist.cs | 4 +- Harmonia.Tests/PlaylistTests.cs | 8 +- 7 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 Harmonia.Core/Data/FileRepository.cs create mode 100644 Harmonia.Core/Data/IRepository.cs create mode 100644 Harmonia.Core/Data/JsonFileRepository.cs create mode 100644 Harmonia.Core/Data/PlaylistRepository.cs create mode 100644 Harmonia.Core/Data/XMLFileRepository.cs diff --git a/Harmonia.Core/Data/FileRepository.cs b/Harmonia.Core/Data/FileRepository.cs new file mode 100644 index 0000000..a2d7b0e --- /dev/null +++ b/Harmonia.Core/Data/FileRepository.cs @@ -0,0 +1,94 @@ +namespace Harmonia.Core.Data; + +public abstract class FileRepository : IRepository where TObject : notnull +{ + private readonly Dictionary _fileNameMap = []; + + protected abstract string DirectoryName { get; } + protected abstract string Extension { get; } + + protected abstract string GetNewFileName(); + protected abstract string Serialize(TObject playlist); + protected abstract TObject Deserialize(Stream stream); + + public FileRepository() + { + if (string.IsNullOrWhiteSpace(DirectoryName) || Directory.Exists(DirectoryName) == false) + return; + + if (string.IsNullOrWhiteSpace(Extension)) + return; + + List fileNames = GetAllFileNames(); + LoadFileNamesIntoMap(fileNames); + } + + private List GetAllFileNames() + { + var directoryInfo = new DirectoryInfo(DirectoryName); + var directories = directoryInfo.GetDirectories().Where(x => x.Attributes.HasFlag(FileAttributes.Hidden) == false); + + var fileInfoList = directoryInfo.EnumerateFiles("*." + Extension, SearchOption.TopDirectoryOnly).Where(x => x.Attributes.HasFlag(FileAttributes.Hidden) == false); + + return fileInfoList.Select(fileInfo => fileInfo.FullName).ToList(); + } + + private void LoadFileNamesIntoMap(List fileNames) + { + foreach (var fileName in fileNames) + { + using StreamReader textReader = new(fileName); + + try + { + TObject obj = Deserialize(textReader.BaseStream); + _fileNameMap.Add(obj, fileName); + } + catch (Exception) + { + + } + } + } + + public List Get() + { + return [.. _fileNameMap.Keys]; + } + + public void Save(TObject obj) + { + string serializedObject = Serialize(obj); + + string fileName = Path.Combine(DirectoryName, GetFileName(obj)); + string? path = Path.GetDirectoryName(fileName); + + if (string.IsNullOrWhiteSpace(path)) + return; + + if (Directory.Exists(path) == false) + Directory.CreateDirectory(path); + + using TextWriter textWriter = new StreamWriter(fileName); + textWriter.Write(serializedObject); + } + + private string GetFileName(TObject obj) + { + if (_fileNameMap.TryGetValue(obj, out string? value)) + return value; + + string fileName = GetNewFileName(); + _fileNameMap.Add(obj, fileName); + + return fileName; + } + + public void Delete(TObject obj) + { + string fileName = Path.Combine(DirectoryName, GetFileName(obj)); + + if (File.Exists(fileName)) + File.Delete(fileName); + } +} \ No newline at end of file diff --git a/Harmonia.Core/Data/IRepository.cs b/Harmonia.Core/Data/IRepository.cs new file mode 100644 index 0000000..c7a09ba --- /dev/null +++ b/Harmonia.Core/Data/IRepository.cs @@ -0,0 +1,8 @@ +namespace Harmonia.Core.Data; + +public interface IRepository +{ + List Get(); + void Save(TObject value); + void Delete(TObject value); +} \ No newline at end of file diff --git a/Harmonia.Core/Data/JsonFileRepository.cs b/Harmonia.Core/Data/JsonFileRepository.cs new file mode 100644 index 0000000..9b655fc --- /dev/null +++ b/Harmonia.Core/Data/JsonFileRepository.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; +using System.Text.Json; + +namespace Harmonia.Core.Data; + +public abstract class JsonFileRepository : FileRepository where TObject : notnull, new() +{ + private readonly JsonSerializerOptions _options = new() + { + WriteIndented = true, + IgnoreReadOnlyProperties = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + + protected override string Extension => "json"; + + protected override TObject Deserialize(Stream stream) + { + return JsonSerializer.Deserialize(stream) ?? new(); + } + + protected override string Serialize(TObject obj) + { + return JsonSerializer.Serialize(obj, _options); + } +} \ No newline at end of file diff --git a/Harmonia.Core/Data/PlaylistRepository.cs b/Harmonia.Core/Data/PlaylistRepository.cs new file mode 100644 index 0000000..d7402e6 --- /dev/null +++ b/Harmonia.Core/Data/PlaylistRepository.cs @@ -0,0 +1,22 @@ +using Harmonia.Core.Models; + +namespace Harmonia.Core.Data; + +public class PlaylistRepository : JsonFileRepository +{ + protected override string DirectoryName => string.Empty; + + protected override string GetNewFileName() + { + for (int i = 0; i < 1000; i++) + { + string shortFileName = $"Playlist{i.ToString().PadLeft(3, '0')}.{Extension}"; + string filePath = Path.Combine(DirectoryName, shortFileName); + + if (File.Exists(filePath) == false) + return shortFileName; + } + + throw new Exception("Unable to determine new fileName"); + } +} \ No newline at end of file diff --git a/Harmonia.Core/Data/XMLFileRepository.cs b/Harmonia.Core/Data/XMLFileRepository.cs new file mode 100644 index 0000000..0b84afd --- /dev/null +++ b/Harmonia.Core/Data/XMLFileRepository.cs @@ -0,0 +1,26 @@ +using System.Xml.Serialization; + +namespace Harmonia.Core.Data; + +public abstract class XMLFileRepository : FileRepository where TObject : notnull, new() +{ + private readonly XmlSerializer _serializer = new(typeof(TObject)); + + protected override string Extension => "xml"; + + protected override TObject Deserialize(Stream stream) + { + using TextReader textReader = new StreamReader(stream); + + return (TObject?)_serializer.Deserialize(textReader) ?? new(); + } + + protected override string Serialize(TObject obj) + { + using TextWriter textWriter = new StringWriter(); + + _serializer.Serialize(textWriter, obj); + + return textWriter.ToString() ?? string.Empty; + } +} \ No newline at end of file diff --git a/Harmonia.Core/Models/Playlist.cs b/Harmonia.Core/Models/Playlist.cs index cf75da7..28e4b7e 100644 --- a/Harmonia.Core/Models/Playlist.cs +++ b/Harmonia.Core/Models/Playlist.cs @@ -3,12 +3,12 @@ using Harmonia.Core.Extensions; namespace Harmonia.Core.Models; -public class Playlist(string name) +public class Playlist { private readonly List _songs = []; public string UID { get; init; } = Guid.NewGuid().ToString(); - public string Name { get; set; } = name; + public string? Name { get; set; } public IReadOnlyList Songs => _songs; public List GroupOptions { get; set; } = []; public List SortOptions { get; set; } = []; diff --git a/Harmonia.Tests/PlaylistTests.cs b/Harmonia.Tests/PlaylistTests.cs index e88e574..d1bd254 100644 --- a/Harmonia.Tests/PlaylistTests.cs +++ b/Harmonia.Tests/PlaylistTests.cs @@ -9,7 +9,7 @@ public class PlaylistTests [Fact] public void Add_Songs() { - Playlist playlist = new("Test"); + Playlist playlist = new(); Song[] songs = [ @@ -38,7 +38,7 @@ public class PlaylistTests [Fact] public void Sort_Songs() { - Playlist playlist = new("Test"); + Playlist playlist = new(); Song[] songs = [ @@ -75,7 +75,7 @@ public class PlaylistTests [Fact] public void Remove_Songs() { - Playlist playlist = new("Test"); + Playlist playlist = new(); Song[] songs = [ @@ -101,7 +101,7 @@ public class PlaylistTests [Fact] public void Lock_Playlist() { - Playlist playlist = new("Test"); + Playlist playlist = new(); Song[] songs = [