diff --git a/KfChatDotNetBot/Services/YouTubeApi.cs b/KfChatDotNetBot/Services/YouTubeApi.cs new file mode 100644 index 0000000..8bfd7b5 --- /dev/null +++ b/KfChatDotNetBot/Services/YouTubeApi.cs @@ -0,0 +1,6 @@ +namespace KfChatDotNetBot.Services; + +public class YouTubeApi +{ + +} \ No newline at end of file diff --git a/KfChatDotNetBot/Services/YouTubePubSub.cs b/KfChatDotNetBot/Services/YouTubePubSub.cs new file mode 100644 index 0000000..d97fecf --- /dev/null +++ b/KfChatDotNetBot/Services/YouTubePubSub.cs @@ -0,0 +1,92 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using KfChatDotNetBot.Settings; +using NLog; +using StackExchange.Redis; + +namespace KfChatDotNetBot.Services; + +public class YouTubePubSub : IDisposable +{ + private string _connectionString; + private CancellationToken _ct; + private Logger _logger = LogManager.GetCurrentClassLogger(); + private ConnectionMultiplexer? _redis; + private ISubscriber? _sub; + + public delegate void OnNewVideoEventHandler(object sender, YouTubePubSubNotificationModel data); + + public event OnNewVideoEventHandler? OnNewVideo; + + public YouTubePubSub(CancellationToken cancellationToken = default) + { + _ct = cancellationToken; + _connectionString = SettingsProvider.GetValueAsync(BuiltIn.Keys.YouTubePubSubRedisConnectionString).Result + .Value ?? throw new InvalidOperationException("YouTube PubSub Redis connection string was not defined"); + } + + public async Task Connect() + { + var channel = await SettingsProvider.GetValueAsync(BuiltIn.Keys.YouTubePubSubRedisChannel); + if (channel.Value == null) + { + throw new InvalidOperationException("Redis channel was null"); + } + _redis = await ConnectionMultiplexer.ConnectAsync(_connectionString); + _sub = _redis.GetSubscriber(); + await _sub.SubscribeAsync(new RedisChannel(channel.Value, RedisChannel.PatternMode.Literal), PubSubMessageReceived); + } + + public bool IsConnected() + { + if (_redis == null || _sub == null) return false; + return _sub.IsConnected(); + } + + private void PubSubMessageReceived(RedisChannel channel, RedisValue message) + { + try + { + var payload = JsonSerializer.Deserialize(message.ToString()); + if (payload == null) + { + throw new InvalidOperationException("Caught a null when attempting to deserialize the PubSub JSON"); + } + OnNewVideo?.Invoke(this, payload); + } + catch (Exception e) + { + _logger.Error("PubSub shit itself when trying to handle a message"); + _logger.Error(e); + _logger.Error("--- Payload ---"); + _logger.Error(message.ToString()); + } + } + + public void Dispose() + { + _sub?.UnsubscribeAll(); + _redis?.Dispose(); + GC.SuppressFinalize(this); + } +} + +public class YouTubePubSubNotificationModel +{ + [JsonPropertyName("id")] + public required string Id { get; set; } + [JsonPropertyName("title")] + public required string Title { get; set; } + [JsonPropertyName("url")] + public required string Url { get; set; } + [JsonPropertyName("channel")] + public required YouTubePubSubNotificationChannelModel Channel { get; set; } +} + +public class YouTubePubSubNotificationChannelModel +{ + [JsonPropertyName("id")] + public required string Id { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } +} \ No newline at end of file diff --git a/KfChatDotNetBot/Settings/BuiltIn.cs b/KfChatDotNetBot/Settings/BuiltIn.cs index df9e133..5775199 100644 --- a/KfChatDotNetBot/Settings/BuiltIn.cs +++ b/KfChatDotNetBot/Settings/BuiltIn.cs @@ -441,6 +441,10 @@ public static class BuiltIn public static string KasinoEventTextLengthLimit = "Kasino.Event.TextLengthLimit"; [BuiltInSetting("Length limit for Kasino event option text", SettingValueType.Text, "250", WholeNumberRegex)] public static string KasinoEventOptionTextLengthLimit = "Kasino.Event.OptionTextLengthLimit"; + [BuiltInSetting("Connection string for YouTube PubSub Redis", SettingValueType.Text, "localhost:6379")] + public static string YouTubePubSubRedisConnectionString = "YouTube.PubSub.RedisConnectionString"; + [BuiltInSetting("Channel for YouTube PubSub with Redis", SettingValueType.Text, "yt-pubsub")] + public static string YouTubePubSubRedisChannel = "YouTube.PubSub.RedisChannel"; } }