Пример #1
0
        public static void ParseEmotes(this TwitchMessage message, ref char imgPlacementDesignator, ref StringBuilder messageBuilder, out bool isActionMessage, ChatMessage chatMessage)
        {
            _imageInfoByID.Clear();
            _imageInfoByName.Clear();

            // Action messages
            isActionMessage = chatMessage.displayMsg.StartsWith((char)0x1 + "ACTION");
            if (isActionMessage)
            {
                messageBuilder = messageBuilder.Remove(messageBuilder.Length - 1, 1).Remove(0, 8);
            }

            var emojilessMessage = EmojiUtilities.emojiRegex.Replace(chatMessage.displayMsg, " ");


            // Emotes
            var twitchEmotes = _emoteRegex.Matches(chatMessage.origMessage.Twitch.emotes);

            if (twitchEmotes.Count > 0)
            {
                foreach (Match e in twitchEmotes)
                {
                    string emoteIndex = $"T{e.Groups["EmoteIndex"].Value}";
                    if (!ImageDownloader.CachedTextures.ContainsKey(emoteIndex))
                    {
                        ImageDownloader.Instance.Queue(new TextureDownloadInfo(emoteIndex, ImageType.Twitch, chatMessage.origMessage.id));
                    }

                    if (!_imageInfoByID.TryGetValue(emoteIndex, out var emoteInfo))
                    {
                        int    startIndex = Convert.ToInt32(e.Groups["StartIndex"].Value);
                        string emoteName  = emojilessMessage.Substring(startIndex, Convert.ToInt32(e.Groups["EndIndex"].Value) - startIndex + 1);

                        //Plugin.Log($"Emote: {emoteName}");

                        emoteInfo = new EmoteInfo()
                        {
                            swapChar     = imgPlacementDesignator++,
                            swapString   = emoteName,
                            textureIndex = emoteIndex,
                            imageType    = ImageType.Twitch
                        };
                        _imageInfoByID[emoteIndex]  = emoteInfo;
                        _imageInfoByName[emoteName] = emoteInfo;
                    }
                    Thread.Sleep(0);
                }
            }

            // BTTV/FFZ/cheeremotes
            int lastSpaceIndex = 0;

            while (true)
            {
                bool done       = false;
                int  spaceIndex = messageBuilder.IndexOf(" ", lastSpaceIndex, false);
                if (spaceIndex == -1)
                {
                    done = true;
                }

                int    startIndex = lastSpaceIndex;
                int    endIndex   = spaceIndex == -1 ? messageBuilder.Length - lastSpaceIndex : spaceIndex - lastSpaceIndex;
                string word       = messageBuilder.ToString(lastSpaceIndex, endIndex);
                lastSpaceIndex = spaceIndex + 1;

                if (!_imageInfoByName.TryGetValue(word, out var imageInfo))
                {
                    string    textureIndex    = String.Empty;
                    ImageType imageType       = ImageType.None;
                    string    tmpTextureIndex = "";
                    if (ImageDownloader.BTTVEmoteIDs.TryGetValue(word, out tmpTextureIndex))
                    {
                        if (ChatConfig.instance.ShowBTTVEmotes)
                        {
                            textureIndex = $"B{tmpTextureIndex}";
                            imageType    = ImageType.BTTV;
                        }
                    }
                    else if (ImageDownloader.BTTVAnimatedEmoteIDs.TryGetValue(word, out tmpTextureIndex))
                    {
                        if (ChatConfig.instance.ShowBTTVEmotes)
                        {
                            textureIndex = $"AB{tmpTextureIndex}";
                            imageType    = ImageType.BTTV_Animated;
                        }
                    }
                    else if (ImageDownloader.FFZEmoteIDs.TryGetValue(word, out tmpTextureIndex))
                    {
                        if (ChatConfig.instance.ShowFFZEmotes)
                        {
                            textureIndex = $"F{tmpTextureIndex}";
                            imageType    = ImageType.FFZ;
                        }
                    }
                    else if (chatMessage.origMessage.Twitch.bits > 0 && EmojiUtilities.cheermoteRegex.IsMatch(word.ToLower()))
                    {
                        word = word.ToLower();
                        Match  match  = EmojiUtilities.cheermoteRegex.Match(word);
                        string prefix = match.Groups["Prefix"].Value;
                        if (ImageDownloader.TwitchCheermoteIDs.TryGetValue(prefix, out var cheermote))
                        {
                            int    bits = Convert.ToInt32(match.Groups["Value"].Value);
                            string tier = cheermote.GetTier(bits);
                            textureIndex = $"{prefix}{tier}";
                            imageType    = ImageType.Cheermote;
                        }
                    }

                    if (imageType != ImageType.None)
                    {
                        if (!ImageDownloader.CachedTextures.ContainsKey(textureIndex))
                        {
                            ImageDownloader.Instance.Queue(new TextureDownloadInfo(textureIndex, imageType, chatMessage.origMessage.id));
                        }

                        imageInfo = new EmoteInfo()
                        {
                            imageType    = imageType,
                            swapChar     = imgPlacementDesignator++,
                            swapString   = word,
                            textureIndex = textureIndex
                        };
                        _imageInfoByID[textureIndex] = imageInfo;
                        _imageInfoByName[word]       = imageInfo;
                    }
                }
                if (imageInfo != null)
                {
                    var emoteInfo = (EmoteInfo)imageInfo;
                    chatMessage.parsedEmotes[emoteInfo.textureIndex] = emoteInfo;

                    var    cachedSprite = emoteInfo.GetCachedSprite();
                    string extraInfo    = String.Empty;
                    if (emoteInfo.imageType == ImageType.Cheermote)
                    {
                        try
                        {
                            Match cheermote = EmojiUtilities.cheermoteRegex.Match(emoteInfo.swapString);
                            if (cheermote.Success)
                            {
                                string numBits = cheermote.Groups["Value"].Value;
                                string prefix  = cheermote.Groups["Prefix"].Value.ToLower();
                                extraInfo = $"\u200A<color={ImageDownloader.TwitchCheermoteIDs[prefix].GetColor(Convert.ToInt32(numBits))}><size=4><b>{numBits}</b></size></color>\u200A";
                            }
                            else
                            {
                                Plugin.Log($"Cheermote regex failed for message {chatMessage.origMessage}");
                            }
                        }
                        catch (Exception ex)
                        {
                            Plugin.Log($"Failed to parse cheermote! {ex.ToString()}");
                        }
                    }
                    var replaceStr = $"\ufeff{Char.ConvertFromUtf32(emoteInfo.swapChar)}{emoteInfo.spacingString}{extraInfo}";
                    messageBuilder.Remove(startIndex, endIndex);
                    messageBuilder.Insert(startIndex, replaceStr);
                    lastSpaceIndex += (replaceStr.Length - emoteInfo.swapString.Length);
                }

                if (done)
                {
                    break;
                }

                Thread.Sleep(0);
            }
        }
Пример #2
0
        public static void Parse(ChatMessage chatMessage)
        {
            _messageBuilder.Clear();

            // Emojis
            chatMessage.displayMsg = EmojiUtilities.emojiRegex.Replace(chatMessage.displayMsg, (m) =>
            {
                string emojiIndex    = EmojiUtilities.WebParseEmojiRegExMatchEvaluator(m);
                string replaceString = m.Value;

                // Couldn't find a match, replace it with a space
                if (emojiIndex == String.Empty)
                {
                    return(" ");
                }

                emojiIndex += ".png";
                if (!ImageDownloader.CachedTextures.ContainsKey(emojiIndex))
                {
                    ImageDownloader.Instance.Queue(new TextureDownloadInfo(emojiIndex, ImageType.Emoji, chatMessage.origMessage.id));
                }

                if (!_emojiInfoByName.TryGetValue(emojiIndex, out var emojiInfo))
                {
                    emojiInfo = new EmoteInfo()
                    {
                        imageType    = ImageType.Emoji,
                        swapChar     = imgPlacementDesignator++,
                        swapString   = replaceString,
                        textureIndex = emojiIndex
                    };
                    _emojiInfoByName[emojiIndex] = emojiInfo;
                }
                chatMessage.parsedEmotes[emojiInfo.textureIndex] = emojiInfo;
                var cachedSprite = emojiInfo.GetCachedSprite();
                return($"\ufeff{Char.ConvertFromUtf32(emojiInfo.swapChar)}{emojiInfo.spacingString}");
            });

            _messageBuilder.Append(chatMessage.displayMsg);
            bool isActionMessage = false;

            if (chatMessage.origMessage is TwitchMessage)
            {
                chatMessage.origMessage.Twitch.ParseEmotes(ref imgPlacementDesignator, ref _messageBuilder, out isActionMessage, chatMessage);
            }
            else if (chatMessage.origMessage is YouTubeMessage)
            {
                chatMessage.origMessage.YouTube.Parse(ref imgPlacementDesignator, ref _messageBuilder, chatMessage);
            }
            else if (chatMessage.origMessage is BilibiliMessage)
            {
                /*Plugin.Log("Is bilibli message!");*/
                chatMessage.origMessage.Bilibili.Parse(ref imgPlacementDesignator, ref _messageBuilder, chatMessage);
            }
            /*Plugin.Log("Parse 1");*/
            string displayColor = "";

            try
            {
                displayColor = chatMessage.origMessage.user.color;
            }
            catch (Exception ex) {
                Plugin.Log(ex.ToString());
            }
            /*Plugin.Log("displayColor: " + displayColor);*/
            int nameHash = chatMessage.origMessage.user.displayName.GetHashCode();

            /*Plugin.Log("nameHash: " + nameHash);
             * Plugin.Log("Parse 2");*/
            // If the user doesn't already have a displayColor, generate one and store it for later user
            if (string.IsNullOrEmpty(displayColor) && !_userColors.TryGetValue(nameHash, out displayColor))
            {
                // Generate a random color
                Random rand = new Random(nameHash);
                int    r    = rand.Next(255);
                int    g    = rand.Next(255);
                int    b    = rand.Next(255);

                // Convert it to a pastel color
                System.Drawing.Color pastelColor = Drawing.GetPastelShade(System.Drawing.Color.FromArgb(255, r, g, b));
                int    argb        = ((int)pastelColor.R << 16) + ((int)pastelColor.G << 8) + (int)pastelColor.B;
                string colorString = String.Format("#{0:X6}", argb) + "FF";
                _userColors.Add(nameHash, colorString);
                displayColor = colorString;
            }
            /*Plugin.Log("Parse 3");*/
            // Set the final displayColor to our message
            chatMessage.displayColor = displayColor;
            /*Plugin.Log("Parse 4");*/
            _messageBuilder.Insert(0, $"<color={chatMessage.displayColor}><b>{chatMessage.origMessage.user.displayName}</b>{(!isActionMessage ? "</color>:" : "")} ");
            _messageBuilder.Append($"{(isActionMessage ? "</color>" : "")}");
            /*Plugin.Log("Parse 5");*/
            if (chatMessage.origMessage is TwitchMessage)
            {
                chatMessage.origMessage.Twitch.ParseBadges(ref imgPlacementDesignator, ref _messageBuilder, chatMessage);
            }
            /*Plugin.Log("Parse 6");*/
            // Finally, push the final message into the render queue
            chatMessage.displayMsg = _messageBuilder.ToString();
            /*Plugin.Log("The message in queue is " + chatMessage.displayMsg);*/
            ChatHandler.RenderQueue.Enqueue(chatMessage);
        }
Пример #3
0
        public static async void Parse(ChatMessage newChatMessage)
        {
            // Setup local variables
            char             swapChar     = (char)0xE000;
            List <EmoteInfo> parsedEmotes = new List <EmoteInfo>();
            List <BadgeInfo> parsedBadges = new List <BadgeInfo>();

            bool isActionMessage = false;

            if (newChatMessage.origMessage is TwitchMessage)
            {
                // If this is a twitch message, check if they used /me and color it accordingly
                isActionMessage = newChatMessage.displayMsg.Substring(1).StartsWith("ACTION") && newChatMessage.displayMsg[0] == (char)0x1;
                if (isActionMessage)
                {
                    newChatMessage.displayMsg = newChatMessage.displayMsg.TrimEnd((char)0x1).Substring(8);
                }
            }

            StringBuilder emojilessMessageBuilder = new StringBuilder(newChatMessage.displayMsg);
            // Parse and download any emojis included in the message
            var matches = EmojiUtilities.GetEmojisInString(newChatMessage.displayMsg);

            if (matches.Count > 0)
            {
                List <string> foundEmojis = new List <string>();
                foreach (Match m in matches)
                {
                    string emojiIndex    = EmojiUtilities.WebParseEmojiRegExMatchEvaluator(m);
                    string replaceString = m.Value;

                    // Build up a copy of the message with no emojis so we can parse out our twitch emotes properly
                    emojilessMessageBuilder = emojilessMessageBuilder.Replace(m.Value, " ");

                    if (emojiIndex != String.Empty)
                    {
                        emojiIndex += ".png";
                        if (!ImageDownloader.CachedTextures.ContainsKey(emojiIndex))
                        {
                            ImageDownloader.Instance.Queue(new TextureDownloadInfo(emojiIndex, ImageType.Emoji, newChatMessage.origMessage.id));
                        }

                        if (!foundEmojis.Contains(emojiIndex))
                        {
                            foundEmojis.Add(emojiIndex);
                            EmoteInfo swapInfo = new EmoteInfo();
                            swapInfo.imageType    = ImageType.Emoji;
                            swapInfo.isEmoji      = true;
                            swapInfo.swapChar     = swapChar;
                            swapInfo.swapString   = replaceString;
                            swapInfo.textureIndex = emojiIndex;
                            parsedEmotes.Add(swapInfo);
                            swapChar++;
                        }
                    }
                }
                parsedEmotes = parsedEmotes.OrderByDescending(o => o.swapString.Length).ToList();
                Thread.Sleep(5);
            }

            if (newChatMessage.origMessage is TwitchMessage)
            {
                // Parse and download any twitch emotes in the message
                var emotes = _emoteRegex.Matches(newChatMessage.origMessage.Twitch.emotes);
                if (emotes.Count > 0)
                {
                    string emojilessMessage = emojilessMessageBuilder.ToString();
                    foreach (Match e in emotes)
                    {
                        string emoteIndex = $"T{e.Groups["EmoteIndex"].Value}";
                        if (!ImageDownloader.CachedTextures.ContainsKey(emoteIndex))
                        {
                            ImageDownloader.Instance.Queue(new TextureDownloadInfo(emoteIndex, ImageType.Twitch, newChatMessage.origMessage.id));
                        }

                        int    startReplace = Convert.ToInt32(e.Groups["StartIndex"].Value);
                        int    endReplace   = Convert.ToInt32(e.Groups["EndIndex"].Value);
                        string emoteName    = emojilessMessage.Substring(startReplace, endReplace - startReplace + 1);

                        EmoteInfo swapInfo = new EmoteInfo();
                        swapInfo.swapChar     = swapChar;
                        swapInfo.swapString   = emoteName;
                        swapInfo.textureIndex = emoteIndex;
                        swapInfo.imageType    = ImageType.Twitch;
                        parsedEmotes.Add(swapInfo);
                        swapChar++;
                    }
                    Thread.Sleep(5);
                }

                // Parse and download any twitch badges included in the message
                var badges = _badgeRegex.Matches(newChatMessage.origMessage.user.Twitch.badges);
                if (badges.Count > 0)
                {
                    foreach (Match b in badges)
                    {
                        string badgeName  = $"{b.Groups["BadgeName"].Value}{b.Groups["BadgeVersion"].Value}";
                        string badgeIndex = string.Empty;
                        if (ImageDownloader.TwitchBadgeIDs.ContainsKey(badgeName))
                        {
                            badgeIndex = ImageDownloader.TwitchBadgeIDs[badgeName];
                            if (!ImageDownloader.CachedTextures.ContainsKey(badgeIndex))
                            {
                                ImageDownloader.Instance.Queue(new TextureDownloadInfo(badgeIndex, ImageType.Badge, newChatMessage.origMessage.id));
                            }

                            BadgeInfo swapInfo = new BadgeInfo();
                            swapInfo.swapChar     = swapChar;
                            swapInfo.textureIndex = badgeIndex;
                            swapInfo.imageType    = ImageType.Badge;
                            parsedBadges.Add(swapInfo);
                            swapChar++;
                        }
                    }
                    Thread.Sleep(5);
                }

                // Parse and download any BTTV/FFZ emotes and cheeremotes in the message
                string[] msgParts = newChatMessage.displayMsg.Split(' ').Distinct().ToArray();
                foreach (string w in msgParts)
                {
                    string word = w;
                    //Plugin.Log($"WORD: {word}");
                    string    textureIndex = String.Empty;
                    ImageType imageType    = ImageType.None;
                    if (ImageDownloader.BTTVEmoteIDs.ContainsKey(word))
                    {
                        if (ChatConfig.Instance.ShowBTTVEmotes)
                        {
                            textureIndex = $"B{ImageDownloader.BTTVEmoteIDs[word]}";
                            imageType    = ImageType.BTTV;
                        }
                    }
                    else if (ImageDownloader.BTTVAnimatedEmoteIDs.ContainsKey(word))
                    {
                        if (ChatConfig.Instance.ShowBTTVEmotes)
                        {
                            textureIndex = $"AB{ImageDownloader.BTTVAnimatedEmoteIDs[word]}";
                            imageType    = ImageType.BTTV_Animated;
                        }
                    }
                    else if (ImageDownloader.FFZEmoteIDs.ContainsKey(word))
                    {
                        if (ChatConfig.Instance.ShowFFZEmotes)
                        {
                            textureIndex = $"F{ImageDownloader.FFZEmoteIDs[word]}";
                            imageType    = ImageType.FFZ;
                        }
                    }
                    else if (newChatMessage.origMessage.Twitch.bits > 0 && EmojiUtilities.cheermoteRegex.IsMatch(word.ToLower()))
                    {
                        Match  match  = EmojiUtilities.cheermoteRegex.Match(word.ToLower());
                        string prefix = match.Groups["Prefix"].Value;
                        if (ImageDownloader.TwitchCheermoteIDs.ContainsKey(prefix))
                        {
                            int    bits = Convert.ToInt32(match.Groups["Value"].Value);
                            string tier = ImageDownloader.TwitchCheermoteIDs[prefix].GetTier(bits);
                            textureIndex = $"{prefix}{tier}";
                            imageType    = ImageType.Cheermote;
                        }
                    }

                    if (imageType != ImageType.None)
                    {
                        if (!ImageDownloader.CachedTextures.ContainsKey(textureIndex))
                        {
                            ImageDownloader.Instance.Queue(new TextureDownloadInfo(textureIndex, imageType, newChatMessage.origMessage.id));
                        }

                        EmoteInfo swapInfo = new EmoteInfo();
                        swapInfo.imageType    = imageType;
                        swapInfo.swapChar     = swapChar;
                        swapInfo.swapString   = word;
                        swapInfo.textureIndex = textureIndex;
                        parsedEmotes.Add(swapInfo);
                        swapChar++;
                    }
                }


                Thread.Sleep(5);
            }
            else if (newChatMessage.origMessage is YouTubeMessage)
            {
                if (!ImageDownloader.CachedTextures.ContainsKey(newChatMessage.origMessage.user.YouTube.profileImageUrl))
                {
                    ImageDownloader.Instance.Queue(new TextureDownloadInfo(newChatMessage.origMessage.user.YouTube.profileImageUrl, ImageType.YouTube_Profile, newChatMessage.origMessage.id, true));
                }

                BadgeInfo swapInfo = new BadgeInfo();
                swapInfo.swapChar     = swapChar;
                swapInfo.textureIndex = newChatMessage.origMessage.user.YouTube.profileImageUrl;
                swapInfo.imageType    = ImageType.YouTube_Profile;
                parsedBadges.Add(swapInfo);
                swapChar++;
            }

            string[] parts = newChatMessage.displayMsg.Split(' ');
            // Replace each emote with a unicode character from a private range; we'll draw the emote at the position of this character later on
            foreach (EmoteInfo e in parsedEmotes.Where(e => !e.isEmoji))
            {
                var    cachedSprite = e.GetCachedSprite();
                string extraInfo    = String.Empty;
                if (e.imageType == ImageType.Cheermote)
                {
                    // Insert an animated cheermote into the message
                    Match  cheermote = EmojiUtilities.cheermoteRegex.Match(e.swapString);
                    string numBits   = cheermote.Groups["Value"].Value;
                    extraInfo = $"\u200A<color={ImageDownloader.TwitchCheermoteIDs[cheermote.Groups["Prefix"].Value].GetColor(Convert.ToInt32(numBits))}>\u200A<size=3><b>{numBits}</b></size></color>\u200A";
                }

                // Replace any instances of the swapString we find in the message
                string replaceString = $"\ufeff{Char.ConvertFromUtf32(e.swapChar)}{e.spacingString}{extraInfo}";
                for (int i = 0; i < parts.Length; i++)
                {
                    if (parts[i] == e.swapString)
                    {
                        parts[i] = replaceString;
                    }
                }
            }

            // Then replace our emojis after all the emotes are handled, since these aren't sensitive to spacing
            StringBuilder sb = new StringBuilder(string.Join(" ", parts));

            foreach (EmoteInfo e in parsedEmotes.Where(e => e.isEmoji))
            {
                var cachedSprite = e.GetCachedSprite();
                sb.Replace(e.swapString, $"{Char.ConvertFromUtf32(e.swapChar)}{e.spacingString}");
            }
            newChatMessage.displayMsg = sb.ToString();

            Thread.Sleep(5);

            //// TODO: Re-add tagging, why doesn't unity have highlighting in its default rich text markup?
            //// Highlight messages that we've been tagged in
            //if (Plugin._twitchUsername != String.Empty && msg.Contains(Plugin._twitchUsername)) {
            //    msg = $"<mark=#ffff0050>{msg}</mark>";
            //}

            string displayColor = newChatMessage.origMessage.user.color;
            int    nameHash     = newChatMessage.origMessage.user.displayName.GetHashCode();

            // If the user doesn't already have a displayColor, generate one and store it for later user
            if (string.IsNullOrEmpty(displayColor) && !_userColors.TryGetValue(nameHash, out displayColor))
            {
                // Generate a random color
                Random rand = new Random(nameHash);
                int    r    = rand.Next(255);
                int    g    = rand.Next(255);
                int    b    = rand.Next(255);

                // Convert it to a pastel color
                System.Drawing.Color pastelColor = Drawing.GetPastelShade(System.Drawing.Color.FromArgb(255, r, g, b));
                int    argb        = ((int)pastelColor.R << 16) + ((int)pastelColor.G << 8) + (int)pastelColor.B;
                string colorString = String.Format("#{0:X6}", argb) + "FF";
                _userColors.Add(nameHash, colorString);
                displayColor = colorString;
            }
            // Set the final displayColor to our message
            newChatMessage.displayColor = displayColor;

            // Add the users name to the message with the correct color
            newChatMessage.displayMsg = $"<color={newChatMessage.displayColor}><b>{newChatMessage.origMessage.user.displayName}</b>{(!isActionMessage?"</color>:":"")} {newChatMessage.displayMsg}{(isActionMessage?"</color>":"")}";

            // Prepend the users badges to the front of the message
            StringBuilder badgeStr = new StringBuilder();

            if (parsedBadges.Count > 0)
            {
                parsedBadges.Reverse();
                foreach (BadgeInfo b in parsedBadges)
                {
                    var cachedSprite = b.GetCachedSprite();
                    badgeStr.Insert(0, $"{Char.ConvertFromUtf32(b.swapChar)}{b.spacingString}\u00A0");
                }
            }
            badgeStr.Insert(0, "\uFEFF");
            badgeStr.Append(newChatMessage.displayMsg);


            // Finally, store our final message, parsedEmotes and parsedBadges; then render the message
            newChatMessage.displayMsg   = badgeStr.ToString();
            newChatMessage.parsedEmotes = parsedEmotes;
            newChatMessage.parsedBadges = parsedBadges;

            ChatHandler.RenderQueue.Enqueue(newChatMessage);
        }