private async Task <(IEnumerable <KeyValuePair <ulong, int> >, IEnumerable <KeyValuePair <string, int> >)> GetStatsOfChannel(DiscordChannel channel) { var messagesListByUser = new Dictionary <ulong, int>(); var messagesListByDate = new Dictionary <string, int>(); var lastMessageId = (await channel.GetMessagesAsync(1)).FirstOrDefault()?.Id; while (lastMessageId != null) { var last100Messages = await channel.GetMessagesBeforeAsync(lastMessageId.Value, 100); var lastUserGroupedMessages = last100Messages .GroupBy(p => p.Author.Id, (authorId, messages) => new { AuthorId = authorId, MessagesCount = messages.Count() }); var lastDateGroupedMessages = last100Messages .GroupBy(p => p.CreationTimestamp.ToString("yyyy/MM"), (monthAndYear, messagesInMonth) => new { Date = monthAndYear, MessagesCount = messagesInMonth.Count() }); foreach (var message in lastUserGroupedMessages) { if (messagesListByUser.ContainsKey(message.AuthorId)) { messagesListByUser[message.AuthorId] += message.MessagesCount; } else { messagesListByUser[message.AuthorId] = message.MessagesCount; } } foreach (var message in lastDateGroupedMessages) { if (messagesListByDate.ContainsKey(message.Date)) { messagesListByDate[message.Date] += message.MessagesCount; } else { messagesListByDate[message.Date] = message.MessagesCount; } } if (last100Messages.Count < 100) { break; } lastMessageId = last100Messages.Last().Id; } return(messagesListByUser.AsEnumerable(), messagesListByDate.AsEnumerable()); }
internal static Task <List <DiscordMessage> > GetMessagesBeforeCachedAsync(this DiscordChannel ch, ulong msgId, int count = 100) { if (!MessageQueue.TryGetValue(ch.Id, out var queue)) { lock (MessageQueue) if (!MessageQueue.TryGetValue(ch.Id, out queue)) { MessageQueue[ch.Id] = queue = new FixedLengthBuffer <ulong, DiscordMessage>(KeyGen); } } List <DiscordMessage> result; lock (queue.syncObj) result = queue.Reverse().SkipWhile(m => m.Id >= msgId).Take(count).ToList(); var cacheCount = result.Count; var fetchCount = Math.Max(count - cacheCount, 0); if (fetchCount > 0) { IReadOnlyList <DiscordMessage> fetchedList; if (result.Any()) { fetchedList = ch.GetMessagesBeforeAsync(result[0].Id, fetchCount).ConfigureAwait(false).GetAwaiter().GetResult(); if (queue.Count < Config.ChannelMessageHistorySize) { lock (queue.syncObj) { // items in queue might've changed since the previous check at the beginning of this method var freshCopy = queue.Reverse().ToList(); queue.Clear(); queue.AddRange(freshCopy.Concat(fetchedList).Distinct().Reverse()); } } } else { fetchedList = ch.GetMessagesBeforeAsync(msgId, fetchCount).ConfigureAwait(false).GetAwaiter().GetResult(); } result.AddRange(fetchedList); } return(Task.FromResult(result)); }
public static async Task <(string productCode, TitleInfo info)> LookupGameAsync(DiscordChannel channel, DiscordMessage message, string gameTitle) { var lastBotMessages = await channel.GetMessagesBeforeAsync(message.Id, 20, DateTime.UtcNow.AddSeconds(-30)).ConfigureAwait(false); foreach (var msg in lastBotMessages) { if (BotReactionsHandler.NeedToSilence(msg).needToChill) { return(null, null); } } try { var requestBuilder = RequestBuilder.Start().SetSearch(gameTitle); var searchCompatListTask = Client.GetCompatResultAsync(requestBuilder, Config.Cts.Token); var localList = CompatList.GetLocalCompatResult(requestBuilder); var status = await searchCompatListTask.ConfigureAwait(false); status = status.Append(localList); if ((status.ReturnCode == 0 || status.ReturnCode == 2) && status.Results.Any()) { var sortedList = status.GetSortedList(); var bestMatch = sortedList.First(); var listWithStatus = sortedList .TakeWhile(i => Math.Abs(i.score - bestMatch.score) < double.Epsilon) .Where(i => !string.IsNullOrEmpty(i.info.Status) && i.info.Status != "Unknown") .ToList(); if (listWithStatus.Count > 0) { bestMatch = listWithStatus.First(); } var(code, info, score) = bestMatch; Config.Log.Debug($"Looked up \"{gameTitle}\", got \"{info?.Title}\" with score {score}"); if (score < Config.GameTitleMatchThreshold) { return(null, null); } if (!string.IsNullOrEmpty(info?.Title)) { StatsStorage.GameStatCache.TryGetValue(info.Title, out int stat); StatsStorage.GameStatCache.Set(info.Title, ++stat, StatsStorage.CacheTime); } return(code, info); } } catch (Exception e) { Config.Log.Warn(e); } return(null, null); }
public async Task AnalyzeAsync(CommandContext ctx, [Description("Member to calculate toxicity from")] DiscordMember member, [Description("Channel to calculate in")] DiscordChannel channel) { var msg = await channel.GetMessagesBeforeAsync(channel.LastMessageId, 100); var msgstr = msg.Where(x => x.Author.Id == member.Id).Select(x => x.Content); var str = string.Join('\n', msgstr); var a = await Shared.Perspective.RequestAnalysis(str); await ctx.SafeRespondAsync($"Toxicity: {a.AttributeScores.First().Value.SummaryScore.Value}"); }
public static async Task <IReadOnlyCollection <DiscordMessage> > GetMessagesBeforeAsync(this DiscordChannel channel, ulong beforeMessageId, int limit = 100, DateTime?timeLimit = null) { if (timeLimit > DateTime.UtcNow) { throw new ArgumentException(nameof(timeLimit)); } var afterTime = timeLimit ?? DateTime.UtcNow.AddSeconds(-30); var messages = await channel.GetMessagesBeforeAsync(beforeMessageId, limit).ConfigureAwait(false); return(messages.TakeWhile(m => m.CreationTimestamp > afterTime).ToList().AsReadOnly()); }
private async Task <DiscordMessage> FindStarPost(DiscordChannel starboardChannel, ulong messageId, bool timeLimited = true) { var dateThreshold = DateTimeOffset.Now.AddDays(-1); // TODO: optimize this with a cache when we hit 100+ servers with star msg id -> chan,msg id var cacheEntry = await _database.StarboardCache.FirstOrDefaultAsync(e => e.MessageId == messageId && e.GuildId == starboardChannel.GuildId); if (cacheEntry != null) { var message = await starboardChannel.GetMessageAsync(cacheEntry.StarboardId); return(message); } var messageIdStr = messageId.ToString(); var messages = await starboardChannel.GetMessagesAsync(); var count = 0; while (messages.Count > 0) { foreach (var message in messages) { count++; // break when message is too old. if (timeLimited && message.CreationTimestamp <= dateThreshold) { return(null); } if (message.Author.Id == _client.CurrentUser.Id && message.Embeds .SelectMany(e => e.Fields ?? EmptyEmbedFields) .Any(f => f.Name == "Message ID" && f.Value == messageIdStr)) { return(message); } } // break when we hit 400 messages if (count > 400) { return(null); } messages = await starboardChannel.GetMessagesBeforeAsync(messages.Last().Id); } return(null); }
public async Task Purge(CommandContext ctx, int amount = 100, DiscordChannel channel = null) { if (channel == null) { channel = ctx.Channel; } var messages = await channel.GetMessagesBeforeAsync(ctx.Message.Id, amount); await channel.DeleteMessagesAsync(messages); if (ctx.Channel.Id == channel.Id) { await ctx.Message.DeleteAsync(); return; } await ctx.RespondAsync("Channel cleared"); }
public static async Task <(string productCode, TitleInfo info)> LookupGameAsync(DiscordChannel channel, DiscordMessage message, string gameTitle) { var lastBotMessages = await channel.GetMessagesBeforeAsync(message.Id, 20, DateTime.UtcNow.AddSeconds(-30)).ConfigureAwait(false); foreach (var msg in lastBotMessages) { if (BotReactionsHandler.NeedToSilence(msg).needToChill) { return(null, null); } } try { var requestBuilder = RequestBuilder.Start().SetSearch(gameTitle); var status = await Client.GetCompatResultAsync(requestBuilder, Config.Cts.Token).ConfigureAwait(false); if ((status.ReturnCode == 0 || status.ReturnCode == 2) && status.Results.Any()) { var(code, info, score) = status.GetSortedList().First(); Config.Log.Debug($"Looked up \"{gameTitle}\", got \"{info?.Title}\" with score {score}"); if (score < 0.51) { return(null, null); } if (!string.IsNullOrEmpty(info?.Title)) { StatsStorage.GameStatCache.TryGetValue(info.Title, out int stat); StatsStorage.GameStatCache.Set(info.Title, ++stat, StatsStorage.CacheTime); } return(code, info); } } catch (Exception e) { Config.Log.Warn(e); } return(null, null); }
public static async Task <IReadOnlyList <DiscordMessage> > GetMessagesFromAsync(this DiscordChannel channel, DiscordMember member, int limit = 1) { var messages = new List <DiscordMessage>(); for (int step = 50; messages.Count < limit && step < 400; step *= 2) { ulong?lastId = messages.FirstOrDefault()?.Id; IReadOnlyList <DiscordMessage> requested; if (lastId is null) { requested = await channel.GetMessagesAsync(step); } else { requested = await channel.GetMessagesBeforeAsync(messages.FirstOrDefault().Id, step - messages.Count); } messages.AddRange(requested.Where(m => m.Author.Id == member.Id).Take(limit)); } return(messages.AsReadOnly()); }
private async Task <List <DiscordMessage> > GetAllMessagesFromChannel(DiscordChannel channel) { var messagesList = new List <DiscordMessage>(); var lastMessageId = (await channel.GetMessagesAsync(1)).FirstOrDefault()?.Id; while (lastMessageId != null) { var last100Messages = await channel.GetMessagesBeforeAsync(lastMessageId.Value, 100); messagesList.AddRange(last100Messages); if (last100Messages.Count < 100) { break; } lastMessageId = last100Messages.Last().Id; } return(messagesList); }
public static async IAsyncEnumerator <DiscordMessage> GetAsyncEnumerator(this DiscordChannel channel) { bool hasMorePages = true; DiscordMessage last = null; do { var messages = last != null ? await channel.GetMessagesBeforeAsync(last.Id) : await channel.GetMessagesAsync(); if (messages.Count < 100) { hasMorePages = false; } foreach (var message in messages) { last = message; yield return(message); } } while (hasMorePages); }
QueryMemberMentions(List <ulong> memberIds, DiscordChannel actionChannel, int warnThreshold, DiscordMessage originalMessage) { const int MESSAGE_COUNT = 2000; // Remember to use DTO in the current timezone and not in UTC! API is running on OUR time. DateTimeOffset startTime = DateTimeOffset.Now.AddMonths(warnThreshold * -1); // We want to set the initial messages. IReadOnlyList <DiscordMessage> messages; if (originalMessage.ChannelId != Program.Settings.ActionChannelId) { // If the original message is anywhere besides the action channel, we want to start at the most recent message. messages = await actionChannel.GetMessagesAsync(MESSAGE_COUNT); } else { // If the original message is in the action channel, we want to exclude the message that triggered this response, as to not count it. messages = await actionChannel.GetMessagesBeforeAsync(originalMessage.Id, MESSAGE_COUNT); } // We want a "stop" value, so to speak. If this is true, it means we've gone before startTime. bool exceededStartTime = false; // Every instance where this user has been mentioned. var warnInstances = new Dictionary <ulong, List <DiscordMessage> >(); // Populate the dictionary. memberIds.ForEach(a => warnInstances.Add(a, new List <DiscordMessage>())); do { if (messages.Count > 0) { foreach (var message in messages) { // For each message, we want to check its mentioned users. if (startTime.ToUnixTimeMilliseconds() <= message.CreationTimestamp.ToUnixTimeMilliseconds()) { // We only want to continue if this is after our startValue. foreach (ulong memberId in memberIds) { if (MentionedUsersContains(message, memberId)) { // Only continue if there are actually mentioned users, and if the mentioned users has the member we want. warnInstances[memberId].Add(message); } // end if } // end foreach } // end if else { // We've gone way too far back, so we need to stop this. exceededStartTime = true; break; // Break out of the foreach. NON-SESE ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! } // end else } // end foreach if (!exceededStartTime && messages.Count == MESSAGE_COUNT) { // Only repopulate if we're still within the time range AND if there are still messages to grab. My logic behind checking the // message count is that there should be 2,000 or more messages if there's still messages to be found, unless the message // count is exactly a multiple of 2,000. messages = await actionChannel.GetMessagesBeforeAsync(messages.Last().Id, MESSAGE_COUNT); // Give the bot some time to process. await Task.Delay(500); } else { // Stop the loop. exceededStartTime = false; messages = default; } // end else } // end if } while (!exceededStartTime && !(messages is null) && messages.Count > 0); // ^ Only continue if we haven't gone back far enough in history AND if we still have messages. return(warnInstances); }
public static async Task <DiscordMessage?> GetLastMessageAsync(this DiscordChannel channel) { IReadOnlyList <DiscordMessage> m = await channel.GetMessagesBeforeAsync(channel.LastMessageId, 1); return(m.FirstOrDefault()); }