// 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 ArtistPluginWrapper : IArtist, IPluginWrapper { private readonly SdkModelPlugin[] _plugins; private readonly IArtist _artist; /// /// Initializes a new instance of the class. /// /// An existing instance to wrap around and provide plugins on top of. /// The plugins to import and apply to everything returned from this wrapper. internal ArtistPluginWrapper(IArtist artist, params SdkModelPlugin[] plugins) { foreach (var plugin in plugins) ActivePlugins.Import(plugin); ActivePlugins = GlobalModelPluginConnector.Create(ActivePlugins); _plugins = plugins; _artist = ActivePlugins.Artist.Execute(artist); AttachEvents(_artist); } /// public SdkModelPlugin ActivePlugins { get; } = new(PluginModelWrapperInfo.Metadata); private void AttachEvents(IArtist artist) { artist.SourcesChanged += OnSourcesChanged; artist.ImagesCountChanged += OnImagesCountChanged; artist.UrlsCountChanged += OnUrlsCountChanged; artist.PlaybackStateChanged += OnPlaybackStateChanged; artist.NameChanged += OnNameChanged; artist.DescriptionChanged += OnDescriptionChanged; artist.DurationChanged += OnDurationChanged; artist.LastPlayedChanged += OnLastPlayedChanged; artist.IsChangeNameAsyncAvailableChanged += OnIsChangeNameAsyncAvailableChanged; artist.IsChangeDescriptionAsyncAvailableChanged += OnIsChangeDescriptionAsyncAvailableChanged; artist.IsChangeDurationAsyncAvailableChanged += OnIsChangeDurationAsyncAvailableChanged; artist.IsPlayTrackCollectionAsyncAvailableChanged += OnIsPlayTrackCollectionAsyncAvailableChanged; artist.IsPauseTrackCollectionAsyncAvailableChanged += OnIsPauseTrackCollectionAsyncAvailableChanged; artist.TracksCountChanged += OnTracksCountChanged; artist.IsPlayAlbumCollectionAsyncAvailableChanged += OnIsPlayAlbumCollectionAsyncAvailableChanged; artist.IsPauseAlbumCollectionAsyncAvailableChanged += OnIsPauseAlbumCollectionAsyncAvailableChanged; artist.AlbumItemsCountChanged += OnAlbumItemsCountChanged; artist.ImagesChanged += OnImagesChanged; artist.UrlsChanged += OnUrlsChanged; artist.DownloadInfoChanged += OnDownloadInfoChanged; artist.TracksChanged += OnTracksChanged; artist.AlbumItemsChanged += OnAlbumItemsChanged; artist.GenresChanged += OnGenresChanged; artist.GenresCountChanged += OnGenresCountChanged; } private void DetachEvents(IArtist artist) { artist.SourcesChanged -= OnSourcesChanged; artist.ImagesCountChanged -= OnImagesCountChanged; artist.UrlsCountChanged -= OnUrlsCountChanged; artist.PlaybackStateChanged -= OnPlaybackStateChanged; artist.NameChanged -= OnNameChanged; artist.DescriptionChanged -= OnDescriptionChanged; artist.DurationChanged -= OnDurationChanged; artist.LastPlayedChanged -= OnLastPlayedChanged; artist.IsChangeNameAsyncAvailableChanged -= OnIsChangeNameAsyncAvailableChanged; artist.IsChangeDescriptionAsyncAvailableChanged -= OnIsChangeDescriptionAsyncAvailableChanged; artist.IsChangeDurationAsyncAvailableChanged -= OnIsChangeDurationAsyncAvailableChanged; artist.IsPlayTrackCollectionAsyncAvailableChanged -= OnIsPlayTrackCollectionAsyncAvailableChanged; artist.IsPauseTrackCollectionAsyncAvailableChanged -= OnIsPauseTrackCollectionAsyncAvailableChanged; artist.TracksCountChanged -= OnTracksCountChanged; artist.IsPlayAlbumCollectionAsyncAvailableChanged -= OnIsPlayAlbumCollectionAsyncAvailableChanged; artist.IsPauseAlbumCollectionAsyncAvailableChanged -= OnIsPauseAlbumCollectionAsyncAvailableChanged; artist.AlbumItemsCountChanged -= OnAlbumItemsCountChanged; artist.ImagesChanged -= OnImagesChanged; artist.UrlsChanged -= OnUrlsChanged; artist.DownloadInfoChanged -= OnDownloadInfoChanged; artist.TracksChanged -= OnTracksChanged; artist.AlbumItemsChanged -= OnAlbumItemsChanged; artist.GenresChanged -= OnGenresChanged; artist.GenresCountChanged -= OnGenresCountChanged; } private void OnSourcesChanged(object sender, EventArgs e) => SourcesChanged?.Invoke(sender, e); private void OnAlbumItemsChanged(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(); AlbumItemsChanged?.Invoke(sender, wrappedAdded, wrappedRemoved); } private void OnTracksChanged(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(); TracksChanged?.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 OnGenresCountChanged(object sender, int e) => GenresCountChanged?.Invoke(sender, e); private void OnGenresChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) { var wrappedAdded = addedItems.Select(x => new CollectionChangedItem(new GenrePluginWrapper(x.Data, _plugins), x.Index)).ToList(); var wrappedRemoved = removedItems.Select(x => new CollectionChangedItem(new GenrePluginWrapper(x.Data, _plugins), x.Index)).ToList(); GenresChanged?.Invoke(sender, wrappedAdded, wrappedRemoved); } private void OnDownloadInfoChanged(object sender, DownloadInfo e) => DownloadInfoChanged?.Invoke(sender, e); private void OnAlbumItemsCountChanged(object sender, int e) => AlbumItemsCountChanged?.Invoke(sender, e); private void OnIsPauseAlbumCollectionAsyncAvailableChanged(object sender, bool e) => IsPauseAlbumCollectionAsyncAvailableChanged?.Invoke(sender, e); private void OnIsPlayAlbumCollectionAsyncAvailableChanged(object sender, bool e) => IsPlayAlbumCollectionAsyncAvailableChanged?.Invoke(sender, e); private void OnTracksCountChanged(object sender, int e) => TracksCountChanged?.Invoke(sender, e); private void OnIsPauseTrackCollectionAsyncAvailableChanged(object sender, bool e) => IsPauseTrackCollectionAsyncAvailableChanged?.Invoke(sender, e); private void OnIsPlayTrackCollectionAsyncAvailableChanged(object sender, bool e) => IsPlayTrackCollectionAsyncAvailableChanged?.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? IsPlayTrackCollectionAsyncAvailableChanged; /// public event EventHandler? IsPauseTrackCollectionAsyncAvailableChanged; /// public event EventHandler? TracksCountChanged; /// public event EventHandler? IsPlayAlbumCollectionAsyncAvailableChanged; /// public event EventHandler? IsPauseAlbumCollectionAsyncAvailableChanged; /// public event EventHandler? AlbumItemsCountChanged; /// public event CollectionChangedEventHandler? ImagesChanged; /// public event CollectionChangedEventHandler? UrlsChanged; /// public event EventHandler? DownloadInfoChanged; /// public event CollectionChangedEventHandler? TracksChanged; /// public event CollectionChangedEventHandler? AlbumItemsChanged; /// public event CollectionChangedEventHandler? GenresChanged; /// public event EventHandler? GenresCountChanged; /// public int TotalImageCount => _artist.TotalImageCount; /// public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddImageAvailableAsync(index, cancellationToken); /// public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveImageAvailableAsync(index, cancellationToken); /// public Task RemoveImageAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveImageAsync(index, cancellationToken); /// public int TotalUrlCount => _artist.TotalUrlCount; /// public Task RemoveUrlAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveUrlAsync(index, cancellationToken); /// public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddUrlAvailableAsync(index, cancellationToken); /// public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveUrlAvailableAsync(index, cancellationToken); /// public string Id => _artist.Id; /// public string Name => _artist.Name; /// public string? Description => _artist.Description; /// public DateTime? LastPlayed => _artist.LastPlayed; /// public PlaybackState PlaybackState => _artist.PlaybackState; /// public TimeSpan Duration => _artist.Duration; /// public bool IsChangeNameAsyncAvailable => _artist.IsChangeNameAsyncAvailable; /// public bool IsChangeDescriptionAsyncAvailable => _artist.IsChangeDescriptionAsyncAvailable; /// public bool IsChangeDurationAsyncAvailable => _artist.IsChangeDurationAsyncAvailable; /// public Task ChangeNameAsync(string name, CancellationToken cancellationToken = default) => _artist.ChangeNameAsync(name, cancellationToken); /// public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _artist.ChangeDescriptionAsync(description, cancellationToken); /// public Task ChangeDurationAsync(TimeSpan duration, CancellationToken cancellationToken = default) => _artist.ChangeDurationAsync(duration, cancellationToken); /// public DateTime? AddedAt => _artist.AddedAt; /// public int TotalTrackCount => _artist.TotalTrackCount; /// public bool IsPlayTrackCollectionAsyncAvailable => _artist.IsPlayTrackCollectionAsyncAvailable; /// public bool IsPauseTrackCollectionAsyncAvailable => _artist.IsPauseTrackCollectionAsyncAvailable; /// public Task PlayTrackCollectionAsync(CancellationToken cancellationToken = default) => _artist.PlayTrackCollectionAsync(cancellationToken); /// public Task PauseTrackCollectionAsync(CancellationToken cancellationToken = default) => _artist.PauseTrackCollectionAsync(cancellationToken); /// public Task RemoveTrackAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveTrackAsync(index, cancellationToken); /// public Task IsAddTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddTrackAvailableAsync(index, cancellationToken); /// public Task IsRemoveTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveTrackAvailableAsync(index, cancellationToken); /// public int TotalAlbumItemsCount => _artist.TotalAlbumItemsCount; /// public bool IsPlayAlbumCollectionAsyncAvailable => _artist.IsPlayAlbumCollectionAsyncAvailable; /// public bool IsPauseAlbumCollectionAsyncAvailable => _artist.IsPauseAlbumCollectionAsyncAvailable; /// public Task PlayAlbumCollectionAsync(CancellationToken cancellationToken = default) => _artist.PlayAlbumCollectionAsync(cancellationToken); /// public Task PauseAlbumCollectionAsync(CancellationToken cancellationToken = default) => _artist.PauseAlbumCollectionAsync(cancellationToken); /// public Task RemoveAlbumItemAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveAlbumItemAsync(index, cancellationToken); /// public Task IsAddAlbumItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddAlbumItemAvailableAsync(index, cancellationToken); /// public Task IsRemoveAlbumItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveAlbumItemAvailableAsync(index, cancellationToken); /// public bool Equals(ICoreImageCollection other) => _artist.Equals(other); /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// IReadOnlyList IMerged.Sources => ((IMerged)_artist).Sources; /// public IAsyncEnumerable GetImagesAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetImagesAsync(limit, offset, cancellationToken).Select(x => new ImagePluginWrapper(x, _plugins)); /// public Task AddImageAsync(IImage image, int index, CancellationToken cancellationToken = default) => _artist.AddImageAsync(image, index, cancellationToken); /// public bool Equals(ICoreUrlCollection other) => _artist.Equals(other); /// public IAsyncEnumerable GetUrlsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetUrlsAsync(limit, offset, cancellationToken).Select(x => new UrlPluginWrapper(x, _plugins)); /// public Task AddUrlAsync(IUrl url, int index, CancellationToken cancellationToken = default) => _artist.AddUrlAsync(url, index, cancellationToken); /// public DownloadInfo DownloadInfo => _artist.DownloadInfo; /// public Task StartDownloadOperationAsync(DownloadOperation operation, CancellationToken cancellationToken = default) => _artist.StartDownloadOperationAsync(operation, cancellationToken); /// public bool Equals(ICoreTrackCollection other) => _artist.Equals(other); /// public Task PlayTrackCollectionAsync(ITrack track, CancellationToken cancellationToken = default) => _artist.PlayTrackCollectionAsync(track, cancellationToken); /// public IAsyncEnumerable GetTracksAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetTracksAsync(limit, offset, cancellationToken).Select(Transform); /// public Task AddTrackAsync(ITrack track, int index, CancellationToken cancellationToken = default) => _artist.AddTrackAsync(track, index, cancellationToken); /// public bool Equals(ICoreAlbumCollectionItem other) => _artist.Equals(other); /// public bool Equals(ICoreAlbumCollection other) => _artist.Equals(other); /// public Task PlayAlbumCollectionAsync(IAlbumCollectionItem albumItem, CancellationToken cancellationToken = default) => _artist.PlayAlbumCollectionAsync(albumItem, cancellationToken); /// public IAsyncEnumerable GetAlbumItemsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetAlbumItemsAsync(limit, offset, cancellationToken).Select(Transform); /// public Task AddAlbumItemAsync(IAlbumCollectionItem albumItem, int index, CancellationToken cancellationToken = default) => _artist.AddAlbumItemAsync(albumItem, index, cancellationToken); /// public bool Equals(ICoreArtistCollectionItem other) => _artist.Equals(other); /// public ValueTask DisposeAsync() { DetachEvents(_artist); return _artist.DisposeAsync(); } private IAlbumCollectionItem Transform(IAlbumCollectionItem item) => item switch { IAlbum album => new AlbumPluginWrapper(album, _plugins), IAlbumCollection albumCollection => new AlbumCollectionPluginWrapper(albumCollection, _plugins), _ => ThrowHelper.ThrowArgumentOutOfRangeException() }; private ITrack Transform(ITrack item) => new TrackPluginWrapper(item, _plugins); /// public int TotalGenreCount => _artist.TotalGenreCount; /// public Task RemoveGenreAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveGenreAsync(index, cancellationToken); /// public Task IsAddGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddGenreAvailableAsync(index, cancellationToken); /// public Task IsRemoveGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveGenreAvailableAsync(index, cancellationToken); /// public bool Equals(ICoreGenreCollection other) => _artist.Equals(other); /// public IAsyncEnumerable GetGenresAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetGenresAsync(limit, offset, cancellationToken).Select(x => new GenrePluginWrapper(x, _plugins)); /// public Task AddGenreAsync(IGenre genre, int index, CancellationToken cancellationToken = default) => _artist.AddGenreAsync(genre, index, cancellationToken); /// public bool Equals(ICoreArtist other) => _artist.Equals(other); /// public IPlayableCollectionGroup? RelatedItems => _artist.RelatedItems is not null ? new PlayableCollectionGroupPluginWrapper(_artist.RelatedItems, _plugins) : null; }