Example #1
0
async def main():
    bot = SkyComicBot(command_prefix=commands.when_mentioned_or("$", "!"),
                      help_command=None,
                      case_insensitive=True,
                      intents=discord.Intents.all())

    now = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    utils.ensure_dir(utils.abs_join("logs"))

    logging.setLoggerClass(utils.DBLogger)
    log_handlers = [
        logging.FileHandler(utils.abs_join("logs", f"{now}.log")),
        logging.StreamHandler()
    ]
    if "logging" in bot.config and "socket_handlers" in bot.config["logging"]:
        for num, handler in enumerate(bot.config["logging"]["socket_handlers"], start=1):
            buffer = utils.abs_join("logs", f"log_buffer_{num}.bin")
            socket_handler = BufferingSocketHandler(handler["host"], handler["port"], buffer)
            socket_handler.closeOnError = True
            log_handlers.append(socket_handler)

    # noinspection PyArgumentList
    logging.basicConfig(
        level=logging.DEBUG,
        format="[%(asctime)s] [%(levelname)-9.9s]-[%(name)-15.15s]: %(message)s",
        handlers=log_handlers
    )
    logging.getLogger("tortoise").setLevel(logging.INFO)
    logging.getLogger("db_client").setLevel(logging.INFO)
    logging.getLogger("aiomysql").setLevel(logging.INFO)
    logging.getLogger("discord.client").setLevel(logging.CRITICAL)
    logging.getLogger("discord.gateway").setLevel(logging.ERROR)
    logging.getLogger("discord.http").setLevel(logging.ERROR)
    logging.getLogger("PIL").setLevel(logging.ERROR)
    logging.getLogger("cogs.automod").setLevel(logging.INFO)

    initial_extensions = ["cogs.errors", "cogs.permissions", "cogs.service", "cogs.channels",
                          "cogs.greetings", "cogs.automod", "cogs.timezones",
                          "cogs.reactions", "cogs.emotes", "cogs.roles", "cogs.games"]

    bot.load_initial_extensions(initial_extensions)

    models = ["cogs.permissions", "cogs.roles", "cogs.timezones", "cogs.channels", "cogs.automod", "cogs.greetings", ]  # "cogs.comics",
    current_models = [model for model in bot.extensions if model in models]
    try:
        await Tortoise.init(db_url=bot.config["auth"]["db_url"],
                            modules={"models": current_models})
        await Tortoise.generate_schemas()
        await bot.start()
    finally:
        await bot.logout()
        await Tortoise.close_connections()
Example #2
0
    def load_config(self, path):
        with open(utils.abs_join(path), "r") as f:
            self.config = json.load(f)

        self.owner_ids = set(self.config["discord"]["owner_ids"])
        utils.guild_ids = self.config["discord"]["guild_ids"]
        self.token = self.config["auth"]["discord_token"]
Example #3
0
    async def load_emotes(self):
        files = multi_glob(*(abs_join("emotes", f"*{ext}")
                             for ext in image_exts))

        self.emotes = {
            os.path.splitext(os.path.split(filename)[1])[0].replace(
                "_", " ").strip().lower(): filename
            for filename in files
        }

        self.emote_pick.options[0]["choices"] = [
            create_choice(name=key, value=key) for key in self.emotes.keys()
        ][:25]

        if self.emotes:
            self.generate_thumbnail_image()
            self.has_thumbnail = True
        else:
            if os.path.exists(self.emotes_thumbnail):
                os.remove(self.emotes_thumbnail)
            self.has_thumbnail = False

        logger.debug(f"Loaded emotes: {self.emotes}")
        if not self._first_ready:
            await self.bot.slash.sync_all_commands()
Example #4
0
 def __init__(self, bot):
     utils.StartupCog.__init__(self)
     utils.AutoLogCog.__init__(self, logger)
     self.bot = bot
     self.activity_file_path = utils.abs_join("last_activity")
     self._last_greeted_member = None
     self._started_at = None
     self._last_active_at = None
Example #5
0
    def __init__(self, bot):
        utils.AutoLogCog.__init__(self, logger)
        utils.StartupCog.__init__(self)

        self.bot = bot
        self.emotes = dict()

        self.emotes_thumbnail = abs_join("emotes", "tmp", "thumbnail.png")
        self.has_thumbnail = False

        utils.ensure_path_dirs(self.emotes_thumbnail)
Example #6
0
    async def emote_add(self, ctx: SlashContext, name: str,
                        attachment_link: str):
        """Adds new emote. Will replace old emote with same name."""
        await ctx.defer(hidden=False)
        logger.important(
            f"{self.format_caller(ctx)} trying to add emote '{name}' (image link - {attachment_link})"
        )

        ext = Path(urlparse(attachment_link).path).suffix
        if ext not in image_exts:
            logger.error(f"Unsupported image extension '{ext}'")
            raise commands.BadArgument(
                f"File extension ({ext}) should be one of ({', '.join(image_exts)})"
            )

        if not re.fullmatch("[A-z\\s]+", name):
            logger.error(f"Unsupported image name '{name}'")
            raise commands.BadArgument(
                "Emote name should contain only english letters, whitespaces and underscores!"
            )
        filename = f"{name.strip().replace(' ', '_')}{ext}"

        # Create directory for emotes, if it not exists, attachment.save won't do it
        utils.ensure_dir(os.path.abspath("emotes"))

        async with aiohttp.ClientSession() as session:
            async with session.get(attachment_link) as response:
                if response.ok:
                    attachment = await response.read()

        with open(abs_join("emotes", filename), 'wb') as f:
            f.write(attachment)
        logger.important(f"Saved emote '{name}' as '{filename}'")

        await self.load_emotes()
        await ctx.send(
            f"Successfully added emote **{fuzzy_search(filename, self.emotes.keys())}**."
        )
Example #7
0
    def generate_thumbnail_image(self):
        logger.debug("Constructing thumbnail mosaic image...")
        frame_width = 1920
        images_per_row = min(6, len(self.emotes))
        padding = 15
        v_padding = 100

        max_width = (frame_width -
                     (images_per_row - 1) * padding) / images_per_row

        images = {name: Image.open(path) for name, path in self.emotes.items()}
        images = {
            k: v
            for k, v in sorted(images.items(),
                               key=lambda x: (x[1].width / x[1].height, x[0]))
        }
        image_rows = [
            dict(row) for row in grouper(images_per_row, images.items())
        ]

        row_heights = []
        for row_num, row in enumerate(image_rows):
            max_height = 0
            for col_num, item in enumerate(row.items()):
                name, image = item

                scale = image.width / max_width
                new_width = ceil(image.width / scale)
                new_height = ceil(image.height / scale)

                image = image.resize((new_width, new_height), Image.ANTIALIAS)
                row[name] = image

                max_height = max(max_height, image.height)

            row_heights.append(max_height)

        total_height = sum(row_heights) + (padding +
                                           v_padding) * len(image_rows)
        canvas = Image.new('RGBA', (frame_width, total_height))
        draw = ImageDraw.Draw(canvas)
        font = ImageFont.truetype(utils.abs_join("v_ComicGeek_v1.0.ttf"),
                                  size=48)
        y = 0
        for row_num, row in enumerate(image_rows):
            for col_num, item in enumerate(row.items()):
                name, image = item
                x = (padding + max_width) * col_num
                width_diff = (max_width - image.width) / 2
                height_diff = (row_heights[row_num] - image.height) / 2

                x_p = ceil(x + width_diff)
                y_p = ceil(y + height_diff)

                canvas.paste(image, (x_p, y_p))
                # draw.rectangle([(x_p, y_p), (x_p+image.width, y_p+image.height)], outline=(255, 0, 0, 255), width=5)
                # draw.rectangle([(x, y), (x+max_width, y+row_heights[row_num])], outline=(0, 255, 0, 255), width=5)
                if Path(self.emotes[name]).suffix == ".gif":
                    name += " [GIF]"

                text = "\n".join(text_to_lines(name, max_width, draw, font))
                draw.text((ceil(x_p + max_width / 2),
                           y + row_heights[row_num] + padding),
                          text,
                          anchor="ma",
                          align="center",
                          font=font)

            y += row_heights[row_num] + padding + v_padding
        logger.info("Constructed thumbnail mosaic image")

        with open(self.emotes_thumbnail, "wb") as image_file:
            canvas.save(image_file, "PNG")

        logger.debug("Saved thumbnail mosaic image")
Example #8
0
 async def timezones(self, message):
     await send_file(message.channel, abs_join("reactions",
                                               "timezones.gif"),
                     "timezones.gif")
Example #9
0
 async def wrong_layer(self, message):
     await send_file(message.channel,
                     abs_join("reactions", "wrong_layer.gif"),
                     "wronglayersong.gif")
Example #10
0
 async def telling(self, message):
     await send_file(message.channel, abs_join("reactions", "telling.gif"),
                     "thatwouldbetelling.gif")