working without redis, player watcher event tweaking, graceful exception handling
This commit is contained in:
parent
35eee0f068
commit
a401280edf
@ -44,12 +44,14 @@ namespace Selector.CLI
|
||||
IAudioFeatureInjectorFactory audioFeatureInjectorFactory,
|
||||
IPlayCounterFactory playCounterFactory,
|
||||
|
||||
IPublisherFactory publisherFactory,
|
||||
ICacheWriterFactory cacheWriterFactory,
|
||||
|
||||
ILogger<DbWatcherService> logger,
|
||||
IServiceProvider serviceProvider
|
||||
) {
|
||||
IServiceProvider serviceProvider,
|
||||
|
||||
IPublisherFactory publisherFactory = null,
|
||||
ICacheWriterFactory cacheWriterFactory = null
|
||||
)
|
||||
{
|
||||
Logger = logger;
|
||||
ServiceProvider = serviceProvider;
|
||||
|
||||
@ -105,8 +107,8 @@ namespace Selector.CLI
|
||||
watcher = await WatcherFactory.Get<PlayerWatcher>(spotifyFactory, id: dbWatcher.UserId, pollPeriod: PollPeriod);
|
||||
|
||||
consumers.Add(await AudioFeatureInjectorFactory.Get(spotifyFactory));
|
||||
consumers.Add(await CacheWriterFactory.Get());
|
||||
consumers.Add(await PublisherFactory.Get());
|
||||
if (CacheWriterFactory is not null) consumers.Add(await CacheWriterFactory.Get());
|
||||
if (PublisherFactory is not null) consumers.Add(await PublisherFactory.Get());
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(dbWatcher.User.LastFmUsername))
|
||||
{
|
||||
|
@ -123,7 +123,7 @@ namespace Selector.CLI
|
||||
case Consumers.PlayCounter:
|
||||
if(!string.IsNullOrWhiteSpace(watcherOption.LastFmUsername))
|
||||
{
|
||||
consumers.Add(await ServiceProvider.GetService<PlayCounterCachingFactory>().Get(creds: new() { Username = watcherOption.LastFmUsername }));
|
||||
consumers.Add(await ServiceProvider.GetService<PlayCounterFactory>().Get(creds: new() { Username = watcherOption.LastFmUsername }));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -55,8 +55,13 @@ namespace Selector.CLI
|
||||
Console.WriteLine("> Adding Last.fm credentials...");
|
||||
|
||||
services.AddLastFm(config.LastfmClient, config.LastfmSecret);
|
||||
|
||||
if(config.RedisOptions.Enabled)
|
||||
{
|
||||
Console.WriteLine("> Adding caching Last.fm consumers...");
|
||||
services.AddCachingLastFm();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("> No Last.fm credentials, skipping init...");
|
||||
@ -101,11 +106,19 @@ namespace Selector.CLI
|
||||
Console.WriteLine("> Adding Services...");
|
||||
// SERVICES
|
||||
services.AddConsumerFactories();
|
||||
if (config.RedisOptions.Enabled)
|
||||
{
|
||||
Console.WriteLine("> Adding caching consumers...");
|
||||
services.AddCachingConsumerFactories();
|
||||
}
|
||||
services.AddWatcher();
|
||||
|
||||
services.AddSpotify();
|
||||
if (config.RedisOptions.Enabled) {
|
||||
Console.WriteLine("> Adding caching Spotify consumers...");
|
||||
services.AddCachingSpotify();
|
||||
}
|
||||
|
||||
ConfigureLastFm(config, services);
|
||||
ConfigureDb(config, services);
|
||||
|
||||
@ -140,6 +153,8 @@ namespace Selector.CLI
|
||||
|
||||
static IHostBuilder CreateHostBuilder(string[] args, Action<HostBuilderContext, IServiceCollection> BuildServices, Action<HostBuilderContext, ILoggingBuilder> BuildLogs)
|
||||
=> Host.CreateDefaultBuilder(args)
|
||||
.UseWindowsService()
|
||||
.UseSystemd()
|
||||
.ConfigureServices((context, services) => BuildServices(context, services))
|
||||
.ConfigureLogging((context, builder) => BuildLogs(context, builder));
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||
<PackageReference Include="NLog" Version="4.7.12" />
|
||||
@ -26,7 +28,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.Development.json">
|
||||
<None Update="appsettings.Development.json" Condition="Exists('appsettings.Development.json')">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.Release.json" Condition="Exists('appsettings.Release.json')">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
|
@ -57,7 +57,6 @@ namespace Selector.Cache
|
||||
if (watcher is IPlayerWatcher watcherCast)
|
||||
{
|
||||
watcherCast.ItemChange += Callback;
|
||||
watcherCast.PlayingChange += Callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -72,7 +71,6 @@ namespace Selector.Cache
|
||||
if (watcher is IPlayerWatcher watcherCast)
|
||||
{
|
||||
watcherCast.ItemChange -= Callback;
|
||||
watcherCast.PlayingChange -= Callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -27,8 +27,8 @@ namespace Selector.Cache.Extensions
|
||||
|
||||
public static void AddCachingConsumerFactories(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IAudioFeatureInjectorFactory, AudioFeatureInjectorFactory>();
|
||||
services.AddTransient<AudioFeatureInjectorFactory>();
|
||||
services.AddTransient<IAudioFeatureInjectorFactory, CachingAudioFeatureInjectorFactory>();
|
||||
services.AddTransient<CachingAudioFeatureInjectorFactory>();
|
||||
services.AddTransient<IPlayCounterFactory, PlayCounterCachingFactory>();
|
||||
services.AddTransient<PlayCounterCachingFactory>();
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Selector.Cache
|
||||
|
||||
public AudioFeaturePuller(
|
||||
IRefreshTokenFactoryProvider spotifyFactory,
|
||||
IDatabaseAsync cache
|
||||
IDatabaseAsync cache = null
|
||||
)
|
||||
{
|
||||
SpotifyFactory = spotifyFactory;
|
||||
@ -24,8 +24,8 @@ namespace Selector.Cache
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(trackId)) throw new ArgumentNullException("No track Id provided");
|
||||
|
||||
var track = await Cache.StringGetAsync(Key.AudioFeature(trackId));
|
||||
if (track == RedisValue.Null)
|
||||
var track = await Cache?.StringGetAsync(Key.AudioFeature(trackId));
|
||||
if (Cache is null || track == RedisValue.Null)
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(refreshToken))
|
||||
{
|
||||
|
@ -23,13 +23,13 @@ namespace Selector.Cache
|
||||
protected readonly IUserApi UserClient;
|
||||
|
||||
public PlayCountPuller(
|
||||
IDatabaseAsync cache,
|
||||
ILogger<PlayCountPuller> logger,
|
||||
|
||||
ITrackApi trackClient,
|
||||
IAlbumApi albumClient,
|
||||
IArtistApi artistClient,
|
||||
IUserApi userClient
|
||||
IUserApi userClient,
|
||||
IDatabaseAsync cache = null
|
||||
)
|
||||
{
|
||||
Cache = cache;
|
||||
@ -45,14 +45,14 @@ namespace Selector.Cache
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentNullException("No username provided");
|
||||
|
||||
var trackCache = Cache.StringGetAsync(Key.TrackPlayCount(track, artist));
|
||||
var albumCache = Cache.StringGetAsync(Key.AlbumPlayCount(album, albumArtist));
|
||||
var artistCache = Cache.StringGetAsync(Key.ArtistPlayCount(artist));
|
||||
var userCache = Cache.StringGetAsync(Key.UserPlayCount(username));
|
||||
var trackCache = Cache?.StringGetAsync(Key.TrackPlayCount(track, artist));
|
||||
var albumCache = Cache?.StringGetAsync(Key.AlbumPlayCount(album, albumArtist));
|
||||
var artistCache = Cache?.StringGetAsync(Key.ArtistPlayCount(artist));
|
||||
var userCache = Cache?.StringGetAsync(Key.UserPlayCount(username));
|
||||
|
||||
var cacheTasks = new Task[] { trackCache, albumCache, artistCache, userCache };
|
||||
|
||||
await Task.WhenAll(cacheTasks);
|
||||
await Task.WhenAll(cacheTasks.Where(t => t is not null));
|
||||
|
||||
PlayCount playCount = new()
|
||||
{
|
||||
@ -64,64 +64,36 @@ namespace Selector.Cache
|
||||
Task<LastResponse<LastArtist>> artistHttp = null;
|
||||
Task<LastResponse<LastUser>> userHttp = null;
|
||||
|
||||
if (trackCache.IsCompletedSuccessfully)
|
||||
{
|
||||
if(trackCache.Result == RedisValue.Null)
|
||||
{
|
||||
trackHttp = TrackClient.GetInfoAsync(track, artist, username);
|
||||
}
|
||||
else
|
||||
if (trackCache is not null && trackCache.IsCompletedSuccessfully && trackCache.Result != RedisValue.Null)
|
||||
{
|
||||
playCount.Track = (int) trackCache.Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trackHttp = TrackClient.GetInfoAsync(track, artist, username);
|
||||
}
|
||||
|
||||
if (albumCache.IsCompletedSuccessfully)
|
||||
if (albumCache is not null && albumCache.IsCompletedSuccessfully && albumCache.Result != RedisValue.Null)
|
||||
{
|
||||
if (albumCache.Result == RedisValue.Null)
|
||||
{
|
||||
albumHttp = AlbumClient.GetInfoAsync(albumArtist, album, username: username);
|
||||
}
|
||||
else
|
||||
{
|
||||
playCount.Album = (int)albumCache.Result;
|
||||
}
|
||||
playCount.Album = (int) albumCache.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
albumHttp = AlbumClient.GetInfoAsync(albumArtist, album, username: username);
|
||||
}
|
||||
|
||||
if (artistCache.IsCompletedSuccessfully)
|
||||
if (artistCache is not null && artistCache.IsCompletedSuccessfully && artistCache.Result != RedisValue.Null)
|
||||
{
|
||||
if (artistCache.Result == RedisValue.Null)
|
||||
{
|
||||
artistHttp = ArtistClient.GetInfoAsync(artist);
|
||||
}
|
||||
else
|
||||
{
|
||||
playCount.Artist = (int)artistCache.Result;
|
||||
}
|
||||
playCount.Artist = (int) artistCache.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
artistHttp = ArtistClient.GetInfoAsync(artist);
|
||||
}
|
||||
|
||||
if (userCache.IsCompletedSuccessfully)
|
||||
if (userCache is not null && userCache.IsCompletedSuccessfully && userCache.Result != RedisValue.Null)
|
||||
{
|
||||
if (userCache.Result == RedisValue.Null)
|
||||
{
|
||||
userHttp = UserClient.GetInfoAsync(username);
|
||||
}
|
||||
else
|
||||
{
|
||||
playCount.User = (int)userCache.Result;
|
||||
}
|
||||
playCount.User = (int) userCache.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -64,11 +64,28 @@ namespace Selector.Model
|
||||
|
||||
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
|
||||
{
|
||||
private static string GetPath(string env) => $"{@Directory.GetCurrentDirectory()}/../Selector.Web/appsettings.{env}.json";
|
||||
|
||||
public ApplicationDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
string configFile;
|
||||
|
||||
if(File.Exists(GetPath("Development")))
|
||||
{
|
||||
configFile = GetPath("Development");
|
||||
}
|
||||
else if(File.Exists(GetPath("Release")))
|
||||
{
|
||||
configFile = GetPath("Release");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileNotFoundException("No config file available to load a connection string from");
|
||||
}
|
||||
|
||||
IConfigurationRoot configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile(@Directory.GetCurrentDirectory() + "/../Selector.Web/appsettings.Development.json")
|
||||
.AddJsonFile(configFile)
|
||||
.Build();
|
||||
|
||||
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||||
|
@ -22,7 +22,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -85,7 +85,7 @@ namespace Selector.Web.Areas.Identity.Pages.Account
|
||||
var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberMe, lockoutOnFailure: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation("User logged in.");
|
||||
_logger.LogInformation($"[{Input.Username}] logged in.");
|
||||
return LocalRedirect(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
@ -94,7 +94,7 @@ namespace Selector.Web.Areas.Identity.Pages.Account
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
_logger.LogWarning("User account locked out.");
|
||||
_logger.LogWarning($"[{Input.Username}] locked out.");
|
||||
return RedirectToPage("./Lockout");
|
||||
}
|
||||
else
|
||||
|
@ -18,19 +18,10 @@ namespace Selector.Web.Pages
|
||||
public class NowModel : PageModel
|
||||
{
|
||||
private readonly ILogger<NowModel> Logger;
|
||||
private readonly INowPlayingMappingFactory MappingFactory;
|
||||
private readonly CacheHubProxy HubProxy;
|
||||
private readonly UserManager<ApplicationUser> UserManager;
|
||||
|
||||
public NowModel(ILogger<NowModel> logger,
|
||||
INowPlayingMappingFactory mappingFactory,
|
||||
CacheHubProxy hubProxy,
|
||||
UserManager<ApplicationUser> userManager)
|
||||
public NowModel(ILogger<NowModel> logger)
|
||||
{
|
||||
Logger = logger;
|
||||
MappingFactory = mappingFactory;
|
||||
HubProxy = hubProxy;
|
||||
UserManager = userManager;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
|
@ -34,7 +34,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.Development.json">
|
||||
<None Update="appsettings.Development.json" Condition="Exists('appsettings.Development.json')">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.Release.json" Condition="Exists('appsettings.Release.json')">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
|
@ -97,11 +97,14 @@ namespace Selector.Web
|
||||
services.AddRedisServices(config.RedisOptions.ConnectionString);
|
||||
|
||||
services.AddSpotify();
|
||||
if (config.RedisOptions.Enabled)
|
||||
{
|
||||
Console.WriteLine("> Adding caching Spotify consumers...");
|
||||
services.AddCachingSpotify();
|
||||
services.AddCacheHubProxy();
|
||||
}
|
||||
|
||||
ConfigureLastFm(config, services);
|
||||
|
||||
services.AddCacheHubProxy();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
@ -141,8 +144,13 @@ namespace Selector.Web
|
||||
Console.WriteLine("> Adding Last.fm credentials...");
|
||||
|
||||
services.AddLastFm(config.LastfmClient, config.LastfmSecret);
|
||||
|
||||
if (config.RedisOptions.Enabled)
|
||||
{
|
||||
Console.WriteLine("> Adding caching Last.fm consumers...");
|
||||
services.AddCachingLastFm();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("> No Last.fm credentials, skipping init...");
|
||||
|
@ -22,6 +22,7 @@ namespace Selector
|
||||
}
|
||||
|
||||
public abstract Task WatchOne(CancellationToken token);
|
||||
public abstract Task Reset();
|
||||
|
||||
public async Task Watch(CancellationToken cancelToken)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ namespace Selector
|
||||
public class WatcherCollection: IWatcherCollection, IDisposable, IEnumerable<WatcherContext>
|
||||
{
|
||||
private readonly ILogger<WatcherCollection> Logger;
|
||||
public bool IsRunning { get; private set; } = true;
|
||||
public bool IsRunning { get; private set; } = false;
|
||||
private List<WatcherContext> Watchers { get; set; } = new();
|
||||
|
||||
public WatcherCollection(ILogger<WatcherCollection> logger = null)
|
||||
|
@ -58,10 +58,24 @@ namespace Selector
|
||||
|
||||
Consumers.ForEach(c => c.Subscribe(Watcher));
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
if(Task is not null && !Task.IsCompleted)
|
||||
{
|
||||
TokenSource.Cancel();
|
||||
}
|
||||
|
||||
TokenSource = new();
|
||||
|
||||
Task = Watcher.Watch(TokenSource.Token);
|
||||
Task.ContinueWith(t =>
|
||||
{
|
||||
if (t.Exception != null) throw t.Exception;
|
||||
Watcher.Reset();
|
||||
Reset();
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ namespace Selector
|
||||
/// <summary>
|
||||
/// Track or episode changes
|
||||
/// </summary>
|
||||
public event EventHandler<ListeningChangeEventArgs> NetworkPoll;
|
||||
public event EventHandler<ListeningChangeEventArgs> ItemChange;
|
||||
public event EventHandler<ListeningChangeEventArgs> AlbumChange;
|
||||
public event EventHandler<ListeningChangeEventArgs> ArtistChange;
|
||||
|
@ -18,6 +18,8 @@ namespace Selector
|
||||
/// <returns></returns>
|
||||
public Task Watch(CancellationToken cancelToken);
|
||||
|
||||
public Task Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Time interval in ms between polls from Watch()
|
||||
/// </summary>
|
||||
|
@ -15,6 +15,7 @@ namespace Selector
|
||||
private readonly IPlayerClient spotifyClient;
|
||||
private readonly IEqual eq;
|
||||
|
||||
public event EventHandler<ListeningChangeEventArgs> NetworkPoll;
|
||||
public event EventHandler<ListeningChangeEventArgs> ItemChange;
|
||||
public event EventHandler<ListeningChangeEventArgs> AlbumChange;
|
||||
public event EventHandler<ListeningChangeEventArgs> ArtistChange;
|
||||
@ -26,6 +27,7 @@ namespace Selector
|
||||
public event EventHandler<ListeningChangeEventArgs> PlayingChange;
|
||||
|
||||
public CurrentlyPlayingContext Live { get; private set; }
|
||||
private CurrentlyPlayingContext Previous { get; set; }
|
||||
public PlayerTimeline Past { get; set; } = new();
|
||||
|
||||
public PlayerWatcher(IPlayerClient spotifyClient,
|
||||
@ -40,6 +42,15 @@ namespace Selector
|
||||
PollPeriod = pollPeriod;
|
||||
}
|
||||
|
||||
public override Task Reset()
|
||||
{
|
||||
Previous = null;
|
||||
Live = null;
|
||||
Past = new();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task WatchOne(CancellationToken token = default)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
@ -52,104 +63,100 @@ namespace Selector
|
||||
if (polledCurrent != null) StoreCurrentPlaying(polledCurrent);
|
||||
|
||||
// swap new item into live and bump existing down to previous
|
||||
CurrentlyPlayingContext previous;
|
||||
if(Live is null) {
|
||||
Previous = Live;
|
||||
Live = polledCurrent;
|
||||
previous = polledCurrent;
|
||||
}
|
||||
else {
|
||||
previous = Live;
|
||||
Live = polledCurrent;
|
||||
}
|
||||
|
||||
OnNetworkPoll(GetEvent());
|
||||
|
||||
// NOT PLAYING
|
||||
if(previous is null && Live is null)
|
||||
if(Previous is null && Live is null)
|
||||
{
|
||||
// Console.WriteLine("not playing");
|
||||
}
|
||||
else
|
||||
{
|
||||
// STARTED PLAYBACK
|
||||
if(previous is null
|
||||
&& (Live.Item is FullTrack || Live.Item is FullEpisode))
|
||||
if(Previous is null && Live is not null)
|
||||
{
|
||||
Logger.LogDebug($"Playback started: {Live.DisplayString()}");
|
||||
OnPlayingChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnItemChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnPlayingChange(GetEvent());
|
||||
OnItemChange(GetEvent());
|
||||
OnContextChange(GetEvent());
|
||||
}
|
||||
// STOPPED PLAYBACK
|
||||
else if((previous.Item is FullTrack || previous.Item is FullEpisode)
|
||||
&& Live is null)
|
||||
else if(Previous is not null && Live is null)
|
||||
{
|
||||
Logger.LogDebug($"Playback stopped: {previous.DisplayString()}");
|
||||
OnPlayingChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnItemChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
Logger.LogDebug($"Playback stopped: {Previous.DisplayString()}");
|
||||
OnPlayingChange(GetEvent());
|
||||
OnItemChange(GetEvent());
|
||||
OnContextChange(GetEvent());
|
||||
}
|
||||
// CONTINUING PLAYBACK
|
||||
else {
|
||||
|
||||
// MUSIC
|
||||
if(previous.Item is FullTrack previousTrack
|
||||
if(Previous.Item is FullTrack previousTrack
|
||||
&& Live.Item is FullTrack currentTrack)
|
||||
{
|
||||
if(!eq.IsEqual(previousTrack, currentTrack)) {
|
||||
Logger.LogDebug($"Track changed: {previousTrack.DisplayString()} -> {currentTrack.DisplayString()}");
|
||||
OnItemChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnItemChange(GetEvent());
|
||||
}
|
||||
|
||||
if(!eq.IsEqual(previousTrack.Album, currentTrack.Album)) {
|
||||
Logger.LogDebug($"Album changed: {previousTrack.Album.DisplayString()} -> {currentTrack.Album.DisplayString()}");
|
||||
OnAlbumChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnAlbumChange(GetEvent());
|
||||
}
|
||||
|
||||
if(!eq.IsEqual(previousTrack.Artists[0], currentTrack.Artists[0])) {
|
||||
Logger.LogDebug($"Artist changed: {previousTrack.Artists.DisplayString()} -> {currentTrack.Artists.DisplayString()}");
|
||||
OnArtistChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnArtistChange(GetEvent());
|
||||
}
|
||||
}
|
||||
// CHANGED CONTENT
|
||||
else if((previous.Item is FullTrack && Live.Item is FullEpisode)
|
||||
|| (previous.Item is FullEpisode && Live.Item is FullTrack))
|
||||
// CHANGED CONTENT TYPE
|
||||
else if((Previous.Item is FullTrack && Live.Item is FullEpisode)
|
||||
|| (Previous.Item is FullEpisode && Live.Item is FullTrack))
|
||||
{
|
||||
Logger.LogDebug($"Media type changed: {previous.Item}, {previous.Item}");
|
||||
OnContentChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnItemChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
Logger.LogDebug($"Media type changed: {Previous.Item}, {Previous.Item}");
|
||||
OnContentChange(GetEvent());
|
||||
OnItemChange(GetEvent());
|
||||
}
|
||||
// PODCASTS
|
||||
else if(previous.Item is FullEpisode previousEp
|
||||
else if(Previous.Item is FullEpisode previousEp
|
||||
&& Live.Item is FullEpisode currentEp)
|
||||
{
|
||||
if(!eq.IsEqual(previousEp, currentEp)) {
|
||||
Logger.LogDebug($"Podcast changed: {previousEp.DisplayString()} -> {currentEp.DisplayString()}");
|
||||
OnItemChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
OnItemChange(GetEvent());
|
||||
}
|
||||
}
|
||||
else {
|
||||
Logger.LogError($"Unknown combination of previous and current playing contexts, [{Previous.DisplayString()}] [{Live.DisplayString()}]");
|
||||
throw new NotSupportedException("Unknown item combination");
|
||||
}
|
||||
|
||||
// CONTEXT
|
||||
if(!eq.IsEqual(previous.Context, Live.Context)) {
|
||||
Logger.LogDebug($"Context changed: {previous.Context.DisplayString()} -> {Live.Context.DisplayString()}");
|
||||
OnContextChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
if(!eq.IsEqual(Previous.Context, Live.Context)) {
|
||||
Logger.LogDebug($"Context changed: {Previous.Context.DisplayString()} -> {Live.Context.DisplayString()}");
|
||||
OnContextChange(GetEvent());
|
||||
}
|
||||
|
||||
// DEVICE
|
||||
if(!eq.IsEqual(previous?.Device, Live?.Device)) {
|
||||
Logger.LogDebug($"Device changed: {previous?.Device.DisplayString()} -> {Live?.Device.DisplayString()}");
|
||||
OnDeviceChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
if(!eq.IsEqual(Previous?.Device, Live?.Device)) {
|
||||
Logger.LogDebug($"Device changed: {Previous?.Device.DisplayString()} -> {Live?.Device.DisplayString()}");
|
||||
OnDeviceChange(GetEvent());
|
||||
}
|
||||
|
||||
// IS PLAYING
|
||||
if(previous.IsPlaying != Live.IsPlaying) {
|
||||
Logger.LogDebug($"Playing state changed: {previous.IsPlaying} -> {Live.IsPlaying}");
|
||||
OnPlayingChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
if(Previous.IsPlaying != Live.IsPlaying) {
|
||||
Logger.LogDebug($"Playing state changed: {Previous.IsPlaying} -> {Live.IsPlaying}");
|
||||
OnPlayingChange(GetEvent());
|
||||
}
|
||||
|
||||
// VOLUME
|
||||
if(previous.Device.VolumePercent != Live.Device.VolumePercent) {
|
||||
Logger.LogDebug($"Volume changed: {previous.Device.VolumePercent}% -> {Live.Device.VolumePercent}%");
|
||||
OnVolumeChange(ListeningChangeEventArgs.From(previous, Live, Past, id: Id, username: SpotifyUsername));
|
||||
if(Previous.Device.VolumePercent != Live.Device.VolumePercent) {
|
||||
Logger.LogDebug($"Volume changed: {Previous.Device.VolumePercent}% -> {Live.Device.VolumePercent}%");
|
||||
OnVolumeChange(GetEvent());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,6 +179,8 @@ namespace Selector
|
||||
}
|
||||
}
|
||||
|
||||
private ListeningChangeEventArgs GetEvent() => ListeningChangeEventArgs.From(Previous, Live, Past, id: Id, username: SpotifyUsername);
|
||||
|
||||
/// <summary>
|
||||
/// Store currently playing in last plays. Determine whether new list or appending required
|
||||
/// </summary>
|
||||
@ -182,6 +191,11 @@ namespace Selector
|
||||
}
|
||||
|
||||
#region Event Firers
|
||||
protected virtual void OnNetworkPoll(ListeningChangeEventArgs args)
|
||||
{
|
||||
NetworkPoll?.Invoke(this, args);
|
||||
}
|
||||
|
||||
protected virtual void OnItemChange(ListeningChangeEventArgs args)
|
||||
{
|
||||
ItemChange?.Invoke(this, args);
|
||||
|
Loading…
Reference in New Issue
Block a user