using NetCord; using NetCord.Gateway; using NetCord.Hosting.Gateway; using NetCord.Rest; using SquadBot.Providers; namespace SquadBot.StateMangers; public class VoiceStateManager { // Key: GuildId Value: List of UserId for users in voice channel // TODO: We probably want to persist this somewhere else (Redis/Valkey) private Dictionary> _guildVoiceStates; private Dictionary _yapperNotificationTimeouts; private RestClient _restClient; private ILogger _logger; public VoiceStateManager(ILogger logger, RestClient restClient) { _guildVoiceStates = new Dictionary>(); _yapperNotificationTimeouts = new Dictionary(); _restClient = restClient ?? throw new System.ArgumentNullException(nameof(restClient)); _logger = logger ?? throw new System.ArgumentNullException(nameof(logger)); } public async Task HandleVoiceStateChange(VoiceState voice_state) { if (voice_state.ChannelId is not null) { // Joining channel _logger.LogInformation($"New yapper detected: {voice_state.User.Username}"); if (!_guildVoiceStates.TryGetValue(voice_state.GuildId, out var yappers) || yappers.Count < 0) { var channels = await _restClient.GetGuildChannelsAsync(voice_state.GuildId); var alertChannelId = channels.FirstOrDefault(channel => channel.Name == "bot-tinkering")?.Id; var guildRoles = await _restClient.GetGuildRolesAsync(voice_state.GuildId, new RestRequestProperties() { AuditLogReason = "Role lookup" }); var yapperRoleId = guildRoles.FirstOrDefault(role => role.Name.ToLower() == "yapper")?.Id; if (alertChannelId is not null && yapperRoleId is not null && (!_yapperNotificationTimeouts.TryGetValue(voice_state.GuildId, out var timeout) || DateTimeOffset.UtcNow.CompareTo(timeout) > 0)) { // Notify that new yapper has arrived await _restClient.SendMessageAsync( alertChannelId.GetValueOrDefault(), new MessageProperties() { AllowedMentions = new AllowedMentionsProperties() {AllowedRoles = [yapperRoleId.GetValueOrDefault()]}, Content = $"<@&{yapperRoleId.GetValueOrDefault()}> " + PhraseProvider.GetYapperPhrase() }); } yappers = new HashSet() { voice_state.UserId }; } else { yappers = yappers.Append(voice_state.UserId).ToHashSet(); } _guildVoiceStates[voice_state.GuildId] = yappers; } else { // Leaving channel _logger.LogInformation($"Yapper leaving: {voice_state.User.Username}"); if (_guildVoiceStates.TryGetValue(voice_state.GuildId, out var yappers)) { yappers.Remove(voice_state.UserId); _guildVoiceStates[voice_state.GuildId] = yappers; _yapperNotificationTimeouts[voice_state.GuildId] = DateTimeOffset.UtcNow.AddHours(2); } } return; } }