Twitch connection now relies on events to connect. Added logging for when TTS filter is not a regex. Minor code clean up.

This commit is contained in:
Tom
2025-01-19 01:23:29 +00:00
parent 86fc6bc24d
commit cbdca1c008
9 changed files with 102 additions and 68 deletions

View File

@ -53,19 +53,24 @@ namespace TwitchChatTTS.Hermes.Socket.Handlers
_user.VoicesEnabled = new HashSet<string>(message.EnabledTTSVoices); _user.VoicesEnabled = new HashSet<string>(message.EnabledTTSVoices);
_user.TwitchConnection = message.Connections.FirstOrDefault(c => c.Default && c.Type == "twitch"); _user.TwitchConnection = message.Connections.FirstOrDefault(c => c.Default && c.Type == "twitch");
_user.NightbotConnection = message.Connections.FirstOrDefault(c => c.Default && c.Type == "nightbot"); _user.NightbotConnection = message.Connections.FirstOrDefault(c => c.Default && c.Type == "nightbot");
if (_user.TwitchConnection != null)
_bus.Send(this, "twitch id", _user.TwitchUserId); {
_logger.Information("Twitch connection: " + _user.TwitchConnection.Name + " / " + _user.TwitchConnection.AccessToken);
}
var filters = message.WordFilters.Where(f => f.Search != null && f.Replace != null).ToList(); var filters = message.WordFilters.Where(f => f.Search != null && f.Replace != null).ToList();
foreach (var filter in filters) foreach (var filter in filters)
{ {
try try
{ {
var re = new Regex(filter.Search, ((RegexOptions) filter.Flag) | RegexOptions.Compiled); var re = new Regex(filter.Search, ((RegexOptions)filter.Flag) | RegexOptions.Compiled);
re.Match(string.Empty); re.Match(string.Empty);
filter.Regex = re; filter.Regex = re;
} }
catch (Exception) { } catch (Exception)
{
_logger.Warning($"Failed to create a regular expression for a TTS filter [filter id: {filter.Search}]");
}
} }
_user.RegexFilters = filters; _user.RegexFilters = filters;
@ -93,6 +98,7 @@ namespace TwitchChatTTS.Hermes.Socket.Handlers
} }
_logger.Information("TTS is now ready."); _logger.Information("TTS is now ready.");
_bus.Send(this, "tts_connected", _user);
client.Ready = true; client.Ready = true;
} }
} }

View File

@ -247,7 +247,7 @@ namespace TwitchChatTTS.Hermes.Socket
public void Initialize() public void Initialize()
{ {
_logger.Information("Initializing Hermes websocket client."); _logger.Information("Initializing Tom to Speech websocket client.");
OnConnected += async (sender, e) => OnConnected += async (sender, e) =>
{ {
@ -257,7 +257,7 @@ namespace TwitchChatTTS.Hermes.Socket
return; return;
Connected = true; Connected = true;
} }
_logger.Information("Hermes websocket client connected."); _logger.Information("Tom to Speech websocket client connected.");
_heartbeatTimer.Enabled = true; _heartbeatTimer.Enabled = true;
LastHeartbeatReceived = DateTime.UtcNow; LastHeartbeatReceived = DateTime.UtcNow;
@ -281,7 +281,7 @@ namespace TwitchChatTTS.Hermes.Socket
LoggedIn = false; LoggedIn = false;
Ready = false; Ready = false;
_logger.Warning("Hermes websocket client disconnected."); _logger.Warning("Tom to Speech websocket client disconnected.");
_heartbeatTimer.Enabled = false; _heartbeatTimer.Enabled = false;
await Reconnect(_backoff); await Reconnect(_backoff);
@ -396,7 +396,7 @@ namespace TwitchChatTTS.Hermes.Socket
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Failed to send a heartbeat back to the Hermes websocket server."); _logger.Error(ex, "Failed to send a heartbeat back to the Tom to Speech websocket server.");
} }
} }
else if (signalTime - LastHeartbeatReceived > TimeSpan.FromSeconds(120)) else if (signalTime - LastHeartbeatReceived > TimeSpan.FromSeconds(120))
@ -407,7 +407,7 @@ namespace TwitchChatTTS.Hermes.Socket
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Failed to disconnect from Hermes websocket server."); _logger.Error(ex, "Failed to disconnect from Tom to Speech websocket server.");
Ready = false; Ready = false;
LoggedIn = false; LoggedIn = false;
Connected = false; Connected = false;
@ -423,7 +423,7 @@ namespace TwitchChatTTS.Hermes.Socket
{ {
if (!Connected) if (!Connected)
{ {
_logger.Warning("Hermes websocket client is not connected. Not sending a message."); _logger.Warning("Tom to Speech websocket client is not connected. Not sending a message.");
return; return;
} }

View File

@ -48,7 +48,7 @@ namespace TwitchChatTTS.Hermes.Socket.Requests
} }
catch (Exception) catch (Exception)
{ {
_logger.Warning($"Failed to generate a Regular Expression using '{filter.Search}' [filter id: {filter.Id}]"); _logger.Warning($"Failed to create a regular expression for a TTS filter [filter id: {filter.Search}]");
} }
_logger.Debug($"Filter data [filter id: {filter.Id}][search: {filter.Search}][replace: {filter.Replace}]"); _logger.Debug($"Filter data [filter id: {filter.Id}][search: {filter.Search}][replace: {filter.Replace}]");

View File

@ -33,11 +33,14 @@ namespace TwitchChatTTS.Hermes.Socket.Requests
{ {
try try
{ {
var re = new Regex(filter.Search, ((RegexOptions) filter.Flag) | RegexOptions.Compiled); var re = new Regex(filter.Search, ((RegexOptions)filter.Flag) | RegexOptions.Compiled);
re.Match(string.Empty); re.Match(string.Empty);
filter.Regex = re; filter.Regex = re;
} }
catch (Exception) { } catch (Exception)
{
_logger.Warning($"Failed to create a regular expression for a TTS filter [filter id: {filter.Search}]");
}
} }
_user.RegexFilters = filters; _user.RegexFilters = filters;
_logger.Information($"TTS word filters [count: {_user.RegexFilters.Count}] have been refreshed."); _logger.Information($"TTS word filters [count: {_user.RegexFilters.Count}] have been refreshed.");

View File

@ -52,7 +52,10 @@ namespace TwitchChatTTS.Hermes.Socket.Requests
re.Match(string.Empty); re.Match(string.Empty);
current.Regex = re; current.Regex = re;
} }
catch (Exception) { } catch (Exception)
{
_logger.Warning($"Failed to create a regular expression for a TTS filter [filter id: {filter.Search}]");
}
_logger.Information($"Filter has been updated [filter id: {filter.Id}]"); _logger.Information($"Filter has been updated [filter id: {filter.Id}]");
} }

View File

@ -181,7 +181,6 @@ s.AddKeyedTransient<SocketClient<TwitchWebsocketMessage>, TwitchWebsocketClient>
{ {
var factory = sp.GetRequiredService<ITwitchConnectionManager>(); var factory = sp.GetRequiredService<ITwitchConnectionManager>();
var client = factory.GetWorkingClient(); var client = factory.GetWorkingClient();
client.Connect().Wait();
return client; return client;
}); });
s.AddKeyedTransient<SocketClient<TwitchWebsocketMessage>, TwitchWebsocketClient>("twitch-create"); s.AddKeyedTransient<SocketClient<TwitchWebsocketMessage>, TwitchWebsocketClient>("twitch-create");

104
TTS.cs
View File

@ -1,7 +1,6 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Serilog; using Serilog;
using NAudio.Wave.SampleProviders;
using org.mariuszgromada.math.mxparser; using org.mariuszgromada.math.mxparser;
using TwitchChatTTS.Hermes.Socket; using TwitchChatTTS.Hermes.Socket;
using TwitchChatTTS.Seven.Socket; using TwitchChatTTS.Seven.Socket;
@ -13,10 +12,10 @@ using TwitchChatTTS.Twitch.Socket.Messages;
using TwitchChatTTS.Twitch.Socket; using TwitchChatTTS.Twitch.Socket;
using TwitchChatTTS.Chat.Commands; using TwitchChatTTS.Chat.Commands;
using System.Text; using System.Text;
using TwitchChatTTS.Chat.Speech;
using TwitchChatTTS.Veadotube; using TwitchChatTTS.Veadotube;
using TwitchChatTTS.Bus; using TwitchChatTTS.Bus;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Net.WebSockets;
namespace TwitchChatTTS namespace TwitchChatTTS
{ {
@ -36,8 +35,6 @@ namespace TwitchChatTTS
private readonly ICommandFactory _commandFactory; private readonly ICommandFactory _commandFactory;
private readonly ICommandManager _commandManager; private readonly ICommandManager _commandManager;
private readonly IEmoteDatabase _emotes; private readonly IEmoteDatabase _emotes;
private readonly TTSPlayer _player;
private readonly AudioPlaybackEngine _playback;
private readonly ServiceBusCentral _bus; private readonly ServiceBusCentral _bus;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly ILogger _logger; private readonly ILogger _logger;
@ -54,8 +51,6 @@ namespace TwitchChatTTS
ICommandFactory commandFactory, ICommandFactory commandFactory,
ICommandManager commandManager, ICommandManager commandManager,
IEmoteDatabase emotes, IEmoteDatabase emotes,
TTSPlayer player,
AudioPlaybackEngine playback,
ServiceBusCentral bus, ServiceBusCentral bus,
Configuration configuration, Configuration configuration,
ILogger logger ILogger logger
@ -72,8 +67,6 @@ namespace TwitchChatTTS
_commandFactory = commandFactory; _commandFactory = commandFactory;
_commandManager = commandManager; _commandManager = commandManager;
_emotes = emotes; _emotes = emotes;
_player = player;
_playback = playback;
_bus = bus; _bus = bus;
_configuration = configuration; _configuration = configuration;
_logger = logger; _logger = logger;
@ -87,7 +80,7 @@ namespace TwitchChatTTS
if (string.IsNullOrWhiteSpace(_configuration.Hermes?.Token)) if (string.IsNullOrWhiteSpace(_configuration.Hermes?.Token))
{ {
_logger.Error("Hermes API token not set in the configuration file."); _logger.Error("Tom to Speech API token not set in the yml file.");
return; return;
} }
@ -113,56 +106,70 @@ namespace TwitchChatTTS
_logger.Warning("Failed to check for version updates."); _logger.Warning("Failed to check for version updates.");
} }
var disposables = new List<IDisposable>();
// 7tv // 7tv
var twitchTopic = _bus.GetTopic("twitch id"); var connected = _bus.GetTopic("tts_connected");
twitchTopic.FirstAsync().Subscribe(async (data) => disposables.Add(connected.FirstAsync().Subscribe(async (data) =>
{ {
var twitchId = data.Value?.ToString(); if (data.Value is not User user)
if (twitchId == null) {
_logger.Warning("Something went wrong. Unable to fetch 7tv data.");
return; return;
}
if (user.TwitchUserId == default)
{
_logger.Warning("Unable to fetch 7tv data. If this is wrong, ensure your Tom to Speech token is valid.");
return;
}
var emoteSet = await _sevenApiClient.FetchChannelEmoteSet(_user.TwitchUserId); var emoteSet = await _sevenApiClient.FetchChannelEmoteSet(_user.TwitchUserId);
if (emoteSet != null) if (emoteSet != null)
{
_user.SevenEmoteSetId = emoteSet.Id; _user.SevenEmoteSetId = emoteSet.Id;
_logger.Debug($"Fetched the 7tv emote set id [emote set id: {emoteSet.Id}]");
}
await InitializeEmotes(_sevenApiClient, emoteSet); await InitializeEmotes(_sevenApiClient, emoteSet);
await InitializeSevenTv(); await InitializeSevenTv();
}); }));
await InitializeHermesWebsocket(); disposables.Add(connected.FirstAsync().Subscribe(async (data) =>
_playback.AddOnMixerInputEnded((object? s, SampleProviderEventArgs e) =>
{ {
if (_player.Playing?.Audio == e.SampleProvider) if (data.Value is not User user)
{ {
_player.Playing = null; _logger.Warning("Something went wrong. Not connecting to Twitch.");
return;
}
if (user.TwitchUserId == default)
{
_logger.Warning("Not connecting to Twitch. If this is wrong, ensure your Tom to Speech token is valid.");
return;
} }
});
try try
{ {
_veado.Initialize(); await _twitch.Connect();
await _veado.Connect(); }
} catch (Exception e)
catch (Exception e) {
{ _logger.Error(e, "Failed to connect to Twitch websocket server.");
_logger.Warning(e, "Failed to connect to Veado websocket server."); }
} }));
try
{
await _twitch.Connect();
}
catch (Exception e)
{
_logger.Error(e, "Failed to connect to Twitch websocket server.");
await Task.Delay(TimeSpan.FromSeconds(30));
return;
}
_commandManager.Update(_commandFactory); _commandManager.Update(_commandFactory);
await InitializeVeadotube();
await InitializeHermesWebsocket();
await InitializeObs(); await InitializeObs();
// Check if user has successfully connected.
await Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(5));
if (_user.TwitchUserId == default)
_logger.Warning("Ensure your Tom to Speech token in the tts.config.yml file is valid.");
});
} }
public Task StopAsync(CancellationToken cancellationToken) public Task StopAsync(CancellationToken cancellationToken)
@ -181,6 +188,10 @@ namespace TwitchChatTTS
_hermes.Initialize(); _hermes.Initialize();
await _hermes.Connect(); await _hermes.Connect();
} }
catch (WebSocketException e) when (e.Message.Contains("The server returned status code '502'"))
{
_logger.Error("Could not connect to Tom to Speech server.");
}
catch (Exception e) catch (Exception e)
{ {
_logger.Error(e, "Connecting to hermes failed. Skipping hermes websockets."); _logger.Error(e, "Connecting to hermes failed. Skipping hermes websockets.");
@ -213,6 +224,19 @@ namespace TwitchChatTTS
} }
} }
private async Task InitializeVeadotube()
{
try
{
_veado.Initialize();
await _veado.Connect();
}
catch (Exception e)
{
_logger.Warning(e, "Failed to connect to Veado websocket server.");
}
}
private async Task InitializeEmotes(SevenApiClient sevenapi, EmoteSet? channelEmotes) private async Task InitializeEmotes(SevenApiClient sevenapi, EmoteSet? channelEmotes)
{ {
var globalEmotes = await sevenapi.FetchGlobalSevenEmotes(); var globalEmotes = await sevenapi.FetchGlobalSevenEmotes();

View File

@ -30,6 +30,14 @@ namespace TwitchChatTTS
public Task StartAsync(CancellationToken cancellationToken) public Task StartAsync(CancellationToken cancellationToken)
{ {
_playback.AddOnMixerInputEnded((object? s, SampleProviderEventArgs e) =>
{
if (_player.Playing?.Audio == e.SampleProvider)
{
_player.Playing = null;
}
});
Task.Run(async () => Task.Run(async () =>
{ {
while (true) while (true)

View File

@ -29,18 +29,9 @@ namespace TwitchChatTTS.Twitch.Socket.Handlers
return; return;
} }
int waited = 0; var twitchConnection = _user.TwitchConnection!;
while ((_user.TwitchUserId <= 0 || _user.TwitchConnection == null) && ++waited < 5) _api.Initialize(twitchConnection.ClientId, twitchConnection.AccessToken);
await Task.Delay(TimeSpan.FromSeconds(1)); var span = twitchConnection.ExpiresAt - DateTime.Now;
if (_user.TwitchConnection == null)
{
_logger.Error("Ensure you have linked either your Twitch account or TTS' bot to your TTS account. Twitch client will not be connecting.");
return;
}
_api.Initialize(_user.TwitchConnection.ClientId, _user.TwitchConnection.AccessToken);
var span = _user.TwitchConnection.ExpiresAt - DateTime.Now;
var timeLeft = span.Days >= 2 ? span.Days + " days" : (span.Hours >= 2 ? span.Hours + " hours" : span.Minutes + " minutes"); var timeLeft = span.Days >= 2 ? span.Days + " days" : (span.Hours >= 2 ? span.Hours + " hours" : span.Minutes + " minutes");
if (span.Days >= 3) if (span.Days >= 3)
_logger.Information($"Twitch connection has {timeLeft} before it is revoked."); _logger.Information($"Twitch connection has {timeLeft} before it is revoked.");
@ -48,7 +39,7 @@ namespace TwitchChatTTS.Twitch.Socket.Handlers
_logger.Warning($"Twitch connection has {timeLeft} before it is revoked. Refreshing the token is soon required."); _logger.Warning($"Twitch connection has {timeLeft} before it is revoked. Refreshing the token is soon required.");
else else
{ {
_logger.Error("Twitch connection has its permissions revoked. Refresh the token. Twith client will not be connecting."); _logger.Error("Twitch connection has its permissions revoked. Refresh the token. Twitch client will not be connecting.");
return; return;
} }