async def get_image(ctx, bird, addOn=None): # fetch scientific names of birds try: sciBird = await get_sciname(bird) except GenericError: sciBird = bird images = await get_files(sciBird, "images", addOn) logger.info("images: " + str(images)) prevJ = int(str(database.hget(f"channel:{str(ctx.channel.id)}", "prevJ"))[2:-1]) # Randomize start (choose beginning 4/5ths in case it fails checks) if images: j = (prevJ + 1) % len(images) logger.debug("prevJ: " + str(prevJ)) logger.debug("j: " + str(j)) for x in range(j, len(images)): # check file type and size image_link = images[x] extension = image_link.split('.')[-1] logger.debug("extension: " + str(extension)) statInfo = os.stat(image_link) logger.debug("size: " + str(statInfo.st_size)) if extension.lower() in valid_image_extensions and statInfo.st_size < 8000000: # 8mb discord limit logger.info("found one!") break elif x == len(images) - 1: j = (j + 1) % (len(images)) raise GenericError("No Valid Images Found", code=999) database.hset(f"channel:{str(ctx.channel.id)}", "prevJ", str(j)) else: raise GenericError("No Images Found", code=100) return [image_link, extension]
async def skipsong(self, ctx): logger.info("command: skipsong") await channel_setup(ctx) await user_setup(ctx) database.zadd("streak:global", {str(ctx.author.id): 0}) currentSongBird = str(database.hget(f"channel:{str(ctx.channel.id)}", "sBird"))[2:-1] database.hset(f"channel:{str(ctx.channel.id)}", "sBird", "") database.hset(f"channel:{str(ctx.channel.id)}", "sAnswered", "1") if currentSongBird != "": # check if there is bird birdPage = wikipedia.page(f"{currentSongBird} (bird)") await ctx.send(f"Ok, skipping {currentSongBird.lower()}") await ctx.send(birdPage.url if not database.exists(f"race.data:{str(ctx.channel.id)}") else f"<{birdPage.url}>") # sends wiki page if database.exists(f"race.data:{str(ctx.channel.id)}") and str( database.hget(f"race.data:{str(ctx.channel.id)}", "media"))[2:-1] == "song": limit = int(database.hget(f"race.data:{str(ctx.channel.id)}", "limit")) first = database.zrevrange(f"race.scores:{str(ctx.channel.id)}", 0, 0, True)[0] if int(first[1]) >= limit: logger.info("race ending") race = self.bot.get_cog("Race") await race.stop_race_(ctx) else: logger.info("auto sending next bird song") addon, bw = map(str, database.hmget(f"race.data:{str(ctx.channel.id)}", ["addon", "bw"])) birds = self.bot.get_cog("Birds") await birds.send_bird_(ctx, addon[2:-1], bw[2:-1]) else: await ctx.send("You need to ask for a bird first!")
async def get_song(ctx, bird): # fetch scientific names of birds try: sciBird = await get_sciname(bird) except GenericError: sciBird = bird songs = await get_files(sciBird, "songs") logger.info("songs: " + str(songs)) prevK = int(str(database.hget(f"channel:{str(ctx.channel.id)}", "prevK"))[2:-1]) # Randomize start (choose beginning 4/5ths in case it fails checks) if songs: k = (prevK + 1) % len(songs) logger.debug("prevK: " + str(prevK)) logger.debug("k: " + str(k)) for x in range(k, len(songs)): # check file type and size song_link = songs[x] extension = song_link.split('.')[-1] logger.debug("extension: " + str(extension)) statInfo = os.stat(song_link) logger.debug("size: " + str(statInfo.st_size)) if extension.lower() in valid_audio_extensions and statInfo.st_size < 8000000: # 8mb discord limit logger.info("found one!") break elif x == len(songs) - 1: k = (k + 1) % (len(songs)) raise GenericError("No Valid Songs Found", code=999) database.hset(f"channel:{str(ctx.channel.id)}", "prevK", str(k)) else: raise GenericError("No Songs Found", code=100) return [song_link, extension]
async def stop_race_(self, ctx): first = database.zrevrange(f"race.scores:{str(ctx.channel.id)}", 0, 0, True)[0] if ctx.guild is not None: user = ctx.guild.get_member(int(first[0])) else: user = None if user is None: user = self.bot.get_user(int(first[0])) if user is None: user = "******" else: user = f"{user.name}#{user.discriminator}" else: user = f"{user.name}#{user.discriminator} ({str(user.mention)})" await ctx.send(f"**Congratulations, {user}!**\n" + f"You have won the race by correctly identifying `{str(int(first[1]))}` birds. " + "*Way to go!*") database.hset(f"race.data:{str(ctx.channel.id)}", "stop", round(time.time())) await self._send_stats(ctx, "**Race stopped.**") database.delete(f"race.data:{str(ctx.channel.id)}") database.delete(f"race.scores:{str(ctx.channel.id)}")
async def goatsucker(self, ctx): logger.info("command: goatsucker") await channel_setup(ctx) await user_setup(ctx) answered = int( database.hget(f"channel:{str(ctx.channel.id)}", "gsAnswered")) # check to see if previous bird was answered if answered: # if yes, give a new bird if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "total", 1) database.hset(f"channel:{str(ctx.channel.id)}", "gsAnswered", "0") currentBird = random.choice(goatsuckers) database.hset(f"channel:{str(ctx.channel.id)}", "goatsucker", str(currentBird)) logger.info("currentBird: " + str(currentBird)) await send_bird(ctx, currentBird, on_error=error_skip_goat, message=GS_MESSAGE) else: # if no, give the same bird await send_bird(ctx, str( database.hget(f"channel:{str(ctx.channel.id)}", "goatsucker"))[2:-1], on_error=error_skip_goat, message=GS_MESSAGE)
async def stop(self, ctx): logger.info("command: stop session") await channel_setup(ctx) await user_setup(ctx) if database.exists(f"session.data:{str(ctx.author.id)}"): database.hset(f"session.data:{str(ctx.author.id)}", "stop", round(time.time())) await self._send_stats(ctx) database.delete(f"session.data:{str(ctx.author.id)}") else: await ctx.send("**There is no session running.** *You can start one with `f!session start`*")
async def check(self, ctx, *, guess): logger.info("command: check") await channel_setup(ctx) await user_setup(ctx) current_fossil = str( database.hget(f"channel:{str(ctx.channel.id)}", "fossil"))[2:-1] if current_fossil == "": await ctx.send("You must ask for a fossil first!") else: # if there is a fossil, it checks answer await fossil_setup(ctx, current_fossil) database.hset(f"channel:{str(ctx.channel.id)}", "fossil", "") database.hset(f"channel:{str(ctx.channel.id)}", "answered", "1") if spellcheck(guess.split(" ")[-1], current_fossil.split(" ")[-1]): logger.info("correct") if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "correct", 1) await ctx.send("Correct! Good job!") page = wikipedia.page(current_fossil) await ctx.send(page.url) score_increment(ctx, 1) if int(database.zscore("users:global", str(ctx.author.id))) in achievements: number = str( int(database.zscore("users:global", str(ctx.author.id)))) await ctx.send( f"Wow! You have answered {number} fossils correctly!") filename = 'achievements/' + number + ".PNG" with open(filename, 'rb') as img: await ctx.send( file=discord.File(img, filename="award.png")) else: logger.info("incorrect") if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "incorrect", 1) incorrect_increment(ctx, str(current_fossil), 1) await ctx.send("Sorry, the fossil was actually " + current_fossil.lower() + ".") page = wikipedia.page(current_fossil) await ctx.send(page.url) logger.info("current_fossil: " + str(current_fossil.lower().replace("-", " "))) logger.info("guess: " + str(guess.lower().replace("-", " ")))
async def skipgoat(self, ctx): logger.info("command: skipgoat") await channel_setup(ctx) await user_setup(ctx) database.zadd("streak:global", {str(ctx.author.id): 0}) currentBird = str(database.hget(f"channel:{str(ctx.channel.id)}", "goatsucker"))[2:-1] database.hset(f"channel:{str(ctx.channel.id)}", "goatsucker", "") database.hset(f"channel:{str(ctx.channel.id)}", "gsAnswered", "1") if currentBird != "": # check if there is bird birdPage = wikipedia.page(f"{currentBird} (bird)") await ctx.send(f"Ok, skipping {currentBird.lower()}\n{birdPage.url}") # sends wiki page else: await ctx.send("You need to ask for a bird first!")
async def skip(self, ctx): logger.info("command: skip") await channel_setup(ctx) await user_setup(ctx) current_fossil = str( database.hget(f"channel:{str(ctx.channel.id)}", "fossil"))[2:-1] database.hset(f"channel:{str(ctx.channel.id)}", "fossil", "") database.hset(f"channel:{str(ctx.channel.id)}", "answered", "1") if current_fossil != "": # check if there is fossil fossil_page = wikipedia.page(current_fossil) await ctx.send( f"Ok, skipping {current_fossil.title()}\n{fossil_page.url}" ) # sends wiki page else: await ctx.send("You need to ask for a fossil first!")
async def send_song_(self, ctx): songAnswered = int( database.hget(f"channel:{str(ctx.channel.id)}", "sAnswered")) # check to see if previous bird was answered if songAnswered: # if yes, give a new bird roles = check_state_role(ctx) if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "total", 1) roles = str( database.hget(f"session.data:{ctx.author.id}", "state"))[2:-1].split(" ") if roles[0] == "": roles = [] if len(roles) is 0: logger.info("no session lists") roles = check_state_role(ctx) logger.info(f"roles: {roles}") if roles: birds = list( itertools.chain.from_iterable(states[state]["songBirds"] for state in roles)) else: birds = songBirds logger.info(f"number of birds: {len(birds)}") currentSongBird = random.choice(birds) prevS = str( database.hget(f"channel:{str(ctx.channel.id)}", "prevS"))[2:-1] while currentSongBird == prevS: currentSongBird = random.choice(birds) database.hset(f"channel:{str(ctx.channel.id)}", "prevS", str(currentSongBird)) database.hset(f"channel:{str(ctx.channel.id)}", "sBird", str(currentSongBird)) logger.info("currentSongBird: " + str(currentSongBird)) await send_birdsong(ctx, currentSongBird, on_error=error_skip_song, message=SONG_MESSAGE) database.hset(f"channel:{str(ctx.channel.id)}", "sAnswered", "0") else: await send_birdsong( ctx, str(database.hget(f"channel:{str(ctx.channel.id)}", "sBird"))[2:-1], on_error=error_skip_song, message=SONG_MESSAGE)
async def fossil(self, ctx): logger.info("command: fossil") await channel_setup(ctx) await user_setup(ctx) logger.info("fossil: " + str( database.hget(f"channel:{str(ctx.channel.id)}", "fossil"))[2:-1]) answered = int( database.hget(f"channel:{str(ctx.channel.id)}", "answered")) logger.info(f"answered: {answered}") # check to see if previous fossil was answered if answered: # if yes, give a new fossil if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "total", 1) logger.info(f"number of fossils: {len(fossils_list)}") current_fossil = random.choice(fossils_list) prevB = str( database.hget(f"channel:{str(ctx.channel.id)}", "prevB"))[2:-1] while current_fossil == prevB: current_fossil = random.choice(fossils_list) database.hset(f"channel:{str(ctx.channel.id)}", "prevB", str(current_fossil)) database.hset(f"channel:{str(ctx.channel.id)}", "fossil", str(current_fossil)) logger.info("current fossil: " + str(current_fossil)) await send_fossil(ctx, current_fossil, on_error=error_skip, message=FOSSIL_MESSAGE) database.hset(f"channel:{str(ctx.channel.id)}", "answered", "0") else: # if no, give the same fossil await send_fossil( ctx, str(database.hget(f"channel:{str(ctx.channel.id)}", "fossil"))[2:-1], on_error=error_skip, message=FOSSIL_MESSAGE)
def session_increment(ctx, item, amount): logger.info(f"incrementing {item} by {amount}") value = int(database.hget(f"session.data:{ctx.author.id}", item)) value += int(amount) database.hset(f"session.data:{ctx.author.id}", item, str(value))
async def check(self, ctx, *, arg): logger.info("command: check") await channel_setup(ctx) await user_setup(ctx) currentBird = str( database.hget(f"channel:{str(ctx.channel.id)}", "bird"))[2:-1] if currentBird == "": # no bird await ctx.send("You must ask for a bird first!") else: # if there is a bird, it checks answer logger.info("currentBird: " + str(currentBird.lower().replace("-", " "))) logger.info("args: " + str(arg.lower().replace("-", " "))) await bird_setup(ctx, currentBird) sciBird = await get_sciname(currentBird) if spellcheck(arg, currentBird) is True or spellcheck( arg, sciBird) is True: logger.info("correct") database.zincrby("streak:global", 1, str(ctx.author.id)) database.hset(f"channel:{str(ctx.channel.id)}", "bird", "") database.hset(f"channel:{str(ctx.channel.id)}", "answered", "1") if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "correct", 1) # check if streak is greater than max, if so, increases max if database.zscore("streak:global", str( ctx.author.id)) > database.zscore( "streak.max:global", str(ctx.author.id)): database.zadd( "streak.max:global", { str(ctx.author.id): database.zscore("streak:global", str( ctx.author.id)) }) await ctx.send("Correct! Good job!" if not database.exists( f"race.data:{str(ctx.channel.id)}" ) else f"**{str(ctx.author.mention)}**, you are correct!") page = wikipedia.page(f"{currentBird} (bird)") await ctx.send(page.url if not database.exists( f"race.data:{str(ctx.channel.id)}") else f"<{page.url}>") score_increment(ctx, 1) if int(database.zscore("users:global", str(ctx.author.id))) in achievement: number = str( int(database.zscore("users:global", str(ctx.author.id)))) await ctx.send( f"Wow! You have answered {number} birds correctly!") filename = 'achievements/' + number + ".PNG" with open(filename, 'rb') as img: await ctx.send( file=discord.File(img, filename="award.png")) if database.exists(f"race.data:{str(ctx.channel.id)}") and str( database.hget(f"race.data:{str(ctx.channel.id)}", "media"))[2:-1] == "image": limit = int( database.hget(f"race.data:{str(ctx.channel.id)}", "limit")) first = database.zrevrange( f"race.scores:{str(ctx.channel.id)}", 0, 0, True)[0] if int(first[1]) >= limit: logger.info("race ending") race = self.bot.get_cog("Race") await race.stop_race_(ctx) else: logger.info("auto sending next bird image") addon, bw = map( str, database.hmget(f"race.data:{str(ctx.channel.id)}", ["addon", "bw"])) birds = self.bot.get_cog("Birds") await birds.send_bird_(ctx, addon[2:-1], bw[2:-1]) else: logger.info("incorrect") database.zadd("streak:global", {str(ctx.author.id): 0}) if database.exists(f"session.data:{str(ctx.author.id)}"): logger.info("session active") session_increment(ctx, "incorrect", 1) incorrect_increment(ctx, str(currentBird), 1) if database.exists(f"race.data:{str(ctx.channel.id)}"): await ctx.send("Sorry, that wasn't the right answer.") else: database.hset(f"channel:{str(ctx.channel.id)}", "bird", "") database.hset(f"channel:{str(ctx.channel.id)}", "answered", "1") await ctx.send("Sorry, the bird was actually " + currentBird.lower() + ".") page = wikipedia.page(f"{currentBird} (bird)") await ctx.send(page.url)
async def checkgoat(self, ctx, *, arg): logger.info("command: checkgoat") await channel_setup(ctx) await user_setup(ctx) currentBird = str( database.hget(f"channel:{str(ctx.channel.id)}", "goatsucker"))[2:-1] if currentBird == "": # no bird await ctx.send("You must ask for a bird first!") else: # if there is a bird, it checks answer await bird_setup(ctx, currentBird) index = goatsuckers.index(currentBird) sciBird = sciGoat[index] database.hset(f"channel:{str(ctx.channel.id)}", "gsAnswered", "1") database.hset(f"channel:{str(ctx.channel.id)}", "goatsucker", "") if spellcheck(arg, currentBird) is True or spellcheck( arg, sciBird) is True: logger.info("correct") database.zincrby("streak:global", 1, str(ctx.author.id)) if database.zscore("streak:global", str( ctx.author.id)) > database.zscore( "streak.max:global", str(ctx.author.id)): database.zadd( "streak.max:global", { str(ctx.author.id): database.zscore("streak:global", str( ctx.author.id)) }) if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "correct", 1) await ctx.send("Correct! Good job!") page = wikipedia.page(f"{currentBird} (bird)") await ctx.send(page.url) score_increment(ctx, 1) if int(database.zscore("users:global", str(ctx.author.id))) in achievement: number = str( int(database.zscore("users:global", str(ctx.author.id)))) await ctx.send( f"Wow! You have answered {number} birds correctly!") filename = 'achievements/' + number + ".PNG" with open(filename, 'rb') as img: await ctx.send( file=discord.File(img, filename="award.png")) else: logger.info("incorrect") database.zadd("streak:global", {str(ctx.author.id): 0}) if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "incorrect", 1) incorrect_increment(ctx, str(currentBird), 1) await ctx.send("Sorry, the bird was actually " + currentBird.lower() + ".") page = wikipedia.page(f"{currentBird} (bird)") await ctx.send(page.url) logger.info("currentBird: " + str(currentBird.lower().replace("-", " "))) logger.info("args: " + str(arg.lower().replace("-", " ")))
async def send_bird_(self, ctx, add_on: str = "", bw: bool = False, order: str = ""): if add_on == "": message = BIRD_MESSAGE.format(option="n image") else: message = BIRD_MESSAGE.format(option=f" {add_on}") if order: order = order.split(" ") logger.info( "bird: " + str(database.hget(f"channel:{str(ctx.channel.id)}", "bird"))[2:-1]) answered = int( database.hget(f"channel:{str(ctx.channel.id)}", "answered")) logger.info(f"answered: {answered}") # check to see if previous bird was answered if answered: # if yes, give a new bird roles = check_state_role(ctx) if database.exists(f"session.data:{ctx.author.id}"): logger.info("session active") session_increment(ctx, "total", 1) roles = str( database.hget(f"session.data:{ctx.author.id}", "state"))[2:-1].split(" ") if roles[0] == "": roles = [] if not roles: logger.info("no session lists") roles = check_state_role(ctx) logger.info(f"addon: {add_on}; bw: {bw}; roles: {roles}") if order: birds_in_order = set( itertools.chain.from_iterable(orders[o] for o in order)) if roles: birds_in_state = set( itertools.chain.from_iterable(states[state]["birdList"] for state in roles)) birds = list(birds_in_order.intersection(birds_in_state)) else: birds = list(birds_in_order.intersection(set(birdList))) else: if roles: birds = list( set( itertools.chain.from_iterable( states[state]["birdList"] for state in roles))) else: birds = birdList if len(birds) is 0: logger.info("no birds for order/state") await ctx.send( f"**Sorry, no birds could be found for the order/state combo.**\n*Please try again*" ) return logger.info(f"number of birds: {len(birds)}") currentBird = random.choice(birds) prevB = str( database.hget(f"channel:{str(ctx.channel.id)}", "prevB"))[2:-1] while currentBird == prevB: currentBird = random.choice(birds) database.hset(f"channel:{str(ctx.channel.id)}", "prevB", str(currentBird)) database.hset(f"channel:{str(ctx.channel.id)}", "bird", str(currentBird)) logger.info("currentBird: " + str(currentBird)) await send_bird(ctx, currentBird, on_error=error_skip, message=message, addOn=add_on, bw=bw) database.hset(f"channel:{str(ctx.channel.id)}", "answered", "0") else: # if no, give the same bird await send_bird(ctx, str( database.hget(f"channel:{str(ctx.channel.id)}", "bird"))[2:-1], on_error=error_skip, message=message, addOn=add_on, bw=bw)
async def edit(self, ctx, *, args_str: str = ""): logger.info("command: view session") await channel_setup(ctx) await user_setup(ctx) if database.exists(f"session.data:{str(ctx.author.id)}"): args = args_str.split(" ") logger.info(f"args: {args}") if "bw" in args: if len(database.hget(f"session.data:{str(ctx.author.id)}", "bw")) is 0: logger.info("adding bw") database.hset(f"session.data:{str(ctx.author.id)}", "bw", "bw") else: logger.info("removing bw") database.hset(f"session.data:{str(ctx.author.id)}", "bw", "") states_args = set(states.keys()).intersection({arg.upper() for arg in args}) if states_args: toggle_states = list(states_args) current_states = str(database.hget(f"session.data:{str(ctx.author.id)}", "state"))[2:-1].split(" ") add_states = [] logger.info(f"toggle states: {toggle_states}") logger.info(f"current states: {current_states}") for state in set(toggle_states).symmetric_difference(set(current_states)): add_states.append(state) logger.info(f"adding states: {add_states}") database.hset(f"session.data:{str(ctx.author.id)}", "state", " ".join(add_states).strip()) order_args = set(orders["orders"]).intersection({arg.lower() for arg in args}) if order_args: toggle_order = list(order_args) current_orders = str(database.hget(f"session.data:{str(ctx.author.id)}", "order"))[2:-1].split(" ") add_orders = [] logger.info(f"toggle orders: {toggle_order}") logger.info(f"current orders: {current_orders}") for o in set(toggle_order).symmetric_difference(set(current_orders)): add_orders.append(o) logger.info(f"adding orders: {add_orders}") database.hset(f"session.data:{str(ctx.author.id)}", "order", " ".join(add_orders).strip()) female = "female" in args or "f" in args juvenile = "juvenile" in args or "j" in args if female and juvenile: await ctx.send("**Juvenile females are not yet supported.**\n*Please try again*") return elif female: addon = "female" if len(database.hget(f"session.data:{str(ctx.author.id)}", "addon")) is 0: logger.info("adding female") database.hset(f"session.data:{str(ctx.author.id)}", "addon", addon) else: logger.info("removing female") database.hset(f"session.data:{str(ctx.author.id)}", "addon", "") elif juvenile: addon = "juvenile" if len(database.hget(f"session.data:{str(ctx.author.id)}", "addon")) is 0: logger.info("adding juvenile") database.hset(f"session.data:{str(ctx.author.id)}", "addon", addon) else: logger.info("removing juvenile") database.hset(f"session.data:{str(ctx.author.id)}", "addon", "") await self._send_stats(ctx, f"**Session started previously.**\n") else: await ctx.send("**There is no session running.** *You can start one with `b!session start`*")
def error_skip(ctx): logger.info("ok") database.hset(f"channel:{str(ctx.channel.id)}", "bird", "") database.hset(f"channel:{str(ctx.channel.id)}", "answered", "1")
def error_skip_song(ctx): logger.info("ok") database.hset(f"channel:{str(ctx.channel.id)}", "sBird", "") database.hset(f"channel:{str(ctx.channel.id)}", "sAnswered", "1")
def error_skip_goat(ctx): logger.info("ok") database.hset(f"channel:{str(ctx.channel.id)}", "goatsucker", "") database.hset(f"channel:{str(ctx.channel.id)}", "gsAnswered", "1")