async def send_bird(ctx, bird, on_error=None, message=None, addOn="", bw=False): 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:** {str(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 > 8000000: # another filesize check await delete.delete() await ctx.send("**Oops! File too large :(**\n*Please try again.*") else: if bw: 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()
async def send_birdsong(ctx, bird, on_error=None, message=None): 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:** {str(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 > 8000000: # another filesize check 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 send_fossil(ctx, fossil, on_error=None, message=None): if fossil == "": logger.error("error - fossil is blank") await ctx.send( "**There was an error fetching fossils.**\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_image(ctx, fossil) except GenericError as e: logger.exception(e) await delete.delete() await ctx.send( f"**An error has occurred while fetching images.**\n*Please try again.*\n**Reason:** {str(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 > 8000000: # another filesize check await delete.delete() await ctx.send("**Oops! File too large :(**\n*Please try again.*") else: if message is not None: await ctx.send(message) # change filename to avoid spoilers file_obj = discord.File(filename, filename=f"fossil.{extension}") await ctx.send(file=file_obj) await delete.delete()
async def on_command_error(ctx, error): logger.exception(error) # don't handle errors with local handlers if hasattr(ctx.command, 'on_error'): return if isinstance(error, commands.CommandOnCooldown): # send cooldown await ctx.send("**Cooldown.** Try again after " + str(round(error.retry_after)) + " s.", delete_after=5.0) elif isinstance(error, commands.CommandNotFound): await ctx.send("Sorry, the command was not found.") elif isinstance(error, commands.MissingRequiredArgument): await ctx.send("This command requires an argument!") elif isinstance(error, commands.BadArgument): logger.error("bad argument") await ctx.send("The argument passed was invalid. Please try again.") elif isinstance(error, commands.ArgumentParsingError): logger.error("quote error") await ctx.send("An invalid character was detected. Please try again.") elif isinstance(error, commands.TooManyArguments): logger.error("too many args") await ctx.send("Too many arguments were provided. Please try again.") elif isinstance(error, commands.BotMissingPermissions): logger.error("missing permissions error") await ctx.send( f"""**The bot does not have enough permissions to fully function.** **Permissions Missing:** `{', '.join(map(str, error.missing_perms))}` *Please try again once the correct permissions are set.*""" ) elif isinstance(error, commands.NoPrivateMessage): await ctx.send("**This command is unavaliable in DMs!**") elif isinstance(error, commands.CommandInvokeError): if isinstance(error.original, redis.exceptions.ResponseError): if database.exists(f"channel:{str(ctx.channel.id)}"): await ctx.send( """**An unexpected ResponseError has occurred.** *Please log this message in #support in the support server below, or try again.* **Error:** """ + str(error) ) await ctx.send("https://discord.gg/husFeGG") else: await channel_setup(ctx) await ctx.send("Please run that command again.") elif isinstance(error.original, wikipedia.exceptions.DisambiguationError): await ctx.send("Wikipedia page not found. (Disambiguation Error)") elif isinstance(error.original, wikipedia.exceptions.PageError): await ctx.send("Wikipedia page not found. (Page Error)") elif isinstance(error.original, wikipedia.exceptions.WikipediaException): await ctx.send("Wikipedia page unavaliable. Try again later.") elif isinstance(error.original, aiohttp.ClientOSError): if error.original.errno != errno.ECONNRESET: await ctx.send( """**An unexpected ClientOSError has occurred.** *Please log this message in #support in the support server below, or try again.* **Error:** """ + str(error) ) await ctx.send("https://discord.gg/husFeGG") else: await ctx.send("**An error has occured with discord. :(**\n*Please try again.*") else: logger.exception(error) await ctx.send( """**An uncaught command error has occurred.** *Please log this message in #support in the support server below, or try again.* **Error:** """ + str(error) ) await ctx.send("https://discord.gg/husFeGG") raise error else: logger.error("uncaught non-command") await ctx.send( """**An uncaught non-command error has occurred.** *Please log this message in #support in the support server below, or try again.* **Error:** """ + str(error) ) await ctx.send("https://discord.gg/husFeGG") raise error
@bot.event async def on_ready(): print("Ready!") logger.info("Logged in as:") logger.info(bot.user.name) logger.info(bot.user.id) # Change discord activity await bot.change_presence(activity=discord.Activity(type=3, name="f!help")) #refresh_cache.start() for extension in ('cogs.get_fossils', 'cogs.check', 'cogs.skip', 'cogs.hint', 'cogs.score', 'cogs.sessions', 'cogs.other'): try: bot.load_extension(extension) except (discord.ClientException, ModuleNotFoundError): logger.exception(f'Failed to load extension {extension}.') if sys.platform == 'win32': asyncio.set_event_loop(asyncio.ProactorEventLoop()) ###### # Global Command Checks ###### # Global check for dms - remove cooldowns @bot.check async def dm_cooldown(ctx): if ctx.command.is_on_cooldown(ctx) and ctx.guild is None: ctx.command.reset_cooldown(ctx) return True # Global check for correct permissions