Beispiel #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()
Beispiel #2
0
async def get_media(
    request: Request, bird: str, media_type: str, filters: Filter
):  # images or songs
    if bird not in birdList + screech_owls:
        raise GenericError("Invalid Bird", code=990)

    if media_type not in ("images", "songs"):
        logger.error(f"invalid media type {media_type}")
        raise HTTPException(status_code=422, detail="Invalid media type")

    # fetch scientific names of birds
    try:
        sciBird = await get_sciname(bird)
    except GenericError:
        sciBird = bird

    session_id = get_session_id(request)
    database_key = f"web.session:{session_id}"

    media = await get_files(sciBird, media_type, filters)
    logger.info(f"fetched {media_type}: {media}")
    prevJ = int(database.hget(database_key, "prevJ").decode("utf-8"))
    if media:
        j = (prevJ + 1) % len(media)
        logger.info("prevJ: " + str(prevJ))
        logger.info("j: " + str(j))

        for x in range(0, len(media)):  # check file type and size
            y = (x + j) % len(media)
            media_path = media[y]
            extension = media_path.split(".")[-1]
            logger.info("extension: " + str(extension))
            if extension.lower() in valid_types[media_type].values():
                logger.info("found one!")
                break
            if y == prevJ:
                raise GenericError(f"No Valid {media_type.title()} Found", code=999)

        database.hset(database_key, "prevJ", str(j))
    else:
        raise GenericError(f"No {media_type.title()} Found", code=100)

    return media_path, extension, content_type_lookup[extension]
Beispiel #3
0
async def send_bird(request: Request, bird: str, media_type: str, filters: Filter):
    if bird == "":
        logger.error("error - bird is blank")
        raise HTTPException(status_code=404, detail="Bird is blank")

    if media_type not in ("images", "songs"):
        logger.error(f"invalid media type {media_type}")
        raise HTTPException(status_code=422, detail="Invalid media type")

    # 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)

    try:
        filename, ext, content_type = await get_media(
            request, bird, media_type, filters
        )
    except GenericError as e:
        logger.info(e)
        capture_exception(e)
        raise HTTPException(status_code=503, detail=str(e))

    if media_type == "images":
        if filters.bw:
            loop = asyncio.get_running_loop()
            file_stream = await loop.run_in_executor(
                None, partial(_black_and_white, filename)
            )
        else:
            file_stream = filename
    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)

        file_stream = filename

    return file_stream, ext, content_type
Beispiel #4
0
async def send_bird(bird: str, media_type: str, addOn: str = "", bw: bool = False):
    if bird == "":
        logger.error("error - bird is blank")
        abort(406, "Bird is blank")
        return

    if media_type != "images" and media_type != "songs":
        logger.error(f"invalid media type {media_type}")
        abort(406, "Invalid media type")
        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)

    try:
        filename, ext = await get_media(bird, media_type, addOn)
    except GenericError as e:
        logger.info(e)
        capture_exception(e)
        abort(503, str(e))
        return

    if media_type == "images":
        if bw:
            loop = asyncio.get_running_loop()
            file_stream = await loop.run_in_executor(None, partial(_black_and_white, filename))
        else:
            file_stream = f"../{filename}"
    elif media_type == "songs":
        file_stream = f"../{filename}"

    return file_stream, ext
Beispiel #5
0
        '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."""
        logger.info("global check: checking sentry tag")
        with configure_scope() as scope:
            scope.set_tag("command", ctx.command.name)
        return True
Beispiel #6
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()
Beispiel #7
0
    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")
        database.zincrby("frequency.command:global", 1, str(ctx.command))
        return True
Beispiel #8
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()