2023-12-30 04:27:31 -05:00
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using NAudio.Wave;
|
|
|
|
|
using TwitchLib.Api;
|
|
|
|
|
using TwitchLib.Client;
|
|
|
|
|
using TwitchLib.Client.Events;
|
|
|
|
|
using TwitchLib.Client.Models;
|
|
|
|
|
using TwitchLib.Communication.Clients;
|
|
|
|
|
using TwitchLib.Communication.Events;
|
|
|
|
|
using TwitchLib.PubSub;
|
|
|
|
|
using TwitchLib.PubSub.Events;
|
|
|
|
|
using NAudio.Wave.SampleProviders;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
Future handshake/connection procedure:
|
|
|
|
|
- GET all tts config data
|
|
|
|
|
- Continuous connection to server to receive commands from tom & send logs/errors (med priority, though tough task)
|
|
|
|
|
|
|
|
|
|
Ideas:
|
|
|
|
|
- Filter messages by badges, username, ..., etc.
|
|
|
|
|
- Filter messages by content.
|
|
|
|
|
- Speed up TTS based on message queue size?
|
|
|
|
|
- Cut TTS off shortly after raid (based on size of raid)?
|
|
|
|
|
- Limit duration of TTS
|
|
|
|
|
- Voice selection for channel and per user.
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
// dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true
|
|
|
|
|
// dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true
|
|
|
|
|
// SE voices: https://api.streamelements.com/kappa/v2/speech?voice=brian&text=hello
|
|
|
|
|
|
|
|
|
|
// Read redeems from file.
|
|
|
|
|
var redeems = File.Exists(".redeems") ? await File.ReadAllLinesAsync(".redeems") : new string[0];
|
|
|
|
|
|
|
|
|
|
// Fetch id and username based on api key given.
|
|
|
|
|
HermesClient hermes = new HermesClient();
|
|
|
|
|
Console.WriteLine("Fetching Hermes account details...");
|
|
|
|
|
await hermes.UpdateHermesAccount();
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Username: " + hermes.Username);
|
|
|
|
|
Console.WriteLine();
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Fetching Twitch API details from Hermes...");
|
|
|
|
|
TwitchApiClient twitchapiclient = new TwitchApiClient(await hermes.FetchTwitchBotToken());
|
|
|
|
|
await twitchapiclient.Authorize();
|
|
|
|
|
|
2024-01-05 05:07:41 -05:00
|
|
|
|
Console.WriteLine("Fetching TTS username filters...");
|
|
|
|
|
var usernameFilters = (await hermes.FetchTTSUsernameFilters())
|
|
|
|
|
.ToDictionary(x => x.username, x => x);
|
|
|
|
|
Console.WriteLine($"{usernameFilters.Where(f => f.Value.tag == "blacklisted").Count()} username(s) have been blocked.");
|
|
|
|
|
Console.WriteLine($"{usernameFilters.Where(f => f.Value.tag == "priority").Count()} user(s) have been prioritized.");
|
|
|
|
|
|
|
|
|
|
var enabledVoices = await hermes.FetchTTSEnabledVoices();
|
|
|
|
|
Console.WriteLine($"{enabledVoices.Count()} TTS voices enabled.");
|
|
|
|
|
|
|
|
|
|
var wordFilters = await hermes.FetchTTSWordFilters();
|
|
|
|
|
Console.WriteLine($"{wordFilters.Count()} TTS word filters.");
|
|
|
|
|
|
|
|
|
|
var defaultVoice = await hermes.FetchTTSDefaultVoice();
|
|
|
|
|
Console.WriteLine("Default Voice: " + defaultVoice);
|
2023-12-30 04:27:31 -05:00
|
|
|
|
|
|
|
|
|
TTSPlayer player = new TTSPlayer();
|
|
|
|
|
ISampleProvider playing = null;
|
|
|
|
|
|
2024-01-05 05:07:41 -05:00
|
|
|
|
var handler = new ChatMessageHandler(player, defaultVoice, enabledVoices, usernameFilters, wordFilters);
|
|
|
|
|
|
2023-12-30 04:27:31 -05:00
|
|
|
|
var channels = File.Exists(".twitchchannels") ? File.ReadAllLines(".twitchchannels") : new string[] { hermes.Username };
|
2024-01-05 05:07:41 -05:00
|
|
|
|
Console.WriteLine("Twitch channels: " + string.Join(", ", channels));
|
2023-12-30 04:27:31 -05:00
|
|
|
|
twitchapiclient.InitializeClient(hermes, channels);
|
|
|
|
|
twitchapiclient.InitializePublisher(player, redeems);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
twitchapiclient.AddOnNewMessageReceived(async Task (object? s, OnMessageReceivedArgs e) => {
|
2024-01-05 05:07:41 -05:00
|
|
|
|
var result = handler.Handle(e);
|
|
|
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
|
case MessageResult.Skip:
|
|
|
|
|
AudioPlaybackEngine.Instance.RemoveMixerInput(playing);
|
|
|
|
|
playing = null;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2023-12-30 04:27:31 -05:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
AudioPlaybackEngine.Instance.AddOnMixerInputEnded((object? s, SampleProviderEventArgs e) => {
|
|
|
|
|
if (e.SampleProvider == playing) {
|
|
|
|
|
playing = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Task.Run(async () => {
|
|
|
|
|
while (true) {
|
|
|
|
|
try {
|
|
|
|
|
var m = player.ReceiveBuffer();
|
|
|
|
|
if (m == null) {
|
|
|
|
|
await Task.Delay(200);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string url = $"https://api.streamelements.com/kappa/v2/speech?voice={m.Voice}&text={m.Message}";
|
|
|
|
|
var sound = new NetworkWavSound(url);
|
|
|
|
|
var provider = new CachedWavProvider(sound);
|
|
|
|
|
var data = AudioPlaybackEngine.Instance.ConvertSound(provider);
|
2024-01-05 05:07:41 -05:00
|
|
|
|
var resampled = new WdlResamplingSampleProvider(data, AudioPlaybackEngine.Instance.SampleRate);
|
2023-12-30 04:27:31 -05:00
|
|
|
|
|
2024-01-05 05:07:41 -05:00
|
|
|
|
m.Audio = resampled;
|
2023-12-30 04:27:31 -05:00
|
|
|
|
player.Ready(m);
|
|
|
|
|
} catch (COMException e) {
|
|
|
|
|
Console.WriteLine(e.GetType().Name + ": " + e.Message + " (HResult: " + e.HResult + ")");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Console.WriteLine(e.GetType().Name + ": " + e.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Task.Run(async () => {
|
|
|
|
|
while (true) {
|
|
|
|
|
try {
|
|
|
|
|
while (player.IsEmpty() || playing != null) {
|
|
|
|
|
await Task.Delay(200);
|
|
|
|
|
}
|
|
|
|
|
var m = player.ReceiveReady();
|
|
|
|
|
if (m == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(m.File) && File.Exists(m.File)) {
|
|
|
|
|
Console.WriteLine("Playing sfx: " + m.File);
|
|
|
|
|
AudioPlaybackEngine.Instance.PlaySound(m.File);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Playing message: " + m.Message);
|
|
|
|
|
playing = m.Audio;
|
|
|
|
|
AudioPlaybackEngine.Instance.AddMixerInput(m.Audio);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Console.WriteLine(e.GetType().Name + ": " + e.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Twitch API client connecting...");
|
|
|
|
|
twitchapiclient.Connect();
|
|
|
|
|
Console.ReadLine();
|
|
|
|
|
Console.ReadLine();
|