ui tweaks, scrobble matcher trailing dupes

This commit is contained in:
andy 2022-06-22 21:51:38 +01:00
parent 63df0ab0c2
commit 079e126648
10 changed files with 119 additions and 49 deletions

View File

@ -1,13 +1,29 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Selector.Model.Extensions namespace Selector.Model.Extensions
{ {
public static class ScrobbleRepositoryExtensions public static class ScrobbleRepositoryExtensions
{ {
public static int CountToday(this IScrobbleRepository repo, string userId = null, string username = null, string track = null, string album = null, string artist = null)
{
if (!string.IsNullOrWhiteSpace(userId))
{
return repo.Count(userId: userId, from: DateTime.Now.ToUniversalTime().Date,
artistName: artist,
albumName: album,
trackName: track);
}
else if (!string.IsNullOrWhiteSpace(username))
{
return repo.Count(username: username, from: DateTime.Now.ToUniversalTime().Date,
artistName: artist,
albumName: album,
trackName: track);
}
else
{
throw new ArgumentNullException("user");
}
}
} }
} }

View File

@ -83,3 +83,29 @@ input[type=text], input[type=email], input[type=tel], input[type=password] {
color: $text-color; color: $text-color;
} }
} }
.card {
background-color: #333232;
color: $text-color;
margin: 5px;
padding: 15px;
box-shadow: 4px 4px 2px $shadow-color;
transition: box-shadow 0.5s;
&:hover {
box-shadow: none;
offset: 4px 4px;
}
}
.daily-scrobbles-card {
margin-top: 30px;
margin-left: auto;
margin-right: auto;
max-width: 250px;
p {
margin: 10px;
font-size: 45px;
}
}

View File

@ -5,20 +5,6 @@
$text-color: white; $text-color: white;
$shadow-color: #1e1e1e; $shadow-color: #1e1e1e;
.card {
background-color: #333232;
color: $text-color;
margin: 5px;
padding: 15px;
box-shadow: 4px 4px 2px $shadow-color;
transition: box-shadow 0.5s;
&:hover {
box-shadow: none;
offset: 4px 4px;
}
}
.now-playing-card { .now-playing-card {
// max-width: 300px; // max-width: 300px;

View File

@ -1,13 +1,23 @@
@page @page
@model IndexModel @model IndexModel
@{ @{
ViewData["Title"] = "Home page"; ViewData["Title"] = "Selector";
} }
<div class="text-center"> <div class="text-center">
<h1 class="display-4">Welcome</h1> <h1 class="display-4">run that</h1>
<p>Selector is a tool for monitoring Spotify usage.</p> <p>Selector is a live dashboard that presents Spotify data with Last.fm listening stats.</p>
<a href="/now" class="dash-underline-lg link-dark" style="">Now Playing</a> <a href="/now" class="dash-underline-lg link-dark" style="">Now Playing</a>
@if(Model.DailyScrobbles is not null)
{
<div class="card daily-scrobbles-card">
<h3>Today</h3>
<p style="margin: 30px">@Model.DailyScrobbles</p>
<img src="/last-fm.png" class="lastfm-logo" v-else>
</div>
}
</div> </div>

View File

@ -6,6 +6,9 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Identity;
using Selector.Model;
using Selector.Model.Extensions;
namespace Selector.Web.Pages namespace Selector.Web.Pages
{ {
@ -13,15 +16,29 @@ namespace Selector.Web.Pages
public class IndexModel : PageModel public class IndexModel : PageModel
{ {
private readonly ILogger<IndexModel> _logger; private readonly ILogger<IndexModel> _logger;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IScrobbleRepository _scrobbleRepo;
public IndexModel(ILogger<IndexModel> logger) public IndexModel(ILogger<IndexModel> logger, UserManager<ApplicationUser> userManager, IScrobbleRepository scrobbleRepo)
{ {
_logger = logger; _logger = logger;
_userManager = userManager;
_scrobbleRepo = scrobbleRepo;
} }
[BindProperty]
public int? DailyScrobbles { get; set; }
public void OnGet() public void OnGet()
{ {
if(User.Identity.IsAuthenticated)
{
var user = _userManager.GetUserAsync(User).Result;
if(user.ScrobbleSavingEnabled())
{
DailyScrobbles = _scrobbleRepo.CountToday(userId: user.Id);
}
}
} }
} }
} }

View File

@ -1,7 +1,7 @@
@page @page
@model NowModel @model NowModel
@{ @{
ViewData["Title"] = "Now"; ViewData["Title"] = "Now - Selector";
} }
<div class="text-center"> <div class="text-center">

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Selector</title> <title>@ViewData["Title"]</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link href="~/css/index.min.css" rel="stylesheet"> <link href="~/css/index.min.css" rel="stylesheet">
</head> </head>
@ -33,13 +33,15 @@
<div class="container"> <div class="container">
&copy; 2021 - Selector.Web - <a asp-area="" asp-page="/Privacy">Privacy</a> &copy; 2021 - Selector.Web - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div> </div>
<img src="/andy.png" <a href="https://sarsoo.xyz/selector/">
alt="AP" <img src="/andy.png"
width="120px" alt="AP"
style="display: block; width="120px"
margin-left: auto; style="display: block;
margin-right: auto; margin-left: auto;
padding: 8px"> margin-right: auto;
padding: 8px">
</a>
</footer> </footer>
@await RenderSectionAsync("Scripts", required: false) @await RenderSectionAsync("Scripts", required: false)

View File

@ -7,7 +7,7 @@ Chart.register(LineController, CategoryScale, LinearScale, TimeSeriesScale, Poin
const months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]; const months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
export let PlayCountChartCard: Vue.Component = { export let PlayCountChartCard: Vue.Component = {
props: ['data_points', 'title', 'chart_id'], props: ['data_points', 'title', 'chart_id', 'link'],
data() { data() {
return { return {
chartData: { chartData: {
@ -33,6 +33,7 @@ export let PlayCountChartCard: Vue.Component = {
<div class="card info-card chart-card"> <div class="card info-card chart-card">
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
<canvas :id="chartId"></canvas> <canvas :id="chartId"></canvas>
<lastfm-logo :link="link" />
</div> </div>
`, `,
mounted() { mounted() {
@ -56,6 +57,9 @@ export let PlayCountChartCard: Vue.Component = {
// } // }
}, },
scales: { scales: {
yAxis: {
suggestedMin: 0
}
} }
} }
}) })

View File

@ -55,13 +55,13 @@ const app = Vue.createApp({
return ""; return "";
}, },
showArtistChart(){ showArtistChart(){
return this.playCount !== null && this.playCount !== undefined && this.playCount.artistCountData.length > 0; return this.playCount !== null && this.playCount !== undefined && this.playCount.artistCountData.length > 3;
}, },
showAlbumChart() { showAlbumChart() {
return this.playCount !== null && this.playCount !== undefined && this.playCount.albumCountData.length > 0; return this.playCount !== null && this.playCount !== undefined && this.playCount.albumCountData.length > 3;
}, },
showTrackChart(){ showTrackChart(){
return this.playCount !== null && this.playCount !== undefined && this.playCount.trackCountData.length > 0; return this.playCount !== null && this.playCount !== undefined && this.playCount.trackCountData.length > 3;
} }
}, },
created() { created() {

View File

@ -23,27 +23,36 @@ namespace Selector
var toAdd = new List<Scrobble>(); var toAdd = new List<Scrobble>();
var toRemove = new List<Scrobble>(); var toRemove = new List<Scrobble>();
var toApplyOverrun = false;
if (toApplyIter.MoveNext()) if (toApplyIter.MoveNext())
{ {
if (existing.Any()) if (existing.Any())
{ {
foreach (var currentExisting in existing) foreach (var currentExisting in existing)
{ {
while (toApplyIter.Current.Timestamp < currentExisting.Timestamp) if (!toApplyOverrun)
{ {
toAdd.Add(toApplyIter.Current); while (toApplyIter.Current.Timestamp < currentExisting.Timestamp)
toApplyIter.MoveNext();
}
if (MatchTime(currentExisting, toApplyIter.Current))
{
if (matchContents)
{ {
MatchData(currentExisting, toApplyIter.Current); toAdd.Add(toApplyIter.Current);
toApplyIter.MoveNext();
} }
toApplyIter.MoveNext(); if (MatchTime(currentExisting, toApplyIter.Current))
{
if (matchContents)
{
MatchData(currentExisting, toApplyIter.Current);
}
toApplyOverrun = !toApplyIter.MoveNext();
}
else
{
toRemove.Add(currentExisting);
}
} }
else else
{ {
@ -51,7 +60,7 @@ namespace Selector
} }
} }
if (toApplyIter.Current is not null) if (toApplyIter.Current is not null && !toApplyOverrun)
{ {
toAdd.Add(toApplyIter.Current); toAdd.Add(toApplyIter.Current);