//Example IRC message: @badges=moderator/1,warcraft/alliance;color=;display-name=Swiftyspiffyv4;emotes=;mod=1;room-id=40876073;subscriber=0;turbo=0;user-id=103325214;user-type=mod :[email protected] PRIVMSG #swiftyspiffy :asd /// <summary>Constructor for ChatMessage object.</summary> /// <param name="botUsername">The username of the bot that received the message.</param> /// <param name="ircString">The raw string received from Twitch to be processed.</param> /// <param name="emoteCollection">The <see cref="MessageEmoteCollection"/> to register new emotes on and, if desired, use for emote replacement.</param> /// <param name="replaceEmotes">Whether to replace emotes for this chat message. Defaults to false.</param> public ChatMessage(string botUsername, string ircString, ref MessageEmoteCollection emoteCollection, bool replaceEmotes = false) { BotUsername = botUsername; RawIrcMessage = ircString; _emoteCollection = emoteCollection; foreach (var part in ircString.Split(';')) { if (part.Contains("!")) { if (Channel == null) { Channel = part.Split('#')[1].Split(' ')[0]; } if (Username == null) { Username = part.Split('!')[1].Split('@')[0]; } } else if (part.Contains("@badges=")) { Badges = new List <KeyValuePair <string, string> >(); string badges = part.Split('=')[1]; if (badges.Contains('/')) { if (!badges.Contains(",")) { Badges.Add(new KeyValuePair <string, string>(badges.Split('/')[0], badges.Split('/')[1])); } else { foreach (string badge in badges.Split(',')) { Badges.Add(new KeyValuePair <string, string>(badge.Split('/')[0], badge.Split('/')[1])); } } } // Iterate through saved badges for special circumstances foreach (KeyValuePair <string, string> badge in Badges) { if (badge.Key == "bits") { CheerBadge = new TwitchClientClasses.CheerBadge(int.Parse(badge.Value)); } } } else if (part.Contains("bits=")) { Bits = int.Parse(part.Split('=')[1]); BitsInDollars = ConvertBitsToUSD(Bits); } else if (part.Contains("color=")) { if (ColorHex == null) { ColorHex = part.Split('=')[1]; } } else if (part.Contains("display-name")) { if (DisplayName == null) { DisplayName = part.Split('=')[1]; } } else if (part.Contains("emotes=")) { if (EmoteSet == null) { EmoteSet = part.Split('=')[1];; } } else if (part.Contains("subscriber=")) { Subscriber = part.Split('=')[1] == "1"; } else if (part.Contains("turbo=")) { Turbo = part.Split('=')[1] == "1"; } else if (part.Contains("user-id=")) { UserId = int.Parse(part.Split('=')[1]); } else if (part.Contains("user-type=")) { switch (part.Split('=')[1].Split(' ')[0]) { case "mod": UserType = Common.UserType.Moderator; break; case "global_mod": UserType = Common.UserType.GlobalModerator; break; case "admin": UserType = Common.UserType.Admin; break; case "staff": UserType = Common.UserType.Staff; break; default: UserType = Common.UserType.Viewer; break; } } else if (part.Contains("mod=")) { IsModerator = part.Split('=')[1] == "1"; } } Message = ircString.Split(new[] { $" PRIVMSG #{Channel} :" }, StringSplitOptions.None)[1]; if ((byte)Message[0] == 1 && (byte)Message[Message.Length - 1] == 1) { //Actions (/me {action}) are wrapped by byte=1 and prepended with "ACTION " //This setup clears all of that leaving just the action's text. //If you want to clear just the nonstandard bytes, use: //_message = _message.Substring(1, text.Length-2); Message = Message.Substring(8, Message.Length - 9); IsMe = true; } //Parse the emoteSet if (EmoteSet != null && Message != null) { string[] uniqueEmotes = EmoteSet.Split('/'); string id, text; int firstColon, firstComma, firstDash, low, high; foreach (string emote in uniqueEmotes) { firstColon = emote.IndexOf(':'); firstComma = emote.IndexOf(','); if (firstComma == -1) { firstComma = emote.Length; } firstDash = emote.IndexOf('-'); if (firstColon > 0 && firstDash > firstColon && firstComma > firstDash) { if (Int32.TryParse(emote.Substring(firstColon + 1, (firstDash - firstColon) - 1), out low) && Int32.TryParse(emote.Substring(firstDash + 1, (firstComma - firstDash) - 1), out high)) { if (low >= 0 && low < high && high < Message.Length) { //Valid emote, let's parse id = emote.Substring(0, firstColon); //Pull the emote text from the message text = Message.Substring(low, (high - low) + 1); _emoteCollection.Add(new MessageEmote(id, text)); } } } } if (replaceEmotes) { EmoteReplacedMessage = _emoteCollection.ReplaceEmotes(Message); } } // Check if display name was set, and if it wasn't, set it to username if (string.IsNullOrEmpty(DisplayName)) { DisplayName = Username; } // Check if message is from broadcaster if (Channel.ToLower() == Username.ToLower()) { UserType = Common.UserType.Broadcaster; IsBroadcaster = true; } }
/// <summary>[Works] Parse function to detect new commands.</summary> /// <param name="botUsername"></param> /// <param name="message"></param> /// <param name="channels"></param> /// <param name="_channelEmotes"></param> /// <param name="WillReplaceEmotes"></param> /// <param name="_commandIdentifiers"></param> /// <returns></returns> public static DetectionReturn detectCommandReceived(string botUsername, string message, List <JoinedChannel> channels, MessageEmoteCollection _channelEmotes, bool WillReplaceEmotes, List <char> _commandIdentifiers) { string readType = null; string channelRet = null; foreach (JoinedChannel channel in channels) { readType = getReadType(message, channel.Channel); if (readType != null) { channelRet = channel.Channel; break; } } if (readType != null && readType == "PRIVMSG") { var chatMessage = new ChatMessage(botUsername, message, ref _channelEmotes, WillReplaceEmotes); return(new DetectionReturn((_commandIdentifiers.Count != 0 && _commandIdentifiers.Contains(chatMessage.Message[0])), channelRet)); } return(new DetectionReturn(false)); }