diff --git a/README.md b/README.md index 025f0eb..7a589c5 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,6 @@ ![ci](https://github.com/sarsoo/Selector/actions/workflows/ci.yml/badge.svg) -Investigating a Spotify listening agent \ No newline at end of file +Selector is a suite for monitoring and reacting to live changes on a Spotify account. The player watcher keeps an eye on what you're listening to and fires off events when things change. The idea is that various pieces of information will be collated and presented in a now-playing-style dashboard. + +Last.fm play counts will be collected, as will the Spotify audio features. \ No newline at end of file diff --git a/Selector.Cache/Key.cs b/Selector.Cache/Key.cs index 5c46f4d..ef83340 100644 --- a/Selector.Cache/Key.cs +++ b/Selector.Cache/Key.cs @@ -16,6 +16,8 @@ namespace Selector.Cache public const string PlayCountName = "PlayCount"; public const string WorkerName = "Worker"; + public const string WatcherName = "Watcher"; + public const string ReservedName = "Reserved"; /// /// Current playback for a user @@ -29,6 +31,8 @@ namespace Selector.Cache public static string AlbumPlayCount(string name, string artist) => Namespace(AlbumName, artist, name, PlayCountName); public static string ArtistPlayCount(string name) => Namespace(ArtistName, name, PlayCountName); + public static string WatcherReserved(int id) => Namespace(WatcherName, id.ToString(), ReservedName); + public static string Namespace(params string[] args) => string.Join(":", args); } } diff --git a/Selector.Model/ApplicationDbContext.cs b/Selector.Model/ApplicationDbContext.cs index b0211c0..69f565d 100644 --- a/Selector.Model/ApplicationDbContext.cs +++ b/Selector.Model/ApplicationDbContext.cs @@ -1,22 +1,31 @@ using System; using System.IO; +using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; namespace Selector.Model { public class ApplicationDbContext : IdentityDbContext { + private readonly ILogger Logger; + public DbSet Watcher { get; set; } - public ApplicationDbContext(DbContextOptions options) : base(options) + public ApplicationDbContext( + DbContextOptions options, + ILogger logger + ) : base(options) { - + Logger = logger; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) @@ -35,6 +44,22 @@ namespace Selector.Model SeedData.Seed(modelBuilder); } + + public void CreatePlayerWatcher(string userId) + { + if(Watcher.Any(w => w.UserId == userId && w.Type == WatcherType.Player)) + { + Logger.LogWarning($"Trying to create more than one player watcher for user [{userId}]"); + return; + } + + Watcher.Add(new Watcher { + UserId = userId, + Type = WatcherType.Player + }); + + SaveChanges(); + } } public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory @@ -49,7 +74,7 @@ namespace Selector.Model var builder = new DbContextOptionsBuilder(); builder.UseNpgsql(configuration.GetConnectionString("Default")); - return new ApplicationDbContext(builder.Options); + return new ApplicationDbContext(builder.Options, NullLogger.Instance); } } } \ No newline at end of file diff --git a/Selector.Web/Areas/Identity/Pages/Account/Register.cshtml.cs b/Selector.Web/Areas/Identity/Pages/Account/Register.cshtml.cs index 142331f..45d8a81 100644 --- a/Selector.Web/Areas/Identity/Pages/Account/Register.cshtml.cs +++ b/Selector.Web/Areas/Identity/Pages/Account/Register.cshtml.cs @@ -23,17 +23,20 @@ namespace Selector.Web.Areas.Identity.Pages.Account { private readonly SignInManager _signInManager; private readonly UserManager _userManager; + private readonly ApplicationDbContext DbContext; private readonly ILogger _logger; private readonly IEmailSender _emailSender; public RegisterModel( UserManager userManager, SignInManager signInManager, + ApplicationDbContext dbContext, ILogger logger, IEmailSender emailSender) { _userManager = userManager; _signInManager = signInManager; + DbContext = dbContext; _logger = logger; _emailSender = emailSender; } @@ -84,6 +87,8 @@ namespace Selector.Web.Areas.Identity.Pages.Account var result = await _userManager.CreateAsync(user, Input.Password); if (result.Succeeded) { + DbContext.CreatePlayerWatcher(user.Id); + _logger.LogInformation("User created a new account with password."); var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); diff --git a/Selector.Web/scripts/Now/NowPlayingCard.ts b/Selector.Web/scripts/Now/NowPlayingCard.ts index ce38228..55f9735 100644 --- a/Selector.Web/scripts/Now/NowPlayingCard.ts +++ b/Selector.Web/scripts/Now/NowPlayingCard.ts @@ -24,7 +24,10 @@ let component: Vue.Component = { {{ artist.name }} - +
+ + +
@@ -36,7 +39,10 @@ let component: Vue.Component = {
{{ episode.show.publisher }}
- +
+ + +
diff --git a/Selector.Web/wwwroot/live.gif b/Selector.Web/wwwroot/live.gif new file mode 100644 index 0000000..e1d82b7 Binary files /dev/null and b/Selector.Web/wwwroot/live.gif differ