parent
9dfad73397
commit
d139dce719
@ -23,40 +23,39 @@ namespace Selector.CLI
|
||||
Console.WriteLine("~~~ Selector CLI ~~~");
|
||||
Console.WriteLine("");
|
||||
|
||||
Console.WriteLine("Configuring...");
|
||||
Console.WriteLine("> Configuring...");
|
||||
// CONFIG
|
||||
services.Configure<RootOptions>(options => {
|
||||
context.Configuration.GetSection(RootOptions.Key).Bind(options);
|
||||
context.Configuration.GetSection($"{RootOptions.Key}:{WatcherOptions.Key}").Bind(options.WatcherOptions);
|
||||
});
|
||||
var config = context.Configuration.GetSection(RootOptions.Key).Get<RootOptions>();
|
||||
|
||||
Console.WriteLine("Adding Services...");
|
||||
Console.WriteLine("> Adding Services...");
|
||||
// SERVICES
|
||||
services.AddSingleton<IWatcherFactory, WatcherFactory>();
|
||||
services.AddSingleton<IConsumerFactory, AudioFeatureInjectorFactory>();
|
||||
services.AddSingleton<IWatcherCollectionFactory, WatcherCollectionFactory>();
|
||||
// For generating spotify clients
|
||||
services.AddSingleton<IRefreshTokenFactoryProvider, RefreshTokenFactoryProvider>();
|
||||
//services.AddSingleton<IRefreshTokenFactoryProvider, RefreshTokenFactoryProvider>();
|
||||
services.AddSingleton<IRefreshTokenFactoryProvider, CachingRefreshTokenFactoryProvider>();
|
||||
|
||||
switch(context.Configuration.GetValue<EqualityChecker>("selector:equality"))
|
||||
switch(config.Equality)
|
||||
{
|
||||
case EqualityChecker.Uri:
|
||||
Console.WriteLine("Using Uri Equality");
|
||||
Console.WriteLine("> Using Uri Equality");
|
||||
services.AddTransient<IEqual, UriEqual>();
|
||||
break;
|
||||
case EqualityChecker.String:
|
||||
Console.WriteLine("Using String Equality");
|
||||
Console.WriteLine("> Using String Equality");
|
||||
services.AddTransient<IEqual, StringEqual>();
|
||||
break;
|
||||
}
|
||||
|
||||
// HOSTED SERVICES
|
||||
if(context.Configuration
|
||||
.GetSection($"{RootOptions.Key}:{WatcherOptions.Key}")
|
||||
.Get<WatcherOptions>()
|
||||
.Enabled)
|
||||
if(config.WatcherOptions.Enabled)
|
||||
{
|
||||
Console.WriteLine("Adding Watcher Service");
|
||||
Console.WriteLine("> Adding Watcher Service");
|
||||
services.AddHostedService<WatcherService>();
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
autoReload="true"
|
||||
internalLogFile=".\selector.nlog.log"
|
||||
internalLogLevel="Info" >
|
||||
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
autoReload="true"
|
||||
throwConfigExceptions="true"
|
||||
internalLogFile=".\log\selector.nlog.log"
|
||||
internalLogLevel="Info" >
|
||||
|
||||
<variable name="format"
|
||||
value="${longdate}|${level:uppercase=true}|${callsite}:${callsite-linenumber}|${message}${onexception:inner=${newline}}${exception:format=tostring,data:exceptionDataSeparator=\r\n}"/>
|
||||
|
||||
<!-- the targets to write to -->
|
||||
<targets>
|
||||
<!-- write logs to file -->
|
||||
<target xsi:type="File"
|
||||
name="logfile"
|
||||
fileName=".\selector.log"
|
||||
<target xsi:type="File"
|
||||
name="logfile"
|
||||
fileName=".\log\selector-${shortdate}.log"
|
||||
layout="${format}" />
|
||||
<target xsi:type="File"
|
||||
name="tracefile"
|
||||
fileName=".\selector.trace.log"
|
||||
<target xsi:type="File"
|
||||
name="tracefile"
|
||||
fileName=".\log\selector.trace-${shortdate}.log"
|
||||
layout="${format}" />
|
||||
<target xsi:type="Console"
|
||||
<target xsi:type="Console"
|
||||
name="logconsole"
|
||||
layout="${format}" />
|
||||
</targets>
|
||||
@ -29,7 +30,6 @@
|
||||
<rules>
|
||||
<logger name="*" minlevel="Debug" writeTo="logfile" />
|
||||
<logger name="*" minlevel="Trace" writeTo="tracefile" />
|
||||
|
||||
<logger name="Selector.*" minlevel="Debug" writeTo="logconsole" />
|
||||
</rules>
|
||||
</nlog>
|
@ -42,11 +42,28 @@ namespace Selector
|
||||
{
|
||||
if (e.Current.Item is FullTrack track)
|
||||
{
|
||||
Logger.LogTrace("Making Spotify call");
|
||||
var audioFeatures = await TrackClient.GetAudioFeatures(track.Id);
|
||||
Logger.LogDebug($"Adding audio features [{track.DisplayString()}]: [{audioFeatures.DisplayString()}]");
|
||||
try {
|
||||
Logger.LogTrace("Making Spotify call");
|
||||
var audioFeatures = await TrackClient.GetAudioFeatures(track.Id);
|
||||
Logger.LogDebug($"Adding audio features [{track.DisplayString()}]: [{audioFeatures.DisplayString()}]");
|
||||
|
||||
Timeline.Add(AnalysedTrack.From(track, audioFeatures));
|
||||
Timeline.Add(AnalysedTrack.From(track, audioFeatures), DateHelper.FromUnixMilli(e.Current.Timestamp));
|
||||
}
|
||||
catch (APIUnauthorizedException ex)
|
||||
{
|
||||
Logger.LogDebug($"Unauthorised error: [{ex.Message}] (should be refreshed and retried?)");
|
||||
//throw ex;
|
||||
}
|
||||
catch (APITooManyRequestsException ex)
|
||||
{
|
||||
Logger.LogDebug($"Too many requests error: [{ex.Message}]");
|
||||
throw ex;
|
||||
}
|
||||
catch (APIException ex)
|
||||
{
|
||||
Logger.LogDebug($"API error: [{ex.Message}]");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
else if (e.Current.Item is FullEpisode episode)
|
||||
{
|
||||
|
@ -17,11 +17,32 @@ namespace Selector
|
||||
public static string DisplayString(this SimpleShow show) => $"{show.Name} / {show.Publisher}";
|
||||
|
||||
|
||||
public static string DisplayString(this CurrentlyPlayingContext currentPlaying) => $"{currentPlaying.IsPlaying}, {currentPlaying.Item}, {currentPlaying.Device.DisplayString()}";
|
||||
public static string DisplayString(this CurrentlyPlayingContext currentPlaying) {
|
||||
|
||||
if (currentPlaying.Item is FullTrack track)
|
||||
{
|
||||
return $"{currentPlaying.IsPlaying}, {track.DisplayString()}, {currentPlaying.Device.DisplayString()}";
|
||||
}
|
||||
else if (currentPlaying.Item is FullEpisode episode)
|
||||
{
|
||||
return $"{currentPlaying.IsPlaying}, {episode.DisplayString()}, {currentPlaying.Device.DisplayString()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Unknown playing type");
|
||||
}
|
||||
}
|
||||
|
||||
public static string DisplayString(this Context context) => $"{context.Type}, {context.Uri}";
|
||||
public static string DisplayString(this Device device) => $"{device.Name} ({device.Id}) {device.VolumePercent}%";
|
||||
public static string DisplayString(this TrackAudioFeatures feature) => $"Acou. {feature.Acousticness}, Dance {feature.Danceability}, Energy {feature.Energy}, Instru. {feature.Instrumentalness}, Key {feature.Key}, Live {feature.Liveness}, Loud {feature.Loudness}, Mode {feature.Mode}, Speech {feature.Speechiness}, Tempo {feature.Tempo}, Valence {feature.Valence}";
|
||||
public static string DisplayString(this TrackAudioFeatures feature) => $"Acou. {feature.Acousticness}, Dance {feature.Danceability}, Energy {feature.Energy}, Instru. {feature.Instrumentalness}, Key {feature.Key}, Live {feature.Liveness}, Loud {feature.Loudness}dB, Mode {feature.Mode}, Speech {feature.Speechiness}, Tempo {feature.Tempo}BPM, Time Sig. {feature.TimeSignature}, Valence {feature.Valence}";
|
||||
|
||||
public static string DisplayString(this IEnumerable<SimpleArtist> artists) => string.Join(", ", artists.Select(a => a.DisplayString()));
|
||||
|
||||
public static bool IsInstrumental(this TrackAudioFeatures feature) => feature.Instrumentalness > 0.5;
|
||||
public static bool IsLive(this TrackAudioFeatures feature) => feature.Liveness > 0.8f;
|
||||
public static bool IsSpokenWord(this TrackAudioFeatures feature) => feature.Speechiness > 0.66f;
|
||||
public static bool IsSpeechAndMusic(this TrackAudioFeatures feature) => feature.Speechiness is >= 0.33f and <= 0.66f;
|
||||
public static bool IsNotSpeech(this TrackAudioFeatures feature) => feature.Speechiness < 0.33f;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace Selector
|
||||
TokenType = refreshed.TokenType,
|
||||
ExpiresIn = refreshed.ExpiresIn,
|
||||
Scope = refreshed.Scope,
|
||||
RefreshToken = refreshed.RefreshToken,
|
||||
RefreshToken = refreshed.RefreshToken ?? RefreshToken,
|
||||
CreatedAt = refreshed.CreatedAt
|
||||
}));
|
||||
|
||||
|
@ -9,11 +9,18 @@ namespace Selector
|
||||
{
|
||||
public class CachingRefreshTokenFactoryProvider : RefreshTokenFactoryProvider
|
||||
{
|
||||
protected readonly ILogger<CachingRefreshTokenFactoryProvider> Logger;
|
||||
|
||||
public CachingRefreshTokenFactoryProvider(ILogger<CachingRefreshTokenFactoryProvider> logger)
|
||||
{
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
protected Dictionary<string, RefreshTokenFactory> Configs = new();
|
||||
|
||||
public RefreshTokenFactory GetUserConfig(string userId) => Configs.ContainsKey(userId) ? Configs[userId] : null;
|
||||
|
||||
new public async Task<RefreshTokenFactory> GetFactory(string refreshToken)
|
||||
public override async Task<RefreshTokenFactory> GetFactory(string refreshToken)
|
||||
{
|
||||
var configProvider = await base.GetFactory(refreshToken);
|
||||
var newConfig = await configProvider.GetConfig();
|
||||
@ -27,6 +34,7 @@ namespace Selector
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug($"New user token factory added [{userDetails.DisplayName}]");
|
||||
Configs[userDetails.Id] = configProvider;
|
||||
return configProvider;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace Selector
|
||||
|
||||
public bool Initialised => !string.IsNullOrWhiteSpace(ClientId) && !string.IsNullOrWhiteSpace(ClientSecret);
|
||||
|
||||
public Task<RefreshTokenFactory> GetFactory(string refreshToken)
|
||||
public virtual Task<RefreshTokenFactory> GetFactory(string refreshToken)
|
||||
{
|
||||
if(!Initialised) throw new InvalidOperationException("Factory not initialised");
|
||||
if(string.IsNullOrEmpty(refreshToken)) throw new ArgumentException("Null or empty refresh key provided");
|
||||
|
@ -26,7 +26,7 @@ namespace Selector
|
||||
public event EventHandler<ListeningChangeEventArgs> PlayingChange;
|
||||
|
||||
public CurrentlyPlayingContext Live { get; private set; }
|
||||
public PlayerTimeline Past { get; set; }
|
||||
public PlayerTimeline Past { get; set; } = new();
|
||||
|
||||
public PlayerWatcher(IPlayerClient spotifyClient,
|
||||
IEqual equalityChecker,
|
||||
@ -154,14 +154,17 @@ namespace Selector
|
||||
}
|
||||
catch(APIUnauthorizedException e)
|
||||
{
|
||||
throw e;
|
||||
Logger.LogDebug($"Unauthorised error: [{e.Message}] (should be refreshed and retried?)");
|
||||
//throw e;
|
||||
}
|
||||
catch(APITooManyRequestsException e)
|
||||
{
|
||||
Logger.LogDebug($"Too many requests error: [{e.Message}]");
|
||||
throw e;
|
||||
}
|
||||
catch(APIException e)
|
||||
{
|
||||
Logger.LogDebug($"API error: [{e.Message}]");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user