mirror of
https://github.com/barelyprofessional/KfChatDotNet.git
synced 2026-05-15 10:32:44 -04:00
Updated Kick support so admins can now add/remove streamers and force a reconnect to commit the changes
This commit is contained in:
@@ -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; }
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user