Esempio n. 1
0
 public static TwitchBadge?AsTwitchBadge(this IChatBadge badge)
 {
     return(badge as TwitchBadge);
 }
Esempio n. 2
0
        /// <summary>
        /// Takes a raw Twitch message and parses it into an IChatMessage
        /// </summary>
        /// <param name="rawMessage">The raw message sent from Twitch</param>
        /// <param name="loggedInUser"></param>
        /// <param name="parsedMessages">A list of chat messages that were parsed from the rawMessage</param>
        /// <param name="channelInfo"></param>
        /// <returns>True if parsedMessages.Count > 0</returns>
        public bool ParseRawMessage(string rawMessage, ConcurrentDictionary <string, IChatChannel> channelInfo, IChatUser loggedInUser, out IChatMessage[] parsedMessages)
        {
            var stopwatch = Stopwatch.StartNew();

            parsedMessages = null !;
            var matches = _twitchMessageRegex.Matches(rawMessage);

            if (matches.Count == 0)
            {
                _logger.LogInformation($"Unhandled message: {rawMessage}");
                stopwatch.Stop();
                return(false);
            }

            var messages = new List <IChatMessage>();

            _logger.LogInformation($"Parsing message {rawMessage}");
            foreach (Match match in matches)
            {
                if (!match.Groups["MessageType"].Success)
                {
                    _logger.LogInformation($"Failed to get messageType for message {match.Value}");
                    continue;
                }

                //_logger.LogInformation($"Message: {match.Value}");

                var messageType        = match.Groups["MessageType"].Value;
                var messageText        = match.Groups["Message"].Success ? match.Groups["Message"].Value : "";
                var messageChannelName = match.Groups["ChannelName"].Success ? match.Groups["ChannelName"].Value.Trim('#') : "";
                var messageRoomId      = string.Empty;

                if (channelInfo.TryGetValue(messageChannelName, out var channel))
                {
                    messageRoomId = channel.AsTwitchChannel() !.Roomstate?.RoomId;
                }

                try
                {
                    var             userBadges        = new IChatBadge[0];
                    var             messageEmotes     = new List <IChatEmote>();
                    TwitchRoomstate messageRoomstate  = null !;
                    var             foundTwitchEmotes = new HashSet <string>();

                    var isActionMessage = false;
                    var isHighlighted   = false;
                    if (messageText.StartsWith("\u0001ACTION"))
                    {
                        messageText     = messageText.Remove(messageText.Length - 1, 1).Remove(0, 8);
                        isActionMessage = true;
                    }

                    var messageMeta = new ReadOnlyDictionary <string, string>(_tagRegex.Matches(match.Value).Cast <Match>().Aggregate(new Dictionary <string, string>(), (dict, m) =>
                    {
                        dict[m.Groups["Tag"].Value] = m.Groups["Value"].Value;
                        return(dict);
                    }));

                    var messageBits = messageMeta.TryGetValue("bits", out var bitsString) && int.TryParse(bitsString, out var bitsInt) ? bitsInt : 0;

                    if (messageMeta.TryGetValue("badges", out var badgeStr))
                    {
                        userBadges = badgeStr.Split(',').Aggregate(new List <IChatBadge>(), (list, m) =>
                        {
                            var badgeId = m.Replace("/", "");
                            if (_twitchDataProvider.TryGetBadgeInfo(badgeId, messageRoomId, out var badgeInfo))
                            {
                                list.Add(new TwitchBadge
                                {
                                    Id   = $"{badgeInfo.Type}_{badgeId}",
                                    Name = m.Split('/')[0],
                                    Uri  = badgeInfo.Uri
                                });
                            }
                            return(list);
                        }).ToArray();
                    }

                    if (messageType == "PRIVMSG" || messageType == "NOTIFY" || messageType == "USERNOTICE")
                    {
                        if (messageText.Length > 0)
                        {
                            if (_settings.ParseTwitchEmotes && messageMeta.TryGetValue("emotes", out var emoteStr))
                            {
                                // Parse all the normal Twitch emotes
                                messageEmotes = emoteStr.Split('/').Aggregate(new List <IChatEmote>(), (emoteList, emoteInstanceString) =>
                                {
                                    var emoteParts = emoteInstanceString.Split(':');
                                    foreach (var instanceString in emoteParts[1].Split(','))
                                    {
                                        var instanceParts = instanceString.Split('-');
                                        var startIndex    = int.Parse(instanceParts[0]);
                                        var endIndex      = int.Parse(instanceParts[1]);

                                        if (startIndex >= messageText.Length)
                                        {
                                            _logger.LogWarning($"Start index is greater than message length! RawMessage: {match.Value}, InstanceString: {instanceString}, EmoteStr: {emoteStr}, StartIndex: {startIndex}, MessageLength: {messageText.Length}, IsActionMessage: {isActionMessage}");
                                        }

                                        var emoteName = messageText.Substring(startIndex, endIndex - startIndex + 1);
                                        foundTwitchEmotes.Add(emoteName);
                                        emoteList.Add(new TwitchEmote
                                        {
                                            Id         = $"TwitchEmote_{emoteParts[0]}",
                                            Name       = emoteName,//endIndex >= messageText.Length ? messageText.Substring(startIndex) : ,
                                            Uri        = $"https://static-cdn.jtvnw.net/emoticons/v1/{emoteParts[0]}/3.0",
                                            StartIndex = startIndex,
                                            EndIndex   = endIndex,
                                            IsAnimated = false,
                                            Bits       = 0,
                                            Color      = ""
                                        });
                                    }
                                    return(emoteList);
                                });
                            }

                            // Parse all the third party (BTTV, FFZ, etc) emotes
                            var currentWord = new StringBuilder();
                            for (var i = 0; i <= messageText.Length; i++)
                            {
                                if (i == messageText.Length || char.IsWhiteSpace(messageText[i]))
                                {
                                    if (currentWord.Length > 0)
                                    {
                                        var lastWord   = currentWord.ToString();
                                        var startIndex = i - lastWord.Length;
                                        var endIndex   = i - 1;

                                        if (!foundTwitchEmotes.Contains(lastWord))
                                        {
                                            // Make sure we haven't already matched a Twitch emote with the same string, just incase the user has a BTTV/FFZ emote with the same name
                                            if (_settings.ParseCheermotes && messageBits > 0 && _twitchDataProvider.TryGetCheermote(lastWord, messageRoomId, out var cheermoteData, out var numBits) && numBits > 0)
                                            {
                                                //_logger.LogInformation($"Got cheermote! Total message bits: {messageBits}");
                                                var tier = cheermoteData.GetTier(numBits);
                                                if (tier != null)
                                                {
                                                    messageEmotes.Add(new TwitchEmote
                                                    {
                                                        Id         = $"TwitchCheermote_{cheermoteData.Prefix}{tier.MinBits}",
                                                        Name       = lastWord,
                                                        Uri        = tier.Uri,
                                                        StartIndex = startIndex,
                                                        EndIndex   = endIndex,
                                                        IsAnimated = true,
                                                        Bits       = numBits,
                                                        Color      = tier.Color
                                                    });
                                                }
                                            }
                                            else if (_twitchDataProvider.TryGetThirdPartyEmote(lastWord, messageChannelName, out var emoteData))
                                            {
                                                if (emoteData.Type.StartsWith("BTTV") && _settings.ParseBTTVEmotes || emoteData.Type.StartsWith("FFZ") && _settings.ParseFFZEmotes)
                                                {
                                                    messageEmotes.Add(new TwitchEmote
                                                    {
                                                        Id         = $"{emoteData.Type}_{lastWord}",
                                                        Name       = lastWord,
                                                        Uri        = emoteData.Uri,
                                                        StartIndex = startIndex,
                                                        EndIndex   = endIndex,
                                                        IsAnimated = emoteData.IsAnimated,
                                                        Bits       = 0,
                                                        Color      = string.Empty
                                                    });
                                                }
                                            }
                                        }
                                        currentWord.Clear();
                                    }
                                }
                                else
                                {
                                    currentWord.Append(messageText[i]);
                                }
                            }

                            if (_settings.ParseEmojis)
                            {
                                // Parse all emojis
                                messageEmotes.AddRange(_emojiParser.FindEmojis(messageText));
                            }

                            // Sort the emotes in descending order to make replacing them in the string later on easier
                            messageEmotes.Sort((a, b) => b.StartIndex - a.StartIndex);
                        }
                    }