private bool IsDuplicateInput(PublicMessageEventArgs e) { // clean up the input, lowercase it and replace all consecutive non-readable characters to a single _ string str = Regex.Replace($"{e.Message?.Text}{e.Message?.Caption}".ToLowerInvariant(), "[^a-zA-Z0-9]*", "_"); if (str.Length < 256) { return(false); } var hash = HashUtils.CalculateSHA1Hash(str); var hashCollection = DB.GetCollection <MessageHash>(); hashCollection.Delete(x => (DateTime.UtcNow - x.UtcWhen) > TimeSpan.FromDays(3)); // keep it clean var hashRecord = hashCollection.Find(x => x.Hash == hash).FirstOrDefault(); if (hashRecord != null) { InsultUserForCopyPasting(e, hashRecord); return(true); } else { hashRecord = new MessageHash { Hash = hash, User = e.Message.From, UtcWhen = DateTime.UtcNow, MessageID = e.Message.MessageID, ChatID = e.Message.Chat.ID }; hashCollection.Insert(hashRecord); _log.Info($"{e.Message.From.ShortName()} just sent a long message with hash {hash}, which I promptly stored."); return(false); } }
private void TriggerRandomMatchingRecord(PublicMessageEventArgs e, DbSet <VerbodenWoordData> verbodenWoordCollection, List <VerbodenWoordData> matchingRecords) { var selectedIndex = _rnd.Next(matchingRecords.Count); var match = matchingRecords[selectedIndex]; verbodenWoordCollection.Delete(x => x.UniqueID == match.UniqueID); var age = DateTime.UtcNow - match.CreationDate; string message = $"Een verboden woord [{string.Join(", ", match.Woorden.Select(w => MessageUtils.HtmlEscape(w)))}] is geraden door {MessageUtils.HtmlEscape(e.Message.From.DisplayName())}. Dit woord was {TimeService.AsReadableTimespan(age)} geleden aangewezen door {MessageUtils.HtmlEscape(match.OwnerName)}."; Client.SendMessageToChat(e.Message.Chat.ID, message, "HTML", true, false); Client.SendMessageToChat(match.OwnerUserId, message, "HTML", true, false); Client.ForwardMessageToChat(e.Message.Chat.ID, match.ReplyChatID, match.ReplyMessageID); _log.Info($"Selected match with ID {match.ID} - {message}"); var geradenWoord = new GeradenWoord { GuessedByUserId = e.Message.From.ID, GuessedByUserName = e.Message.From.UsernameOrName(), GuessedByUserNameLowerCase = e.Message.From.UsernameOrName().ToLower(), Message = e.Message, OwnerUserId = match.OwnerUserId, OwnerUserName = match.OwnerName, OwnerUserNameLowerCase = match.OwnerName?.ToLower(), VerbodenWoord = match, When = DateTime.UtcNow }; GetGeradenWoordCollection().Insert(geradenWoord); }
private string GetUserSetting(PublicMessageEventArgs e, string settingKey) { var coll = DB.GetCollection <ChatSetting>(); var kvp = coll.Find(x => x.ChatID == e.Message.Chat.ID && x.Key == settingKey).FirstOrDefault(); if (null != kvp) { return(kvp.Value); } return(null); }
private void ProcessCommand(PublicMessageEventArgs e, string command) { command = command?.ToLower() ?? String.Empty; string[] args = e.Message.Text.Split(' ').Where(x => !string.IsNullOrWhiteSpace(x)).Skip(1).ToArray(); switch (command) { case "/hunt": Hunt(e, args); break; } }
private void ProcessCommand(PublicMessageEventArgs e, string command) { command = command?.ToLower() ?? String.Empty; IEnumerable <string> args = StringUtils.SplitArgs(e.Message.Text).Skip(1); switch (command) { case "/admin": OnAdminCommand(e.Message, command, args); break; } }
private void Client_OnPublicMessage(object sender, PublicMessageEventArgs e) { var me = Client.GetMe(); var firstEntity = e.Message?.Entities?.FirstOrDefault(); if (null != firstEntity && firstEntity.Type == "bot_command" && firstEntity.Offset == 0) { string commandText = e.Message.Text.Substring(firstEntity.Offset, firstEntity.Length); if (commandText == "/whereami" || commandText == $"/whereami@{me.Username}") { Client.SendMessageToChat(e.Message.Chat.ID, $"<b>Public chat:</b> {e.Message.Chat.ID}"); } } }
private void ShowStatsForUser(string[] args, PublicMessageEventArgs e) { TimeSpan ago = TimeSpan.FromDays(14); string agoParam = "2w"; if (args.Length >= 1) { agoParam = args[0]; } try { ago = TimeUtils.ParseTimeSpan(agoParam); } catch (FormatException) { Client.SendMessageToChat(e.Message.Chat.ID, $"Ik snap er niks van. Wat bedoel je met '{MessageUtils.HtmlEscape(agoParam)}'? Probeer eens '5d', '8u', '4w' of doe gek met '3w2d7u'.", "HTML", true); return; } var who = e.Message.Entities.Where(x => x.User != null).Select(x => x.User).FirstOrDefault(); if (null == who) { var entity = e.Message.Entities.Where(x => x.Type == "mention" || x.Type == "text_mention").FirstOrDefault(); if (null != entity) { string userName = e.Message.Text.Substring(entity.Offset, entity.Length).TrimStart('@').ToLower(); var user = GetStatisticsCollection().Find((x) => x.UserNameLowerCase == userName && x.ChatID == e.Message.Chat?.ID).FirstOrDefault(); if (null != user) { who = new User { ID = user.UserId, Username = user.UserName }; } } } who = who ?? e.Message.From; var stats = GetStatisticsCollection().Find((x) => x.UserId == who?.ID && x.ChatID == e.Message.Chat?.ID).FirstOrDefault(); if (null == stats) { Client.SendMessageToChat(e.Message.Chat.ID, "Geen statistieken gevonden voor deze gebruiker in deze chat."); } else { StringBuilder reply = BuildStatsForPlayer((int)ago.TotalDays, stats); Client.SendMessageToChat(e.Message.Chat.ID, $"{reply}"); } }
private void InsultUserForCopyPasting(PublicMessageEventArgs e, MessageHash hashRecord) { string[] allReplies = System.IO.File.ReadAllLines("taunts.duplicate.txt").Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); string replyFmt = allReplies[_rnd.Next(allReplies.Length)]; string replyStr = String.Format(replyFmt, MessageUtils.HtmlEscape(hashRecord.User.ShortName()), // {0} TimeService.AsReadableTimespan(DateTime.UtcNow - hashRecord.UtcWhen), // {1} MessageUtils.HtmlEscape(e.Message.From.ShortName()), // {2} hashRecord.MessageID, // {3} hashRecord.ChatID // {4} ); _log.Info($"{e.Message.From.ShortName()} just duplicated {hashRecord.User.ShortName()}'s message and got abused with reply {replyStr}"); Client.SendMessageToChat(e.Message.Chat.ID, replyStr, "HTML", true, false, e.Message.MessageID); }
private void ProcessCommand(PublicMessageEventArgs e, string command) { command = command?.ToLower() ?? String.Empty; string[] args = e.Message.Text.Split(' ').Where(x => !string.IsNullOrWhiteSpace(x)).Skip(1).ToArray(); switch (command) { case "/geraden": ProcessGeraden(args, e, "raders van een verboden woord", x => x.GuessedByUserNameLowerCase, x => x.When, x => x.GuessedByUserName, x => x.OwnerUserId != x.GuessedByUserId); break; case "/geradenvan": ProcessGeraden(args, e, "makers van een geraden verboden woord", x => x.OwnerUserNameLowerCase, x => x.When, x => x.OwnerUserName, x => x.OwnerUserId != x.GuessedByUserId); break; } }
private void DetectForbiddenWord(PublicMessageEventArgs e) { string input = e.Message.Text + ". " + e.Message.Caption; var verbodenWoordCollection = GetVerbodenWoordCollection(); MatchCollection matches = CheckForPossibleWordMatch(input, verbodenWoordCollection); if (matches != null && matches.Count > 0) { _log.Info($"Message \"{input}\" matches regex {_woordenRegexp}. Matched: {matches.Count}: {string.Join(", ", matches.Select(x => x.ToString()))}"); // check if the match is one of the eligible forbidden words var matchingRecords = new List <VerbodenWoordData>(); foreach (var match in matches.Skip(0)) // fixes sily typing error { _log.Info($"{match.Groups[1].Value}"); matchingRecords.AddRange(verbodenWoordCollection.Find(x => x.Woorden.Where(w => string.Equals(w, match.Groups[1].Value, StringComparison.InvariantCultureIgnoreCase)).Any())); } _log.Info($"[0] Message \"{input}\" matches {matchingRecords.Count} record(s)."); foreach (var record in matchingRecords) { var wstr = string.Join(", ", record.Woorden); _log.Info($" [0] {record.OwnerName} - {record.ID} - {wstr} - {record.CreationDate}"); } _log.Info("---"); _ = matchingRecords.RemoveAll(x => x.OwnerUserId == e.Message.From.ID); _log.Info($"[1] Remaining matches: {matchingRecords.Count} record(s) after removing items owned by the sender."); _ = matchingRecords.RemoveAll(x => x.OwnerUserId == 183899219L); // remove anything by @Se7enOfNine _log.Info($"[2] Remaining matches: {matchingRecords.Count} record(s) after removing items owned by the sender."); foreach (var record in matchingRecords) { var wstr = string.Join(", ", record.Woorden); _log.Info($" [1] {record.OwnerName} - {record.ID} - {wstr} - {record.CreationDate}"); } _log.Info("---"); if (matchingRecords.Count > 0) { TriggerRandomMatchingRecord(e, verbodenWoordCollection, matchingRecords); } } }
private void ProcessCommand(PublicMessageEventArgs e, string command) { command = command?.ToLower() ?? String.Empty; string[] args = e.Message.Text.Split(' ').Where(x => !string.IsNullOrWhiteSpace(x)).Skip(1).ToArray(); switch (command) { case "/mentions": ShowStatsTopList(args, e, "mentions", x => x.Mentions); break; case "/mentioned": ShowStatsTopList(args, e, "times mentioned", x => x.Mentioned); break; case "/characters": ShowStatsTopList(args, e, "characters sent", x => x.Characters); break; case "/forwarded": ShowStatsTopList(args, e, "times forwarded", x => x.Forwarded); break; case "/forwards": ShowStatsTopList(args, e, "forwards", x => x.Forwards); break; case "/hashtags": ShowStatsTopList(args, e, "hashtags used", x => x.Hashtags); break; case "/joins": ShowStatsTopList(args, e, "joins", x => x.Joined); break; case "/quits": ShowStatsTopList(args, e, "rage quits", x => x.Left); break; case "/lines": ShowStatsTopList(args, e, "lines sent", x => x.Lines); break; case "/repliedto": ShowStatsTopList(args, e, "times replied to", x => x.Replied); break; case "/replies": ShowStatsTopList(args, e, "times replied", x => x.Replies); break; case "/stickers": ShowStatsTopList(args, e, "stickers sent", x => x.Stickers); break; case "/messages": ShowStatsTopList(args, e, "messages sent", x => x.TotalMessages); break; case "/urls": ShowStatsTopList(args, e, "URLs sent", x => x.URLs); break; case "/words": ShowStatsTopList(args, e, "words sent", x => x.Words); break; case "/stats": case "/me": ShowStatsForUser(args, e); break; } }
private void UpdateUserSetting(PublicMessageEventArgs e, string settingKey, string settingValue) { var coll = DB.GetCollection <ChatSetting>(); var kvp = coll.Find(x => x.ChatID == e.Message.Chat.ID && x.Key == settingKey).FirstOrDefault(); if (null == kvp) { kvp = new ChatSetting { ChatID = e.Message.Chat.ID, Key = settingKey, Value = settingValue, }; coll.Insert(kvp); } else { kvp.Value = settingValue; coll.Update(kvp); } }
private void Client_OnPublicMessage(object sender, PublicMessageEventArgs e) { var me = Client.GetMe(); var firstEntity = e.Message?.Entities?.FirstOrDefault(); if (null != firstEntity && firstEntity.Type == "bot_command" && firstEntity.Offset == 0) { string myName = Client.GetMe().Username; string commandText = e.Message.Text.Substring(firstEntity.Offset, firstEntity.Length); if (commandText.Contains("@") && !commandText.EndsWith($"@{myName}", StringComparison.InvariantCultureIgnoreCase)) { // not for me _log.Trace($"Got command '{commandText}' but it is not for me."); } else { commandText = commandText.Split("@").First(); ProcessCommand(e.Message, commandText); } } }
private void ProcessCommand(PublicMessageEventArgs e, string commandText) { switch (commandText) { case "/nousername": string reply = e.Message.Text.Substring(e.Message.Entities.First().Length)?.Trim(); if (string.IsNullOrWhiteSpace(reply)) { reply = GetUserSetting(e, "NoUsernameText"); if (string.IsNullOrWhiteSpace(reply)) { reply = "not set."; } Client.SendMessageToChat(e.Message.Chat.ID, "<b>New reply: </b>" + MessageUtils.HtmlEscape($"{reply}"), "HTML", true, false); } else { UpdateUserSetting(e, "NoUsernameText", reply); Client.SendMessageToChat(e.Message.Chat.ID, "<b>New reply: </b>" + MessageUtils.HtmlEscape($"{reply}"), "HTML", true, false); } break; } }
private void Hunt(PublicMessageEventArgs e, string[] args) { int number = 5; if (args.Length >= 1) { int.TryParse(args[0], out number); } var collection = GetVerbodenWoordCollection(); var woorden = collection.FindAll().OrderBy(x => x.CreationDate).Take(Math.Max(1, number)).ToList(); var sb = new StringBuilder(); sb.AppendLine($"Top {number} langststaande verboden woorden:"); for (int i = 0; i < woorden.Count; i++) { var w = woorden[i]; var lenstr = string.Join(",", w.Woorden.Select(x => $"{x.Length}")); string woordwoorden = w.Woorden.Count == 1 ? "woord" : "woorden"; sb.AppendLine($" {i + 1}. {MessageUtils.HtmlEscape(w.OwnerName)} heeft al {TimeService.AsReadableTimespan(DateTime.UtcNow - w.CreationDate)} {w.Woorden.Count} {woordwoorden} [{lenstr}] staan"); } Client.SendMessageToChat(e.Message.Chat.ID, $"{sb}"); }
private void UpdateStats(PublicMessageEventArgs e) { if (e.Message.Chat == null) { return; } lock (_statsLock) { var collection = GetStatisticsCollection(); var message = e.Message; if (message.From != null) { GetAndUpdate(collection, message.Chat.ID, message.From, (bucket) => { bucket.TotalMessages++; bucket.MessagesByType[(int)message.Type]++; if (message.ForwardFrom != null) { bucket.Forwards++; } if (message.Sticker != null) { bucket.Stickers++; } if (message.ReplyToMessage != null) { bucket.Replies++; } message.Entities.ForEach((x) => { // Type of the entity. Can be mention (@username), hashtag, bot_command, url, email, bold (bold text), italic (italic text), code (monowidth string), pre (monowidth block), text_link (for clickable text URLs), text_mention (for users without usernames) switch (x.Type) { case "hashtag": bucket.Hashtags++; break; case "mention": bucket.Mentions++; break; case "text_mention": bucket.Mentions++; break; case "text_link": case "url": bucket.URLs++; break; } }); string messageTextRaw = $"{message.Text}{message.Caption}"; string messageText = $"{message.Text}{message.Caption}"; messageText = Regex.Replace(messageText, @"\s+", " ").Trim(); if (message.Type == MessageType.TextMessage && !string.IsNullOrWhiteSpace(messageText) && null == message.ForwardFrom) { bucket.Characters += messageText.Length; bucket.Words += Regex.Split(messageTextRaw, @"\s").Where(x => !string.IsNullOrWhiteSpace(x)).Count(); // use original bucket.Lines += messageTextRaw.Split("\n").Where(x => !string.IsNullOrWhiteSpace(x)).Count(); // use original } }); } if (message.ForwardFrom != null) { GetAndUpdate(collection, message.Chat.ID, message.ForwardFrom, (bucket) => { bucket.Forwarded++; }); } if (message.ReplyToMessage != null && message.ReplyToMessage.From != null) { GetAndUpdate(collection, message.Chat.ID, message.ReplyToMessage.From, (bucket) => { bucket.Replied++; }); } if (message.LeftChatMember != null) { GetAndUpdate(collection, message.Chat.ID, message.LeftChatMember, (bucket) => { bucket.Left++; }); } if (message.NewChatMembers != null) { message.NewChatMembers.ForEach(x => GetAndUpdate(collection, message.Chat.ID, x, (bucket) => { bucket.Joined++; })); } if (message.Entities.Count > 0) { int index = 0; message.Entities.ForEach(entity => { if (null != entity.User) { GetAndUpdate(collection, message.Chat.ID, entity.User, (bucket) => { bucket.Mentioned++; }); } else if (entity.Type == "text_mention" || entity.Type == "mention") { string userName = message.Text.Substring(entity.Offset, entity.Length).TrimStart('@')?.ToLower(); var user = collection.Find((x) => x.UserNameLowerCase == userName && x.ChatID == e.Message.Chat?.ID).FirstOrDefault(); if (null != user) { var bucket = user.GetOrCreateBucket(DateTime.UtcNow); bucket.Mentioned++; collection.Update(user); } } index++; }); } } }
private void ShowStatsTopList(string[] args, PublicMessageEventArgs e, string what, Func <UserStatisticsBucket, int> countMember) { TimeSpan ago = TimeSpan.Zero; string agoParam = "2w"; string numParam = "42"; if (args.Length >= 1) { agoParam = args[0]; } if (args.Length >= 2) { numParam = args[1]; } try { ago = TimeUtils.ParseTimeSpan(agoParam); } catch (FormatException) { Client.SendMessageToChat(e.Message.Chat.ID, $"Ik snap er niks van. Wat bedoel je met '{MessageUtils.HtmlEscape(agoParam)}'? Probeer eens '5d', '8u', '4w' of doe gek met '3w2d7u'.", "HTML", true); return; } if (!Int32.TryParse(numParam, out int number)) { Client.SendMessageToChat(e.Message.Chat.ID, $"Ik snap er niks van. Wat bedoel je met '{MessageUtils.HtmlEscape(agoParam)}'? Hoe moet ik daar een getal van maken?", "HTML", true); return; } if (number == 0 || ago == TimeSpan.Zero) { Client.SendMessageToChat(e.Message.Chat.ID, $"Haha, erg grappig 👏 Hier zijn je nul resultaten, malloot.", "HTML", true); return; } var collection = GetStatisticsCollection(); int numberOfDays = (int)Math.Ceiling(ago.TotalDays); int grandTotal = 0; var sinds = DateTime.UtcNow - TimeSpan.FromDays(numberOfDays); var yearDay = (sinds.Year * 1000) + sinds.DayOfYear; var allStats = new List <(UserStatistics stats, int total)>(); foreach (var stats in collection.FindAll()) { int total = 0; var buckets = stats.Buckets.Where(x => x.YearDay >= yearDay).ToList(); buckets.ForEach(x => total += countMember(x)); if (total > 0) { allStats.Add((stats, total)); grandTotal += total; } } var sortedAggregatedCollection = allStats.OrderByDescending(x => x.total).Take(number); if (sortedAggregatedCollection.Count() < number) { number = sortedAggregatedCollection.Count(); } StringBuilder result = new StringBuilder(); result.AppendLine($"Top <b>{number}</b> {what} vanaf <b>{TimeService.AsDutchString(DateTime.Now - ago)}</b>:"); int place = 1; foreach (var record in sortedAggregatedCollection) { result.AppendLine($"{place}: {MessageUtils.HtmlEscape(record.stats.UserName.TrimStart().TrimStart('@'))} ({record.total})"); place++; } result.AppendLine($"<i>Totaal aantal {what}: {grandTotal} voor {allStats.Count()} personen</i>"); Client.SendMessageToChat(e.Message.Chat.ID, $"{result}", "HTML", disableWebPagePreview: true, disableNotification: true); }
private void ProcessGeraden(string[] args, PublicMessageEventArgs e, string whatisit, Func <GeradenWoord, string> groupByMember, Func <GeradenWoord, DateTime> whenMember, Func <GeradenWoord, string> nameMember, Func <GeradenWoord, bool> filter) { var collection = GetGeradenWoordCollection(); TimeSpan ago = TimeSpan.Zero; string agoParam = "4w"; string numParam = "42"; if (args.Length >= 1) { agoParam = args[0]; } if (args.Length >= 2) { numParam = args[1]; } try { ago = TimeUtils.ParseTimeSpan(agoParam); } catch (FormatException) { Client.SendMessageToChat(e.Message.Chat.ID, $"Ik snap er niks van. Wat bedoel je met '{MessageUtils.HtmlEscape(agoParam)}'? Probeer eens '5d', '8u', '4w' of doe gek met '3w2d7u'.", "HTML", true); return; } if (!Int32.TryParse(numParam, out int number)) { Client.SendMessageToChat(e.Message.Chat.ID, $"Ik snap er niks van. Wat bedoel je met '{MessageUtils.HtmlEscape(agoParam)}'? Hoe moet ik daar een getal van maken?", "HTML", true); return; } if (number == 0 || ago == TimeSpan.Zero) { Client.SendMessageToChat(e.Message.Chat.ID, $"Haha, erg grappig 👏 Hier zijn je nul resultaten, malloot.", "HTML", true); return; } var filteredCollection = collection.Find(x => filter(x) && whenMember(x) >= (DateTime.UtcNow - ago)); var aggregatedCollection = filteredCollection.GroupBy(groupByMember).Select(cl => new ResultLine { Name = nameMember(cl.First()), Count = cl.Count() }); var sortedAggregatedCollection = aggregatedCollection.OrderByDescending(x => x.Count).Take(number); if (sortedAggregatedCollection.Count() < number) { number = sortedAggregatedCollection.Count(); } StringBuilder result = new StringBuilder(); result.AppendLine($"Top <b>{number}</b> {whatisit} vanaf <b>{TimeService.AsDutchString(DateTime.Now - ago)}</b>:"); int place = 1; foreach (var record in sortedAggregatedCollection) { result.AppendLine($"{place}: {record.Name.TrimStart().TrimStart('@')} ({record.Count})"); place++; } result.AppendLine($"<i>Totaal aantal records in deze periode: {filteredCollection.Count()} voor {aggregatedCollection.Count()} personen</i>"); Client.SendMessageToChat(e.Message.Chat.ID, $"{result}", "HTML", disableWebPagePreview: true, disableNotification: true); }
private void Client_OnPublicMessage(object sender, PublicMessageEventArgs e) { ProcessMessage(e.Message); }