From b42e432bcded0790a22cc8b5f4a09c569e4a648c Mon Sep 17 00:00:00 2001 From: klemek Date: Thu, 14 Jan 2021 18:44:10 +0100 Subject: [PATCH] new scanner %chan --- src/data_types/counter.py | 36 ++++++++++--- src/main.py | 9 +++- src/scanners/__init__.py | 1 + src/scanners/channels_scanner.py | 87 +++++++++++++++++++++++++++++++ src/scanners/mentioned_scanner.py | 2 +- src/scanners/mentions_scanner.py | 2 +- src/scanners/messages_scanner.py | 22 +++++--- 7 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 src/scanners/channels_scanner.py diff --git a/src/data_types/counter.py b/src/data_types/counter.py index 82bb19a..972758d 100644 --- a/src/data_types/counter.py +++ b/src/data_types/counter.py @@ -1,17 +1,19 @@ +from typing import Optional, Callable from datetime import datetime +from collections import defaultdict # Custom libs -from utils import plural, from_now, percent +from utils import plural, from_now, percent, val_sum, top_key class Counter: def __init__(self): - self.usages = 0 + self.usages = defaultdict(int) self.last_used = None - def update_use(self, count: int, date: datetime): - self.usages += count + def update_use(self, count: int, date: datetime, item: int = 0): + self.usages[item] += count if self.last_used is None or date > self.last_used: self.last_used = date @@ -20,12 +22,21 @@ class Counter: # When 2 emotes have the same score, # the days since last use is stored in the digits # (more recent first) - return self.usages + 1 / ( + return self.all_usages() + 1 / ( 100000 * ((datetime.today() - self.last_used).days + 1) ) + def all_usages(self) -> int: + return val_sum(self.usages) + def to_string( - self, i: int, name: str, *, total_usage: int, counted: str = "time" + self, + i: int, + name: str, + *, + total_usage: int, + counted: str = "time", + transform: Optional[Callable[[int], str]] = None, ) -> str: # place output = "" @@ -37,5 +48,16 @@ class Counter: output += ":third_place:" else: output += f"**#{i + 1}**" - output += f" {name} - {plural(self.usages, counted)} ({percent(self.usages/total_usage)}) (last {from_now(self.last_used)})" + sum = val_sum(self.usages) + output += f" {name} - {plural(sum, counted)} ({percent(sum/total_usage)}) (last {from_now(self.last_used)})" + top_item = top_key(self.usages) + if top_item != 0 and transform is not None: + if self.usages[top_item] == sum: + output += f" (all{transform(top_item)})" + else: + output += f" ({self.usages[top_item]}{transform(top_item)}, {percent(self.usages[top_item]/sum)})" return output + + @staticmethod + def total(d: dict) -> int: + return sum([val_sum(counter.usages) for counter in d.values()]) diff --git a/src/main.py b/src/main.py index 4616e41..44afa60 100644 --- a/src/main.py +++ b/src/main.py @@ -11,6 +11,7 @@ from scanners import ( MentionsScanner, MentionedScanner, MessagesScanner, + ChannelsScanner, ) from logs import GuildLogs @@ -52,10 +53,16 @@ bot.register_command( "emojis: rank emojis by their usage", EmotesScanner.help(), ) +bot.register_command( + "(channels?|chan)", + lambda *args: ChannelsScanner().compute(*args), + "chan: rank channels by their messages", + ChannelsScanner.help(), +) bot.register_command( "(messages?|msg)", lambda *args: MessagesScanner().compute(*args), - "msg: rank users mentions by their messages", + "msg: rank users by their messages", MessagesScanner.help(), ) bot.register_command( diff --git a/src/scanners/__init__.py b/src/scanners/__init__.py index b65f2e4..495dfaf 100644 --- a/src/scanners/__init__.py +++ b/src/scanners/__init__.py @@ -6,3 +6,4 @@ from .full_scanner import FullScanner from .mentions_scanner import MentionsScanner from .mentioned_scanner import MentionedScanner from .messages_scanner import MessagesScanner +from .channels_scanner import ChannelsScanner diff --git a/src/scanners/channels_scanner.py b/src/scanners/channels_scanner.py new file mode 100644 index 0000000..1b29542 --- /dev/null +++ b/src/scanners/channels_scanner.py @@ -0,0 +1,87 @@ +from typing import Dict, List +from collections import defaultdict +import discord + + +# Custom libs + +from logs import ChannelLogs, MessageLog +from .scanner import Scanner +from data_types import Counter +from utils import COMMON_HELP_ARGS, mention, channel_mention + + +class ChannelsScanner(Scanner): + @staticmethod + def help() -> str: + return ( + "```\n" + + "%chan: Rank channels by their messages\n" + + "arguments:\n" + + COMMON_HELP_ARGS + + "* - top , default is 10\n" + + "* all - include bots\n" + + "Example: %chan 10 @user\n" + + "```" + ) + + def __init__(self): + super().__init__( + has_digit_args=True, + valid_args=["all"], + help=ChannelsScanner.help(), + intro_context="Channels", + ) + + async def init(self, message: discord.Message, *args: str) -> bool: + # get max emotes to view + self.top = 10 + for arg in args: + if arg.isdigit(): + self.top = int(arg) + self.all_messages = "all" in args + # Create mentions dict + self.messages = defaultdict(Counter) + return True + + def compute_message(self, channel: ChannelLogs, message: MessageLog): + return ChannelsScanner.analyse_message( + channel.id, + message, + self.messages, + self.raw_members, + all_messages=self.all_messages, + ) + + def get_results(self, intro: str) -> List[str]: + names = [name for name in self.messages] + names.sort(key=lambda name: self.messages[name].score(), reverse=True) + names = names[: self.top] + usage_count = Counter.total(self.messages) + res = [intro] + res += [ + self.messages[name].to_string( + names.index(name), + channel_mention(name), + total_usage=usage_count, + counted="message", + transform=lambda id: f" by {mention(id)}", + ) + for name in names + ] + return res + + @staticmethod + def analyse_message( + channel_id: int, + message: MessageLog, + messages: Dict[str, Counter], + raw_members: List[int], + *, + all_messages: bool, + ) -> bool: + impacted = False + if not message.bot or all_messages: + impacted = True + messages[channel_id].update_use(1, message.created_at, message.author) + return impacted diff --git a/src/scanners/mentioned_scanner.py b/src/scanners/mentioned_scanner.py index fe4eed1..8cf74d4 100644 --- a/src/scanners/mentioned_scanner.py +++ b/src/scanners/mentioned_scanner.py @@ -60,7 +60,7 @@ class MentionedScanner(Scanner): names.sort(key=lambda name: self.mentions[name].score(), reverse=True) names = names[: self.top] # Get the total of all emotes used - usage_count = sum([mention.usages for mention in self.mentions.values()]) + usage_count = Counter.total(self.mentions) res = [intro] res += [ self.mentions[name].to_string( diff --git a/src/scanners/mentions_scanner.py b/src/scanners/mentions_scanner.py index 23b1298..9c701b0 100644 --- a/src/scanners/mentions_scanner.py +++ b/src/scanners/mentions_scanner.py @@ -63,7 +63,7 @@ class MentionsScanner(Scanner): names.sort(key=lambda name: self.mentions[name].score(), reverse=True) names = names[: self.top] # Get the total of all emotes used - usage_count = sum([mention.usages for mention in self.mentions.values()]) + usage_count = Counter.total(self.mentions) res = [intro] res += [ self.mentions[name].to_string( diff --git a/src/scanners/messages_scanner.py b/src/scanners/messages_scanner.py index cd0fd4e..7e05cb9 100644 --- a/src/scanners/messages_scanner.py +++ b/src/scanners/messages_scanner.py @@ -8,7 +8,7 @@ import discord from logs import ChannelLogs, MessageLog from .scanner import Scanner from data_types import Counter -from utils import COMMON_HELP_ARGS, plural, precise, mention, alt_mention +from utils import COMMON_HELP_ARGS, mention, channel_mention class MessagesScanner(Scanner): @@ -16,7 +16,7 @@ class MessagesScanner(Scanner): def help() -> str: return ( "```\n" - + "%msg: Rank users mentions by their messages\n" + + "%msg: Rank users by their messages\n" + "arguments:\n" + COMMON_HELP_ARGS + "* - top , default is 10\n" @@ -39,21 +39,25 @@ class MessagesScanner(Scanner): for arg in args: if arg.isdigit(): self.top = int(arg) - self.all_mentions = "all" in args + self.all_messages = "all" in args # Create mentions dict self.messages = defaultdict(Counter) return True def compute_message(self, channel: ChannelLogs, message: MessageLog): return MessagesScanner.analyse_message( - message, self.messages, self.raw_members, all_mentions=self.all_mentions + channel.id, + message, + self.messages, + self.raw_members, + all_messages=self.all_messages, ) def get_results(self, intro: str) -> List[str]: names = [name for name in self.messages] names.sort(key=lambda name: self.messages[name].score(), reverse=True) names = names[: self.top] - usage_count = sum([message.usages for message in self.messages.values()]) + usage_count = Counter.total(self.messages) res = [intro] res += [ self.messages[name].to_string( @@ -61,6 +65,7 @@ class MessagesScanner(Scanner): mention(name), total_usage=usage_count, counted="message", + transform=lambda id: f" in {channel_mention(id)}", ) for name in names ] @@ -68,14 +73,15 @@ class MessagesScanner(Scanner): @staticmethod def analyse_message( + channel_id: int, message: MessageLog, messages: Dict[str, Counter], raw_members: List[int], *, - all_mentions: bool, + all_messages: bool, ) -> bool: impacted = False - if not message.bot or all_mentions: + if not message.bot or all_messages: impacted = True - messages[message.author].update_use(1, message.created_at) + messages[message.author].update_use(1, message.created_at, channel_id) return impacted