using Harmonia.Core.Extensions; using Harmonia.Core.Models; namespace Harmonia.Core.Playlists; public class Playlist { public string UID { get; init; } = Guid.NewGuid().ToString(); public string? Name { get; set; } public List Songs { get; init; } = []; // TODO: Change to "private init" once deserialization is fixed public List GroupOptions { get; set; } = []; public List SortOptions { get; set; } = []; public bool IsLocked { get; set; } public event EventHandler? PlaylistUpdated; public void AddSong(Song song, int? index = null) { AddSongs([song], index); } public void AddSongs(Song[] songs, int? index = null) { PlaylistSong[] playlistSongs = [.. songs.Select(song => new PlaylistSong(song))]; AddSongs(playlistSongs, index); } private void AddSongs(PlaylistSong[] playlistSongs, int? index = null) { if (IsLocked) return; if (playlistSongs.Length == 0) return; int insertIndex = index ?? Songs.Count; Songs.InsertRange(insertIndex, playlistSongs); PlaylistUpdatedEventArgs eventArgs = new() { Action = PlaylistUpdateAction.Add, Index = insertIndex, Count = playlistSongs.Length, Songs = playlistSongs }; PlaylistUpdated?.Invoke(this, eventArgs); } public void MoveSong(PlaylistSong playlistSong, int newIndex) { int currentIndex = Songs.IndexOf(playlistSong); MoveSong(currentIndex, newIndex); } public void MoveSong(int oldIndex, int newIndex) { if (IsLocked) return; if (oldIndex == newIndex) return; PlaylistSong playlistSong = Songs[oldIndex]; Songs.Remove(playlistSong); Songs.Insert(newIndex, playlistSong); PlaylistUpdatedEventArgs eventArgs = new() { Action = PlaylistUpdateAction.Move, Index = oldIndex, Count = 1, Songs = [playlistSong], NewIndex = newIndex }; PlaylistUpdated?.Invoke(this, eventArgs); } public void SortSongs(PlaylistSong[] playlistSongs, SortOption[] sortOptions) { Dictionary oldPlaylistSongs = playlistSongs .OrderBy(Songs.IndexOf) .ToDictionary(Songs.IndexOf, playlistSong => playlistSong); Song[] songs = [.. playlistSongs.Select(playlistSong => playlistSong.Song)]; Song[] sortedSongs = [.. songs.SortBy(sortOptions)]; int currentSortIndex = 0; foreach (int index in oldPlaylistSongs.Keys) { PlaylistSong playlistSong = oldPlaylistSongs[index]; Song sortedSong = sortedSongs[currentSortIndex++]; PlaylistSong newPlaylistSong = playlistSongs.First(ps => ps.Song == sortedSong); if (newPlaylistSong == playlistSong) continue; Songs.RemoveAt(index); Songs.Insert(index, newPlaylistSong); } PlaylistUpdatedEventArgs eventArgs = new() { Action = PlaylistUpdateAction.Reset, Index = -1, Count = playlistSongs.Length, Songs = playlistSongs }; PlaylistUpdated?.Invoke(this, eventArgs); } public void RemoveSong(int index) { RemoveSongs(index, 1); } public void RemoveSongs(int index, int count) { PlaylistSong[] playlistSongs = [.. Songs.GetRange(index, count)]; RemoveSongs(playlistSongs); } public void RemoveSong(PlaylistSong playlistSong) { RemoveSongs([playlistSong]); } public void RemoveSongs(PlaylistSong[] playlistSongs) { if (IsLocked) return; List removedSongs = []; foreach (PlaylistSong playlistSong in playlistSongs) { if (Songs.Remove(playlistSong)) { removedSongs.Add(playlistSong); } } if (removedSongs.Count == 0) return; PlaylistUpdatedEventArgs eventArgs = new() { Action = PlaylistUpdateAction.Remove, Index = -1, Count = removedSongs.Count, Songs = playlistSongs }; PlaylistUpdated?.Invoke(this, eventArgs); } public void ImportTags(Song[] songs) { foreach (Song song in songs) { PlaylistSong[] playlistSongs = [.. Songs.Where(playlistSong => string.Equals(playlistSong.Song.FileName, song.FileName, StringComparison.OrdinalIgnoreCase))]; foreach (PlaylistSong playlistSong in playlistSongs) { //playlistSong.Song = song; } } } public void RemoveMissingSongs() { PlaylistSong[] missingSongs = [.. Songs.Where(playlistSong => File.Exists(playlistSong.Song.FileName) == false)]; if (missingSongs.Length == 0) return; RemoveSongs(missingSongs); } public void RemoveDuplicateSongs() { List songsToRemove = []; string[] fileNames = Songs .GroupBy(x => x.Song.FileName) .Where(x => x.Count() > 1) .Select(x => x.Key) .ToArray(); foreach (string fileName in fileNames) { List songs = Songs.Where(x => string.Equals(x.Song.FileName, fileName, StringComparison.OrdinalIgnoreCase)).ToList(); for (int i = songs.Count - 1; i > 0; i--) songsToRemove.Add(songs[i]); } if (songsToRemove.Count == 0) return; RemoveSongs(songsToRemove.ToArray()); } }