past page QOL
This commit is contained in:
parent
20232f4abe
commit
99cb615161
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using IF.Lastfm.Core.Objects;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Selector.Cache;
|
||||
@ -49,6 +51,16 @@ namespace Selector.Web.Hubs
|
||||
|
||||
}
|
||||
|
||||
private static IEnumerable<string> AlbumSuffixes = new[]
|
||||
{
|
||||
" (Deluxe)",
|
||||
" (Deluxe Edition)",
|
||||
" (Special)",
|
||||
" (Special Edition)",
|
||||
" (Expanded)",
|
||||
" (Expanded Edition)",
|
||||
};
|
||||
|
||||
public async Task OnSubmitted(PastParams param)
|
||||
{
|
||||
param.Track = string.IsNullOrWhiteSpace(param.Track) ? null : param.Track;
|
||||
@ -67,38 +79,49 @@ namespace Selector.Web.Hubs
|
||||
to: to
|
||||
).ToArray();
|
||||
|
||||
Parallel.ForEach(listenQuery, (listen) =>
|
||||
{
|
||||
foreach (var suffix in AlbumSuffixes)
|
||||
{
|
||||
if (listen.AlbumName.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
listen.AlbumName = listen.AlbumName.Substring(0, listen.AlbumName.Length - suffix.Length);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var artistGrouped = listenQuery
|
||||
.GroupBy(x => x.ArtistName)
|
||||
.GroupBy(x => x.ArtistName.ToLowerInvariant())
|
||||
.Select(x => (x.Key, x.Count()))
|
||||
.OrderByDescending(x => x.Item2)
|
||||
.Take(20)
|
||||
.Take(pastOptions.Value.RankingCount)
|
||||
.ToArray();
|
||||
|
||||
var albumGrouped = listenQuery
|
||||
.GroupBy(x => (x.AlbumName, x.ArtistName))
|
||||
.Select(x => (x.Key, x.Count()))
|
||||
.GroupBy(x => (x.AlbumName.ToLowerInvariant(), x.ArtistName.ToLowerInvariant()))
|
||||
.Select(x => (x.Key, x.Count(), $"{x.FirstOrDefault()?.AlbumName} // {x.FirstOrDefault()?.ArtistName}"))
|
||||
.OrderByDescending(x => x.Item2)
|
||||
.Take(20)
|
||||
.Take(pastOptions.Value.RankingCount)
|
||||
.ToArray();
|
||||
|
||||
var trackGrouped = listenQuery
|
||||
.GroupBy(x => (x.TrackName, x.ArtistName))
|
||||
.Select(x => (x.Key, x.Count()))
|
||||
.GroupBy(x => (x.TrackName.ToLowerInvariant(), x.ArtistName.ToLowerInvariant()))
|
||||
.Select(x => (x.Key, x.Count(), $"{x.FirstOrDefault()?.TrackName} // {x.FirstOrDefault()?.ArtistName}"))
|
||||
.OrderByDescending(x => x.Item2)
|
||||
.Take(20)
|
||||
.Take(pastOptions.Value.RankingCount)
|
||||
.ToArray();
|
||||
|
||||
await Clients.Caller.OnRankResult(new()
|
||||
{
|
||||
TrackEntries = trackGrouped.Select(x => new ChartEntry()
|
||||
{
|
||||
Name = $"{x.Key.TrackName} - {x.Key.ArtistName}",
|
||||
Name = x.Item3,
|
||||
Value = x.Item2
|
||||
}).ToArray(),
|
||||
|
||||
AlbumEntries = albumGrouped.Select(x => new ChartEntry()
|
||||
{
|
||||
Name = $"{x.Key.AlbumName} - {x.Key.ArtistName}",
|
||||
Name = x.Item3,
|
||||
Value = x.Item2
|
||||
}).ToArray(),
|
||||
|
||||
|
@ -9,9 +9,9 @@
|
||||
<div id="pastapp" class="app col-12">
|
||||
<div class="card" style="width: 100%">
|
||||
<div>
|
||||
<input v-model="track" class="form-input form-control" placeholder="Track" />
|
||||
<input v-model="album" class="form-input form-control" placeholder="Album" />
|
||||
<input v-model="artist" class="form-input form-control" placeholder="Artist" />
|
||||
<input v-model="track" class="form-input form-control" placeholder="Track" v-on:keyup.enter="submit" />
|
||||
<input v-model="album" class="form-input form-control" placeholder="Album" v-on:keyup.enter="submit" />
|
||||
<input v-model="artist" class="form-input form-control" placeholder="Artist" v-on:keyup.enter="submit" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="from-picker">From</label>
|
||||
@ -27,7 +27,6 @@
|
||||
<count-card :count="totalCount"></count-card>
|
||||
|
||||
<play-count-chart-card :data_points="resampledSeries"
|
||||
:title="'Time Series'"
|
||||
:chart_id="'time_series'"
|
||||
:colour="'#ffffff'"
|
||||
v-if="resampledSeries.length > 0"></play-count-chart-card>
|
||||
@ -37,6 +36,11 @@
|
||||
<rank-card :title="'Album'" :entries="albumEntries" v-if="albumEntries.length > 1"></rank-card>
|
||||
<rank-card :title="'Artist'" :entries="artistEntries" v-if="artistEntries.length > 1"></rank-card>
|
||||
</div>
|
||||
|
||||
<album-chart-card :data_points="mutatedAlbums"
|
||||
:chart_id="'past'"
|
||||
:colour="'#ffffff'"
|
||||
v-if="albumEntries.length > 1"></album-chart-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -52,7 +52,7 @@ export let PlayCountChartCard: Vue.Component = {
|
||||
},
|
||||
scales: {
|
||||
yAxis: {
|
||||
suggestedMin: 0
|
||||
beginAtZero: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'time',
|
||||
@ -112,7 +112,7 @@ export let CombinedPlayCountChartCard: Vue.Component = {
|
||||
},
|
||||
scales: {
|
||||
yAxis: {
|
||||
suggestedMin: 0
|
||||
beginAtZero: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'time',
|
||||
|
48
Selector.Web/scripts/Past/BarGraphCard.ts
Normal file
48
Selector.Web/scripts/Past/BarGraphCard.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import * as Vue from "vue";
|
||||
import { Chart, BarElement, BarController } from "chart.js";
|
||||
import 'chartjs-adapter-luxon';
|
||||
import { CountSample, RankEntry } from "scripts/HubInterfaces";
|
||||
|
||||
Chart.register(BarElement, BarController);
|
||||
|
||||
export let BarChartCard: Vue.Component = {
|
||||
props: ['data_points', 'title', 'chart_id', 'link', 'earliest_date', 'latest_date', 'colour'],
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
datasets: [{
|
||||
data: this.data_points.map((e: RankEntry) => {
|
||||
return {x: e.name, y: e.value};
|
||||
}),
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
chartId() {
|
||||
return "bar-chart-" + this.chart_id;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`
|
||||
<div class="chart-card card" style="width: 100%">
|
||||
<h1>{{ title }}</h1>
|
||||
<canvas :id="chartId"></canvas>
|
||||
<lastfm-logo :link="link" v-if="link" />
|
||||
</div>
|
||||
`,
|
||||
mounted() {
|
||||
new Chart(`bar-chart-${this.chart_id}`, {
|
||||
type: "bar",
|
||||
data: this.chartData,
|
||||
options: {
|
||||
backgroundColor: 'white',
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -3,12 +3,21 @@ import * as Vue from "vue";
|
||||
export let CountCard: Vue.Component = {
|
||||
props: ['count'],
|
||||
computed: {
|
||||
|
||||
formattedCount() {
|
||||
if(this.count != null)
|
||||
{
|
||||
return this.count.toLocaleString()
|
||||
}
|
||||
else
|
||||
{
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
},
|
||||
template:
|
||||
`
|
||||
<div class="card">
|
||||
<h2>{{ count }}</h2>
|
||||
<h2>{{ formattedCount }}</h2>
|
||||
</div>
|
||||
`
|
||||
}
|
@ -6,9 +6,11 @@ import { RankCard } from "./Past/RankCard";
|
||||
import { CountCard } from "./Past/CountCard";
|
||||
import { PlayCountChartCard } from "./Now/PlayCountGraph";
|
||||
import { LastFmLogoLink } from "./Now/LastFm";
|
||||
import { BarChartCard } from "./Past/BarGraphCard";
|
||||
|
||||
const connection = new signalR.HubConnectionBuilder()
|
||||
.withUrl("/pasthub")
|
||||
.withAutomaticReconnect()
|
||||
.build();
|
||||
|
||||
connection.start()
|
||||
@ -60,12 +62,26 @@ const app = Vue.createApp({
|
||||
|
||||
console.log(context);
|
||||
|
||||
this.trackEntries = [];
|
||||
this.albumEntries = [];
|
||||
this.artistEntries = [];
|
||||
this.resampledSeries = [];
|
||||
|
||||
connection.invoke("OnSubmitted", context);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mutatedAlbums() {
|
||||
return this.albumEntries.map((e: RankEntry) => {
|
||||
e.name = e.name.split(' // ')[0];
|
||||
return e;
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
app.component("play-count-chart-card", PlayCountChartCard);
|
||||
app.component("album-chart-card", BarChartCard);
|
||||
app.component("rank-card", RankCard);
|
||||
app.component("lastfm-logo", LastFmLogoLink);
|
||||
app.component("count-card", CountCard);
|
||||
|
@ -24,6 +24,7 @@ namespace Selector
|
||||
public const string Key = "Past";
|
||||
|
||||
public TimeSpan ResampleWindow { get; set; } = TimeSpan.FromDays(7);
|
||||
public int RankingCount { get; set; } = 20;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user