Example #1
0
async def send_birdsong(ctx, bird: str, on_error=None, message=None):
    """Gets a bird sound and sends it to the user.

    `ctx` - Discord context object\n
    `bird` (str) - bird picture to send\n
    `on_error` (function) - function to run when an error occurs\n
    `message` (str) - text message to send before bird picture
    """
    if bird == "":
        logger.error("error - bird is blank")
        await ctx.send(
            "**There was an error fetching birds.**\n*Please try again.*")
        if on_error is not None:
            on_error(ctx)
        return

    delete = await ctx.send("**Fetching.** This may take a while.")
    # trigger "typing" discord message
    await ctx.trigger_typing()

    try:
        response = await get_song(ctx, bird)
    except GenericError as e:
        await delete.delete()
        await ctx.send(
            f"**An error has occurred while fetching songs.**\n*Please try again.*\n**Reason:** {e}"
        )
        logger.exception(e)
        if on_error is not None:
            on_error(ctx)
        return

    filename = str(response[0])
    extension = str(response[1])

    # remove spoilers in tag metadata
    audioFile = eyed3.load(filename)
    if audioFile is not None and audioFile.tag is not None:
        audioFile.tag.remove(filename)

    statInfo = os.stat(filename)
    if statInfo.st_size > 4000000:  # another filesize check (4mb)
        await delete.delete()
        await ctx.send("**Oops! File too large :(**\n*Please try again.*")
    else:
        with open(filename, 'rb') as img:
            if message is not None:
                await ctx.send(message)
            # change filename to avoid spoilers
            await ctx.send(file=discord.File(img, filename="bird." + extension)
                           )
            await delete.delete()
Example #2
0
 async def remove_role(self, ctx, *, args):
     logger.info("command: remove role")
     logger.info(f"args: {args}")
     try:
         guild_id = int(args.split(' ')[0])
         role_id = int(args.split(' ')[1])
         guild = self.bot.get_guild(guild_id)
         role = guild.get_role(role_id)
         await guild.get_member(ctx.author.id).remove_roles(role)
         await ctx.send("Ok, done!")
     except Exception as e:
         capture_exception(e)
         logger.exception(e)
         await ctx.send(f"Error: {e}")
Example #3
0
    # Here we load our extensions(cogs) that are located in the cogs directory, each cog is a collection of commands
    core_extensions = [
        'bot.cogs.get_birds', 'bot.cogs.check', 'bot.cogs.skip',
        'bot.cogs.hint', 'bot.cogs.score', 'bot.cogs.state',
        'bot.cogs.sessions', 'bot.cogs.race', 'bot.cogs.other'
    ]
    extra_extensions = ['bot.cogs.covid']
    for extension in core_extensions + extra_extensions:
        try:
            bot.load_extension(extension)
        except (discord.errors.ClientException,
                commands.errors.ExtensionNotFound,
                commands.errors.ExtensionFailed) as e:
            if extension in core_extensions:
                logger.exception(f'Failed to load extension {extension}.', e)
                capture_exception(e)
                raise e
            else:
                logger.error(f'Failed to load extension {extension}.', e)

    if sys.platform == 'win32':
        asyncio.set_event_loop(asyncio.ProactorEventLoop())

    ######
    # Global Command Checks
    ######

    @bot.check
    def set_sentry_tag(ctx):
        """Tags sentry errors with current command."""
Example #4
0
async def send_bird(ctx,
                    bird: str,
                    media_type: str,
                    filters: Filter,
                    on_error=None,
                    message=None):
    """Gets bird media and sends it to the user.

    `ctx` - Discord context object\n
    `bird` (str) - bird to send\n
    `media_type` (str) - type of media (images/songs)\n
    `filters` (bot.filters Filter)\n
    `on_error` (function) - async function to run when an error occurs, passes error as argument\n
    `message` (str) - text message to send before bird\n
    """
    if bird == "":
        logger.error("error - bird is blank")
        await ctx.send("**There was an error fetching birds.**")
        if on_error is not None:
            await on_error(GenericError("bird is blank", code=100))
        else:
            await ctx.send("*Please try again.*")
        return

    # add special condition for screech owls
    # since screech owl is a genus and SciOly
    # doesn't specify a species
    if bird == "Screech Owl":
        logger.info("choosing specific Screech Owl")
        bird = random.choice(screech_owls)

    delete = await ctx.send("**Fetching.** This may take a while.")
    # trigger "typing" discord message
    await ctx.trigger_typing()

    try:
        filename, extension = await get_media(ctx, bird, media_type, filters)
    except GenericError as e:
        await delete.delete()
        if e.code == 100:
            await ctx.send(
                f"**This combination of filters has no valid {media_type} for the current bird.**"
            )
        else:
            await ctx.send(
                f"**An error has occurred while fetching {media_type}.**\n**Reason:** {e}"
            )
            logger.exception(e)
        if on_error is not None:
            await on_error(e)
        else:
            await ctx.send("*Please try again.*")
        return

    if os.stat(
            filename).st_size > MAX_FILESIZE:  # another filesize check (4mb)
        await delete.delete()
        await ctx.send("**Oops! File too large :(**\n*Please try again.*")
        return

    if media_type == "images":
        if filters.bw:
            # prevent the black and white conversion from blocking
            loop = asyncio.get_running_loop()
            fn = functools.partial(_black_and_white, filename)
            filename = await loop.run_in_executor(None, fn)

    elif media_type == "songs":
        # remove spoilers in tag metadata
        audioFile = eyed3.load(filename)
        if audioFile is not None and audioFile.tag is not None:
            audioFile.tag.remove(filename)

    # change filename to avoid spoilers
    file_obj = discord.File(filename, filename=f"bird.{extension}")
    if message is not None:
        await ctx.send(message)
    await ctx.send(file=file_obj)
    await delete.delete()
Example #5
0
            and len(os.environ["SCIOLY_ID_BOT_EXTRA_COGS"].strip()) > 0):
        extra_extensions = os.environ["SCIOLY_ID_BOT_EXTRA_COGS"].strip(
        ).split(",")
    else:
        extra_extensions = []

    for extension in core_extensions + extra_extensions:
        try:
            bot.load_extension(extension)
        except (
                discord.errors.ClientException,
                commands.errors.ExtensionNotFound,
                commands.errors.ExtensionFailed,
        ) as e:
            if extension in core_extensions:
                logger.exception(f"Failed to load extension {extension}.", e)
                capture_exception(e)
                raise e
            logger.error(f"Failed to load extension {extension}.", e)

    if sys.platform == "win32":
        asyncio.set_event_loop(asyncio.ProactorEventLoop())

    ######
    # Global Command Checks
    ######

    @bot.check
    def log_command_frequency(ctx):
        """Logs the command used to the database."""
        logger.info("global check: logging command frequency")
Example #6
0
async def send_bird(ctx,
                    bird: str,
                    on_error=None,
                    message=None,
                    addOn="",
                    bw=False):
    """Gets a bird picture and sends it to the user.

    `ctx` - Discord context object\n
    `bird` (str) - bird picture to send\n
    `on_error` (function)- function to run when an error occurs\n
    `message` (str) - text message to send before bird picture\n
    `addOn` (str) - string to append to search for female/juvenile birds\n
    `bw` (bool) - whether the image should be black and white (converts with `_black_and_white()`)
    """
    if bird == "":
        logger.error("error - bird is blank")
        await ctx.send(
            "**There was an error fetching birds.**\n*Please try again.*")
        if on_error is not None:
            on_error(ctx)
        return

    # add special condition for screech owls
    # since screech owl is a genus and SciOly
    # doesn't specify a species
    if bird == "Screech Owl":
        logger.info("choosing specific Screech Owl")
        bird = random.choice(screech_owls)

    delete = await ctx.send("**Fetching.** This may take a while.")
    # trigger "typing" discord message
    await ctx.trigger_typing()

    try:
        response = await get_image(ctx, bird, addOn)
    except GenericError as e:
        await delete.delete()
        await ctx.send(
            f"**An error has occurred while fetching images.**\n*Please try again.*\n**Reason:** {e}"
        )
        logger.exception(e)
        if on_error is not None:
            on_error(ctx)
        return

    filename = str(response[0])
    extension = str(response[1])
    statInfo = os.stat(filename)
    if statInfo.st_size > 4000000:  # another filesize check (4mb)
        await delete.delete()
        await ctx.send("**Oops! File too large :(**\n*Please try again.*")
    else:
        if bw:
            # prevent the black and white conversion from blocking
            loop = asyncio.get_running_loop()
            fn = partial(_black_and_white, filename)
            file_stream = await loop.run_in_executor(None, fn)
        else:
            file_stream = filename

        if message is not None:
            await ctx.send(message)

        # change filename to avoid spoilers
        file_obj = discord.File(file_stream, filename=f"bird.{extension}")
        await ctx.send(file=file_obj)
        await delete.delete()