def __init__(self, name: str, bot, commands=None): """ Set's up the plugin's base resources Walks the Subclass's structure and search for any hooks to request :param bot: Monitor instance :param commands: A list of command strings to respond to if on_command is hooked """ self.name = name self.bot = bot self.depends = [] self.commands = commands methods = [m for m in dir(self) if m.startswith('on_')] for dep in methods: method = self.__getattribute__(dep) if asyncio.iscoroutinefunction(method): self.depends.append(dep) self._cache = CachedDict(self.name) self.disabled_channels = []
def __init__(self, name, bot): super().__init__(name, bot, commands=[ 'bindmeme', 'unbindmeme', 'listmemes', 'searchmemes', 'copymemes', 'linkmemes', 'unlinkmemes', ]) self._memes = CachedDict('shitposts') self.server_id = 0
class Plugin: """ Base plugin class """ def __init__(self, name: str, bot, commands=None): """ Set's up the plugin's base resources Walks the Subclass's structure and search for any hooks to request :param bot: Monitor instance :param commands: A list of command strings to respond to if on_command is hooked """ self.name = name self.bot = bot self.depends = [] self.commands = commands methods = [m for m in dir(self) if m.startswith('on_')] for dep in methods: method = self.__getattribute__(dep) if asyncio.iscoroutinefunction(method): self.depends.append(dep) self._cache = CachedDict(self.name) self.disabled_channels = [] async def on_load(self): data = await self._cache.load() if not data or not self._cache.setdefault('disabled_channels', []): self._cache['disabled_channels'] = [] self.disabled_channels = self._cache['disabled_channels'] async def cache(self): await self._cache.cache() def disable(self, channel_id): self.disabled_channels.append(channel_id) def enable(self, channel_id): self.disabled_channels.remove(channel_id) @property def enabled(self): if self.bot.current_message: chan_id = self.bot.current_message.channel.id if chan_id not in self.disabled_channels: return True return False @staticmethod def build_embed(title: str = None, description: str = None, fields: dict = None, thumbnail: str = 'https://i.imgur.com/rJYfMZk.png', level: int = 0): """ A wrapper for Discord's ritch embed system :param title: Title of embed :param description: Body of embed :param fields: A dict of title/descriptions :param thumbnail: Optional post thumbnail """ colors = { 0: 0x227C22, 1: 0x7C7C00, 2: 0xFF2B2B, } embed = discord.Embed(title=title, description=description, color=colors[level]) if thumbnail: embed.set_thumbnail(url=thumbnail) if fields: for k, v in fields.items(): embed.add_field(name=k, value=v) return embed def on_ready(self): """ on_ready discord.py hook """ pass def on_message(self, message: discord.Message): """ on_message discord.py hook """ pass def on_command(self, command, message: discord.Message): """ on_command discord.py hook """ pass def on_message_delete(self, message: discord.Message): """ on_message_delete discord.py hook """ pass def on_message_edit(self, before: discord.Message, after: discord.Message): """ on_message_edit discord.py hook """ pass def on_channel_delete(self, channel: discord.Channel): """ on_channel_delete discord.py hook """ pass def on_channel_create(self, channel: discord.Channel): """ on_channel_create discord.py hook """ pass def on_channel_update(self, before: discord.Channel, after: discord.Channel): """ on_channel_update discord.py hook """ pass def on_member_join(self, member: discord.Member): """ on_member_join discord.py hook """ pass def on_member_remove(self, member: discord.Member): """ on_member_remove discord.py hook """ pass def on_member_update(self, before: discord.Member, after: discord.Member): """ on_member_update discord.py hook """ pass def on_server_join(self, server: discord.Server): """ on_server_join discord.py hook """ pass def on_server_remove(self, server: discord.Server): """ on_server_remove discord.py hook """ pass def on_server_update(self, before: discord.Server, after: discord.Server): """ on_server_update discord.py hook """ pass def on_server_role_create(self, role: discord.Role): """ on_server_role_create discord.py hook """ pass def on_server_role_updated(self, before: discord.Role, after: discord.Role): """ on_server_role_updated discord.py hook """ pass def on_server_emojis_update(self, before: discord.Server, after: discord.Server): """ on_server_em discord.py hook """ pass def on_server_available(self, server: discord.Server): """ on_server_available discord.py hook """ pass def on_server_unavailable(self, server: discord.Server): """ on_server_unavailable discord.py hook """ pass def on_voice_state_update(self, before: discord.Member, after: discord.Member): """ on_voice_state_update discord.py hook """ pass def on_member_ban(self, member: discord.Member): """ on_member_ban discord.py hook """ pass def on_member_unban(self, server: discord.Server, user: discord.User): """ on_member_unban discord.py hook """ pass def on_typing(self, channel: discord.Channel, user: discord.User, when: datetime.datetime): """ on_typing discord.py hook """ pass def on_group_join(self, channel: discord.Channel, user: discord.User): """ on_group_join discord.py hook """ pass def on_group_remove(self, channel: discord.Channel, user: discord.User): """ on_group_remove discord.py hook """ pass def on_plugin_message(self, *args, **kwargs): """ Internal plugin message passing """ pass async def help(self, command: str): await self.bot.say("Help hasn't been added for this command yet") def __repr__(self): return self.name
def __init__(self, name, bot: Monitor): super().__init__(name, bot, commands=['slothstats']) self.rolls = CachedDict('slothrolls') self.bonus = CachedDict('slothbonus') self.rates = CachedDict('slothrates')
class SlothStats(Plugin): def __init__(self, name, bot: Monitor): super().__init__(name, bot, commands=['slothstats']) self.rolls = CachedDict('slothrolls') self.bonus = CachedDict('slothbonus') self.rates = CachedDict('slothrates') async def help(self, command: str, message): embed = self.build_embed( title='Stats for Sloths', description='A simple utility to help visualize sloth brutality.\n' 'USAGE: `{}slothstats [subcommand]`\n\n' 'Sub commands:'.format(self.bot.prefix), ) embed.add_field(name='`rolls`', value='Shows a scatter plot of all rolls and ' 'their frequency.\n\n', inline=True) embed.add_field(name='`bonus`', value='Shows the rate of MEGAWIN and TAXMAN\n\n', inline=True) embed.add_field(name='`grinder`', value='Shows the daily rate of sloth consumption\n\n', inline=True) await self.bot.send_embed(embed) async def on_load(self): await self.rolls.load() await self.bonus.load() await self.rates.load() async def on_ready(self): while True: await self.bot.send_message( content='$slothgrinder', destination=self.bot.get_channel('408915420557344768')) # Wait for a day await asyncio.sleep(24 * 60 * 60) def roll_plot(self): x_axis = list(range(1, 100)) y_axis = [] for i in x_axis: y_axis.append(self.rolls.setdefault(str(i), 0)) fig = plt.figure() ax = fig.gca() ax.set_yticks(range(max(y_axis) + 1)) plt.scatter(x_axis, y_axis) plt.title('Sloth Rolls') plt.xlabel('Results') plt.ylabel('Number of rolls') plt.grid() def bonus_plot(self): x_axis = [k for k in self.bonus] y_axis = [] for i in x_axis: y_axis.append(self.bonus[i]) fig = plt.figure() ax = fig.gca() if not y_axis: y_axis.append(0) ax.set_yticks(range(max(y_axis) + 1)) plt.bar(x_axis, y_axis) plt.title('Sloth Bonus rolls') def ground_plot(self): x_axis = sorted([k for k in self.rates]) if len(x_axis) > 30: x_axis = x_axis[-30:] y_axis = [] for i in x_axis: y_axis.append(self.rates[i]) # Calculate deltas x_axis = x_axis[1:] y_axis = [y - x for x, y in zip(y_axis[:-1], y_axis[1:])] if not x_axis or not y_axis: plt.title('Not enough carnage, please wait') return if not y_axis: y_axis.append(0) average = [] total = x_axis[0] for i, x in enumerate(y_axis): if i > 0: total -= total / 30 total += x / 30 else: total = x average.append(total) plt.plot(x_axis, average, 'r--') plt.bar(x_axis, y_axis) ax = plt.subplot() # if len(ax.xaxis.get_ticklabels()) > 10: # for label in ax.xaxis.get_ticklabels()[::len(x_axis) / 2]: # label.set_visible(False) plt.xticks(rotation=45) plt.xlabel('Days') plt.ylabel('Ground Sloths') plt.title('Oh the slothmanity!') async def on_message(self, message: discord.Message): if not message.author.id == ROBAWK_CHICKEN_ID: return if message.content.startswith('Rolled'): _, raw_result, *_ = message.content.split() raw_result = ''.join( [ch for ch in raw_result if ch in '0123456789']) try: result = int(raw_result) self.rolls.setdefault(result, 0) self.rolls[result] += 1 await self.rolls.cache() except ValueError: return if 'TAXMAN' in message.content: self.bonus.setdefault('TAXMAN', 0) self.bonus['TAXMAN'] += 1 await self.bonus.cache() if 'MEGAWIN' in message.content: self.bonus.setdefault('MEGAWIN', 0) self.bonus['MEGAWIN'] += 1 await self.bonus.cache() if 'sloths have been thrown to the grinder' in message.content: sloths, *_ = message.content.split() try: sloths = int(numeric(sloths)) self.rates[time.strftime('%Y-%m-%d')] = sloths await self.rates.cache() except ValueError: return async def send_image(self, message): image_path = gen_image() await self.bot.send_file(message.channel, image_path) os.remove(image_path) plt.clf() async def on_command(self, command, message: discord.Message): sub_command, *args = message.content.replace(command, '').split() if sub_command == 'rolls': self.roll_plot() await self.send_image(message) if sub_command == 'bonus': self.bonus_plot() await self.send_image(message) if sub_command == 'grinder': self.ground_plot() await self.send_image(message)
def __init__(self, name: str, bot): super().__init__(name, bot, commands=['rss']) self.feeds = CachedDict('rss-feeds')
class RSS(Plugin): def __init__(self, name: str, bot): super().__init__(name, bot, commands=['rss']) self.feeds = CachedDict('rss-feeds') async def help(self, command: str, message): embed = self.build_embed( title='RSS Feeds', description='Tracks RSS feeds, and gives you updates\n\n' '**Usage**: `{}rss [subcommand]`\n\n' '**Subcommands**:'.format(self.bot.prefix)) embed.add_field(name='`subscribe [Feed Link]`', value='Adds a new feed to this channel', inline=False) embed.add_field(name='`unsubscribe [Feed Link]`', value='Removes a feed from this channel', inline=False) embed.add_field(name='`list`', value='Lists registered feeds', inline=False) await self.bot.send_embed(embed) async def on_ready(self): await self.feeds.load() while True: try: await self.update_feeds() except BaseException as e: logging.error(str(e)) await asyncio.sleep(60 * 60) # Poll feeds every hour def build_message(self, feed_title, post): message = "**{}** | {}\n\n{}".format(feed_title, post['title'], post['link']) return message async def post_feed(self, channels, feed_title, post): message = self.build_message(feed_title, post) for chan_id in channels: channel = self.bot.get_channel(chan_id) await self.bot.send_message(channel, message) async def update_feed(self, items, feed): new_posts = [] first_update = bool(not feed['last']) for new in items: if new['link'] == feed['last'] or len(new_posts) >= 5: break new_posts.append(new) feed['last'] = new_posts[0]['link'] await self.feeds.cache() if first_update: return for post in new_posts[::-1]: await self.post_feed(feed['channels'], feed['title'], post) async def do_update(self, link, feed): try: raw_feed = await get(link) except: # Need to come up with a better Error Strategy raise items = get_items(raw_feed) if feed.setdefault('title', 'N/A') == 'N/A': feed['title'] = get_title(raw_feed) await self.feeds.cache() try: if not feed['last']: feed['link'] = items[0]['link'] await self.feeds.cache() if items and items[0]['link'] != feed['last']: await self.update_feed(items, feed) except IndexError: logging.info("Failed to fetch feed {}".format(link)) async def update_feeds(self): logging.info('Updating RSS Feeds') for link, feed in self.feeds.items(): if link: await self.do_update(link, feed) logging.info('RSS Update finished') async def register_feed(self, channel, feed): if feed not in self.feeds: self.feeds[feed] = { 'title': 'N/A', 'last': '', 'channels': [channel.id] } else: if channel.id not in self.feeds[feed]['channels']: self.feeds[feed]['channels'].append(channel.id) await self.feeds.cache() await self.bot.send_embed( self.build_embed(title='Success', description='Feed registered')) async def remove_feed(self, channel, feed): if feed in self.feeds: self.feeds[feed]['channels'].remove(channel.id) if not self.feeds[feed]['channels']: del self.feeds[feed] await self.feeds.cache() await self.bot.send_embed( self.build_embed( title='Success', description='Unsubscribed from feed <{}>'.format(feed))) else: await self.bot.send_embed( self.build_embed( title='Error', description='Feed (<{}>) not subscribed on this channel'. format(feed), level=2)) async def list(self, channel): embed = self.build_embed(title='Registered RSS Feeds', description='Feeds registered for #{}'.format( self.bot.current_message.channel.name)) num_feeds = 0 for link, feed in self.feeds.items(): if channel.id in feed['channels']: num_feeds += 1 embed.add_field(name='{}. {}'.format( num_feeds, feed.setdefault('title', 'N/A')), value=link, inline=False) await self.bot.send_embed(embed) async def on_channel_delete(self, channel: discord.Channel): for _, feed in self.feeds.items(): if channel.id in feed['channels']: feed['channels'].remove(channel.id) async def on_command(self, command, message: discord.Message): subcommand, *args = message.content.replace(command, '').split() if subcommand == 'subscribe': if len(args) != 1: await self.help(command, None) return await self.register_feed(message.channel, args[0]) if subcommand == 'list': if len(args) != 1: await self.list(message.channel) else: await self.list(args[0]) if subcommand == 'unsubscribe': if len(args) != 1: await self.help(command, None) await self.remove_feed(message.channel, args[0]) if int(message.author.id) == int( self.bot.settings['owner']) and subcommand == 'force-update': await self.update_feeds() await self.bot.say('Feeds updated.')
def __init__(self, name: str, bot): super().__init__(name, bot, commands=['thanos']) self.list = CachedDict('thanosdidnothingwrong')