Updated Kick support so admins can now add/remove streamers and force a reconnect to commit the changes

This commit is contained in:
barelyprofessional
2024-09-21 00:28:16 +08:00
parent 1a0197a4c3
commit 12980a86c3
4 changed files with 167 additions and 21 deletions
+75
View File
@@ -1,6 +1,7 @@
using System.Runtime.Caching; using System.Runtime.Caching;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Humanizer; using Humanizer;
using KfChatDotNetBot.Models;
using KfChatDotNetBot.Models.DbModels; using KfChatDotNetBot.Models.DbModels;
using KfChatDotNetBot.Settings; using KfChatDotNetBot.Settings;
using KfChatDotNetWsClient.Models.Events; using KfChatDotNetWsClient.Models.Events;
@@ -162,4 +163,78 @@ public class CacheClearAdminCommand : ICommand
} }
await botInstance.SendChatMessageAsync("Cache wiped", true); await botInstance.SendChatMessageAsync("Cache wiped", true);
} }
}
public class NewKickChannelCommand : ICommand
{
public List<Regex> Patterns => [
new Regex(@"^admin kick add (?<forum_id>\d+) (?<channel_id>\d+) (?<slug>\S+)$")
];
public string? HelpText => "Add a Kick channel to the bot's database";
public UserRight RequiredRight => UserRight.Admin;
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
{
var channels = (await Helpers.GetValue(BuiltIn.Keys.KickChannels)).JsonDeserialize<List<KickChannelModel>>();
var channelId = Convert.ToInt32(arguments["channel_id"].Value);
if (channels.Any(channel => channel.ChannelId == channelId))
{
await botInstance.SendChatMessageAsync("Channel is already in the database", true);
return;
}
var forumId = Convert.ToInt32(arguments["forum_id"].Value);
channels.Add(new KickChannelModel
{
ChannelId = channelId,
ForumId = forumId,
ChannelSlug = arguments["slug"].Value
});
await Helpers.SetValueAsJsonObject(BuiltIn.Keys.KickChannels, channels);
await botInstance.SendChatMessageAsync("Updated list of channels", true);
}
}
public class RemoveKickChannelCommand : ICommand
{
public List<Regex> Patterns => [
new Regex(@"^admin kick remove (?<channel_id>\d+)$")
];
public string? HelpText => "Remove a Kick channel from the bot's database";
public UserRight RequiredRight => UserRight.Admin;
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
{
var channels = (await Helpers.GetValue(BuiltIn.Keys.KickChannels)).JsonDeserialize<List<KickChannelModel>>();
var channelId = Convert.ToInt32(arguments["channel_id"].Value);
var channel = channels.FirstOrDefault(ch => ch.ChannelId == channelId);
if (channel == null)
{
await botInstance.SendChatMessageAsync("Channel is not in the database", true);
return;
}
channels.Remove(channel);
await Helpers.SetValueAsJsonObject(BuiltIn.Keys.KickChannels, channels);
await botInstance.SendChatMessageAsync("Updated list of channels", true);
}
}
public class ReconnectKickCommand : ICommand
{
public List<Regex> Patterns => [
new Regex(@"^admin kick reconnect$")
];
public string? HelpText => "Disconnect from Kick so the watchdog can reconnect it";
public UserRight RequiredRight => UserRight.Admin;
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
{
botInstance.BotServices.KickClient.Disconnect();
await botInstance.SendChatMessageAsync("Disconnected from Kick. Client should reconnect shortly.", true);
}
} }
@@ -0,0 +1,8 @@
namespace KfChatDotNetBot.Models;
public class KickChannelModel
{
public required int ChannelId { get; set; }
public required int ForumId { get; set; }
public required string ChannelSlug { get; set; }
}
+74 -21
View File
@@ -18,7 +18,7 @@ public class BotServices
private readonly CancellationToken _cancellationToken; private readonly CancellationToken _cancellationToken;
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private KickWsClient.KickWsClient _kickClient; internal KickWsClient.KickWsClient KickClient;
private Twitch _twitch; private Twitch _twitch;
private Shuffle _shuffle; private Shuffle _shuffle;
private DiscordService _discord; private DiscordService _discord;
@@ -166,24 +166,30 @@ public class BotServices
{ {
var settings = await Helpers.GetMultipleValues([ var settings = await Helpers.GetMultipleValues([
BuiltIn.Keys.PusherEndpoint, BuiltIn.Keys.Proxy, BuiltIn.Keys.PusherReconnectTimeout, BuiltIn.Keys.KickEnabled, BuiltIn.Keys.PusherEndpoint, BuiltIn.Keys.Proxy, BuiltIn.Keys.PusherReconnectTimeout, BuiltIn.Keys.KickEnabled,
BuiltIn.Keys.PusherChannels BuiltIn.Keys.PusherChannels, BuiltIn.Keys.KickChannels
]); ]);
_kickClient = new KickWsClient.KickWsClient(settings[BuiltIn.Keys.PusherEndpoint].Value!, KickClient = new KickWsClient.KickWsClient(settings[BuiltIn.Keys.PusherEndpoint].Value!,
settings[BuiltIn.Keys.Proxy].Value, settings[BuiltIn.Keys.PusherReconnectTimeout].ToType<int>()); settings[BuiltIn.Keys.Proxy].Value, settings[BuiltIn.Keys.PusherReconnectTimeout].ToType<int>());
_kickClient.OnStreamerIsLive += OnStreamerIsLive; KickClient.OnStreamerIsLive += OnStreamerIsLive;
_kickClient.OnChatMessage += OnKickChatMessage; KickClient.OnChatMessage += OnKickChatMessage;
_kickClient.OnWsReconnect += OnPusherWsReconnected; KickClient.OnWsReconnect += OnPusherWsReconnected;
_kickClient.OnPusherSubscriptionSucceeded += OnPusherSubscriptionSucceeded; KickClient.OnPusherSubscriptionSucceeded += OnPusherSubscriptionSucceeded;
_kickClient.OnStopStreamBroadcast += OnStopStreamBroadcast; KickClient.OnStopStreamBroadcast += OnStopStreamBroadcast;
if (settings[BuiltIn.Keys.KickEnabled].ToBoolean()) if (settings[BuiltIn.Keys.KickEnabled].ToBoolean())
{ {
await _kickClient.StartWsClient(); await KickClient.StartWsClient();
var pusherChannels = settings[BuiltIn.Keys.PusherChannels].ToList(); // var pusherChannels = settings[BuiltIn.Keys.PusherChannels].ToList();
foreach (var channel in pusherChannels) // foreach (var channel in pusherChannels)
// {
// _kickClient.SendPusherSubscribe(channel);
// }
var kickChannels = settings[BuiltIn.Keys.KickChannels].JsonDeserialize<List<KickChannelModel>>();
if (kickChannels == null) return;
foreach (var channel in kickChannels)
{ {
_kickClient.SendPusherSubscribe(channel); KickClient.SendPusherSubscribe($"channel.{channel.ChannelId}");
} }
} }
} }
@@ -270,11 +276,11 @@ public class BotServices
await BuildChipsgg(); await BuildChipsgg();
} }
if (settings[BuiltIn.Keys.KickEnabled].ToBoolean() && !_kickClient.IsConnected()) if (settings[BuiltIn.Keys.KickEnabled].ToBoolean() && !KickClient.IsConnected())
{ {
_logger.Error("Kick died, recreating it"); _logger.Error("Kick died, recreating it");
_kickClient.Dispose(); KickClient.Dispose();
_kickClient = null!; KickClient = null!;
await BuildKick(); await BuildKick();
} }
} }
@@ -631,11 +637,11 @@ public class BotServices
private void OnPusherWsReconnected(object sender, ReconnectionInfo reconnectionInfo) private void OnPusherWsReconnected(object sender, ReconnectionInfo reconnectionInfo)
{ {
_logger.Error($"Pusher reconnected due to {reconnectionInfo.Type}"); _logger.Error($"Pusher reconnected due to {reconnectionInfo.Type}");
var channels = Helpers.GetValue(BuiltIn.Keys.PusherChannels).Result.ToList(); var kickChannels = Helpers.GetValue(BuiltIn.Keys.KickChannels).Result.JsonDeserialize<List<KickChannelModel>>();
foreach (var channel in channels) if (kickChannels == null) return;
foreach (var channel in kickChannels)
{ {
_logger.Info($"Rejoining {channel}"); KickClient.SendPusherSubscribe($"channel.{channel.ChannelId}");
_kickClient.SendPusherSubscribe(channel);
} }
} }
@@ -659,11 +665,58 @@ public class BotServices
private void OnStreamerIsLive(object sender, KickModels.StreamerIsLiveEventModel? e) private void OnStreamerIsLive(object sender, KickModels.StreamerIsLiveEventModel? e)
{ {
if (e == null) return; if (e == null) return;
_chatBot.SendChatMessage($"Dirt Devils LFG! @Juhlonduss is live! {e.Livestream.SessionTitle} https://kick.com/dirtdevil-enjoyer", true); var channels = Helpers.GetValue(BuiltIn.Keys.KickChannels).Result.JsonDeserialize<List<KickChannelModel>>();
if (channels == null)
{
_logger.Error("Caught null when grabbing Kick channels");
return;
}
var channel = channels.FirstOrDefault(ch => ch.ChannelId == e.Livestream.ChannelId);
if (channel == null)
{
_logger.Error($"Caught null when grabbing channel data for {e.Livestream.ChannelId}");
return;
}
using var db = new ApplicationDbContext();
var user = db.Users.FirstOrDefault(u => u.KfId == channel.ForumId);
if (user == null)
{
_logger.Error($"Caught null when retrieving forum user {channel.ForumId}");
return;
}
_chatBot.SendChatMessage(
$"@{user.KfUsername} is live! {e.Livestream.SessionTitle} https://kick.com/{channel.ChannelSlug}", true);
} }
private void OnStopStreamBroadcast(object sender, KickModels.StopStreamBroadcastEventModel? e) private void OnStopStreamBroadcast(object sender, KickModels.StopStreamBroadcastEventModel? e)
{ {
_chatBot.SendChatMessage("Dirt Devils felted. Stream is over. :lossmanjack:", true); if (e == null) return;
var channels = Helpers.GetValue(BuiltIn.Keys.KickChannels).Result.JsonDeserialize<List<KickChannelModel>>();
if (channels == null)
{
_logger.Error("Caught null when grabbing Kick channels");
return;
}
var channel = channels.FirstOrDefault(ch => ch.ChannelId == e.Livestream.Channel.Id);
if (channel == null)
{
_logger.Error($"Caught null when grabbing channel data for {e.Livestream.Channel.Id}");
return;
}
using var db = new ApplicationDbContext();
var user = db.Users.FirstOrDefault(u => u.KfId == channel.ForumId);
if (user == null)
{
_logger.Error($"Caught null when retrieving forum user {channel.ForumId}");
return;
}
_chatBot.SendChatMessage(
$"@{user.KfUsername} is no longer live! :lossmanjack:", true);
} }
} }
+10
View File
@@ -534,6 +534,15 @@ public static class BuiltIn
Default = "2", Default = "2",
IsSecret = false, IsSecret = false,
CacheDuration = TimeSpan.FromHours(1) CacheDuration = TimeSpan.FromHours(1)
},
new BuiltInSettingsModel
{
Key = Keys.KickChannels,
Regex = ".+",
Description = "Kick channels the bot knows about for notifications",
Default = "[]",
IsSecret = false,
CacheDuration = TimeSpan.FromHours(1)
} }
]; ];
@@ -585,5 +594,6 @@ public static class BuiltIn
public static string WinmanjackImgUrl = "Winmanjack.ImgUrl"; public static string WinmanjackImgUrl = "Winmanjack.ImgUrl";
public static string BotDisconnectReplayLimit = "Bot.DisconnectReplayLimit"; public static string BotDisconnectReplayLimit = "Bot.DisconnectReplayLimit";
public static string KiwiFarmsJoinFailLimit = "KiwiFarms.JoinFailLimit"; public static string KiwiFarmsJoinFailLimit = "KiwiFarms.JoinFailLimit";
public static string KickChannels = "Kick.Channels";
} }
} }