diff --git a/TwitchDownloaderCore.Tests/HighlightIconsTests.cs b/TwitchDownloaderCore.Tests/HighlightIconsTests.cs new file mode 100644 index 00000000..febcd73b --- /dev/null +++ b/TwitchDownloaderCore.Tests/HighlightIconsTests.cs @@ -0,0 +1,264 @@ +using System.Text.Json; +using TwitchDownloaderCore.Tools; +using TwitchDownloaderCore.TwitchObjects; + +namespace TwitchDownloaderCore.Tests +{ + // ReSharper disable StringLiteralTypo + public class HighlightIconsTests + { + private static Comment CreateCommentWithCommenterAndMessage(Commenter commenter, Message message) + { + return new Comment + { + _id = Guid.NewGuid().ToString(), + created_at = DateTime.Today, + channel_id = Random.Shared.Next(10_000_000, 99_999_999).ToString(), + content_type = "video", + content_id = Random.Shared.NextInt64(10_000_000, 99_999_999_999).ToString(), + content_offset_seconds = Random.Shared.NextDouble() * 100, + commenter = commenter, + message = message + }; + } + + private static Comment CreateCommentWithMessage(string viewerDisplayName, string viewerName, Message message) + { + return CreateCommentWithCommenterAndMessage( + new Commenter + { + display_name = viewerDisplayName, + _id = Random.Shared.Next(10_000_000, 99_999_999).ToString(), + name = viewerName, + bio = "I am a test user.", + created_at = DateTime.Today, + updated_at = DateTime.Today, + logo = @"https://vod-secure.twitch.tv/_404/404_processing_320x180.png" + }, + message); + } + + [Theory] + // SubscribedTier no custom message + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + HighlightType.SubscribedTier)] + // SubscribedTier custom message + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months! Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months! Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + HighlightType.SubscribedTier)] + // SubscribedPrime no custom message + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"premium\",\"version\":\"1\"}],\"user_color\":\"#FF69B4\",\"emoticons\":[]}", + HighlightType.SubscribedPrime)] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 2 months! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 2 months! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"premium\",\"version\":\"1\"}],\"user_color\":\"#FF69B4\",\"emoticons\":[]}", + HighlightType.SubscribedPrime)] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 8 months, currently on a 8 month streak! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 8 months, currently on a 8 month streak! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"premium\",\"version\":\"1\"}],\"user_color\":\"#FF69B4\",\"emoticons\":[]}", + HighlightType.SubscribedPrime)] + // SubscribedPrime custom message + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + HighlightType.SubscribedPrime)] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 3 months! Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 3 months! Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + HighlightType.SubscribedPrime)] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 3 months, currently on a 3 month streak! Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 3 months, currently on a 3 month streak! Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + HighlightType.SubscribedPrime)] + // Converted + [InlineData( + "{\"body\":\"viewer8 converted from a Prime sub to a Tier 1 sub! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 converted from a Prime sub to a Tier 1 sub! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"0\"},{\"_id\":\"bits\",\"version\":\"100\"}],\"user_color\":null,\"emoticons\":[]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 converted from a Tier 1 sub to a Tier 2 sub! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 converted from a Tier 2 sub to a Tier 3 sub! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"0\"},{\"_id\":\"bits\",\"version\":\"100\"}],\"user_color\":null,\"emoticons\":[]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 converted from a Tier 1 sub to a Tier 3 sub! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 converted from a Tier 1 sub to a Tier 3 sub! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"0\"},{\"_id\":\"bits\",\"version\":\"100\"}],\"user_color\":null,\"emoticons\":[]}", + HighlightType.SubscribedTier)] + [InlineData( + "{\"body\":\"viewer8 converted from a Tier 1 sub to a Prime sub! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 converted from a Tier 1 sub to a Prime sub! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"0\"},{\"_id\":\"bits\",\"version\":\"100\"}],\"user_color\":null,\"emoticons\":[]}", + HighlightType.SubscribedPrime)] + // GiftedMany + [InlineData( + "{\"body\":\"viewer8 is gifting 5 Tier 1 Subs to streamer8's community! They've gifted a total of 349 in the channel! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 is gifting 5 Tier 1 Subs to streamer8's community! They've gifted a total of 349 in the channel! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"6\"},{\"_id\":\"bits\",\"version\":\"50000\"}],\"user_color\":\"#DAA520\",\"emoticons\":[]}", + HighlightType.GiftedMany)] + // GiftedSingle + [InlineData( + "{\"body\":\"viewer8 gifted a Tier 1 sub to viewer9! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 gifted a Tier 1 sub to viewer9! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"6\"},{\"_id\":\"bits\",\"version\":\"50000\"}],\"user_color\":\"#DAA520\",\"emoticons\":[]}", + HighlightType.GiftedSingle)] + // GiftedAnonymous + // Special case, in separate method. + // ContinuingGift + [InlineData( + "{\"body\":\"viewer8 is continuing the Gift Sub they got from an anonymous user! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 is continuing the Gift Sub they got from an anonymous user! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"0\"}],\"user_color\":\"#8A2BE2\",\"emoticons\":[]}", + HighlightType.ContinuingGift)] + // PayingForward + [InlineData( + "{\"body\":\"viewer8 is paying forward the Gift they got from an anonymous gifter to the community! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 is paying forward the Gift they got from an anonymous gifter to the community! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"0\"},{\"_id\":\"bits\",\"version\":\"100\"}],\"user_color\":null,\"emoticons\":[]}", + HighlightType.PayingForward)] + // ChannelPointHighlight + // Not yet supported + // Raid + [InlineData( + "{\"body\":\"5180 raiders from viewer8 have joined! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"5180 raiders from viewer8 have joined! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"moderator\",\"version\":\"1\"},{\"_id\":\"partner\",\"version\":\"1\"}],\"user_color\":\"#8A2BE2\",\"emoticons\":[]}", + HighlightType.Raid)] + // BitBadgeTierNotification + [InlineData( + "{\"body\":\"bits badge tier notification \",\"bits_spent\":0,\"fragments\":[{\"text\":\"bits badge tier notification \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"6\"},{\"_id\":\"bits\",\"version\":\"1000\"}],\"user_color\":\"#9E1A67\",\"emoticons\":[]}", + HighlightType.BitBadgeTierNotification)] + // WatchStreak no custom message + [InlineData( + "{\"body\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! \",\"emoticon\":null}],\"user_badges\":[],\"user_color\":\"#008000\",\"emoticons\":[]}", + HighlightType.WatchStreak)] + // WatchStreak custom message + [InlineData( + "{\"body\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too!\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too!\",\"emoticon\":null}],\"user_badges\":[],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + HighlightType.WatchStreak)] + [InlineData( + "{\"body\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":84,\"end\":88}]}", + HighlightType.WatchStreak)] + // Regular messages + [InlineData( + "{\"body\":\"Hi\",\"bits_spent\":0,\"fragments\":[{\"text\":\"Hi\",\"emoticon\":null}],\"user_badges\":[],\"user_color\":\"#5F9EA0\",\"emoticons\":[]}", + HighlightType.None)] + [InlineData( + "{\"body\":\"\",\"bits_spent\":0,\"fragments\":[{\"text\":\"\",\"emoticon\":null}],\"user_badges\":[],\"user_color\":\"#5F9EA0\",\"emoticons\":[]}", + HighlightType.None)] + public void CorrectlyIdentifiesHighlightTypes(string messageString, HighlightType expectedType) + { + var message = JsonSerializer.Deserialize(messageString)!; + var comment = CreateCommentWithMessage("viewer8", "viewer8", message); + + var actualType = HighlightIcons.GetHighlightType(comment); + + Assert.Equal(expectedType, actualType); + } + + [Fact] + public void CorrectlyIdentifiesAnonymousGiftSub() + { + const string COMMENTER_STRING = + "{\"display_name\":\"AnAnonymousGifter\",\"_id\":\"274598607\",\"name\":\"ananonymousgifter\",\"type\":\"user\",\"bio\":\"?????????????????????????????\",\"created_at\":\"2018-11-12T21:57:31.811529Z\",\"updated_at\":\"2022-04-18T21:57:27.392173Z\",\"logo\":\"https://static-cdn.jtvnw.net/jtv_user_pictures/ae7b05c6-c924-44ab-8203-475a2d3e488c-profile_image-300x300.png\"}"; + const string MESSAGE_STRING = + "{\"body\":\"An anonymous user gifted a Tier 1 sub to viewer8! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"An anonymous user gifted a Tier 1 sub to viewer8! \",\"emoticon\":null}],\"user_badges\":[],\"user_color\":null,\"emoticons\":[]}"; + const HighlightType EXPECTED_TYPE = HighlightType.GiftedAnonymous; + + var commenter = JsonSerializer.Deserialize(COMMENTER_STRING)!; + var message = JsonSerializer.Deserialize(MESSAGE_STRING)!; + var comment = CreateCommentWithCommenterAndMessage(commenter, message); + + var actualType = HighlightIcons.GetHighlightType(comment); + + Assert.Equal(EXPECTED_TYPE, actualType); + } + + [Theory] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}")] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 2. They've subscribed for 3 months! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 2. They've subscribed for 3 months! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}")] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 3. They've subscribed for 3 months, currently on a 3 month streak! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 3. They've subscribed for 3 months, currently on a 3 month streak! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}")] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"premium\",\"version\":\"1\"}],\"user_color\":\"#FF69B4\",\"emoticons\":[]}")] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 2 months! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 2 months! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"premium\",\"version\":\"1\"}],\"user_color\":\"#FF69B4\",\"emoticons\":[]}")] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 8 months, currently on a 8 month streak! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 8 months, currently on a 8 month streak! \",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"premium\",\"version\":\"1\"}],\"user_color\":\"#FF69B4\",\"emoticons\":[]}")] + public void DoesNotSplitSubCommentWithoutCustomMessage(string messageString) + { + var message = JsonSerializer.Deserialize(messageString)!; + var comment = CreateCommentWithMessage("viewer8", "viewer8", message); + + var (actual, shouldBeNull) = HighlightIcons.SplitSubComment(comment); + + Assert.Same(comment, actual); + Assert.Null(shouldBeNull); + } + + [Theory] + // 1 Fragment + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months! Hello!\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months! Hello!\",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + "viewer8 subscribed at Tier 1. They've subscribed for 3 months! ", "Hello!")] + [InlineData( + "{\"body\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! Hello!\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! Hello!\",\"emoticon\":null}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + "viewer8 subscribed at Tier 1. They've subscribed for 3 months, currently on a 3 month streak! ", "Hello!")] + // > 1 Fragment + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 3 months! Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 3 months! Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + "viewer8 subscribed with Prime. They've subscribed for 3 months! ", "Hello LUL LUL LUL")] + [InlineData( + "{\"body\":\"viewer8 subscribed with Prime. They've subscribed for 3 months, currently on a 3 month streak! Hello LUL LUL LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 subscribed with Prime. They've subscribed for 3 months, currently on a 3 month streak! Hello \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}},{\"text\":\" \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[{\"_id\":\"subscriber\",\"version\":\"3\"},{\"_id\":\"sub-gifter\",\"version\":\"5\"}],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":100,\"end\":104},{\"_id\":\"425618\",\"begin\":104,\"end\":108},{\"_id\":\"425618\",\"begin\":108,\"end\":112}]}", + "viewer8 subscribed with Prime. They've subscribed for 3 months, currently on a 3 month streak! ", "Hello LUL LUL LUL")] + public void CorrectlySplitsSubCommentWithCustomMessage(string messageString, string subMessageString, string customMessageString) + { + var message = JsonSerializer.Deserialize(messageString)!; + var comment = CreateCommentWithMessage("viewer8", "viewer8", message); + + var (subComment, customMessage) = HighlightIcons.SplitSubComment(comment); + + Assert.NotSame(comment, subComment); + Assert.Equal(subComment.message.body, subMessageString); + Assert.True(subComment.message.fragments.Count == 1, $"{subComment.message.fragments.Count} fragments were found in {nameof(subComment)}. Expected 1."); + Assert.Equal(subComment.message.fragments[0].text, subMessageString); + + Assert.NotNull(customMessage); + Assert.Equal(customMessage.message.body, customMessageString); + Assert.True(customMessage.message.fragments.Count > 0, $"0 fragments were found in {nameof(customMessage)}. Expected more than 0."); + } + + [Fact] + public void DoesNotSplitWatchStreakWithoutCustomMessage() + { + const string MESSAGE_STRING = + "{\"body\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! \",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! \",\"emoticon\":null}],\"user_badges\":[],\"user_color\":\"#008000\",\"emoticons\":[]}"; + + var message = JsonSerializer.Deserialize(MESSAGE_STRING)!; + var comment = CreateCommentWithMessage("viewer8", "viewer8", message); + + var (actual, shouldBeNull) = HighlightIcons.SplitWatchStreakComment(comment); + + Assert.Same(comment, actual); + Assert.Null(shouldBeNull); + } + + [Theory] + [InlineData( + "{\"body\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too!\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too!\",\"emoticon\":null}],\"user_badges\":[],\"user_color\":\"#1E90FF\",\"emoticons\":[]}", + "viewer8 watched 3 consecutive streams this month and sparked a watch streak! ", "me too!")] + [InlineData( + "{\"body\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too LUL\",\"bits_spent\":0,\"fragments\":[{\"text\":\"viewer8 watched 3 consecutive streams this month and sparked a watch streak! me too \",\"emoticon\":null},{\"text\":\"LUL\",\"emoticon\":{\"emoticon_id\":\"425618\"}}],\"user_badges\":[],\"user_color\":\"#1E90FF\",\"emoticons\":[{\"_id\":\"425618\",\"begin\":84,\"end\":88}]}", + "viewer8 watched 3 consecutive streams this month and sparked a watch streak! ", "me too LUL")] + public void CorrectlySplitsWatchStreakWithCustomMessage(string messageString, string subMessageString, string customMessageString) + { + var message = JsonSerializer.Deserialize(messageString)!; + var comment = CreateCommentWithMessage("viewer8", "viewer8", message); + + var (watchStreakMessage, customMessage) = HighlightIcons.SplitWatchStreakComment(comment); + + Assert.NotSame(comment, watchStreakMessage); + Assert.Equal(watchStreakMessage.message.body, subMessageString); + Assert.True(watchStreakMessage.message.fragments.Count == 1, $"{watchStreakMessage.message.fragments.Count} fragments were found in {nameof(watchStreakMessage)}. Expected 1."); + Assert.Equal(watchStreakMessage.message.fragments[0].text, subMessageString); + + Assert.NotNull(customMessage); + Assert.Equal(customMessage.message.body, customMessageString); + Assert.True(customMessage.message.fragments.Count > 0, $"0 fragments were found in {nameof(customMessage)}. Expected more than 0."); + } + } +} \ No newline at end of file diff --git a/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj b/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj index 376054f4..c5e90bf8 100644 --- a/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj +++ b/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj @@ -7,6 +7,7 @@ false true + latest diff --git a/TwitchDownloaderCore/Tools/HighlightIcons.cs b/TwitchDownloaderCore/Tools/HighlightIcons.cs index 5aeb5aa8..9c70f5aa 100644 --- a/TwitchDownloaderCore/Tools/HighlightIcons.cs +++ b/TwitchDownloaderCore/Tools/HighlightIcons.cs @@ -36,9 +36,9 @@ public sealed class HighlightIcons : IDisposable private const string WATCH_STREAK_ICON_SVG = "M 38.84325,21.169078 33.156748,14.060989 21.215093,27.992844 a 21.267516,21.267402 0 0 0 -5.11785,13.846557 c 0,9.752298 7.961102,17.713358 17.713453,17.713358 H 38.50206 A 17.400696,17.400602 0 0 0 55.902755,42.152157 c 0,-5.288419 -1.848114,-10.406242 -5.231581,-14.500501 L 41.686501,16.904225 Z m -13.306415,10.519973 7.619913,-9.098354 5.686502,7.108089 2.843251,-4.264854 4.606066,5.885497 a 16.945776,16.945684 0 0 1 3.923686,10.832728 c 0,5.91393 -4.407039,10.804296 -10.121973,11.600401 1.02357,-1.336321 1.592221,-2.985397 1.592221,-4.719771 0,-1.478483 -0.511786,-2.900101 -1.421626,-4.065827 l -4.264877,-5.316851 -4.264876,5.316851 c -0.90984,1.137294 -1.421625,2.587344 -1.421625,4.065827 0,1.705941 0.56865,3.355018 1.535355,4.662906 A 12.026952,12.026887 0 0 1 21.783744,41.839401 c 0,-3.72464 1.336328,-7.335548 3.753091,-10.15035 z"; private const string CHANNEL_POINT_ICON_SVG = "m 34.074833,10.317667 a 25.759205,25.759174 0 0 0 -23.83413,25.686052 25.759298,25.759267 0 0 0 51.518594,0 25.759205,25.759174 0 0 0 -27.684464,-25.686052 z m 0.329458,6.432744 a 19.319404,19.319381 0 0 1 20.915597,19.253308 19.319888,19.319865 0 0 1 -38.639776,0 19.319404,19.319381 0 0 1 17.724179,-19.253308 z M 36,23.124918 v 6.439401 a 6.4398012,6.4397935 0 0 1 6.439407,6.4394 H 48.88048 A 12.879602,12.879587 0 0 0 36,23.124918 Z"; - private static readonly Regex SubMessageRegex = new(@"^(subscribed (?:with Prime|at Tier \d)\. They've subscribed for \d{1,3} months(?:, currently on a \d{1,3} month streak)?! )(.+)$", RegexOptions.Compiled); + private static readonly Regex SubMessageRegex = new(@"^((?:\w+ )?subscribed (?:with Prime|at Tier \d)\. They've subscribed for \d{1,3} months(?:, currently on a \d{1,3} month streak)?! )(.+)$", RegexOptions.Compiled); private static readonly Regex GiftAnonymousRegex = new(@"^An anonymous user (?:gifted a|is gifting \d{1,4}) Tier \d", RegexOptions.Compiled); - private static readonly Regex WatchStreakRegex = new(@"^(watched \d+ consecutive streams this month and sparked a watch streak! )(.*)$", RegexOptions.Compiled); + private static readonly Regex WatchStreakRegex = new(@"^((?:\w+ )?watched \d+ consecutive streams this month and sparked a watch streak! )(.+)$", RegexOptions.Compiled); private SKImage _subscribedTierIcon; private SKImage _subscribedPrimeIcon; @@ -91,7 +91,7 @@ public static HighlightType GetHighlightType(Comment comment) if (bodyWithoutName.StartsWith(" is paying forward the Gift they got from")) return HighlightType.PayingForward; - if (bodyWithoutName.EndsWith(" consecutive streams this month and sparked a watch streak! ")) + if (bodyWithoutName.Contains(" consecutive streams this month and sparked a watch streak! ", StringComparison.Ordinal)) return HighlightType.WatchStreak; if (bodyWithoutName.StartsWith(" converted from a")) @@ -119,7 +119,7 @@ public static HighlightType GetHighlightType(Comment comment) if (char.IsDigit(bodySpan[0]) && bodySpan.EndsWith(" have joined! ")) { // TODO: use bodySpan when .NET 7 - if (Regex.IsMatch(comment.message.body, $@"^\d+ raiders from {comment.commenter.display_name} have joined!")) + if (Regex.IsMatch(comment.message.body, $@"^\d+ raiders from {comment.commenter.display_name} have joined! ")) return HighlightType.Raid; }