// Send Messages public static void SendMessage(TwitchChannel channel, string _message, bool isMod) { if (channel != null) { if (!_message.StartsWith(".color ")) { if (!isMod && nextMessageSendTime > DateTime.Now) { Task.Run(async() => { await Task.Delay(300); channel.AddMessage(new Message("Sending messages too fast, message not sent.", HSLColor.Gray, false)); }); return; } nextMessageSendTime = DateTime.Now.AddSeconds(1.1); } var message = Commands.ProcessMessage(_message, channel, true); if (!Client.Say(message, channel.Name.TrimStart('#'), isMod)) { if (nextProtectMessageSendTime < DateTime.Now) { channel.AddMessage(new Message($"Message not sent to protect you from a global ban. (try again in {Client.GetTimeUntilNextMessage(isMod).Seconds} seconds)", HSLColor.Gray, false)); nextProtectMessageSendTime = DateTime.Now.AddSeconds(1); } } } }
public Message(IrcMessage data, TwitchChannel channel, bool enableTimestamp = true, bool enablePingSound = true, bool isReceivedWhisper = false, bool isSentWhisper = false, bool includeChannel = false, bool isPastMessage = false) { //var w = Stopwatch.StartNew(); ParseTime = DateTime.Now; Channel = channel; List <Word> words = new List <Word>(); string value; string text = data.Params ?? ""; Params = text; Username = data.PrefixNickname ?? ""; if (string.IsNullOrWhiteSpace(Username)) { string login; if (data.Tags.TryGetValue("login", out login)) { Username = login; } } if (data.Tags.TryGetValue("user-id", out value)) { UserId = value; } var slashMe = false; // Handle /me messages if (text.Length > 8 && text.StartsWith("\u0001ACTION ")) { text = text.Substring("\u0001ACTION ".Length, text.Length - "\u0001ACTION ".Length - 1); slashMe = true; } if (data.Tags.TryGetValue("display-name", out value)) { DisplayName = value; } // Username if (string.IsNullOrWhiteSpace(DisplayName)) { DisplayName = Username; } // Highlights if (!IrcManager.Account.IsAnon) { if ((AppSettings.ChatEnableHighlight || AppSettings.ChatEnableHighlightSound || AppSettings.ChatEnableHighlightTaskbar) && Username != IrcManager.Account.Username.ToLower()) { if (!AppSettings.HighlightIgnoredUsers.ContainsKey(Username)) { if (!IrcManager.IgnoredUsers.Contains(Username)) { if (AppSettings.CustomHighlightRegex != null && AppSettings.CustomHighlightRegex.IsMatch(text)) { if (AppSettings.ChatEnableHighlight) { HighlightType = HighlightType.Highlighted; } if (EnablePings && enablePingSound) { if (AppSettings.ChatEnableHighlightSound) { GuiEngine.Current.PlaySound(NotificationSound.Ping); } if (AppSettings.ChatEnableHighlightTaskbar) { GuiEngine.Current.FlashTaskbar(); } } } else if (AppSettings.HighlightUserNames != null && (AppSettings.HighlightUserNames.ContainsKey(Username) || AppSettings.HighlightUserNames.ContainsKey(DisplayName))) { if (AppSettings.ChatEnableHighlight) { HighlightType = HighlightType.UsernameHighlighted; } } } } } } // Tags if (data.Tags.TryGetValue("color", out value)) { try { if (value.Length == 7 && value[0] == '#') { UsernameColor = HSLColor.FromRGB(Convert.ToInt32(value.Substring(1), 16)); } } catch { } } // Bits string bits = null; data.Tags.TryGetValue("bits", out bits); // Add timestamp string timestampTag; string timestamp = null; string tmiTimestamp; long tmiTimestampInt; DateTime timestampTime = DateTime.Now; if (data.Tags.TryGetValue("tmi-sent-ts", out tmiTimestamp)) { if (long.TryParse(tmiTimestamp, out tmiTimestampInt)) { var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); var time = dtDateTime.AddSeconds(tmiTimestampInt / 1000).ToLocalTime(); timestampTime = time; //timestamp = time.ToString(AppSettings.ChatShowTimestampSeconds ? "HH:mm:ss" : "HH:mm"); //enableTimestamp = true; } } else if (data.Tags.TryGetValue("timestamp-utc", out timestampTag)) { DateTime time; if (DateTime.TryParseExact(timestampTag, "yyyyMMdd-HHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out time)) { timestampTime = time; //timestamp = time.ToString(AppSettings.ChatShowTimestampSeconds ? "HH:mm:ss" : "HH:mm"); //enableTimestamp = true; } } if (enableTimestamp && AppSettings.ChatShowTimestamps) { string timestampFormat; if (AppSettings.ChatShowTimestampSeconds) { timestampFormat = AppSettings.TimestampsAmPm ? "hh:mm:ss tt" : "HH:mm:ss"; } else { timestampFormat = AppSettings.TimestampsAmPm ? "hh:mm tt" : "HH:mm"; } timestamp = timestampTime.ToString(timestampFormat, enUS); words.Add(new Word { Type = SpanType.Text, Value = timestamp, Color = HSLColor.FromRGB(-8355712), Font = FontType.Small, CopyText = timestamp }); } // add channel name if (includeChannel) { words.Add(new Word { Type = SpanType.Text, Link = new Link(LinkType.ShowChannel, channel.Name), Value = "#" + channel.Name, Color = HSLColor.FromRGB(-8355712), Font = FontType.Medium, CopyText = "#" + channel.Name }); } // add moderation buttons if (channel.IsModOrBroadcaster && !string.Equals(IrcManager.Account.Username, Username)) { string badges; if (data.Tags.TryGetValue("badges", out badges)) { if (badges.Contains("broadcaster")) { goto aftermod; } if (badges.Contains("moderator") && !channel.IsBroadcaster) { goto aftermod; } } if (AppSettings.EnableBanButton) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = new LazyLoadedImage(GuiEngine.Current.GetImage(ImageType.Ban)), Link = new Link(LinkType.BanUser, Tuple.Create(Username, channel.Name)), Tooltip = "Ban User" }); } if (AppSettings.EnableTimeoutButton) { foreach (var amount in AppSettings.TimeoutButtons) { int tmpAmount = amount; string tooltip = ""; if (tmpAmount > 60 * 60 * 24) { tooltip += tmpAmount / (60 * 60 * 24) + " days "; tmpAmount %= 60 * 60 * 24; } if (tmpAmount > 60 * 60) { tooltip += tmpAmount / (60 * 60) + " hours "; tmpAmount %= 60 * 60; } if (tmpAmount > 60) { tooltip += tmpAmount / (60) + " mins "; tmpAmount %= 60; } if (tmpAmount > 0) { tooltip += tmpAmount + " secs "; } Image image; if (AppSettings.TimeoutButtons.Count > 1) { image = ((dynamic)GuiEngine.Current).GetImageForTimeout(amount); } else { image = GuiEngine.Current.GetImage(ImageType.Timeout); } words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = new LazyLoadedImage(image), Link = new Link(LinkType.TimeoutUser, Tuple.Create(Username, channel.Name, amount)), Tooltip = $"Timeout User ({tooltip.Trim()})" }); } } } aftermod: // get badges from tags if (data.Tags.TryGetValue("badges", out value)) { var badges = value.Split(','); LazyLoadedImage image; foreach (var badge in badges) { if (badge.StartsWith("subscriber/")) { try { int n = int.Parse(badge.Substring("subscriber/".Length)); Badges |= MessageBadges.Sub; image = channel.GetSubscriberBadge(n); if (image != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = image, Link = new Link(LinkType.Url, Channel.SubLink), Tooltip = image.Tooltip }); } else { image = GuiEngine.Current.GetBadge(badge); if (image != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = image, Link = new Link(LinkType.Url, image.click_url), Tooltip = image.Tooltip }); } } } catch { } } else if (badge.Equals("moderator/1") && channel.ModeratorBadge != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = channel.ModeratorBadge, Tooltip = channel.ModeratorBadge.Tooltip }); } else if (badge.StartsWith("bits/")) { try { int n = int.Parse(badge.Substring("bits/".Length)); image = channel.GetCheerBadge(n); if (image != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = image, Link = new Link(LinkType.Url, image.click_url), Tooltip = image.Tooltip }); } else { image = GuiEngine.Current.GetBadge(badge); if (image != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = image, Link = new Link(LinkType.Url, image.click_url), Tooltip = image.Tooltip }); } } } catch {} } else { image = GuiEngine.Current.GetBadge(badge); if (image != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = image, Link = new Link(LinkType.Url, image.click_url), Tooltip = image.Tooltip }); } } } } var messageUser = (isSentWhisper ? IrcManager.Account.Username + " -> " : ""); messageUser += DisplayName; if (!isReceivedWhisper && !isSentWhisper) { messageUser += (DisplayName.ToLower() != Username ? $" ({Username})" : ""); } if (isReceivedWhisper) { messageUser += " -> " + IrcManager.Account.Username; } if (!slashMe) { messageUser += ":"; } words.Add(new Word { Type = SpanType.Text, Value = messageUser, Color = UsernameColor, Font = FontType.MediumBold, Link = new Link(LinkType.UserInfo, new UserInfoData { UserName = Username, UserId = UserId, Channel = channel }), CopyText = messageUser }); var twitchEmotes = new List <Tuple <int, LazyLoadedImage> >(); if (data.Tags.TryGetValue("msg-id", out value)) { if (value.Contains("highlighted-message")) { if (!isPastMessage) { Message message; message = new Message("Highlighted Message", HSLColor.Gray, true) { HighlightType = HighlightType.HighlightedMessage }; channel.AddMessage(message); } HighlightType = HighlightType.HighlightedMessage; } } // Twitch Emotes if (AppSettings.ChatEnableTwitchEmotes && data.Tags.TryGetValue("emotes", out value)) { // 93064:0-6,8-14/80481:16-20,22-26 value.Split('/').Do(emote => { if (emote != "") { var x = emote.Split(':'); try { var id = x[0]; foreach (var y in x[1].Split(',')) { var coords = y.Split('-'); var index = int.Parse(coords[0]); var name = text.Substring(index, int.Parse(coords[1]) - index + 1); // ignore ignored emotes if (!AppSettings.ChatIgnoredEmotes.ContainsKey(name)) { var e = Emotes.GetTwitchEmoteById(id, name); twitchEmotes.Add(Tuple.Create(index, e)); } } ; } catch (Exception e) { GuiEngine.Current.log("Generic Exception Handler: " + " " + emote + " " + x[0] + " " + e.ToString()); } } }); twitchEmotes.Sort((e1, e2) => e1.Item1.CompareTo(e2.Item1)); } var i = 0; var currentTwitchEmoteIndex = 0; var currentTwitchEmote = twitchEmotes.FirstOrDefault(); foreach (var split in text.Split(' ')) { if (currentTwitchEmote != null) { if (currentTwitchEmote.Item1 == i) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = currentTwitchEmote.Item2, Link = new Link(LinkType.Url, currentTwitchEmote.Item2.Url), Tooltip = currentTwitchEmote.Item2.Tooltip, CopyText = currentTwitchEmote.Item2.Name }); i += split.Length + 1; currentTwitchEmoteIndex++; currentTwitchEmote = currentTwitchEmoteIndex == twitchEmotes.Count ? null : twitchEmotes[currentTwitchEmoteIndex]; continue; } } foreach (var o in Emojis.ParseEmojis(split)) { var s = o as string; if (s != null) { Match m = Regex.Match(s, "([A-Za-z]+)([1-9][0-9]*)"); if (bits != null && m.Success) { try{ int cheer; string prefix = m.Groups[1].Value; string getcheer = m.Groups[2].Value; if (int.TryParse(getcheer, out cheer)) { string color; string bitsLink; bool found = false; HSLColor bitsColor; LazyLoadedImage emote; if (!(found = channel.GetCheerEmote(prefix, cheer, !GuiEngine.Current.IsDarkTheme, out emote, out color))) { found = GuiEngine.Current.GetCheerEmote(prefix, cheer, !GuiEngine.Current.IsDarkTheme, out emote, out color); } if (found) { bitsColor = HSLColor.FromRGBHex(color); bitsLink = emote.Url; words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = Emotes.MiscEmotesByUrl.GetOrAdd(bitsLink, url => new LazyLoadedImage { Name = "cheer", Url = url, Tooltip = "Twitch Bits Badge" }), Tooltip = "Twitch Bits Donation", CopyText = s, Link = new Link(LinkType.Url, "https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6") }); words.Add(new Word { Type = SpanType.Text, Value = getcheer, Font = FontType.Small, Color = bitsColor }); } continue; } } catch (Exception e) { GuiEngine.Current.log("Generic Exception Handler: " + e.ToString()); } } LazyLoadedImage bttvEmote; if (!AppSettings.ChatIgnoredEmotes.ContainsKey(s) && (AppSettings.ChatEnableBttvEmotes && (Emotes.BttvGlobalEmotes.TryGetValue(s, out bttvEmote) || channel.BttvChannelEmotes.TryGetValue(s, out bttvEmote)) || (AppSettings.ChatEnableFfzEmotes && (Emotes.FfzGlobalEmotes.TryGetValue(s, out bttvEmote) || channel.FfzChannelEmotes.TryGetValue(s, out bttvEmote))))) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = bttvEmote, Color = slashMe ? UsernameColor : new HSLColor?(), Tooltip = bttvEmote.Tooltip, Link = new Link(LinkType.Url, bttvEmote.Url), CopyText = bttvEmote.Name }); } else { var link = _matchLink(split); words.Add(new Word { Type = SpanType.Text, Value = s.Replace('﷽', '?'), Color = slashMe ? UsernameColor : (link == null ? new HSLColor?() : HSLColor.FromRGB(-8355712)), Link = link == null ? null : new Link(LinkType.Url, link), CopyText = s }); } } else { var e = o as LazyLoadedImage; if (e != null) { words.Add(new Word { Type = SpanType.LazyLoadedImage, Value = e, Link = new Link(LinkType.Url, e.Url), Tooltip = e.Tooltip, CopyText = e.Name, HasTrailingSpace = e.HasTrailingSpace }); } } } var splitLength = 0; for (var j = 0; j < split.Length; j++) { splitLength++; if (char.IsHighSurrogate(split[j])) { j += 1; } } i += splitLength + 1; } Words = words; RawMessage = text; if (!isReceivedWhisper && AppSettings.HighlightIgnoredUsers.ContainsKey(Username)) { HighlightTab = false; } //w.Stop(); //Console.WriteLine("Message parsed in " + w.Elapsed.TotalSeconds.ToString("0.000000") + " seconds"); }