Compare commits

...

4 Commits

10 changed files with 127 additions and 21 deletions

View File

@ -62,7 +62,7 @@ namespace TwitchChatTTS.Chat.Messaging
var emoteUsage = GetEmoteUsage(fragments); var emoteUsage = GetEmoteUsage(fragments);
var tasks = new List<Task>(); var tasks = new List<Task>();
if (_obs.Streaming) if (_obs.Streaming && _configuration.Twitch?.Slave != true)
{ {
if (emoteUsage.NewEmotes.Any()) if (emoteUsage.NewEmotes.Any())
tasks.Add(_hermes.SendEmoteDetails(emoteUsage.NewEmotes)); tasks.Add(_hermes.SendEmoteDetails(emoteUsage.NewEmotes));

View File

@ -14,8 +14,8 @@ namespace TwitchChatTTS
} }
public class TwitchConfiguration { public class TwitchConfiguration {
public IEnumerable<string>? Channels;
public bool TtsWhenOffline; public bool TtsWhenOffline;
public bool Slave;
public string? WebsocketUrl; public string? WebsocketUrl;
public string? ApiUrl; public string? ApiUrl;
} }

View File

@ -36,6 +36,7 @@ using TwitchChatTTS.Chat.Commands.Limits;
using TwitchChatTTS.Hermes.Socket.Requests; using TwitchChatTTS.Hermes.Socket.Requests;
using TwitchChatTTS.Bus; using TwitchChatTTS.Bus;
using TwitchChatTTS.Veadotube; using TwitchChatTTS.Veadotube;
using TwitchChatTTS.Veadotube.Handlers;
// dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true // dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true
// dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true // dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true
@ -149,6 +150,8 @@ s.AddKeyedSingleton<MessageTypeManager<IWebSocketHandler>, SevenMessageTypeManag
s.AddKeyedSingleton<SocketClient<WebSocketMessage>, SevenSocketClient>("7tv"); s.AddKeyedSingleton<SocketClient<WebSocketMessage>, SevenSocketClient>("7tv");
// Veadotube // Veadotube
s.AddKeyedSingleton<IVeadotubeMessageHandler, FetchStatesHandler>("veadotube");
s.AddKeyedSingleton<MessageTypeManager<IWebSocketHandler>, VeadoMessageTypeManager>("veadotube"); s.AddKeyedSingleton<MessageTypeManager<IWebSocketHandler>, VeadoMessageTypeManager>("veadotube");
s.AddKeyedSingleton<SocketClient<object>, VeadoSocketClient>("veadotube"); s.AddKeyedSingleton<SocketClient<object>, VeadoSocketClient>("veadotube");

7
TTS.cs
View File

@ -21,7 +21,7 @@ namespace TwitchChatTTS
public class TTS : IHostedService public class TTS : IHostedService
{ {
public const int MAJOR_VERSION = 4; public const int MAJOR_VERSION = 4;
public const int MINOR_VERSION = 4; public const int MINOR_VERSION = 5;
private readonly User _user; private readonly User _user;
private readonly HermesApiClient _hermesApiClient; private readonly HermesApiClient _hermesApiClient;
@ -89,9 +89,10 @@ namespace TwitchChatTTS
var hermesVersion = await _hermesApiClient.GetLatestTTSVersion(); var hermesVersion = await _hermesApiClient.GetLatestTTSVersion();
if (hermesVersion == null) if (hermesVersion == null)
{ {
_logger.Warning("Failed to fetch latest TTS version. Skipping version check."); _logger.Error("Failed to fetch latest TTS version. Something went wrong.");
return;
} }
else if (hermesVersion.MajorVersion > TTS.MAJOR_VERSION || hermesVersion.MajorVersion == TTS.MAJOR_VERSION && hermesVersion.MinorVersion > TTS.MINOR_VERSION) if (hermesVersion.MajorVersion > TTS.MAJOR_VERSION || hermesVersion.MajorVersion == TTS.MAJOR_VERSION && hermesVersion.MinorVersion > TTS.MINOR_VERSION)
{ {
_logger.Information($"A new update for TTS is avaiable! Version {hermesVersion.MajorVersion}.{hermesVersion.MinorVersion} is available at {hermesVersion.Download}"); _logger.Information($"A new update for TTS is avaiable! Version {hermesVersion.MajorVersion}.{hermesVersion.MinorVersion} is available at {hermesVersion.Download}");
var changes = hermesVersion.Changelog.Split("\n"); var changes = hermesVersion.Changelog.Split("\n");

View File

@ -55,6 +55,12 @@ namespace TwitchChatTTS
return; return;
} }
if (DateTime.UtcNow - group.Timestamp > TimeSpan.FromSeconds(60))
{
_logger.Debug("Ignored message due to being in queue for too long.");
continue;
}
FetchMasterAudio(group); FetchMasterAudio(group);
} }
catch (COMException e) catch (COMException e)

View File

@ -52,7 +52,8 @@ namespace TwitchChatTTS.Twitch.Redemptions
_isReady = false; _isReady = false;
var topic = _bus.GetTopic("redemptions_initiation"); var topic = _bus.GetTopic("redemptions_initiation");
topic.Subscribe(new ServiceBusObserver(data => { topic.Subscribe(new ServiceBusObserver(data =>
{
if (data.Value is RedemptionInitiation obj) if (data.Value is RedemptionInitiation obj)
Initialize(obj.Redemptions, obj.Actions); Initialize(obj.Redemptions, obj.Actions);
}, _logger)); }, _logger));
@ -225,14 +226,35 @@ namespace TwitchChatTTS.Twitch.Redemptions
await _nightbot.ClearQueue(); await _nightbot.ClearQueue();
break; break;
case "VEADOTUBE_SET_STATE": case "VEADOTUBE_SET_STATE":
await _veado.SetCurrentState(action.Data["state"]); {
break; var state = _veado.GetStateId(action.Data["state"]);
if (state == null) {
_logger.Warning($"Could not find the state named '{action.Data["state"]}'.");
break;
}
await _veado.SetCurrentState(state);
break;
}
case "VEADOTUBE_PUSH_STATE": case "VEADOTUBE_PUSH_STATE":
await _veado.PushState(action.Data["state"]); {
break; var state = _veado.GetStateId(action.Data["state"]);
if (state == null) {
_logger.Warning($"Could not find the state named '{action.Data["state"]}'.");
break;
}
await _veado.PushState(state);
break;
}
case "VEADOTUBE_POP_STATE": case "VEADOTUBE_POP_STATE":
await _veado.PopState(action.Data["state"]); {
break; var state = _veado.GetStateId(action.Data["state"]);
if (state == null) {
_logger.Warning($"Could not find the state named '{action.Data["state"]}'.");
break;
}
await _veado.PopState(state);
break;
}
default: default:
_logger.Warning($"Unknown redeemable action has occured. Update needed? [type: {action.Type}][chatter: {senderDisplayName}][chatter id: {senderId}]"); _logger.Warning($"Unknown redeemable action has occured. Update needed? [type: {action.Type}][chatter: {senderDisplayName}][chatter id: {senderId}]");
break; break;

View File

@ -0,0 +1,34 @@
using System.Text.Json;
using Serilog;
namespace TwitchChatTTS.Veadotube.Handlers
{
public class FetchStatesHandler : IVeadotubeMessageHandler
{
private readonly JsonSerializerOptions _options;
private readonly ILogger _logger;
public string Name => "list";
public FetchStatesHandler(JsonSerializerOptions options, ILogger logger)
{
_options = options;
_logger = logger;
}
public Task Handle(VeadoSocketClient client, VeadoPayloadMessage message)
{
_logger.Information("Triggered Veadotube handler.");
var payload = JsonSerializer.Deserialize<VeadoNodeStateListMessage>(message.Payload.ToString()!, _options);
if (payload == null)
{
_logger.Warning("Invalid message received from Veadotube for listing states.");
return Task.CompletedTask;
}
var states = payload.States.ToDictionary(s => s.Name, s => s.Id);
client.UpdateState(states);
return Task.CompletedTask;
}
}
}

View File

@ -0,0 +1,8 @@
namespace TwitchChatTTS.Veadotube.Handlers
{
public interface IVeadotubeMessageHandler
{
string Name { get; }
Task Handle(VeadoSocketClient client, VeadoPayloadMessage message);
}
}

View File

@ -1,5 +1,4 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Newtonsoft.Json;
namespace TwitchChatTTS.Veadotube namespace TwitchChatTTS.Veadotube
{ {
@ -8,6 +7,7 @@ namespace TwitchChatTTS.Veadotube
public string Event { get; set; } public string Event { get; set; }
public string Type { get; set; } public string Type { get; set; }
public string Id { get; set; } public string Id { get; set; }
public string Name { get; set; }
public object Payload { get; set; } public object Payload { get; set; }
} }
@ -23,7 +23,7 @@ namespace TwitchChatTTS.Veadotube
} }
public class VeadoNodeStateListMessage : VeadoEventMessage { public class VeadoNodeStateListMessage : VeadoEventMessage {
public IEnumerable<VeadoNodeState> Entries { get; set; } public IEnumerable<VeadoNodeState> States { get; set; }
} }
public class VeadoNodeStateMessage : VeadoEventMessage { public class VeadoNodeStateMessage : VeadoEventMessage {

View File

@ -1,4 +1,3 @@
using CommonSocketLibrary.Common;
using CommonSocketLibrary.Abstract; using CommonSocketLibrary.Abstract;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Serilog; using Serilog;
@ -6,6 +5,7 @@ using System.Text.Json;
using CommonSocketLibrary.Backoff; using CommonSocketLibrary.Backoff;
using System.Text; using System.Text;
using System.Net.WebSockets; using System.Net.WebSockets;
using TwitchChatTTS.Veadotube.Handlers;
namespace TwitchChatTTS.Veadotube namespace TwitchChatTTS.Veadotube
{ {
@ -13,14 +13,17 @@ namespace TwitchChatTTS.Veadotube
{ {
private VeadoInstanceInfo? Instance; private VeadoInstanceInfo? Instance;
private IDictionary<string, IVeadotubeMessageHandler> _handlers;
private IDictionary<string, string> _states;
public bool Connected { get; set; } public bool Connected { get; set; }
public bool Identified { get; set; } public bool Identified { get; set; }
public bool Streaming { get; set; } public bool Streaming { get; set; }
public VeadoSocketClient( public VeadoSocketClient(
[FromKeyedServices("veadotube")] IEnumerable<IWebSocketHandler> handlers, [FromKeyedServices("veadotube")] IEnumerable<IVeadotubeMessageHandler> handlers,
[FromKeyedServices("veadotube")] MessageTypeManager<IWebSocketHandler> typeManager, //[FromKeyedServices("veadotube")] MessageTypeManager<IVeadotubeMessageHandler> typeManager,
ILogger logger ILogger logger
) : base(logger, new JsonSerializerOptions() ) : base(logger, new JsonSerializerOptions()
{ {
@ -28,6 +31,8 @@ namespace TwitchChatTTS.Veadotube
PropertyNamingPolicy = JsonNamingPolicy.CamelCase PropertyNamingPolicy = JsonNamingPolicy.CamelCase
}) })
{ {
_handlers = handlers.ToDictionary(h => h.Name, h => h);
_states = new Dictionary<string, string>();
} }
protected override async Task<T> Deserialize<T>(Stream stream) protected override async Task<T> Deserialize<T>(Stream stream)
@ -43,10 +48,12 @@ namespace TwitchChatTTS.Veadotube
public void Initialize() public void Initialize()
{ {
_logger.Information($"Initializing Veadotube websocket client."); _logger.Information($"Initializing Veadotube websocket client.");
OnConnected += (sender, e) => OnConnected += async (sender, e) =>
{ {
Connected = true; Connected = true;
_logger.Information("Veadotube websocket client connected."); _logger.Information("Veadotube websocket client connected.");
await FetchStates();
}; };
OnDisconnected += async (sender, e) => OnDisconnected += async (sender, e) =>
@ -97,6 +104,13 @@ namespace TwitchChatTTS.Veadotube
}); });
} }
public string? GetStateId(string state)
{
if (_states.TryGetValue(state, out var id))
return id;
return null;
}
public async Task SetCurrentState(string stateId) public async Task SetCurrentState(string stateId)
{ {
await Send(new VeadoPayloadMessage() await Send(new VeadoPayloadMessage()
@ -180,6 +194,11 @@ namespace TwitchChatTTS.Veadotube
} }
} }
public void UpdateState(IDictionary<string, string> states)
{
_states = states;
}
private bool UpdateURL() private bool UpdateURL()
{ {
string path = Environment.ExpandEnvironmentVariables("%userprofile%/.veadotube/instances"); string path = Environment.ExpandEnvironmentVariables("%userprofile%/.veadotube/instances");
@ -212,11 +231,24 @@ namespace TwitchChatTTS.Veadotube
return false; return false;
} }
protected override Task OnResponseReceived(object? content) protected override async Task OnResponseReceived(object? content)
{ {
var contentAsString = JsonSerializer.Serialize(content); var contentAsString = JsonSerializer.Serialize(content, _options);
_logger.Debug("VEADO RX: " + contentAsString); _logger.Debug("VEADO RX: " + contentAsString);
return Task.CompletedTask;
var data = JsonSerializer.Deserialize<VeadoPayloadMessage>(contentAsString, _options);
if (data == null)
{
return;
}
var payload = JsonSerializer.Deserialize<VeadoEventMessage>(data.Payload.ToString()!, _options);
if (_handlers.TryGetValue(payload?.Event ?? string.Empty, out var handler))
{
await handler.Handle(this, data);
}
return;
} }
} }
} }