Exemple #1
0
        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));
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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}");
        }
Exemple #5
0
        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());
        }
Exemple #6
0
        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);
        }
Exemple #7
0
            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());
        }
Exemple #10
0
        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);
        }
Exemple #12
0
        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);
        }
Exemple #13
0
        public static async Task <DiscordMessage?> GetLastMessageAsync(this DiscordChannel channel)
        {
            IReadOnlyList <DiscordMessage> m = await channel.GetMessagesBeforeAsync(channel.LastMessageId, 1);

            return(m.FirstOrDefault());
        }