protected void Page_Load(object sender, EventArgs e)
    {
        if (this.drpBadges.Items.Count == 0)
        {
            DataSet ds = BadgeInfoProvider.GetBadges(null, null, 0, "BadgeDisplayName, BadgeIsAutomatic, BadgeID");

            // Check dataset
            if (!DataHelper.DataSourceIsEmpty(ds))
            {
                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    BadgeInfo bi = new BadgeInfo(dr);

                    // Create and add custom table list item
                    string name = ResHelper.LocalizeString(bi.BadgeDisplayName);
                    if (bi.BadgeIsAutomatic)
                    {
                        name += GetString("badge.automatic");
                    }

                    drpBadges.Items.Add(new ListItem(name, bi.BadgeID.ToString()));
                }

                drpBadges.Items.Insert(0, new ListItem(GetString("general.selectnone"), "0"));

                drpBadges.SelectedValue = mValue;
            }
        }
    }
    /// <summary>
    /// OK button click event handler.
    /// </summary>
    protected void btnOK_Click(object sender, EventArgs e)
    {
        // Validate entered values
        string error = new Validator().IsCodeName(txtName.Text.Trim(), GetString("general.invalidcodename"))
            .NotEmpty(txtDisplayName.Text.Trim(), GetString("badge.errors.displayname")).Result;

        // Save new values
        if (DataHelper.IsEmpty(error))
        {
            // Check that code name is unique
            BadgeInfo bi = BadgeInfoProvider.GetBadgeInfo(txtName.Text.Trim());
            if ((bi == null) || ((bi != null) && (bi.BadgeID == badgeId)))
            {
                // Update existing record
                if (bi == null)
                {
                    bi = new BadgeInfo();
                }

                // Set properties
                bi.BadgeID = badgeId;
                bi.BadgeName = txtName.Text.Trim();
                bi.BadgeDisplayName = txtDisplayName.Text.Trim();
                bi.BadgeImageURL = txtImageURL.Text.Trim();
                int topLimit = ValidationHelper.GetInteger(txtTopLimit.Text.Trim(), 0);
                if (topLimit >= 0)
                {
                    bi.BadgeTopLimit = topLimit;
                }
                else
                {
                    bi.BadgeTopLimit = 0;
                }
                bi.BadgeIsAutomatic = chkIsAutomatic.Checked;

                // Save BadgeInfo
                BadgeInfoProvider.SetBadgeInfo(bi);
                URLHelper.Redirect("~/CMSModules/Badges/Badges_Edit.aspx?saved=1&badgeid=" + bi.BadgeID);
            }
            else
            {
                lblError.ResourceString = "badge.errors.uniquecodename";
                lblError.Visible = true;
            }
        }
        else
        {
            lblError.ResourceString = error;
            //badge.errors.values
            lblError.Visible = true;
        }
    }
 /// <summary>
 /// Loads data to fields.
 /// </summary>
 /// <param name="badgeId">ID of badge record</param>
 private void LoadData(BadgeInfo bi)
 {
     if (bi != null)
     {
         // Load data to appropriate fields
         txtName.Text = bi.BadgeName;
         txtDisplayName.Text = bi.BadgeDisplayName;
         txtImageURL.Text = bi.BadgeImageURL;
         chkIsAutomatic.Checked = bi.BadgeIsAutomatic;
         txtTopLimit.Text = bi.BadgeTopLimit.ToString();
     }
 }
    /// <summary>
    /// Creates badge. Called when the "Create badge" button is pressed.
    /// </summary>
    private bool CreateBadge()
    {
        // Create new badge object
        BadgeInfo newBadge = new BadgeInfo();

        // Set the properties
        newBadge.BadgeDisplayName = "My new badge";
        newBadge.BadgeName = "MyNewBadge";
        newBadge.BadgeTopLimit = 50;
        newBadge.BadgeImageURL = GetImageUrl("Objects/CMS_Badge/Default/siteadmin.gif");
        newBadge.BadgeIsAutomatic = true;

        // Save the badge
        BadgeInfoProvider.SetBadgeInfo(newBadge);

        return true;
    }
Beispiel #5
0
    /// <summary>
    /// Gets and bulk updates badges. Called when the "Get and bulk update badges" button is pressed.
    /// Expects the CreateBadge method to be run first.
    /// </summary>
    private bool GetAndBulkUpdateBadges()
    {
        // Prepare the parameters
        string where = "BadgeName LIKE N'MyNewBadge%'";

        // Get the data
        DataSet badges = BadgeInfoProvider.GetBadges(where, null);
        if (!DataHelper.DataSourceIsEmpty(badges))
        {
            // Loop through the individual items
            foreach (DataRow badgeDr in badges.Tables[0].Rows)
            {
                // Create object from DataRow
                BadgeInfo modifyBadge = new BadgeInfo(badgeDr);

                // Update the properties
                modifyBadge.BadgeDisplayName = modifyBadge.BadgeDisplayName.ToUpper();

                // Save the changes
                BadgeInfoProvider.SetBadgeInfo(modifyBadge);
            }

            return true;
        }

        return false;
    }
    /// <summary>
    /// OnPrerender check whether.
    /// </summary>
    protected override void OnPreRender(EventArgs e)
    {
        postTreeElem.Selected = ValidationHelper.GetInteger(hdnSelected.Value, SelectedPost);
        if ((mSelectedPost == 0) && (RequestHelper.IsAJAXRequest()))
        {
            mSelectedPost = postTreeElem.Selected;
        }

        if (mSelectedPost > 0)
        {
            ForumPostInfo fpi = ForumPostInfoProvider.GetForumPostInfo(mSelectedPost);
            if ((fpi != null) && (ForumContext.CurrentForum != null) && (fpi.PostForumID == ForumContext.CurrentForum.ForumID))
            {
                plcPostPreview.Visible = true;
                ltlPostSubject.Text    = HTMLHelper.HTMLEncode(fpi.PostSubject);
                ltlPostText.Text       = ResolvePostText(fpi.PostText);
                ltlSignature.Text      = GetSignatureArea(fpi, "<div class=\"SignatureArea\">", "</div>");
                ltlPostTime.Text       = TimeZoneHelper.ConvertToUserTimeZone(fpi.PostTime, false, MembershipContext.AuthenticatedUser, SiteContext.CurrentSite).ToString();
                ltlPostUser.Text       = "<span class=\"PostUserName\">" + GetUserName(fpi) + "</span>";
                ltlAvatar.Text         = AvatarImage(fpi);
                mUnapproved            = !fpi.PostApproved ? " Unapproved" : "";

                if (ForumContext.CurrentForum.ForumEnableAdvancedImage)
                {
                    ltlPostText.AllowedControls = ControlsHelper.ALLOWED_FORUM_CONTROLS;
                }
                else
                {
                    ltlPostText.AllowedControls = "none";
                }

                attachmentDisplayer.ClearData();
                attachmentDisplayer.PostID = fpi.PostId;
                attachmentDisplayer.PostAttachmentCount = fpi.PostAttachmentCount;
                attachmentDisplayer.ReloadData();


                #region "Badge"

                if (DisplayBadgeInfo)
                {
                    if (fpi.PostUserID > 0)
                    {
                        UserInfo ui = UserInfoProvider.GetUserInfo(fpi.PostUserID);
                        if ((ui != null) && (!ui.IsPublic()))
                        {
                            BadgeInfo bi = BadgeInfoProvider.GetBadgeInfo(ui.UserSettings.UserBadgeID);
                            if (bi != null)
                            {
                                ltlBadge.Text = "<div class=\"Badge\">" + HTMLHelper.HTMLEncode(bi.BadgeDisplayName) + "</div>";
                                if (!String.IsNullOrEmpty(bi.BadgeImageURL))
                                {
                                    ltlBadge.Text += "<div class=\"BadgeImage\"><img alt=\"" + HTMLHelper.HTMLEncode(bi.BadgeDisplayName) + "\" src=\"" + HTMLHelper.HTMLEncode(GetImageUrl(bi.BadgeImageURL)) + "\" /></div>";
                                }
                            }
                        }
                    }

                    // Set public badge if no badge is set
                    if (String.IsNullOrEmpty(ltlBadge.Text))
                    {
                        ltlBadge.Text = "<div class=\"Badge\">" + GetString("Forums.PublicBadge") + "</div>";
                    }
                }

                #endregion


                #region "Post actions"

                // Get the parent thread ID (for reply and quote)
                int threadId = ForumPostInfoProvider.GetPostRootFromIDPath(fpi.PostIDPath);

                ltlReply.Text     = GetLink(fpi, GetString("Forums_WebInterface_ForumPost.replyLinkText"), "PostActionLink", ForumActionType.Reply, threadId);
                ltlQuote.Text     = GetLink(fpi, GetString("Forums_WebInterface_ForumPost.quoteLinkText"), "PostActionLink", ForumActionType.Quote, threadId);
                ltlSubscribe.Text = GetLink(fpi, GetString("Forums_WebInterface_ForumPost.Subscribe"), "PostActionLink", ForumActionType.SubscribeToPost, threadId);

                ltlAnswer.Text    = GetLink(fpi, GetString("general.yes"), "ActionLink", ForumActionType.IsAnswer);
                ltlNotAnswer.Text = GetLink(fpi, GetString("general.no"), "ActionLink", ForumActionType.IsNotAnswer);

                if (ltlAnswer.Text != String.Empty)
                {
                    ltlWasHelpful.Text = GetString("Forums_WebInterface_ForumPost.Washelpful") + "&nbsp;";
                    ltlAnswer.Text    += "|";
                }

                ltlAddPostToFavorites.Text = GetLink(fpi, GetString("Forums_WebInterface_ForumPost.AddPostToFavorites"), "ActionLink", ForumActionType.AddPostToFavorites);

                ltlDelete.Text      = GetLink(fpi, GetString("general.delete"), "ActionLink", ForumActionType.Delete);
                ltlEdit.Text        = GetLink(fpi, GetString("general.edit"), "ActionLink", ForumActionType.Edit);
                ltlAttachments.Text = GetLink(fpi, GetString("general.attachments"), "ActionLink", ForumActionType.Attachment);

                #endregion


                #region "Extended actions"

                if ((EnableFriendship || EnableMessaging) && (fpi.PostUserID > 0))
                {
                    GenerateActionScripts = true;

                    ltlActions.Text = "<div class=\"PostExtendedActions\">";

                    if (EnableMessaging)
                    {
                        ltlActions.Text += "<a class=\"SendMessage\" onclick=\"PrivateMessage(" + fpi.PostUserID + "); return false;\" title=\"" + GetString("sendmessage.sendmessage") + "\"  href=\"#\"><span>" + GetString("sendmessage.sendmessage") + "</span></a>";
                    }

                    if (EnableFriendship)
                    {
                        ltlActions.Text += "<a class=\"Friendship\" onclick=\"FriendshipRequest(" + fpi.PostUserID + "); return false;\" title=\"" + GetString("friends.requestfriendship") + "\" href=\"#\"><span>" + GetString("friends.requestfriendship") + "</span></a>";
                    }

                    ltlActions.Text += "</div>";
                }

                #endregion


                // Hide separators
                if ((ltlReply.Text == "") || (ltlReply.Text != "" && ltlQuote.Text == ""))
                {
                    plcFirstSeparator.Visible = false;
                }

                if ((ltlSubscribe.Text == "") || (ltlSubscribe.Text != "" && ltlQuote.Text == ""))
                {
                    plcSecondSeparator.Visible = false;
                }

                if (ltlReply.Text != "" && ltlSubscribe.Text != "")
                {
                    plcFirstSeparator.Visible = true;
                }

                pnlManage.Visible = (EnableOnSiteManagement && (ForumContext.CurrentForum != null)) ? ForumContext.UserIsModerator(ForumContext.CurrentForum.ForumID, CommunityGroupID) : false;
                if (pnlManage.Visible)
                {
                    ltlApprove.Text    = GetLink(fpi, GetString("general.approve"), "ActionLink", ForumActionType.Appprove);
                    ltlApproveAll.Text = GetLink(fpi, GetString("forums.approveall"), "ActionLink", ForumActionType.ApproveAll);
                    ltlReject.Text     = GetLink(fpi, GetString("general.reject"), "ActionLink", ForumActionType.Reject);
                    ltlRejectAll.Text  = GetLink(fpi, GetString("forums.rejectall"), "ActionLink", ForumActionType.RejectAll);
                    ltlSplit.Text      = GetLink(fpi, GetString("forums.splitthread"), "ActionLink", ForumActionType.SplitThread);
                    ltlMove.Text       = GetLink(fpi, GetString("forums.movethread"), "ActionLink", ForumActionType.MoveToTheOtherForum, threadId);
                }
            }
        }
        else
        {
            plcPostPreview.Visible = false;
        }

        if (ControlsHelper.IsInUpdatePanel(this))
        {
            ControlsHelper.GetUpdatePanel(this).Update();
        }

        base.OnPreRender(e);
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsAdHocForum)
        {
            plcHeader.Visible = false;
        }

        forumEdit.OnPreview            += new EventHandler(forumEdit_OnPreview);
        forumEdit.OnModerationRequired += new EventHandler(forumEdit_OnModerationRequired);

        // Check whether subscription is for forum or post
        if (ForumContext.CurrentReplyThread == null)
        {
            ltrTitle.Text = GetString("Forums_ForumNewPost_Header.NewThread");

            if (ForumContext.CurrentPost != null && ForumContext.CurrentMode == ForumMode.Edit)
            {
                ltrTitle.Text = GetString("Forums_ForumNewPost_Header.EditPost");
            }
        }
        else
        {
            plcPreview.Visible = true;

            ltrTitle.Text = GetString("Forums_ForumNewPost_Header.Reply");

            ltrAvatar.Text  = AvatarImage(ForumContext.CurrentReplyThread);
            ltrSubject.Text = HTMLHelper.HTMLEncode(ForumContext.CurrentReplyThread.PostSubject);
            if (ForumContext.CurrentForum != null)
            {
                if (ForumContext.CurrentForum.ForumEnableAdvancedImage)
                {
                    ltrText.AllowedControls = ControlsHelper.ALLOWED_FORUM_CONTROLS;
                }
                else
                {
                    ltrText.AllowedControls = "none";
                }
                ltrText.Text = ResolvePostText(ForumContext.CurrentReplyThread.PostText);
            }
            ltrUserName.Text = HTMLHelper.HTMLEncode(ForumContext.CurrentReplyThread.PostUserName);
            ltrTime.Text     = CMSContext.ConvertDateTime(ForumContext.CurrentReplyThread.PostTime, this).ToString();

            UserSettingsInfo usi           = UserSettingsInfoProvider.GetUserSettingsInfoByUser(ForumContext.CurrentReplyThread.PostUserID);
            BadgeInfo        bi            = null;
            string           badgeName     = null;
            string           badgeImageUrl = null;

            if (usi != null)
            {
                bi = BadgeInfoProvider.GetBadgeInfo(usi.UserBadgeID);
                if (bi != null)
                {
                    badgeName     = HTMLHelper.HTMLEncode(ResHelper.LocalizeString(bi.BadgeDisplayName));
                    badgeImageUrl = HTMLHelper.HTMLEncode(bi.BadgeImageURL);
                }
            }

            ltrBadge.Text = GetNotEmpty(badgeName, "<div class=\"Badge\">" + badgeName + "</div>", "<div class=\"Badge\">" + GetString("Forums.PublicBadge") + "</div>", ForumActionType.Badge) +
                            GetNotEmpty(badgeImageUrl, "<div class=\"BadgeImage\"><img alt=\"" + badgeName + "\" src=\"" + GetImageUrl(ValidationHelper.GetString(badgeImageUrl, "")) + "\" /></div>", "", ForumActionType.Badge);
        }
    }
Beispiel #8
0
        public static void Parse(ChatMessage newChatMessage)
        {
            // Setup local variables
            char             swapChar     = (char)0xE000;
            List <EmoteInfo> parsedEmotes = new List <EmoteInfo>();
            List <BadgeInfo> parsedBadges = new List <BadgeInfo>();

            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);
            }

            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);
                }


                // 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);

                        EmoteInfo swapInfo = new EmoteInfo();
                        swapInfo.swapChar     = swapChar;
                        swapInfo.swapString   = emojilessMessage.Substring(startReplace, endReplace - startReplace + 1);
                        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))
            {
                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 = $"\u00A0{Drawing.imageSpacing}{Char.ConvertFromUtf32(e.swapChar)}{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))
            {
                sb.Replace(e.swapString, $"\u00A0{Drawing.imageSpacing}{Char.ConvertFromUtf32(e.swapChar)}");
            }
            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></color>{(isActionMessage ? String.Empty : ":")} {newChatMessage.displayMsg}";

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

            if (parsedBadges.Count > 0)
            {
                parsedBadges.Reverse();
                for (int i = 0; i < parsedBadges.Count; i++)
                {
                    badgeStr.Insert(0, $"\u200A{Drawing.imageSpacing}{Char.ConvertFromUtf32(parsedBadges[i].swapChar)}\u2004");
                }
            }
            badgeStr.Append("\u200A");
            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;
            newChatMessage.isActionMessage = isActionMessage;
            ChatHandler.RenderQueue.Enqueue(newChatMessage);
        }
        //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="ircMessage">The IRC message 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,
            IrcMessage ircMessage,
            ref MessageEmoteCollection emoteCollection,
            bool replaceEmotes = false)
        {
            BotUsername      = botUsername;
            RawIrcMessage    = ircMessage.ToString();
            Message          = ircMessage.Message;
            _emoteCollection = emoteCollection;

            Username = ircMessage.User;
            Channel  = ircMessage.Channel;

            foreach (var tag in ircMessage.Tags.Keys)
            {
                var tagValue = ircMessage.Tags[tag];

                switch (tag)
                {
                case Tags.Badges:
                    Badges = Common.Helpers.ParseBadges(tagValue);
                    // Iterate through saved badges for special circumstances
                    foreach (var badge in Badges)
                    {
                        switch (badge.Key)
                        {
                        case "bits":
                            CheerBadge = new CheerBadge(int.Parse(badge.Value));
                            break;

                        case "subscriber":
                            // Prioritize BadgeInfo subscribe count, as its more accurate
                            if (SubscribedMonthCount == 0)
                            {
                                SubscribedMonthCount = int.Parse(badge.Value);
                            }
                            break;

                        case "vip":
                            IsVip = true;
                            break;

                        case "admin":
                            IsStaff = true;
                            break;

                        case "staff":
                            IsStaff = true;
                            break;

                        case "partner":
                            IsPartner = true;
                            break;
                        }
                    }
                    break;

                case Tags.BadgeInfo:
                    BadgeInfo = Common.Helpers.ParseBadges(tagValue);
                    // check if founder is one of them, and get months from that
                    var founderBadge = BadgeInfo.Find(b => b.Key == "founder");
                    if (!founderBadge.Equals(default(KeyValuePair <string, string>)))
                    {
                        IsSubscriber         = true;
                        SubscribedMonthCount = int.Parse(founderBadge.Value);
                    }
                    else
                    {
                        var subBadge = BadgeInfo.Find(b => b.Key == "subscriber");
                        // BadgeInfo has better accuracy than Badges subscriber value
                        if (!subBadge.Equals(default(KeyValuePair <string, string>)))
                        {
                            SubscribedMonthCount = int.Parse(subBadge.Value);
                        }
                    }
                    break;

                case Tags.Bits:
                    Bits          = int.Parse(tagValue);
                    BitsInDollars = ConvertBitsToUsd(Bits);
                    break;

                case Tags.Color:
                    ColorHex = tagValue;
                    if (!string.IsNullOrWhiteSpace(ColorHex))
                    {
                        Color = ColorTranslator.FromHtml(ColorHex);
                    }
                    break;

                case Tags.CustomRewardId:
                    CustomRewardId = tagValue;
                    break;

                case Tags.DisplayName:
                    DisplayName = tagValue;
                    break;

                case Tags.Emotes:
                    EmoteSet = new EmoteSet(tagValue, Message);
                    break;

                case Tags.Id:
                    Id = tagValue;
                    break;

                case Tags.MsgId:
                    handleMsgId(tagValue);
                    break;

                case Tags.Mod:
                    IsModerator = Common.Helpers.ConvertToBool(tagValue);
                    break;

                case Tags.Noisy:
                    Noisy = Common.Helpers.ConvertToBool(tagValue) ? Noisy.True : Noisy.False;
                    break;

                case Tags.ReplyParentDisplayName:
                    if (ChatReply == null)
                    {
                        ChatReply = new ChatReply();
                    }                                                           // ChatReply is null if not reply
                    ChatReply.ParentDisplayName = tagValue;
                    break;

                case Tags.ReplyParentMsgBody:
                    if (ChatReply == null)
                    {
                        ChatReply = new ChatReply();
                    }                                                           // ChatReply is null if not reply
                    ChatReply.ParentMsgBody = tagValue;
                    break;

                case Tags.ReplyParentMsgId:
                    if (ChatReply == null)
                    {
                        ChatReply = new ChatReply();
                    }                                                           // ChatReply is null if not reply
                    ChatReply.ParentMsgId = tagValue;
                    break;

                case Tags.ReplyParentUserId:
                    if (ChatReply == null)
                    {
                        ChatReply = new ChatReply();
                    }                                                           // ChatReply is null if not reply
                    ChatReply.ParentUserId = tagValue;
                    break;

                case Tags.ReplyParentUserLogin:
                    if (ChatReply == null)
                    {
                        ChatReply = new ChatReply();
                    }                                                           // ChatReply is null if not reply
                    ChatReply.ParentUserLogin = tagValue;
                    break;

                case Tags.RoomId:
                    RoomId = tagValue;
                    break;

                case Tags.Subscriber:
                    // this check because when founder is set, the subscriber value is actually 0, which is problematic
                    IsSubscriber = IsSubscriber == false?Common.Helpers.ConvertToBool(tagValue) : true;

                    break;

                case Tags.TmiSentTs:
                    TmiSentTs = tagValue;
                    break;

                case Tags.Turbo:
                    IsTurbo = Common.Helpers.ConvertToBool(tagValue);
                    break;

                case Tags.UserId:
                    UserId = tagValue;
                    break;

                case Tags.UserType:
                    switch (tagValue)
                    {
                    case "mod":
                        UserType = UserType.Moderator;
                        break;

                    case "global_mod":
                        UserType = UserType.GlobalModerator;
                        break;

                    case "admin":
                        UserType = UserType.Admin;
                        IsStaff  = true;
                        break;

                    case "staff":
                        UserType = UserType.Staff;
                        IsStaff  = true;
                        break;

                    default:
                        UserType = UserType.Viewer;
                        break;
                    }
                    break;
                }
            }

            if (Message.Length > 0 && (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);
                if (Message.StartsWith("\u0001ACTION ") && Message.EndsWith("\u0001"))
                {
                    Message = Message.Trim('\u0001').Substring(7);
                    IsMe    = true;
                }
            }

            //Parse the emoteSet
            if (EmoteSet != null && Message != null && EmoteSet.Emotes.Count > 0)
            {
                var uniqueEmotes = EmoteSet.RawEmoteSetString.Split('/');
                foreach (var emote in uniqueEmotes)
                {
                    var firstColon = emote.IndexOf(':');
                    var firstComma = emote.IndexOf(',');
                    if (firstComma == -1)
                    {
                        firstComma = emote.Length;
                    }
                    var firstDash = emote.IndexOf('-');
                    if (firstColon > 0 && firstDash > firstColon && firstComma > firstDash)
                    {
                        if (int.TryParse(emote.Substring(firstColon + 1, firstDash - firstColon - 1), out var low) &&
                            int.TryParse(emote.Substring(firstDash + 1, firstComma - firstDash - 1), out var high))
                        {
                            if (low >= 0 && low < high && high < Message.Length)
                            {
                                //Valid emote, let's parse
                                var id = emote.Substring(0, firstColon);
                                //Pull the emote text from the message
                                var text = Message.Substring(low, high - low + 1);
                                _emoteCollection.Add(new MessageEmote(id, text));
                            }
                        }
                    }
                }
                if (replaceEmotes)
                {
                    EmoteReplacedMessage = _emoteCollection.ReplaceEmotes(Message);
                }
            }

            if (EmoteSet == null)
            {
                EmoteSet = new EmoteSet(default(string), 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 (string.Equals(Channel, Username, StringComparison.InvariantCultureIgnoreCase))
            {
                UserType      = UserType.Broadcaster;
                IsBroadcaster = true;
            }

            if (Channel.Split(':').Length == 3)
            {
                if (string.Equals(Channel.Split(':')[1], UserId, StringComparison.InvariantCultureIgnoreCase))
                {
                    UserType      = UserType.Broadcaster;
                    IsBroadcaster = true;
                }
            }
        }