Skip to content

Commit

Permalink
Merge pull request #280 from rGunti/249-feature-special-raid-message-…
Browse files Browse the repository at this point in the history
…for-stream-team-members

Implemented automated Raid Messages
  • Loading branch information
rGunti authored May 9, 2024
2 parents 3f2d5cf + 1da9fd7 commit 457a3b1
Show file tree
Hide file tree
Showing 33 changed files with 500 additions and 59 deletions.
3 changes: 2 additions & 1 deletion src/FloppyBot.Aux.TwitchAlerts.Core/DiSetup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FloppyBot.Aux.TwitchAlerts.Core.Entities;
using FloppyBot.Aux.TwitchAlerts.Core.Entities.Storage;
using Microsoft.Extensions.DependencyInjection;

namespace FloppyBot.Aux.TwitchAlerts.Core;
Expand All @@ -14,6 +15,6 @@ public static IServiceCollection AddTwitchAlertService(this IServiceCollection s
{
return services
.AddTransient<ITwitchAlertService, TwitchAlertService>()
.AddAutoMapper(typeof(TwitchAlertListener));
.AddAutoMapper(typeof(TwitchAlertStorageProfile));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public record TwitchAlertSettingsEo(
TwitchAlertMessageEo[] SubMessages,
TwitchAlertMessageEo[] ReSubMessages,
TwitchAlertMessageEo[] GiftSubMessages,
TwitchAlertMessageEo[] GiftSubCommunityMessages
TwitchAlertMessageEo[] GiftSubCommunityMessages,
TwitchAlertMessageEo[] RaidAlertMessages
) : IEntity<TwitchAlertSettingsEo>
{
public TwitchAlertSettingsEo WithId(string newId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public TwitchAlertStorageProfile()
dto.GiftSubCommunityMessage.Select(msg =>
ctx.Mapper.Map<TwitchAlertMessageEo>(msg)
)
.ToArray(),
dto.RaidAlertMessage.Select(msg =>
ctx.Mapper.Map<TwitchAlertMessageEo>(msg)
)
.ToArray()
)
);
Expand Down Expand Up @@ -50,6 +54,11 @@ public TwitchAlertStorageProfile()
ctx.Mapper.Map<TwitchAlertMessage>(msg)
)
.ToImmutableList(),
RaidAlertMessage = eo
.RaidAlertMessages.Select(msg =>
ctx.Mapper.Map<TwitchAlertMessage>(msg)
)
.ToImmutableList(),
}
);
CreateMap<TwitchAlertMessageEo, TwitchAlertMessage>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public record TwitchAlertSettings : IEntity<TwitchAlertSettings>
ImmutableList<TwitchAlertMessage>.Empty;
private readonly IImmutableList<TwitchAlertMessage> _giftSubCommunityMessages =
ImmutableList<TwitchAlertMessage>.Empty;
private readonly IImmutableList<TwitchAlertMessage> _raidAlertMessage =
ImmutableList<TwitchAlertMessage>.Empty;

public string Id { get; init; }

Expand Down Expand Up @@ -44,6 +46,12 @@ public IImmutableList<TwitchAlertMessage> GiftSubCommunityMessage
init => _giftSubCommunityMessages = value.WithValueSemantics();
}

public IImmutableList<TwitchAlertMessage> RaidAlertMessage
{
get => _raidAlertMessage;
init => _raidAlertMessage = value.WithValueSemantics();
}

public TwitchAlertSettings WithId(string newId)
{
return this with { Id = newId };
Expand Down
19 changes: 11 additions & 8 deletions src/FloppyBot.Aux.TwitchAlerts.Core/TwitchAlertListener.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.Collections.Frozen;
using System.Collections.Immutable;
using System.Text.Json;
using FloppyBot.Aux.TwitchAlerts.Core.Entities;
using FloppyBot.Base.Configuration;
Expand All @@ -15,13 +16,13 @@ namespace FloppyBot.Aux.TwitchAlerts.Core;

public class TwitchAlertListener : IDisposable
{
private static readonly ISet<string> AllowedEvents = new[]
private static readonly FrozenSet<string> AllowedEvents = new[]
{
TwitchEventTypes.SUBSCRIPTION,
TwitchEventTypes.RE_SUBSCRIPTION,
TwitchEventTypes.SUBSCRIPTION_GIFT,
TwitchEventTypes.SUBSCRIPTION_GIFT_COMMUNITY,
}.ToHashSet();
}.ToFrozenSet();

private static readonly IImmutableDictionary<
TwitchSubscriptionPlanTier,
Expand Down Expand Up @@ -52,6 +53,7 @@ private static readonly IImmutableDictionary<
{ TwitchEventTypes.RE_SUBSCRIPTION, s => s.ReSubMessage },
{ TwitchEventTypes.SUBSCRIPTION_GIFT, s => s.GiftSubMessage },
{ TwitchEventTypes.SUBSCRIPTION_GIFT_COMMUNITY, s => s.GiftSubCommunityMessage },
{ TwitchEventTypes.RAID, s => s.RaidAlertMessage },
}.ToImmutableDictionary();

private static string? DetermineTemplate(
Expand Down Expand Up @@ -84,6 +86,7 @@ TwitchReSubscriptionReceivedEvent reSubscriptionReceivedEvent
TwitchSubscriptionGiftEvent subGiftEvent => subGiftEvent.SubscriptionPlanTier.Tier,
TwitchSubscriptionCommunityGiftEvent subCommunityGiftEvent
=> subCommunityGiftEvent.SubscriptionPlanTier.Tier,
TwitchRaidEvent _ => TwitchSubscriptionPlanTier.Unknown,
_ => throw new ArgumentOutOfRangeException(nameof(twitchEvent)),
};
}
Expand All @@ -100,6 +103,7 @@ TwitchSubscriptionCommunityGiftEvent subCommunityGiftEvent
=> JsonSerializer.Deserialize<TwitchSubscriptionGiftEvent>(content),
TwitchEventTypes.SUBSCRIPTION_GIFT_COMMUNITY
=> JsonSerializer.Deserialize<TwitchSubscriptionCommunityGiftEvent>(content),
TwitchEventTypes.RAID => JsonSerializer.Deserialize<TwitchRaidEvent>(content),
_ => throw new ArgumentOutOfRangeException(nameof(type)),
};
}
Expand Down Expand Up @@ -166,15 +170,14 @@ private void OnMessageReceived(ChatMessage chatMessage)
#endif

var twitchEvent = ParseTwitchEvent(chatMessage.EventName, chatMessage.Content);
if (twitchEvent == null)
if (twitchEvent is null)
{
_logger.LogWarning("Failed to parse chat message content");
return;
}

var alertMessage = GetFormattedMessage(chatMessage, twitchEvent);

if (alertMessage == null)
if (alertMessage is null)
{
return;
}
Expand All @@ -193,7 +196,7 @@ private void OnMessageReceived(ChatMessage chatMessage)
{
var channelId = chatMessage.Identifier.GetChannel();
var alertSettings = _alertService.GetAlertSettings(channelId);
if (alertSettings == null)
if (alertSettings is null)
{
_logger.LogDebug("No alert settings found for channel {Channel}, skipping", channelId);
return null;
Expand All @@ -202,7 +205,7 @@ private void OnMessageReceived(ChatMessage chatMessage)
var subTier = GetTier(twitchEvent);

var template = DetermineTemplate(twitchEvent, alertSettings, subTier);
if (template == null)
if (template is null)
{
_logger.LogDebug(
"No template found for event {EventName} and tier {Tier}, skipping",
Expand Down
5 changes: 5 additions & 0 deletions src/FloppyBot.Base.Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ public static string Capitalize(this string s)
_ => $"{char.ToUpperInvariant(s[0])}{s[1..]}",
};
}

public static int ParseInt(this string s, int defaultValue = 0)
{
return int.TryParse(s, out var result) ? result : defaultValue;
}
}
23 changes: 22 additions & 1 deletion src/FloppyBot.Base.Storage.MongoDb/MongoDbRepositoryFactory.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
using FloppyBot.Base.Storage.Utils;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;

namespace FloppyBot.Base.Storage.MongoDb;

public class MongoDbRepositoryFactory : IRepositoryFactory
{
private readonly ILogger<MongoDbRepositoryFactory> _logger;
private readonly IMongoDatabase _database;

public MongoDbRepositoryFactory(IMongoDatabase database)
public MongoDbRepositoryFactory(
IMongoDatabase database,
ILogger<MongoDbRepositoryFactory> logger
)
{
_database = database;
_logger = logger;
}

public IRepository<T> GetRepository<T>()
Expand All @@ -19,6 +26,20 @@ public IRepository<T> GetRepository<T>()
public IRepository<T> GetRepository<T>(string collectionName)
where T : class, IEntity<T>
{
var collectionExists = _database
.ListCollections(
new ListCollectionsOptions
{
Filter = Builders<BsonDocument>.Filter.Eq(f => f["name"], collectionName),
}
)
.Any();
if (!collectionExists)
{
_logger.LogDebug("Creating collection {CollectionName}", collectionName);
_database.CreateCollection(collectionName);
}

return new MongoDbRepository<T>(_database.GetCollection<T>(collectionName));
}
}
1 change: 1 addition & 0 deletions src/FloppyBot.Chat.Twitch.Events/TwitchEventTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public static class TwitchEventTypes
public const string RE_SUBSCRIPTION = "Twitch.ReSubscription";
public const string SUBSCRIPTION_GIFT = "Twitch.SubscriptionGift";
public const string SUBSCRIPTION_GIFT_COMMUNITY = "Twitch.SubscriptionGiftCommunity";
public const string RAID = "Twitch.Raid";
}
10 changes: 10 additions & 0 deletions src/FloppyBot.Chat.Twitch.Events/TwitchRaidEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace FloppyBot.Chat.Twitch.Events;

public record TwitchRaidEvent(
string ChannelName,
string ChannelDisplayName,
int ViewerCount,
StreamTeam? StreamTeam
) : TwitchEvent(TwitchEventTypes.RAID);

public record StreamTeam(string Name, string DisplayName);
18 changes: 8 additions & 10 deletions src/FloppyBot.Chat.Twitch.Tests/TwitchChatInterfaceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using FloppyBot.Base.Testing;
using FloppyBot.Chat.Entities;
using FloppyBot.Chat.Entities.Identifiers;
using FloppyBot.Chat.Twitch.Api;
using FloppyBot.Chat.Twitch.Config;
using FloppyBot.Chat.Twitch.Events;
using FloppyBot.Chat.Twitch.Monitor;
Expand All @@ -22,15 +23,12 @@ namespace FloppyBot.Chat.Twitch.Tests;
[TestClass]
public class TwitchChatInterfaceTests
{
private readonly ITwitchClient _client;
private readonly ITwitchChannelOnlineMonitor _onlineMonitor;
private TwitchConfiguration _configuration;
private readonly ITwitchClient _client = A.Fake<ITwitchClient>();
private readonly ITwitchChannelOnlineMonitor _onlineMonitor =
A.Fake<ITwitchChannelOnlineMonitor>();

public TwitchChatInterfaceTests()
{
_client = A.Fake<ITwitchClient>();
_onlineMonitor = A.Fake<ITwitchChannelOnlineMonitor>();
_configuration = new TwitchConfiguration(
private TwitchConfiguration _configuration =
new(
"atwitchbot",
"sometoken",
"atwitchchannel",
Expand All @@ -40,7 +38,6 @@ public TwitchChatInterfaceTests()
0,
false
);
}

[TestMethod]
public void BroadcasterHasAdminRights()
Expand Down Expand Up @@ -234,7 +231,8 @@ private TwitchChatInterface CreateInterface(TwitchConfiguration? configuration =
LoggingUtils.GetLogger<TwitchClient>(),
_client,
_configuration,
_onlineMonitor
_onlineMonitor,
A.Fake<ITwitchApiService>()
);
}

Expand Down
3 changes: 3 additions & 0 deletions src/FloppyBot.Chat.Twitch/Api/Dtos/StreamTeam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace FloppyBot.Chat.Twitch.Api.Dtos;

public record StreamTeam(string Id, string Name, string DisplayName);
54 changes: 54 additions & 0 deletions src/FloppyBot.Chat.Twitch/Api/ITwitchApiService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using FloppyBot.Chat.Twitch.Api.Dtos;
using TwitchLib.Api.Helix.Models.Teams;
using TwitchLib.Api.Interfaces;

namespace FloppyBot.Chat.Twitch.Api;

public interface ITwitchApiService
{
IEnumerable<StreamTeam> GetStreamTeamsOfChannel(string channel);
string? GetBroadcasterId(string channel);
}

public class TwitchApiService : ITwitchApiService
{
private readonly ITwitchAPI _twitchApi;

public TwitchApiService(ITwitchAPI twitchApi)
{
_twitchApi = twitchApi;
}

public IEnumerable<StreamTeam> GetStreamTeamsOfChannel(string channel)
{
return DoGetStreamTeamName(channel).GetAwaiter().GetResult();
}

public string? GetBroadcasterId(string channel)
{
return DoGetBroadcasterId(channel).GetAwaiter().GetResult();
}

private static StreamTeam ConvertToStreamTeam(Team team)
{
return new StreamTeam(team.Id, team.TeamName, team.TeamDisplayName);
}

private async Task<IEnumerable<StreamTeam>> DoGetStreamTeamName(string channel)
{
var broadcasterId = await DoGetBroadcasterId(channel);
if (broadcasterId == null)
{
return Enumerable.Empty<StreamTeam>();
}

var teams = await _twitchApi.Helix.Teams.GetTeamsAsync(broadcasterId);
return teams.Teams.Select(ConvertToStreamTeam);
}

private async Task<string?> DoGetBroadcasterId(string channel)
{
var program = await _twitchApi.Helix.Users.GetUsersAsync(logins: [channel]);
return program.Users.Select(u => u.Id).FirstOrDefault();
}
}
2 changes: 2 additions & 0 deletions src/FloppyBot.Chat.Twitch/Config/Registration.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using FloppyBot.Chat.Twitch.Api;
using FloppyBot.Chat.Twitch.Monitor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -60,6 +61,7 @@ public static IServiceCollection AddTwitchChatInterface(this IServiceCollection
return new LiveStreamMonitorService(api, config.MonitorInterval);
})
.AddSingleton<ITwitchChannelOnlineMonitor, TwitchChannelOnlineMonitor>()
.AddSingleton<ITwitchApiService, TwitchApiService>()
// - Chat Interface
.AddSingleton<IChatInterface, TwitchChatInterface>();
}
Expand Down
1 change: 1 addition & 0 deletions src/FloppyBot.Chat.Twitch/FloppyBot.Chat.Twitch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FloppyBot.Base.Extensions\FloppyBot.Base.Extensions.csproj" />
<ProjectReference Include="..\FloppyBot.Chat.Twitch.Events\FloppyBot.Chat.Twitch.Events.csproj" />
<ProjectReference Include="..\FloppyBot.Chat\FloppyBot.Chat.csproj" />
</ItemGroup>
Expand Down
Loading

0 comments on commit 457a3b1

Please sign in to comment.