// Copyright (c) Arlo Godfrey. All Rights Reserved. // Licensed under the GNU Lesser General Public License, Version 3.0 with additional terms. // See the LICENSE, LICENSE.LESSER and LICENSE.ADDITIONAL files in the project root for more information. using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Diagnostics; using OwlCore.Events; using StrixMusic.Sdk.AdapterModels; using StrixMusic.Sdk.AppModels; using StrixMusic.Sdk.CoreModels; using StrixMusic.Sdk.MediaPlayback; using StrixMusic.Sdk.Plugins.Model; namespace StrixMusic.Sdk.PluginModels; /// /// Wraps an instance of with the provided plugins. /// public class PlaylistCollectionPluginWrapper : IPlaylistCollection, IPluginWrapper { private readonly IPlaylistCollection _playlistCollection; private readonly SdkModelPlugin[] _plugins; /// /// Initializes a new instance of the class. /// /// The instance to wrap around and apply plugins to. /// The plugins that are applied to items returned from or emitted by this collection. internal PlaylistCollectionPluginWrapper(IPlaylistCollection playlistCollection, params SdkModelPlugin[] plugins) { foreach (var item in plugins) ActivePlugins.Import(item); ActivePlugins = GlobalModelPluginConnector.Create(ActivePlugins); _playlistCollection = ActivePlugins.PlaylistCollection.Execute(playlistCollection); _plugins = plugins; AttachEvents(_playlistCollection); } /// public SdkModelPlugin ActivePlugins { get; } = new(PluginModelWrapperInfo.Metadata); private void AttachEvents(IPlaylistCollection playlistCollection) { playlistCollection.SourcesChanged += OnSourcesChanged; playlistCollection.ImagesCountChanged += OnImagesCountChanged; playlistCollection.UrlsCountChanged += OnUrlsCountChanged; playlistCollection.PlaybackStateChanged += OnPlaybackStateChanged; playlistCollection.NameChanged += OnNameChanged; playlistCollection.DescriptionChanged += OnDescriptionChanged; playlistCollection.DurationChanged += OnDurationChanged; playlistCollection.LastPlayedChanged += OnLastPlayedChanged; playlistCollection.IsChangeNameAsyncAvailableChanged += OnIsChangeNameAsyncAvailableChanged; playlistCollection.IsChangeDescriptionAsyncAvailableChanged += OnIsChangeDescriptionAsyncAvailableChanged; playlistCollection.IsChangeDurationAsyncAvailableChanged += OnIsChangeDurationAsyncAvailableChanged; playlistCollection.IsPlayPlaylistCollectionAsyncAvailableChanged += OnIsPlayPlaylistCollectionAsyncAvailableChanged; playlistCollection.IsPausePlaylistCollectionAsyncAvailableChanged += OnIsPausePlaylistCollectionAsyncAvailableChanged; playlistCollection.PlaylistItemsCountChanged += OnPlaylistItemsCountChanged; playlistCollection.ImagesChanged += OnImagesChanged; playlistCollection.UrlsChanged += OnUrlsChanged; playlistCollection.DownloadInfoChanged += OnDownloadInfoChanged; playlistCollection.PlaylistItemsChanged += OnPlaylistItemsChanged; } private void DetachEvents(IPlaylistCollection playlistCollection) { playlistCollection.SourcesChanged -= OnSourcesChanged; playlistCollection.ImagesCountChanged -= OnImagesCountChanged; playlistCollection.UrlsCountChanged -= OnUrlsCountChanged; playlistCollection.PlaybackStateChanged -= OnPlaybackStateChanged; playlistCollection.NameChanged -= OnNameChanged; playlistCollection.DescriptionChanged -= OnDescriptionChanged; playlistCollection.DurationChanged -= OnDurationChanged; playlistCollection.LastPlayedChanged -= OnLastPlayedChanged; playlistCollection.IsChangeNameAsyncAvailableChanged -= OnIsChangeNameAsyncAvailableChanged; playlistCollection.IsChangeDescriptionAsyncAvailableChanged -= OnIsChangeDescriptionAsyncAvailableChanged; playlistCollection.IsChangeDurationAsyncAvailableChanged -= OnIsChangeDurationAsyncAvailableChanged; playlistCollection.IsPlayPlaylistCollectionAsyncAvailableChanged -= OnIsPlayPlaylistCollectionAsyncAvailableChanged; playlistCollection.IsPausePlaylistCollectionAsyncAvailableChanged -= OnIsPausePlaylistCollectionAsyncAvailableChanged; playlistCollection.PlaylistItemsCountChanged -= OnPlaylistItemsCountChanged; playlistCollection.ImagesChanged -= OnImagesChanged; playlistCollection.UrlsChanged -= OnUrlsChanged; playlistCollection.DownloadInfoChanged -= OnDownloadInfoChanged; playlistCollection.PlaylistItemsChanged -= OnPlaylistItemsChanged; } private void OnSourcesChanged(object sender, EventArgs e) => SourcesChanged?.Invoke(sender, e); private void OnPlaylistItemsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) { var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(Transform(x.Data), x.Index)).ToList(); var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(Transform(x.Data), x.Index)).ToList(); PlaylistItemsChanged?.Invoke(sender, wrappedAdded, wrappedRemoved); } private void OnUrlsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) { var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(new UrlPluginWrapper(x.Data, _plugins), x.Index)).ToList(); var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(new UrlPluginWrapper(x.Data, _plugins), x.Index)).ToList(); UrlsChanged?.Invoke(sender, wrappedAdded, wrappedRemoved); } private void OnImagesChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) { var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(new ImagePluginWrapper(x.Data, _plugins), x.Index)).ToList(); var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(new ImagePluginWrapper(x.Data, _plugins), x.Index)).ToList(); ImagesChanged?.Invoke(sender, wrappedAdded, wrappedRemoved); } private void OnDownloadInfoChanged(object sender, DownloadInfo e) => DownloadInfoChanged?.Invoke(sender, e); private void OnPlaylistItemsCountChanged(object sender, int e) => PlaylistItemsCountChanged?.Invoke(sender, e); private void OnIsPausePlaylistCollectionAsyncAvailableChanged(object sender, bool e) => IsPausePlaylistCollectionAsyncAvailableChanged?.Invoke(sender, e); private void OnIsPlayPlaylistCollectionAsyncAvailableChanged(object sender, bool e) => IsPlayPlaylistCollectionAsyncAvailableChanged?.Invoke(sender, e); private void OnIsChangeDurationAsyncAvailableChanged(object sender, bool e) => IsChangeDurationAsyncAvailableChanged?.Invoke(sender, e); private void OnIsChangeDescriptionAsyncAvailableChanged(object sender, bool e) => IsChangeDescriptionAsyncAvailableChanged?.Invoke(sender, e); private void OnIsChangeNameAsyncAvailableChanged(object sender, bool e) => IsChangeNameAsyncAvailableChanged?.Invoke(sender, e); private void OnLastPlayedChanged(object sender, DateTime? e) => LastPlayedChanged?.Invoke(sender, e); private void OnDurationChanged(object sender, TimeSpan e) => DurationChanged?.Invoke(sender, e); private void OnDescriptionChanged(object sender, string? e) => DescriptionChanged?.Invoke(sender, e); private void OnNameChanged(object sender, string e) => NameChanged?.Invoke(sender, e); private void OnPlaybackStateChanged(object sender, PlaybackState e) => PlaybackStateChanged?.Invoke(sender, e); private void OnUrlsCountChanged(object sender, int e) => UrlsCountChanged?.Invoke(sender, e); private void OnImagesCountChanged(object sender, int e) => ImagesCountChanged?.Invoke(sender, e); /// public event EventHandler? SourcesChanged; /// public event EventHandler? ImagesCountChanged; /// public event EventHandler? UrlsCountChanged; /// public event EventHandler? PlaybackStateChanged; /// public event EventHandler? NameChanged; /// public event EventHandler? DescriptionChanged; /// public event EventHandler? DurationChanged; /// public event EventHandler? LastPlayedChanged; /// public event EventHandler? IsChangeNameAsyncAvailableChanged; /// public event EventHandler? IsChangeDescriptionAsyncAvailableChanged; /// public event EventHandler? IsChangeDurationAsyncAvailableChanged; /// public event EventHandler? IsPlayPlaylistCollectionAsyncAvailableChanged; /// public event EventHandler? IsPausePlaylistCollectionAsyncAvailableChanged; /// public event EventHandler? PlaylistItemsCountChanged; /// public event CollectionChangedEventHandler? ImagesChanged; /// public event CollectionChangedEventHandler? UrlsChanged; /// public event EventHandler? DownloadInfoChanged; /// public event CollectionChangedEventHandler? PlaylistItemsChanged; /// public int TotalImageCount => _playlistCollection.TotalImageCount; /// public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsAddImageAvailableAsync(index, cancellationToken); /// public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsRemoveImageAvailableAsync(index, cancellationToken); /// public Task RemoveImageAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.RemoveImageAsync(index, cancellationToken); /// public int TotalUrlCount => _playlistCollection.TotalUrlCount; /// public Task RemoveUrlAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.RemoveUrlAsync(index, cancellationToken); /// public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsAddUrlAvailableAsync(index, cancellationToken); /// public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsRemoveUrlAvailableAsync(index, cancellationToken); /// public string Id => _playlistCollection.Id; /// public string Name => _playlistCollection.Name; /// public string? Description => _playlistCollection.Description; /// public DateTime? LastPlayed => _playlistCollection.LastPlayed; /// public PlaybackState PlaybackState => _playlistCollection.PlaybackState; /// public TimeSpan Duration => _playlistCollection.Duration; /// public bool IsChangeNameAsyncAvailable => _playlistCollection.IsChangeNameAsyncAvailable; /// public bool IsChangeDescriptionAsyncAvailable => _playlistCollection.IsChangeDescriptionAsyncAvailable; /// public bool IsChangeDurationAsyncAvailable => _playlistCollection.IsChangeDurationAsyncAvailable; /// public Task ChangeNameAsync(string name, CancellationToken cancellationToken = default) => _playlistCollection.ChangeNameAsync(name, cancellationToken); /// public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _playlistCollection.ChangeDescriptionAsync(description, cancellationToken); /// public Task ChangeDurationAsync(TimeSpan duration, CancellationToken cancellationToken = default) => _playlistCollection.ChangeDurationAsync(duration, cancellationToken); /// public DateTime? AddedAt => _playlistCollection.AddedAt; /// public int TotalPlaylistItemsCount => _playlistCollection.TotalPlaylistItemsCount; /// public bool IsPlayPlaylistCollectionAsyncAvailable => _playlistCollection.IsPlayPlaylistCollectionAsyncAvailable; /// public bool IsPausePlaylistCollectionAsyncAvailable => _playlistCollection.IsPausePlaylistCollectionAsyncAvailable; /// public Task RemovePlaylistItemAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.RemovePlaylistItemAsync(index, cancellationToken); /// public Task IsAddPlaylistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsAddPlaylistItemAvailableAsync(index, cancellationToken); /// public Task IsRemovePlaylistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _playlistCollection.IsRemovePlaylistItemAvailableAsync(index, cancellationToken); /// public Task PlayPlaylistCollectionAsync(CancellationToken cancellationToken = default) => _playlistCollection.PlayPlaylistCollectionAsync(cancellationToken); /// public Task PausePlaylistCollectionAsync(CancellationToken cancellationToken = default) => _playlistCollection.PausePlaylistCollectionAsync(cancellationToken); /// public bool Equals(ICoreImageCollection other) => _playlistCollection.Equals(other); /// IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_playlistCollection).Sources; /// public IAsyncEnumerable GetImagesAsync(int limit, int offset, CancellationToken cancellationToken = default) => _playlistCollection.GetImagesAsync(limit, offset, cancellationToken).Select(x => new ImagePluginWrapper(x, _plugins)); /// public Task AddImageAsync(IImage image, int index, CancellationToken cancellationToken = default) => _playlistCollection.AddImageAsync(image, index, cancellationToken); /// public bool Equals(ICoreUrlCollection other) => _playlistCollection.Equals(other); /// public IAsyncEnumerable GetUrlsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _playlistCollection.GetUrlsAsync(limit, offset, cancellationToken).Select(x => new UrlPluginWrapper(x, _plugins)); /// public Task AddUrlAsync(IUrl url, int index, CancellationToken cancellationToken = default) => _playlistCollection.AddUrlAsync(url, index, cancellationToken); /// public DownloadInfo DownloadInfo => _playlistCollection.DownloadInfo; /// public Task StartDownloadOperationAsync(DownloadOperation operation, CancellationToken cancellationToken = default) => _playlistCollection.StartDownloadOperationAsync(operation, cancellationToken); /// public bool Equals(ICorePlaylistCollectionItem other) => _playlistCollection.Equals(other); /// public Task PlayPlaylistCollectionAsync(IPlaylistCollectionItem playlistItem, CancellationToken cancellationToken = default) => _playlistCollection.PlayPlaylistCollectionAsync(playlistItem, cancellationToken); /// public IAsyncEnumerable GetPlaylistItemsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _playlistCollection.GetPlaylistItemsAsync(limit, offset, cancellationToken).Select(Transform); /// public Task AddPlaylistItemAsync(IPlaylistCollectionItem playlistItem, int index, CancellationToken cancellationToken = default) => _playlistCollection.AddPlaylistItemAsync(playlistItem, index, cancellationToken); /// public bool Equals(ICorePlaylistCollection other) => _playlistCollection.Equals(other); /// public ValueTask DisposeAsync() { DetachEvents(_playlistCollection); return _playlistCollection.DisposeAsync(); } private IPlaylistCollectionItem Transform(IPlaylistCollectionItem item) => item switch { IPlaylist playlist => new PlaylistPluginWrapper(playlist, _plugins), IPlaylistCollection playlistCollection => new PlaylistCollectionPluginWrapper(playlistCollection, _plugins), _ => ThrowHelper.ThrowArgumentOutOfRangeException() }; }