added play count puller, play count rendering in UI
This commit is contained in:
parent
e9f593862e
commit
ab058c769f
@ -55,6 +55,7 @@ namespace Selector.CLI
|
|||||||
Console.WriteLine("> Adding Last.fm credentials...");
|
Console.WriteLine("> Adding Last.fm credentials...");
|
||||||
|
|
||||||
services.AddLastFm(config.LastfmClient, config.LastfmSecret);
|
services.AddLastFm(config.LastfmClient, config.LastfmSecret);
|
||||||
|
services.AddCachingLastFm();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ namespace Selector.Cache
|
|||||||
|
|
||||||
public void CacheCallback(object sender, AnalysedTrack e)
|
public void CacheCallback(object sender, AnalysedTrack e)
|
||||||
{
|
{
|
||||||
Task.Run(() => { return AsyncCacheCallback(e); }, CancelToken);
|
Task.Run(async () => { await AsyncCacheCallback(e); }, CancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AsyncCacheCallback(AnalysedTrack e)
|
public async Task AsyncCacheCallback(AnalysedTrack e)
|
||||||
|
@ -15,7 +15,7 @@ namespace Selector.Cache
|
|||||||
private readonly IPlayerWatcher Watcher;
|
private readonly IPlayerWatcher Watcher;
|
||||||
private readonly IDatabaseAsync Db;
|
private readonly IDatabaseAsync Db;
|
||||||
private readonly ILogger<CacheWriter> Logger;
|
private readonly ILogger<CacheWriter> Logger;
|
||||||
public TimeSpan CacheExpiry { get; set; } = TimeSpan.FromMinutes(10);
|
public TimeSpan CacheExpiry { get; set; } = TimeSpan.FromMinutes(20);
|
||||||
|
|
||||||
public CancellationToken CancelToken { get; set; }
|
public CancellationToken CancelToken { get; set; }
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ namespace Selector.Cache
|
|||||||
{
|
{
|
||||||
if (e.Current is null) return;
|
if (e.Current is null) return;
|
||||||
|
|
||||||
Task.Run(() => { return AsyncCallback(e); }, CancelToken);
|
Task.Run(async () => { await AsyncCallback(e); }, CancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
||||||
@ -57,6 +57,7 @@ namespace Selector.Cache
|
|||||||
if (watcher is IPlayerWatcher watcherCast)
|
if (watcher is IPlayerWatcher watcherCast)
|
||||||
{
|
{
|
||||||
watcherCast.ItemChange += Callback;
|
watcherCast.ItemChange += Callback;
|
||||||
|
watcherCast.PlayingChange += Callback;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -71,6 +72,7 @@ namespace Selector.Cache
|
|||||||
if (watcher is IPlayerWatcher watcherCast)
|
if (watcher is IPlayerWatcher watcherCast)
|
||||||
{
|
{
|
||||||
watcherCast.ItemChange -= Callback;
|
watcherCast.ItemChange -= Callback;
|
||||||
|
watcherCast.PlayingChange -= Callback;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ namespace Selector.Cache
|
|||||||
|
|
||||||
public void CacheCallback(object sender, PlayCount e)
|
public void CacheCallback(object sender, PlayCount e)
|
||||||
{
|
{
|
||||||
Task.Run(() => { return AsyncCacheCallback(e); }, CancelToken);
|
Task.Run(async () => { await AsyncCacheCallback(e); }, CancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AsyncCacheCallback(PlayCount e)
|
public async Task AsyncCacheCallback(PlayCount e)
|
||||||
|
@ -34,7 +34,7 @@ namespace Selector.Cache
|
|||||||
{
|
{
|
||||||
if (e.Current is null) return;
|
if (e.Current is null) return;
|
||||||
|
|
||||||
Task.Run(() => { return AsyncCallback(e); }, CancelToken);
|
Task.Run(async () => { await AsyncCallback(e); }, CancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
||||||
|
@ -42,5 +42,10 @@ namespace Selector.Cache.Extensions
|
|||||||
{
|
{
|
||||||
services.AddSingleton<AudioFeaturePuller>();
|
services.AddSingleton<AudioFeaturePuller>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddCachingLastFm(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<PlayCountPuller>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
174
Selector.Cache/Services/PlayCountPuller.cs
Normal file
174
Selector.Cache/Services/PlayCountPuller.cs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
using IF.Lastfm.Core.Api;
|
||||||
|
using IF.Lastfm.Core.Api.Helpers;
|
||||||
|
using IF.Lastfm.Core.Objects;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Selector.Cache
|
||||||
|
{
|
||||||
|
public class PlayCountPuller
|
||||||
|
{
|
||||||
|
private readonly IDatabaseAsync Cache;
|
||||||
|
private readonly ILogger<PlayCountPuller> Logger;
|
||||||
|
|
||||||
|
protected readonly ITrackApi TrackClient;
|
||||||
|
protected readonly IAlbumApi AlbumClient;
|
||||||
|
protected readonly IArtistApi ArtistClient;
|
||||||
|
protected readonly IUserApi UserClient;
|
||||||
|
|
||||||
|
public PlayCountPuller(
|
||||||
|
IDatabaseAsync cache,
|
||||||
|
ILogger<PlayCountPuller> logger,
|
||||||
|
|
||||||
|
ITrackApi trackClient,
|
||||||
|
IAlbumApi albumClient,
|
||||||
|
IArtistApi artistClient,
|
||||||
|
IUserApi userClient
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Cache = cache;
|
||||||
|
Logger = logger;
|
||||||
|
|
||||||
|
TrackClient = trackClient;
|
||||||
|
AlbumClient = albumClient;
|
||||||
|
ArtistClient = artistClient;
|
||||||
|
UserClient = userClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PlayCount> Get(string username, string track, string artist, string album, string albumArtist)
|
||||||
|
{
|
||||||
|
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 cacheTasks = new Task[] { trackCache, albumCache, artistCache, userCache };
|
||||||
|
|
||||||
|
await Task.WhenAll(cacheTasks);
|
||||||
|
|
||||||
|
PlayCount playCount = new()
|
||||||
|
{
|
||||||
|
Username = username
|
||||||
|
};
|
||||||
|
|
||||||
|
Task<LastResponse<LastTrack>> trackHttp = null;
|
||||||
|
Task<LastResponse<LastAlbum>> albumHttp = null;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
playCount.Track = (int) trackCache.Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trackHttp = TrackClient.GetInfoAsync(track, artist, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (albumCache.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
if (albumCache.Result == RedisValue.Null)
|
||||||
|
{
|
||||||
|
albumHttp = AlbumClient.GetInfoAsync(albumArtist, album, username: username);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playCount.Album = (int)albumCache.Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
albumHttp = AlbumClient.GetInfoAsync(albumArtist, album, username: username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (artistCache.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
if (artistCache.Result == RedisValue.Null)
|
||||||
|
{
|
||||||
|
artistHttp = ArtistClient.GetInfoAsync(artist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playCount.Artist = (int)artistCache.Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
artistHttp = ArtistClient.GetInfoAsync(artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userCache.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
if (userCache.Result == RedisValue.Null)
|
||||||
|
{
|
||||||
|
userHttp = UserClient.GetInfoAsync(username);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playCount.User = (int)userCache.Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
userHttp = UserClient.GetInfoAsync(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(new Task[] {trackHttp, albumHttp, artistHttp, userHttp}.Where(t => t is not null));
|
||||||
|
|
||||||
|
if (trackHttp is not null && trackHttp.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
if (trackHttp.Result.Success)
|
||||||
|
{
|
||||||
|
playCount.Track = trackHttp.Result.Content.UserPlayCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogDebug($"Track info error [{username}] [{trackHttp.Result.Status}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (albumHttp is not null && albumHttp.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
if (albumHttp.Result.Success)
|
||||||
|
{
|
||||||
|
playCount.Album = albumHttp.Result.Content.UserPlayCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogDebug($"Album info error [{username}] [{albumHttp.Result.Status}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Add artist count
|
||||||
|
|
||||||
|
if (userHttp is not null && userHttp.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
if (userHttp.Result.Success)
|
||||||
|
{
|
||||||
|
playCount.User = userHttp.Result.Content.Playcount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogDebug($"User info error [{username}] [{userHttp.Result.Status}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return playCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,18 +18,26 @@ 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 class NowPlayingHub: Hub<INowPlayingHubClient>
|
public class NowPlayingHub: Hub<INowPlayingHubClient>
|
||||||
{
|
{
|
||||||
private readonly IDatabaseAsync Cache;
|
private readonly IDatabaseAsync Cache;
|
||||||
private readonly AudioFeaturePuller AudioFeaturePuller;
|
private readonly AudioFeaturePuller AudioFeaturePuller;
|
||||||
|
private readonly PlayCountPuller PlayCountPuller;
|
||||||
private readonly ApplicationDbContext Db;
|
private readonly ApplicationDbContext Db;
|
||||||
|
|
||||||
public NowPlayingHub(IDatabaseAsync cache, AudioFeaturePuller puller, ApplicationDbContext db)
|
public NowPlayingHub(
|
||||||
|
IDatabaseAsync cache,
|
||||||
|
AudioFeaturePuller featurePuller,
|
||||||
|
ApplicationDbContext db,
|
||||||
|
PlayCountPuller playCountPuller = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Cache = cache;
|
Cache = cache;
|
||||||
AudioFeaturePuller = puller;
|
AudioFeaturePuller = featurePuller;
|
||||||
|
PlayCountPuller = playCountPuller;
|
||||||
Db = db;
|
Db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,5 +77,27 @@ namespace Selector.Web.Hubs
|
|||||||
await Clients.Caller.OnNewAudioFeature(feature);
|
await Clients.Caller.OnNewAudioFeature(feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendPlayCount(string track, string artist, string album, string albumArtist)
|
||||||
|
{
|
||||||
|
if(PlayCountPuller is not null)
|
||||||
|
{
|
||||||
|
var user = Db.Users
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(u => u.Id == Context.UserIdentifier)
|
||||||
|
.SingleOrDefault()
|
||||||
|
?? throw new SqlNullValueException("No user returned");
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(user.LastFmUsername))
|
||||||
|
{
|
||||||
|
var playCount = await PlayCountPuller.Get(user.LastFmUsername, track, artist, album, albumArtist);
|
||||||
|
|
||||||
|
if (playCount is not null)
|
||||||
|
{
|
||||||
|
await Clients.Caller.OnNewPlayCount(playCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -36,6 +36,8 @@ namespace Selector.Web
|
|||||||
/// Spotify callback for authentication
|
/// Spotify callback for authentication
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SpotifyCallback { get; set; }
|
public string SpotifyCallback { get; set; }
|
||||||
|
public string LastfmClient { get; set; }
|
||||||
|
public string LastfmSecret { get; set; }
|
||||||
|
|
||||||
public RedisOptions RedisOptions { get; set; } = new();
|
public RedisOptions RedisOptions { get; set; } = new();
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<popularity :track="currentlyPlaying.track" v-if="currentlyPlaying !== null && currentlyPlaying !== undefined && currentlyPlaying.track != null && currentlyPlaying.track != undefined" ></popularity>
|
<popularity :track="currentlyPlaying.track" v-if="currentlyPlaying !== null && currentlyPlaying !== undefined && currentlyPlaying.track != null && currentlyPlaying.track != undefined" ></popularity>
|
||||||
<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" 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.html"></info-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -99,6 +99,8 @@ namespace Selector.Web
|
|||||||
services.AddSpotify();
|
services.AddSpotify();
|
||||||
services.AddCachingSpotify();
|
services.AddCachingSpotify();
|
||||||
|
|
||||||
|
ConfigureLastFm(config, services);
|
||||||
|
|
||||||
services.AddCacheHubProxy();
|
services.AddCacheHubProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,5 +133,20 @@ namespace Selector.Web
|
|||||||
endpoints.MapHub<NowPlayingHub>("/hub");
|
endpoints.MapHub<NowPlayingHub>("/hub");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ConfigureLastFm(RootOptions config, IServiceCollection services)
|
||||||
|
{
|
||||||
|
if (config.LastfmClient is not null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("> Adding Last.fm credentials...");
|
||||||
|
|
||||||
|
services.AddLastFm(config.LastfmClient, config.LastfmSecret);
|
||||||
|
services.AddCachingLastFm();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("> No Last.fm credentials, skipping init...");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,22 @@ export interface nowPlayingProxy {
|
|||||||
export interface NowPlayingHubClient {
|
export interface NowPlayingHubClient {
|
||||||
OnNewPlaying: (context: CurrentlyPlayingDTO) => void;
|
OnNewPlaying: (context: CurrentlyPlayingDTO) => void;
|
||||||
OnNewAudioFeature: (features: TrackAudioFeatures) => void;
|
OnNewAudioFeature: (features: TrackAudioFeatures) => void;
|
||||||
|
OnNewPlayCount: (playCount: PlayCount) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NowPlayingHub {
|
export interface NowPlayingHub {
|
||||||
SendNewPlaying(context: CurrentlyPlayingDTO): void;
|
SendNewPlaying(context: CurrentlyPlayingDTO): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PlayCount {
|
||||||
|
track: number | null;
|
||||||
|
album: number | null;
|
||||||
|
artist: number | null;
|
||||||
|
user: number | null;
|
||||||
|
username: string;
|
||||||
|
listeningEvent: ListeningChangeEventArgs;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CurrentlyPlayingDTO {
|
export interface CurrentlyPlayingDTO {
|
||||||
context: CurrentlyPlayingContextDTO;
|
context: CurrentlyPlayingContextDTO;
|
||||||
username: string;
|
username: string;
|
||||||
|
14
Selector.Web/scripts/Now/LastFm.ts
Normal file
14
Selector.Web/scripts/Now/LastFm.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import * as Vue from "vue";
|
||||||
|
|
||||||
|
export let PlayCountCard: Vue.Component = {
|
||||||
|
props: ['count'],
|
||||||
|
template:
|
||||||
|
`
|
||||||
|
<div class="card info-card">
|
||||||
|
<h5 v-if="count.track != null && count.track != undefined" >Track: {{ count.track.toLocaleString() }}</h5>
|
||||||
|
<h5 v-if="count.album != null && count.album != undefined" >Album: {{ count.album.toLocaleString() }}</h5>
|
||||||
|
<h5 v-if="count.artist != null && count.artist != undefined" >Artist: {{ count.artist.toLocaleString() }}</h5>
|
||||||
|
<h5 v-if="count.user != null && count.user != undefined" >User: {{ count.user.toLocaleString() }}</h5>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
import * as signalR from "@microsoft/signalr";
|
import * as signalR from "@microsoft/signalr";
|
||||||
import * as Vue from "vue";
|
import * as Vue from "vue";
|
||||||
import { TrackAudioFeatures, CurrentlyPlayingDTO } from "./HubInterfaces";
|
import { TrackAudioFeatures, PlayCount, CurrentlyPlayingDTO } from "./HubInterfaces";
|
||||||
import NowPlayingCard from "./Now/NowPlayingCard";
|
import NowPlayingCard from "./Now/NowPlayingCard";
|
||||||
import { AudioFeatureCard, AudioFeatureChartCard, PopularityCard, SpotifyLogoLink } from "./Now/Spotify";
|
import { AudioFeatureCard, AudioFeatureChartCard, PopularityCard, SpotifyLogoLink } from "./Now/Spotify";
|
||||||
|
import { PlayCountCard } from "./Now/LastFm";
|
||||||
import BaseInfoCard from "./Now/BaseInfoCard";
|
import BaseInfoCard from "./Now/BaseInfoCard";
|
||||||
|
|
||||||
const connection = new signalR.HubConnectionBuilder()
|
const connection = new signalR.HubConnectionBuilder()
|
||||||
@ -22,6 +23,7 @@ interface InfoCard {
|
|||||||
interface NowPlaying {
|
interface NowPlaying {
|
||||||
currentlyPlaying?: CurrentlyPlayingDTO,
|
currentlyPlaying?: CurrentlyPlayingDTO,
|
||||||
trackFeatures?: TrackAudioFeatures,
|
trackFeatures?: TrackAudioFeatures,
|
||||||
|
playCount?: PlayCount,
|
||||||
cards: InfoCard[]
|
cards: InfoCard[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ const app = Vue.createApp({
|
|||||||
return {
|
return {
|
||||||
currentlyPlaying: undefined,
|
currentlyPlaying: undefined,
|
||||||
trackFeatures: undefined,
|
trackFeatures: undefined,
|
||||||
|
playCount: undefined,
|
||||||
cards: []
|
cards: []
|
||||||
} as NowPlaying
|
} as NowPlaying
|
||||||
},
|
},
|
||||||
@ -39,11 +42,18 @@ const app = Vue.createApp({
|
|||||||
console.log(context);
|
console.log(context);
|
||||||
this.currentlyPlaying = context;
|
this.currentlyPlaying = context;
|
||||||
this.trackFeatures = null;
|
this.trackFeatures = null;
|
||||||
|
this.playCount = null;
|
||||||
this.cards = [];
|
this.cards = [];
|
||||||
|
|
||||||
if(context.track !== null && context.track !== undefined)
|
if(context.track !== null && context.track !== undefined)
|
||||||
{
|
{
|
||||||
connection.invoke("SendAudioFeatures", context.track.id);
|
connection.invoke("SendAudioFeatures", context.track.id);
|
||||||
|
connection.invoke("SendPlayCount",
|
||||||
|
context.track.name,
|
||||||
|
context.track.artists[0].name,
|
||||||
|
context.track.album.name,
|
||||||
|
context.track.album.artists[0].name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,6 +62,12 @@ const app = Vue.createApp({
|
|||||||
console.log(feature);
|
console.log(feature);
|
||||||
this.trackFeatures = feature;
|
this.trackFeatures = feature;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connection.on("OnNewPlayCount", (count: PlayCount) => {
|
||||||
|
|
||||||
|
console.log(count);
|
||||||
|
this.playCount = count;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,4 +77,5 @@ app.component("audio-feature-chart-card", AudioFeatureChartCard);
|
|||||||
app.component("info-card", BaseInfoCard);
|
app.component("info-card", BaseInfoCard);
|
||||||
app.component("popularity", PopularityCard);
|
app.component("popularity", PopularityCard);
|
||||||
app.component("spotify-logo", SpotifyLogoLink);
|
app.component("spotify-logo", SpotifyLogoLink);
|
||||||
|
app.component("play-count-card", PlayCountCard);
|
||||||
const vm = app.mount('#app');
|
const vm = app.mount('#app');
|
@ -37,7 +37,7 @@ namespace Selector
|
|||||||
{
|
{
|
||||||
if (e.Current is null) return;
|
if (e.Current is null) return;
|
||||||
|
|
||||||
Task.Run(() => { return AsyncCallback(e); }, CancelToken);
|
Task.Run(async () => { await AsyncCallback(e); }, CancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
||||||
|
@ -52,7 +52,7 @@ namespace Selector
|
|||||||
{
|
{
|
||||||
if (e.Current is null) return;
|
if (e.Current is null) return;
|
||||||
|
|
||||||
Task.Run(() => { return AsyncCallback(e); }, CancelToken);
|
Task.Run(async () => { await AsyncCallback(e); }, CancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
public async Task AsyncCallback(ListeningChangeEventArgs e)
|
||||||
@ -62,7 +62,7 @@ namespace Selector
|
|||||||
Logger.LogTrace("Making Last.fm call");
|
Logger.LogTrace("Making Last.fm call");
|
||||||
|
|
||||||
var trackInfo = TrackClient.GetInfoAsync(track.Name, track.Artists[0].Name, username: Credentials?.Username);
|
var trackInfo = TrackClient.GetInfoAsync(track.Name, track.Artists[0].Name, username: Credentials?.Username);
|
||||||
var albumInfo = AlbumClient.GetInfoAsync(track.Album.Name, track.Album.Artists[0].Name, username: Credentials?.Username);
|
var albumInfo = AlbumClient.GetInfoAsync(track.Album.Artists[0].Name, track.Album.Name, username: Credentials?.Username);
|
||||||
var artistInfo = ArtistClient.GetInfoAsync(track.Artists[0].Name);
|
var artistInfo = ArtistClient.GetInfoAsync(track.Artists[0].Name);
|
||||||
// TODO: Null checking on credentials
|
// TODO: Null checking on credentials
|
||||||
var userInfo = UserClient.GetInfoAsync(Credentials.Username);
|
var userInfo = UserClient.GetInfoAsync(Credentials.Username);
|
||||||
|
@ -29,6 +29,18 @@ namespace Selector.Extensions
|
|||||||
var lastAuth = new LastAuth(client, secret);
|
var lastAuth = new LastAuth(client, secret);
|
||||||
services.AddSingleton(lastAuth);
|
services.AddSingleton(lastAuth);
|
||||||
services.AddTransient(sp => new LastfmClient(sp.GetService<LastAuth>()));
|
services.AddTransient(sp => new LastfmClient(sp.GetService<LastAuth>()));
|
||||||
|
|
||||||
|
services.AddTransient<ITrackApi>(sp => sp.GetService<LastfmClient>().Track);
|
||||||
|
services.AddTransient<IAlbumApi>(sp => sp.GetService<LastfmClient>().Album);
|
||||||
|
services.AddTransient<IArtistApi>(sp => sp.GetService<LastfmClient>().Artist);
|
||||||
|
|
||||||
|
services.AddTransient<IUserApi>(sp => sp.GetService<LastfmClient>().User);
|
||||||
|
|
||||||
|
services.AddTransient<IChartApi>(sp => sp.GetService<LastfmClient>().Chart);
|
||||||
|
services.AddTransient<ILibraryApi>(sp => sp.GetService<LastfmClient>().Library);
|
||||||
|
services.AddTransient<ITagApi>(sp => sp.GetService<LastfmClient>().Tag);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddWatcher(this IServiceCollection services)
|
public static void AddWatcher(this IServiceCollection services)
|
||||||
|
@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
using SpotifyAPI.Web;
|
using SpotifyAPI.Web;
|
||||||
|
|
||||||
namespace Selector.Cache {
|
namespace Selector {
|
||||||
|
|
||||||
public class CurrentlyPlayingDTO {
|
public class CurrentlyPlayingDTO {
|
||||||
public CurrentlyPlayingContextDTO Context { get; set; }
|
public CurrentlyPlayingContextDTO Context { get; set; }
|
Loading…
Reference in New Issue
Block a user