adding general cards, scrobble density, upgrading nuget packages
This commit is contained in:
parent
97659389af
commit
c8170415b9
@ -8,7 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@ -18,8 +18,8 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" 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" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||||
<PackageReference Include="NLog" Version="4.7.15" />
|
<PackageReference Include="NLog" Version="5.0.0" />
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
|
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
|
||||||
<PackageReference Include="Quartz" Version="3.4.0" />
|
<PackageReference Include="Quartz" Version="3.4.0" />
|
||||||
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.4.0" />
|
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.4.0" />
|
||||||
<PackageReference Include="SpotifyAPI.Web" Version="6.2.2" />
|
<PackageReference Include="SpotifyAPI.Web" Version="6.2.2" />
|
||||||
|
@ -12,20 +12,20 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="Moq" Version="4.17.2" />
|
<PackageReference Include="Moq" Version="4.18.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -12,6 +12,9 @@ using StackExchange.Redis;
|
|||||||
using Selector.Cache;
|
using Selector.Cache;
|
||||||
using Selector.Model;
|
using Selector.Model;
|
||||||
using Selector.Model.Extensions;
|
using Selector.Model.Extensions;
|
||||||
|
using Selector.Web.NowPlaying;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Selector.Web.Hubs
|
namespace Selector.Web.Hubs
|
||||||
{
|
{
|
||||||
@ -20,6 +23,7 @@ namespace Selector.Web.Hubs
|
|||||||
public Task OnNewPlaying(CurrentlyPlayingDTO context);
|
public Task OnNewPlaying(CurrentlyPlayingDTO context);
|
||||||
public Task OnNewAudioFeature(TrackAudioFeatures features);
|
public Task OnNewAudioFeature(TrackAudioFeatures features);
|
||||||
public Task OnNewPlayCount(PlayCount playCount);
|
public Task OnNewPlayCount(PlayCount playCount);
|
||||||
|
public Task OnNewCard(Card card);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NowPlayingHub: Hub<INowPlayingHubClient>
|
public class NowPlayingHub: Hub<INowPlayingHubClient>
|
||||||
@ -30,11 +34,14 @@ namespace Selector.Web.Hubs
|
|||||||
private readonly ApplicationDbContext Db;
|
private readonly ApplicationDbContext Db;
|
||||||
private readonly IScrobbleRepository ScrobbleRepository;
|
private readonly IScrobbleRepository ScrobbleRepository;
|
||||||
|
|
||||||
|
private readonly IOptions<NowPlayingOptions> nowOptions;
|
||||||
|
|
||||||
public NowPlayingHub(
|
public NowPlayingHub(
|
||||||
IDatabaseAsync cache,
|
IDatabaseAsync cache,
|
||||||
AudioFeaturePuller featurePuller,
|
AudioFeaturePuller featurePuller,
|
||||||
ApplicationDbContext db,
|
ApplicationDbContext db,
|
||||||
IScrobbleRepository scrobbleRepository,
|
IScrobbleRepository scrobbleRepository,
|
||||||
|
IOptions<NowPlayingOptions> options,
|
||||||
PlayCountPuller playCountPuller = null
|
PlayCountPuller playCountPuller = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -43,6 +50,7 @@ namespace Selector.Web.Hubs
|
|||||||
PlayCountPuller = playCountPuller;
|
PlayCountPuller = playCountPuller;
|
||||||
Db = db;
|
Db = db;
|
||||||
ScrobbleRepository = scrobbleRepository;
|
ScrobbleRepository = scrobbleRepository;
|
||||||
|
nowOptions = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnConnected()
|
public async Task OnConnected()
|
||||||
@ -108,5 +116,51 @@ namespace Selector.Web.Hubs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendFacts(string track, string artist, string album, string albumArtist)
|
||||||
|
{
|
||||||
|
var user = Db.Users
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(u => u.Id == Context.UserIdentifier)
|
||||||
|
.SingleOrDefault()
|
||||||
|
?? throw new SqlNullValueException("No user returned");
|
||||||
|
|
||||||
|
if (user.ScrobbleSavingEnabled())
|
||||||
|
{
|
||||||
|
var artistScrobbles = ScrobbleRepository.GetAll(userId: user.Id, artistName: artist, from: GetMaximumWindow()).ToArray();
|
||||||
|
var artistDensity = artistScrobbles.Density(DateTime.UtcNow - nowOptions.Value.ArtistDensityWindow, DateTime.UtcNow);
|
||||||
|
|
||||||
|
if (artistDensity > nowOptions.Value.ArtistDensityThreshold)
|
||||||
|
{
|
||||||
|
await Clients.Caller.OnNewCard(new()
|
||||||
|
{
|
||||||
|
Content = $"You're on a {artist} binge! {artistDensity} plays/day recently"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var albumDensity = artistScrobbles.Where(s => s.AlbumName.Equals(album, StringComparison.InvariantCultureIgnoreCase)).Density(DateTime.UtcNow - nowOptions.Value.AlbumDensityWindow, DateTime.UtcNow);
|
||||||
|
|
||||||
|
if (albumDensity > nowOptions.Value.AlbumDensityThreshold)
|
||||||
|
{
|
||||||
|
await Clients.Caller.OnNewCard(new()
|
||||||
|
{
|
||||||
|
Content = $"You're on a {album} binge! {albumDensity} plays/day recently"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var trackDensity = artistScrobbles.Where(s => s.TrackName.Equals(track, StringComparison.InvariantCultureIgnoreCase)).Density(DateTime.UtcNow - nowOptions.Value.TrackDensityWindow, DateTime.UtcNow);
|
||||||
|
|
||||||
|
if (albumDensity > nowOptions.Value.TrackDensityThreshold)
|
||||||
|
{
|
||||||
|
await Clients.Caller.OnNewCard(new()
|
||||||
|
{
|
||||||
|
Content = $"You're on a {track} binge! {trackDensity} plays/day recently"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime GetMaximumWindow() => GetMaximumWindow(new TimeSpan[] { nowOptions.Value.ArtistDensityWindow, nowOptions.Value.AlbumDensityWindow, nowOptions.Value.TrackDensityWindow });
|
||||||
|
private DateTime GetMaximumWindow(IEnumerable<TimeSpan> windows) => windows.Select(w => DateTime.UtcNow - w).Min();
|
||||||
}
|
}
|
||||||
}
|
}
|
9
Selector.Web/NowPlaying/Card.cs
Normal file
9
Selector.Web/NowPlaying/Card.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
namespace Selector.Web.NowPlaying
|
||||||
|
{
|
||||||
|
public class Card
|
||||||
|
{
|
||||||
|
public string Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace Selector.Web
|
namespace Selector.Web
|
||||||
@ -8,6 +9,7 @@ namespace Selector.Web
|
|||||||
{
|
{
|
||||||
config.GetSection(RootOptions.Key).Bind(options);
|
config.GetSection(RootOptions.Key).Bind(options);
|
||||||
config.GetSection(FormatKeys(new[] { RootOptions.Key, RedisOptions.Key })).Bind(options.RedisOptions);
|
config.GetSection(FormatKeys(new[] { RootOptions.Key, RedisOptions.Key })).Bind(options.RedisOptions);
|
||||||
|
config.GetSection(FormatKeys(new[] { RootOptions.Key, NowPlayingOptions.Key })).Bind(options.NowOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RootOptions ConfigureOptions(IConfiguration config)
|
public static RootOptions ConfigureOptions(IConfiguration config)
|
||||||
@ -40,6 +42,7 @@ namespace Selector.Web
|
|||||||
public string LastfmSecret { get; set; }
|
public string LastfmSecret { get; set; }
|
||||||
|
|
||||||
public RedisOptions RedisOptions { get; set; } = new();
|
public RedisOptions RedisOptions { get; set; } = new();
|
||||||
|
public NowPlayingOptions NowOptions { get; set; } = new();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,4 +53,18 @@ namespace Selector.Web
|
|||||||
public bool Enabled { get; set; } = false;
|
public bool Enabled { get; set; } = false;
|
||||||
public string ConnectionString { get; set; }
|
public string ConnectionString { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NowPlayingOptions
|
||||||
|
{
|
||||||
|
public const string Key = "Now";
|
||||||
|
|
||||||
|
public TimeSpan ArtistDensityWindow { get; set; } = TimeSpan.FromDays(10);
|
||||||
|
public decimal ArtistDensityThreshold { get; set; } = 5;
|
||||||
|
|
||||||
|
public TimeSpan AlbumDensityWindow { get; set; } = TimeSpan.FromDays(10);
|
||||||
|
public decimal AlbumDensityThreshold { get; set; } = 5;
|
||||||
|
|
||||||
|
public TimeSpan TrackDensityWindow { get; set; } = TimeSpan.FromDays(10);
|
||||||
|
public decimal TrackDensityThreshold { get; set; } = 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<audio-feature-card :feature="trackFeatures" v-if="trackFeatures !== null && trackFeatures !== undefined" /></audio-feature-card>
|
<audio-feature-card :feature="trackFeatures" v-if="trackFeatures !== null && trackFeatures !== undefined" /></audio-feature-card>
|
||||||
<audio-feature-chart-card :feature="trackFeatures" v-if="trackFeatures !== null && trackFeatures !== undefined" /></audio-feature-chart-card>
|
<audio-feature-chart-card :feature="trackFeatures" v-if="trackFeatures !== null && trackFeatures !== undefined" /></audio-feature-chart-card>
|
||||||
<play-count-card :count="playCount" :track="lastfmTrack" :username="playCount.username" v-if="playCount !== null && playCount !== undefined" /></play-count-card>
|
<play-count-card :count="playCount" :track="lastfmTrack" :username="playCount.username" v-if="playCount !== null && playCount !== undefined" /></play-count-card>
|
||||||
<info-card v-for="card in cards" :html="card.html"></info-card>
|
<info-card v-for="card in cards" :html="card.content"></info-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"iisSettings": {
|
"iisSettings": {
|
||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
@ -17,7 +17,6 @@
|
|||||||
},
|
},
|
||||||
"Selector.Web": {
|
"Selector.Web": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": "true",
|
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.5" />
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@ -28,16 +28,20 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" 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.Hosting.WindowsServices" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.3" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.5" />
|
||||||
<PackageReference Include="NLog" Version="4.7.15" />
|
<PackageReference Include="NLog" Version="5.0.0" />
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
|
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\" />
|
<Folder Include="wwwroot\" />
|
||||||
|
<Folder Include="NowPlaying\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="NowPlaying\" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="appsettings.Development.json" Condition="Exists('appsettings.Development.json')">
|
<None Update="appsettings.Development.json" Condition="Exists('appsettings.Development.json')">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
12
Selector.Web/package-lock.json
generated
12
Selector.Web/package-lock.json
generated
@ -1011,9 +1011,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eventsource": {
|
"node_modules/eventsource": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.1.tgz",
|
||||||
"integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==",
|
"integrity": "sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"original": "^1.0.0"
|
"original": "^1.0.0"
|
||||||
},
|
},
|
||||||
@ -3613,9 +3613,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"eventsource": {
|
"eventsource": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.1.tgz",
|
||||||
"integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==",
|
"integrity": "sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"original": "^1.0.0"
|
"original": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ connection.start()
|
|||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
|
|
||||||
interface InfoCard {
|
interface InfoCard {
|
||||||
html: string
|
Content: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NowPlaying {
|
interface NowPlaying {
|
||||||
@ -64,6 +64,12 @@ const app = Vue.createApp({
|
|||||||
context.track.album.name,
|
context.track.album.name,
|
||||||
context.track.album.artists[0].name
|
context.track.album.artists[0].name
|
||||||
);
|
);
|
||||||
|
connection.invoke("SendFacts",
|
||||||
|
context.track.name,
|
||||||
|
context.track.artists[0].name,
|
||||||
|
context.track.album.name,
|
||||||
|
context.track.album.artists[0].name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -78,6 +84,12 @@ const app = Vue.createApp({
|
|||||||
console.log(count);
|
console.log(count);
|
||||||
this.playCount = count;
|
this.playCount = count;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connection.on("OnNewCard", (card: InfoCard) => {
|
||||||
|
|
||||||
|
console.log(card);
|
||||||
|
this.cards.push(card);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
29
Selector/Scrobble/PlayDensity.cs
Normal file
29
Selector/Scrobble/PlayDensity.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Selector
|
||||||
|
{
|
||||||
|
public static class PlayDensity
|
||||||
|
{
|
||||||
|
public static decimal Density(this IEnumerable<Scrobble> scrobbles, DateTime from, DateTime to)
|
||||||
|
{
|
||||||
|
var filteredScrobbles = scrobbles.Where(s => s.Timestamp > from && s.Timestamp < to);
|
||||||
|
|
||||||
|
var dayDelta = (decimal) (to - from).Days;
|
||||||
|
|
||||||
|
return filteredScrobbles.Count() / dayDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal Density(this IEnumerable<Scrobble> scrobbles)
|
||||||
|
{
|
||||||
|
var minDate = scrobbles.Select(s => s.Timestamp).Min();
|
||||||
|
var maxDate = scrobbles.Select(s => s.Timestamp).Max();
|
||||||
|
|
||||||
|
var dayDelta = (decimal) (maxDate - minDate).Days;
|
||||||
|
|
||||||
|
return scrobbles.Count() / dayDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user