예제 #1
0
    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 = []
예제 #2
0
 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
예제 #3
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
예제 #4
0
 def __init__(self, name, bot: Monitor):
     super().__init__(name, bot, commands=['slothstats'])
     self.rolls = CachedDict('slothrolls')
     self.bonus = CachedDict('slothbonus')
     self.rates = CachedDict('slothrates')
예제 #5
0
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)
예제 #6
0
 def __init__(self, name: str, bot):
     super().__init__(name, bot, commands=['rss'])
     self.feeds = CachedDict('rss-feeds')
예제 #7
0
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.')
예제 #8
0
    def __init__(self, name: str, bot):
        super().__init__(name, bot, commands=['thanos'])

        self.list = CachedDict('thanosdidnothingwrong')