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()
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]
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
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
'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
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()
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
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()