Esempio n. 1
0
    async def goatsucker(self, ctx):
        logger.info("command: goatsucker")

        await channel_setup(ctx)
        await user_setup(ctx)

        answered = int(database.hget(f"channel:{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:{ctx.channel.id}", "gsAnswered", "0")
            currentBird = random.choice(goatsuckers)
            database.hset(f"channel:{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,
                            database.hget(f"channel:{ctx.channel.id}",
                                          "goatsucker").decode("utf-8"),
                            on_error=error_skip_goat,
                            message=GS_MESSAGE)
Esempio n. 2
0
def verify_session(session_id) -> Union[int, bool]:
    session_id = str(session_id)
    logger.info(f"verifying session id: {session_id}")
    if not database.exists(f"web.session:{session_id}"):
        logger.info("doesn't exist")
        return False
    if int(database.hget(f"web.session:{session_id}", "user_id")) == 0:
        logger.info("exists, no user id")
        return True
    logger.info("exists with user id")
    return int(database.hget(f"web.session:{session_id}", "user_id"))
Esempio n. 3
0
    async def song(self, ctx):
        logger.info("command: song")

        await channel_setup(ctx)
        await user_setup(ctx)

        logger.info("bird: " + database.hget(f"channel:{ctx.channel.id}",
                                             "sBird").decode("utf-8"))
        logger.info(
            "answered: " +
            str(int(database.hget(f"channel:{ctx.channel.id}", "sAnswered"))))

        await self.send_song_(ctx)
Esempio n. 4
0
    async def send_song_(self, ctx):
        songAnswered = int(
            database.hget(f"channel:{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 = database.hget(f"session.data:{ctx.author.id}",
                                      "state").decode("utf-8").split(" ")
                if roles[0] == "":
                    roles = []
                if not roles:
                    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 = database.hget(f"channel:{ctx.channel.id}",
                                  "prevS").decode("utf-8")
            while currentSongBird == prevS and len(birds) > 1:
                currentSongBird = random.choice(birds)
            database.hset(f"channel:{ctx.channel.id}", "prevS",
                          str(currentSongBird))
            database.hset(f"channel:{ctx.channel.id}", "sBird",
                          str(currentSongBird))
            logger.info("currentSongBird: " + str(currentSongBird))
            database.hset(f"channel:{ctx.channel.id}", "sAnswered", "0")
            await send_birdsong(ctx,
                                currentSongBird,
                                on_error=error_skip_song,
                                message=SONG_MESSAGE)
        else:
            await send_birdsong(ctx,
                                database.hget(f"channel:{ctx.channel.id}",
                                              "sBird").decode("utf-8"),
                                on_error=error_skip_song,
                                message=SONG_MESSAGE)
Esempio n. 5
0
async def update_web_user(request: Request, user_data: dict):
    logger.info("updating user data")
    session_id = get_session_id(request)
    user_id = str(user_data["id"])
    database.hset(f"web.session:{session_id}", "user_id", user_id)
    database.expire(f"web.session:{session_id}", DATABASE_SESSION_USER_EXPIRE)
    database.hset(
        f"web.user:{user_id}",
        mapping={
            "avatar_hash": str(user_data["avatar"]),
            "avatar_url": f"https://cdn.discordapp.com/avatars/{user_id}/{user_data['avatar']}.png",
            "username": str(user_data["username"]),
            "discriminator": str(user_data["discriminator"]),
        },
    )
    await user_setup(user_id)
    tempScore = int(database.hget(f"web.session:{session_id}", "tempScore"))
    if tempScore not in (0, -1):
        score_increment(user_id, tempScore)
        database.zincrby(
            f"daily.webscore:{str(datetime.datetime.now(datetime.timezone.utc).date())}",
            1,
            user_id,
        )
        database.hset(f"web.session:{session_id}", "tempScore", -1)
    logger.info("updated user data")
Esempio n. 6
0
    async def _send_stats(self, ctx, preamble):
        placings = 5
        database_key = f"race.scores:{ctx.channel.id}"
        if database.zcard(database_key) == 0:
            logger.info(f"no users in {database_key}")
            await ctx.send("There are no users in the database.")
            return

        if placings > database.zcard(database_key):
            placings = database.zcard(database_key)

        leaderboard_list = database.zrevrangebyscore(
            database_key, "+inf", "-inf", 0, placings, True
        )
        embed = discord.Embed(
            type="rich", colour=discord.Color.blurple(), title=preamble
        )
        embed.set_author(name="Bird ID - An Ornithology Bot")
        leaderboard = ""

        for i, stats in enumerate(leaderboard_list):
            if ctx.guild is not None:
                user = await fetch_get_user(int(stats[0]), ctx=ctx, member=True)
            else:
                user = None

            if user is None:
                user = await fetch_get_user(int(stats[0]), ctx=ctx, member=False)
                if user is None:
                    user_info = "**Deleted**"
                else:
                    user_info = f"**{esc(user.name)}#{user.discriminator}**"
            else:
                user_info = f"**{esc(user.name)}#{user.discriminator}** ({user.mention})"

            leaderboard += f"{i+1}. {user_info} - {int(stats[1])}\n"

        start = int(database.hget(f"race.data:{ctx.channel.id}", "start"))
        elapsed = str(datetime.timedelta(seconds=round(time.time()) - start))

        embed.add_field(
            name="Options", value=await self._get_options(ctx), inline=False
        )
        embed.add_field(
            name="Stats", value=f"**Race Duration:** `{elapsed}`", inline=False
        )
        embed.add_field(name="Leaderboard", value=leaderboard, inline=False)

        if ctx.author:
            if database.zscore(database_key, str(ctx.author.id)) is not None:
                placement = int(database.zrevrank(database_key, str(ctx.author.id))) + 1
                embed.add_field(
                    name="You:", value=f"You are #{placement}.", inline=False
                )
            else:
                embed.add_field(
                    name="You:", value="You haven't answered any correctly."
                )

        await ctx.send(embed=embed)
Esempio n. 7
0
    async def skip(self, ctx):
        logger.info("command: skip")

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "bird").decode("utf-8")
        database.hset(f"channel:{ctx.channel.id}", "bird", "")
        database.hset(f"channel:{ctx.channel.id}", "answered", "1")
        if currentBird != "":  # check if there is bird
            url = get_wiki_url(ctx, currentBird)
            await ctx.send(f"Ok, skipping {currentBird.lower()}")
            await ctx.send(url)  # sends wiki page

            streak_increment(ctx, None)  # reset streak

            if database.exists(f"race.data:{ctx.channel.id}"):
                if Filter.from_int(
                        int(
                            database.hget(f"race.data:{ctx.channel.id}",
                                          "filter"))).vc:
                    await voice_functions.stop(ctx, silent=True)

                media = database.hget(f"race.data:{ctx.channel.id}",
                                      "media").decode("utf-8")

                limit = int(
                    database.hget(f"race.data:{ctx.channel.id}", "limit"))
                first = database.zrevrange(f"race.scores:{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(f"auto sending next bird {media}")
                    filter_int, taxon, state = database.hmget(
                        f"race.data:{ctx.channel.id}",
                        ["filter", "taxon", "state"])
                    birds = self.bot.get_cog("Birds")
                    await birds.send_bird_(
                        ctx,
                        media,
                        Filter.from_int(int(filter_int)),
                        taxon.decode("utf-8"),
                        state.decode("utf-8"),
                    )
        else:
            await ctx.send("You need to ask for a bird first!")
Esempio n. 8
0
    async def hint(self, ctx):
        logger.info("command: hint")

        currentBird = database.hget(f"channel:{ctx.channel.id}", "bird").decode("utf-8")
        if currentBird != "":  # check if there is bird
            await ctx.send(f"The first letter is {currentBird[0]}")
        else:
            await ctx.send("You need to ask for a bird first!")
Esempio n. 9
0
    async def song(self, ctx, *, args_str: str = ""):
        logger.info("command: song")

        filters, taxon, state = await self.parse(ctx, args_str)
        media = "songs"
        if database.exists(f"race.data:{ctx.channel.id}"):
            media = database.hget(f"race.data:{ctx.channel.id}",
                                  "media").decode("utf-8")
        await self.send_bird_(ctx, media, filters, taxon, state)
Esempio n. 10
0
    async def skip(self, ctx):
        logger.info("command: skip")

        await channel_setup(ctx)
        await user_setup(ctx)

        currentBird = str(database.hget(f"channel:{ctx.channel.id}",
                                        "bird"))[2:-1]
        database.hset(f"channel:{ctx.channel.id}", "bird", "")
        database.hset(f"channel:{ctx.channel.id}", "answered", "1")
        if currentBird != "":  # check if there is bird
            url = get_wiki_url(currentBird)
            await ctx.send(f"Ok, skipping {currentBird.lower()}")
            await ctx.send(
                url if not database.exists(f"race.data:{ctx.channel.id}") else
                f"<{url}>")  # sends wiki page
            database.zadd("streak:global",
                          {str(ctx.author.id): 0})  # end streak
            if database.exists(
                    f"race.data:{ctx.channel.id}") and database.hget(
                        f"race.data:{ctx.channel.id}",
                        "media").decode("utf-8") == "image":

                limit = int(
                    database.hget(f"race.data:{ctx.channel.id}", "limit"))
                first = database.zrevrange(f"race.scores:{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, taxon = database.hmget(
                        f"race.data:{ctx.channel.id}",
                        ["addon", "bw", "taxon"])
                    birds = self.bot.get_cog("Birds")
                    await birds.send_bird_(ctx, addon.decode("utf-8"),
                                           bw.decode("utf-8"),
                                           taxon.decode("utf-8"))
        else:
            await ctx.send("You need to ask for a bird first!")
Esempio n. 11
0
    async def _send_next_race_media(self, ctx):
        if database.exists(f"race.data:{ctx.channel.id}"):
            if Filter.from_int(
                    int(database.hget(f"race.data:{ctx.channel.id}",
                                      "filter"))).vc:
                await voice_functions.stop(ctx, silent=True)

            media = database.hget(f"race.data:{ctx.channel.id}",
                                  "media").decode("utf-8")

            logger.info(f"auto sending next bird {media}")
            filter_int, taxon, state = database.hmget(
                f"race.data:{ctx.channel.id}", ["filter", "taxon", "state"])

            await self.send_bird_(
                ctx,
                media,
                Filter.from_int(int(filter_int)),
                taxon.decode("utf-8"),
                state.decode("utf-8"),
            )
Esempio n. 12
0
def session_increment(ctx, item: str, amount: int):
    """Increments the value of a database hash field by `amount`.

    `ctx` - Discord context object\n
    `item` - hash field to increment (see data.py for details,
    possible values include correct, incorrect, total)\n
    `amount` (int) - amount to increment by, usually 1
    """
    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))
Esempio n. 13
0
    async def goatsucker(self, ctx):
        logger.info("command: goatsucker")

        if database.exists(f"race.data:{ctx.channel.id}"):
            await ctx.send("This command is disabled during races.")
            return

        answered = int(database.hget(f"channel:{ctx.channel.id}", "answered"))
        # check to see if previous bird was answered
        if answered:  # if yes, give a new bird
            session_increment(ctx, "total", 1)

            database.hset(f"channel:{ctx.channel.id}", "answered", "0")
            currentBird = random.choice(goatsuckers)
            self.increment_bird_frequency(ctx, currentBird)

            database.hset(f"channel:{ctx.channel.id}", "bird",
                          str(currentBird))
            logger.info("currentBird: " + str(currentBird))
            await send_bird(
                ctx,
                currentBird,
                "images",
                Filter(),
                on_error=self.error_skip(ctx),
                message=GS_MESSAGE,
            )
        else:  # if no, give the same bird
            await send_bird(
                ctx,
                database.hget(f"channel:{ctx.channel.id}",
                              "bird").decode("utf-8"),
                "images",
                Filter(),
                on_error=self.error_skip(ctx),
                message=GS_MESSAGE,
            )
Esempio n. 14
0
async def get_media(ctx, bird: str, media_type: str, filters: Filter):
    """Chooses media from a list of filenames.

    This function chooses a valid image to pass to send_bird().
    Valid images are based on file extension and size. (8mb discord limit)

    Returns a list containing the file path and extension type.

    `ctx` - Discord context object\n
    `bird` (str) - bird to get media of\n
    `media_type` (str) - type of media (images/songs)\n
    `filters` (bot.filters Filter)\n
    """

    # fetch scientific names of birds
    try:
        sciBird = await get_sciname(bird)
    except GenericError:
        sciBird = bird
    media = await get_files(sciBird, media_type, filters)
    logger.info("media: " + str(media))
    prevJ = int(database.hget(f"channel:{ctx.channel.id}", "prevJ"))
    # Randomize start (choose beginning 4/5ths in case it fails checks)
    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)
            path = media[y]
            extension = path.split(".")[-1]
            logger.info("extension: " + str(extension))
            statInfo = os.stat(path)
            logger.info("size: " + str(statInfo.st_size))
            if (extension.lower() in valid_types[media_type].values()
                    and statInfo.st_size <
                    MAX_FILESIZE):  # keep files less than 4mb
                logger.info("found one!")
                break
            raise GenericError(f"No Valid {media_type.title()} Found",
                               code=999)

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

    return [path, extension]
Esempio n. 15
0
async def get_image(ctx, bird, addOn=None):
    """Chooses an image from a list of images.

    This function chooses a valid image to pass to send_bird().
    Valid images are based on file extension and size. (8mb discord limit)

    Returns a list containing the file path and extension type.

    `ctx` - Discord context object\n
    `bird` (str) - bird to get image of\n
    `addOn` (str) - string to append to search for female/juvenile birds\n
    """

    # 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:{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.info("prevJ: " + str(prevJ))
        logger.info("j: " + str(j))

        for x in range(0, len(images)):  # check file type and size
            y = (x + j) % len(images)
            image_link = images[y]
            extension = image_link.split('.')[-1]
            logger.info("extension: " + str(extension))
            statInfo = os.stat(image_link)
            logger.info("size: " + str(statInfo.st_size))
            if extension.lower(
            ) in valid_image_extensions and statInfo.st_size < 4000000:  # keep files less than 4mb
                logger.info("found one!")
                break
            elif y == prevJ:
                raise GenericError("No Valid Images Found", code=999)

        database.hset(f"channel:{ctx.channel.id}", "prevJ", str(j))
    else:
        raise GenericError("No Images Found", code=100)

    return [image_link, extension]
Esempio n. 16
0
    async def skipgoat(self, ctx):
        logger.info("command: skipgoat")

        await channel_setup(ctx)
        await user_setup(ctx)

        currentBird = str(
            database.hget(f"channel:{ctx.channel.id}", "goatsucker"))[2:-1]
        database.hset(f"channel:{ctx.channel.id}", "goatsucker", "")
        database.hset(f"channel:{ctx.channel.id}", "gsAnswered", "1")
        if currentBird != "":  # check if there is bird
            url = get_wiki_url(currentBird)
            await ctx.send(f"Ok, skipping {currentBird.lower()}")
            await ctx.send(url)  # sends wiki page
            database.zadd("streak:global", {str(ctx.author.id): 0})
        else:
            await ctx.send("You need to ask for a bird first!")
Esempio n. 17
0
async def get_song(ctx, bird):
    """Chooses a song from a list of songs.

    This function chooses a valid song to pass to send_birdsong().
    Valid songs are based on file extension and size. (8mb discord limit)

    Returns a list containing the file path and extension type.

    `ctx` - Discord context object\n
    `bird` (str) - bird to get song of
    """

    # 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:{ctx.channel.id}", "prevK"))[2:-1])
    if songs:
        k = (prevK + 1) % len(songs)
        logger.info("prevK: " + str(prevK))
        logger.info("k: " + str(k))

        for x in range(0, len(songs)):  # check file type and size
            y = (x + k) % len(songs)
            song_link = songs[y]
            extension = song_link.split('.')[-1]
            logger.info("extension: " + str(extension))
            statInfo = os.stat(song_link)
            logger.info("size: " + str(statInfo.st_size))
            if extension.lower(
            ) in valid_audio_extensions and statInfo.st_size < 4000000:  # keep files less than 4mb
                logger.info("found one!")
                break
            elif y == prevK:
                raise GenericError("No Valid Songs Found", code=999)

        database.hset(f"channel:{ctx.channel.id}", "prevK", str(k))
    else:
        raise GenericError("No Songs Found", code=100)

    return [song_link, extension]
Esempio n. 18
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]
Esempio n. 19
0
def session_increment(ctx, item: str, amount: int):
    """Increments the value of a database hash field by `amount`.

    `ctx` - Discord context object or user id\n
    `item` - hash field to increment (see data.py for details,
    possible values include correct, incorrect, total)\n
    `amount` (int) - amount to increment by, usually 1
    """
    if isinstance(ctx, (str, int)):
        user_id = ctx
    else:
        user_id = ctx.author.id

    if database.exists(f"session.data:{user_id}"):
        logger.info("session active")
        logger.info(f"incrementing {item} by {amount}")
        value = int(database.hget(f"session.data:{user_id}", item))
        value += int(amount)
        database.hset(f"session.data:{user_id}", item, str(value))
    else:
        logger.info("session not active")
Esempio n. 20
0
async def get_media(bird, media_type, filters):  # images or songs
    if bird not in birdList + screech_owls:
        raise GenericError("Invalid Bird", code=990)

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

    session_id = get_session_id()
    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 (media_type == "images" and extension.lower() in valid_types["images"].values()) or \
                    (media_type == "songs" and extension.lower() in valid_types["songs"].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
Esempio n. 21
0
def update_web_user(user_data):
    logger.info("updating user data")
    session_id = get_session_id()
    user_id = str(user_data["id"])
    database.hset(f"web.session:{session_id}", "user_id", user_id)
    database.expire(f"web.session:{session_id}", DATABASE_SESSION_EXPIRE)
    database.hset(
        f"web.user:{user_id}",
        mapping={
            "avatar_hash": str(user_data["avatar"]),
            "avatar_url":
            f"https://cdn.discordapp.com/avatars/{user_id}/{user_data['avatar']}.png",
            "username": str(user_data["username"]),
            "discriminator": str(user_data["discriminator"]),
        },
    )
    asyncio.run(user_setup(user_id))
    tempScore = int(database.hget(f"web.session:{session_id}", "tempScore"))
    if tempScore not in (0, -1):
        database.zincrby("users:global", tempScore, int(user_id))
        database.hset(f"web.session:{session_id}", "tempScore", -1)
    logger.info("updated user data")
Esempio n. 22
0
    async def stop_race_(self, ctx):
        if Filter.from_int(
                int(database.hget(f"race.data:{ctx.channel.id}",
                                  "filter"))).vc:
            await voice_functions.disconnect(ctx, silent=True)
            database.delete(f"voice.server:{ctx.guild.id}")

        first = database.zrevrange(f"race.scores:{ctx.channel.id}", 0, 0,
                                   True)[0]
        if ctx.guild is not None:
            user = await fetch_get_user(int(first[0]), ctx=ctx, member=True)
        else:
            user = None

        if user is None:
            user = await fetch_get_user(int(first[0]), ctx=ctx, member=False)
            if user is None:
                user_info = "Deleted"
            else:
                user_info = f"{esc(user.name)}#{user.discriminator}"
        else:
            user_info = f"{esc(user.name)}#{user.discriminator} ({user.mention})"

        await ctx.send(
            f"**Congratulations, {user_info}!**\n" +
            f"You have won the race by correctly identifying `{int(first[1])}` birds. "
            + "*Way to go!*")

        database.hset(f"race.data:{ctx.channel.id}", "stop",
                      round(time.time()))

        await self._send_stats(ctx, "**Race stopped.**")
        database.delete(f"race.data:{ctx.channel.id}")
        database.delete(f"race.scores:{ctx.channel.id}")

        logger.info("race end: skipping last bird")
        database.hset(f"channel:{ctx.channel.id}", "bird", "")
        database.hset(f"channel:{ctx.channel.id}", "answered", "1")
Esempio n. 23
0
    async def start(self, ctx, *, args_str: str = ""):
        logger.info("command: start race")

        if not str(ctx.channel.name).startswith("racing"):
            logger.info("not race channel")
            await ctx.send(
                "**Sorry, racing is not available in this channel.**\n"
                + "*Set the channel name to start with `racing` to enable it.*"
            )
            return

        if database.exists(f"race.data:{ctx.channel.id}"):
            logger.info("already race")
            await ctx.send(
                "**There is already a race in session.** *Change settings/view stats with `b!race view`*"
            )
            return

        filters = Filter.parse(args_str, use_numbers=False)
        if filters.vc:
            if database.get(f"voice.server:{ctx.guild.id}") is not None:
                logger.info("already vc race")
                await ctx.send(
                    "**There is already a VC race in session in this server!**"
                )
                return
            client = await voice_functions.get_voice_client(ctx, connect=True)
            if client is None:
                return
            database.set(f"voice.server:{ctx.guild.id}", str(ctx.channel.id))

        args = args_str.split(" ")
        logger.info(f"args: {args}")

        taxon_args = set(taxons.keys()).intersection({arg.lower() for arg in args})
        if taxon_args:
            taxon = " ".join(taxon_args).strip()
        else:
            taxon = ""

        if "strict" in args:
            strict = "strict"
        else:
            strict = ""

        if "alpha" in args:
            alpha = "alpha"
        else:
            alpha = ""

        states_args = set(states.keys()).intersection({arg.upper() for arg in args})
        if states_args:
            if {"CUSTOM"}.issubset(states_args):
                if database.exists(
                    f"custom.list:{ctx.author.id}"
                ) and not database.exists(f"custom.confirm:{ctx.author.id}"):
                    states_args.discard("CUSTOM")
                    states_args.add(f"CUSTOM:{ctx.author.id}")
                else:
                    states_args.discard("CUSTOM")
                    await ctx.send(
                        "**You don't have a custom list set.**\n*Ignoring the argument.*"
                    )
            state = " ".join(states_args).strip()
        else:
            state = ""

        song = "song" in args or "songs" in args or "s" in args or filters.vc
        image = (
            "image" in args
            or "images" in args
            or "i" in args
            or "picture" in args
            or "pictures" in args
            or "p" in args
        )
        if song and image:
            await ctx.send(
                "**Songs and images are not yet supported.**\n*Please try again*"
            )
            return
        if song:
            media = "song"
        elif image:
            media = "image"
        else:
            media = "image"

        ints = []
        for n in args:
            try:
                ints.append(int(n))
            except ValueError:
                continue
        if ints:
            limit = int(ints[0])
        else:
            limit = 10

        if limit > 1000000:
            await ctx.send("**Sorry, the maximum amount to win is 1 million.**")
            limit = 1000000

        logger.info(
            f"adding filters: {filters}; state: {state}; media: {media}; limit: {limit}"
        )

        database.hset(
            f"race.data:{ctx.channel.id}",
            mapping={
                "start": round(time.time()),
                "stop": 0,
                "limit": limit,
                "filter": str(filters.to_int()),
                "state": state,
                "media": media,
                "taxon": taxon,
                "strict": strict,
                "alpha": alpha,
            },
        )

        database.zadd(f"race.scores:{ctx.channel.id}", {str(ctx.author.id): 0})
        await ctx.send(
            f"**Race started with options:**\n{await self._get_options(ctx)}"
        )

        media = database.hget(f"race.data:{ctx.channel.id}", "media").decode("utf-8")
        logger.info("clearing previous bird")
        database.hset(f"channel:{ctx.channel.id}", "bird", "")
        database.hset(f"channel:{ctx.channel.id}", "answered", "1")

        logger.info(f"auto sending next bird {media}")
        filter_int, taxon, state = database.hmget(
            f"race.data:{ctx.channel.id}", ["filter", "taxon", "state"]
        )
        birds = self.bot.get_cog("Birds")
        await birds.send_bird_(
            ctx,
            media,
            Filter.from_int(int(filter_int)),  # type: ignore
            taxon.decode("utf-8"),  # type: ignore
            state.decode("utf-8"),  # type: ignore
        )
Esempio n. 24
0
    async def send_bird_(
        self,
        ctx,
        media_type: Optional[str],
        filters: Filter,
        taxon_str: str = "",
        role_str: str = "",
        retries=0,
    ):
        media_type = ("images" if media_type in ("images", "image", "i",
                                                 "p") else
                      ("songs" if media_type in ("songs", "song", "s",
                                                 "a") else None))
        if not media_type:
            raise GenericError("Invalid media type", code=990)

        if media_type == "songs" and filters.vc:
            current_voice = database.get(f"voice.server:{ctx.guild.id}")
            if current_voice is not None and current_voice.decode(
                    "utf-8") != str(ctx.channel.id):
                logger.info("already vc race")
                await ctx.send("**The voice channel is currently in use!**")
                return

        if taxon_str:
            taxon = taxon_str.split(" ")
        else:
            taxon = []

        if role_str:
            roles = role_str.split(" ")
        else:
            roles = []

        logger.info(
            "bird: " +
            database.hget(f"channel:{ctx.channel.id}", "bird").decode("utf-8"))

        currently_in_race = bool(
            database.exists(f"race.data:{ctx.channel.id}"))

        answered = int(database.hget(f"channel:{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
            session_increment(ctx, "total", 1)

            logger.info(f"filters: {filters}; taxon: {taxon}; roles: {roles}")

            if not currently_in_race and retries == 0:
                await ctx.send(
                    "**Recognized arguments:** " +
                    f"*Active Filters*: `{'`, `'.join(filters.display())}`, " +
                    f"*Taxons*: `{'None' if taxon_str == '' else taxon_str}`, "
                    +
                    f"*Detected State*: `{'None' if role_str == '' else role_str}`"
                )

            find_custom_role = {
                i if i.startswith("CUSTOM:") else ""
                for i in roles
            }
            find_custom_role.discard("")
            if (database.exists(f"race.data:{ctx.channel.id}")
                    and len(find_custom_role) == 1):
                custom_role = find_custom_role.pop()
                roles.remove(custom_role)
                roles.append("CUSTOM")
                user_id = custom_role.split(":")[1]
                birds = build_id_list(user_id=user_id,
                                      taxon=taxon,
                                      state=roles,
                                      media=media_type)
            else:
                birds = build_id_list(user_id=ctx.author.id,
                                      taxon=taxon,
                                      state=roles,
                                      media=media_type)

            if not birds:
                logger.info("no birds for taxon/state")
                await ctx.send(
                    "**Sorry, no birds could be found for the taxon/state combo.**\n*Please try again*"
                )
                return

            currentBird = random.choice(birds)
            self.increment_bird_frequency(ctx, currentBird)

            prevB = database.hget(f"channel:{ctx.channel.id}",
                                  "prevB").decode("utf-8")
            while currentBird == prevB and len(birds) > 1:
                currentBird = random.choice(birds)
            database.hset(f"channel:{ctx.channel.id}", "prevB",
                          str(currentBird))
            database.hset(f"channel:{ctx.channel.id}", "bird",
                          str(currentBird))
            logger.info("currentBird: " + str(currentBird))
            database.hset(f"channel:{ctx.channel.id}", "answered", "0")
            await send_bird(
                ctx,
                currentBird,
                media_type,
                filters,
                on_error=self.error_handle(ctx, media_type, filters, taxon_str,
                                           role_str, retries),
                message=(
                    SONG_MESSAGE if media_type == "songs" else BIRD_MESSAGE)
                if not currently_in_race else "*Here you go!*",
            )
        else:  # if no, give the same bird
            await ctx.send(
                f"**Active Filters**: `{'`, `'.join(filters.display())}`")
            await send_bird(
                ctx,
                database.hget(f"channel:{ctx.channel.id}",
                              "bird").decode("utf-8"),
                media_type,
                filters,
                on_error=self.error_handle(ctx, media_type, filters, taxon_str,
                                           role_str, retries),
                message=(
                    SONG_MESSAGE if media_type == "songs" else BIRD_MESSAGE)
                if not currently_in_race else "*Here you go!*",
            )
Esempio n. 25
0
    async def checkgoat(self, ctx, *, arg):
        logger.info("command: checkgoat")

        await channel_setup(ctx)
        await user_setup(ctx)

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "goatsucker").decode("utf-8")
        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:{ctx.channel.id}", "gsAnswered", "1")
            database.hset(f"channel:{ctx.channel.id}", "goatsucker", "")
            if spellcheck(arg, currentBird) or spellcheck(arg, sciBird):
                logger.info("correct")

                if database.exists(f"session.data:{ctx.author.id}"):
                    logger.info("session active")
                    session_increment(ctx, "correct", 1)

                # increment streak and update max
                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))
                        })

                await ctx.send("Correct! Good job!")
                url = get_wiki_url(currentBird)
                await ctx.send(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 = f"bot/media/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() + ".")
                url = get_wiki_url(currentBird)
                await ctx.send(url)
            logger.info("currentBird: " +
                        str(currentBird.lower().replace("-", " ")))
            logger.info("args: " + str(arg.lower().replace("-", " ")))
Esempio n. 26
0
    async def parse(ctx, args_str: str):
        """Parse arguments for options."""

        args = args_str.split(" ")
        logger.info(f"args: {args}")

        if not database.exists(f"race.data:{ctx.channel.id}"):
            roles = check_state_role(ctx)

            taxon_args = set(taxons.keys()).intersection(
                {arg.lower()
                 for arg in args})
            if taxon_args:
                taxon = " ".join(taxon_args).strip()
            else:
                taxon = ""

            state_args = set(states.keys()).intersection(
                {arg.upper()
                 for arg in args})
            if state_args:
                state = " ".join(state_args).strip()
            else:
                state = ""

            if database.exists(f"session.data:{ctx.author.id}"):
                logger.info("session parameters")

                if taxon_args:
                    current_taxons = set(
                        database.hget(f"session.data:{ctx.author.id}",
                                      "taxon").decode("utf-8").split(" "))
                    logger.info(f"toggle taxons: {taxon_args}")
                    logger.info(f"current taxons: {current_taxons}")
                    taxon_args.symmetric_difference_update(current_taxons)
                    taxon_args.discard("")
                    logger.info(f"new taxons: {taxon_args}")
                    taxon = " ".join(taxon_args).strip()
                else:
                    taxon = database.hget(f"session.data:{ctx.author.id}",
                                          "taxon").decode("utf-8")

                roles = (database.hget(f"session.data:{ctx.author.id}",
                                       "state").decode("utf-8").split(" "))
                if roles[0] == "":
                    roles = []
                if not roles:
                    logger.info("no session lists")
                    roles = check_state_role(ctx)

                session_filter = int(
                    database.hget(f"session.data:{ctx.author.id}", "filter"))
                filters = Filter.parse(args_str, defaults=False)
                if filters.vc:
                    filters.vc = False
                    await ctx.send("**The VC filter is not allowed inline!**")

                default_quality = Filter().quality
                if (Filter.from_int(session_filter).quality == default_quality
                        and filters.quality
                        and filters.quality != default_quality):
                    filters ^= Filter()  # clear defaults
                filters ^= session_filter
            else:
                filters = Filter.parse(args_str)
                if filters.vc:
                    filters.vc = False
                    await ctx.send("**The VC filter is not allowed inline!**")

            if state_args:
                logger.info(f"toggle states: {state_args}")
                logger.info(f"current states: {roles}")
                state_args.symmetric_difference_update(set(roles))
                state_args.discard("")
                logger.info(f"new states: {state_args}")
                state = " ".join(state_args).strip()
            else:
                state = " ".join(roles).strip()

            if "CUSTOM" in state.upper().split(" "):
                if not database.exists(f"custom.list:{ctx.author.id}"):
                    await ctx.send("**You don't have a custom list set!**")
                    state_list = state.split(" ")
                    state_list.remove("CUSTOM")
                    state = " ".join(state_list)
                elif database.exists(f"custom.confirm:{ctx.author.id}"):
                    await ctx.send(
                        "**Please verify or confirm your custom list before using!**"
                    )
                    state_list = state.split(" ")
                    state_list.remove("CUSTOM")
                    state = " ".join(state_list)

        else:
            logger.info("race parameters")

            race_filter = int(
                database.hget(f"race.data:{ctx.channel.id}", "filter"))
            filters = Filter.parse(args_str, defaults=False)
            if filters.vc:
                filters.vc = False
                await ctx.send("**The VC filter is not allowed inline!**")

            default_quality = Filter().quality
            if (Filter.from_int(race_filter).quality == default_quality
                    and filters.quality
                    and filters.quality != default_quality):
                filters ^= Filter()  # clear defaults
            filters ^= race_filter

            taxon = database.hget(f"race.data:{ctx.channel.id}",
                                  "taxon").decode("utf-8")
            state = database.hget(f"race.data:{ctx.channel.id}",
                                  "state").decode("utf-8")

        logger.info(
            f"args: filters: {filters}; taxon: {taxon}; state: {state}")

        return (filters, taxon, state)
Esempio n. 27
0
    async def check(self, ctx, *, arg):
        logger.info("command: check")

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "bird").decode("utf-8")
        if currentBird == "":  # no bird
            await ctx.send("You must ask for a bird first!")
            return
        # if there is a bird, it checks answer
        sciBird = (await get_sciname(currentBird)).lower().replace("-", " ")
        arg = arg.lower().replace("-", " ")
        currentBird = currentBird.lower().replace("-", " ")
        alpha_code = alpha_codes.get(string.capwords(currentBird))
        logger.info("currentBird: " + currentBird)
        logger.info("arg: " + arg)

        bird_setup(ctx, currentBird)

        race_in_session = bool(database.exists(f"race.data:{ctx.channel.id}"))
        if race_in_session:
            logger.info("race in session")
            if database.hget(f"race.data:{ctx.channel.id}", "strict"):
                logger.info("strict spelling")
                correct = arg in (currentBird, sciBird)
            else:
                logger.info("spelling leniency")
                correct = spellcheck(arg, currentBird) or spellcheck(
                    arg, sciBird)

            if not correct and database.hget(f"race.data:{ctx.channel.id}",
                                             "alpha"):
                logger.info("checking alpha codes")
                correct = arg.upper() == alpha_code
        else:
            logger.info("no race")
            if database.hget(f"session.data:{ctx.author.id}", "strict"):
                logger.info("strict spelling")
                correct = arg in (currentBird, sciBird)
            else:
                logger.info("spelling leniency")
                correct = (spellcheck(arg, currentBird)
                           or spellcheck(arg, sciBird)
                           or arg.upper() == alpha_code)

        if correct:
            logger.info("correct")

            database.hset(f"channel:{ctx.channel.id}", "bird", "")
            database.hset(f"channel:{ctx.channel.id}", "answered", "1")

            session_increment(ctx, "correct", 1)
            streak_increment(ctx, 1)
            database.zincrby(f"correct.user:{ctx.author.id}", 1,
                             string.capwords(str(currentBird)))

            if (race_in_session and Filter.from_int(
                    int(database.hget(f"race.data:{ctx.channel.id}",
                                      "filter"))).vc):
                await voice_functions.stop(ctx, silent=True)

            await ctx.send(
                f"Correct! Good job! The bird was **{currentBird}**."
                if not race_in_session else
                f"**{ctx.author.mention}**, you are correct! The bird was **{currentBird}**."
            )
            url = get_wiki_url(ctx, currentBird)
            await ctx.send(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 = f"bot/media/achievements/{number}.PNG"
                with open(filename, "rb") as img:
                    await ctx.send(file=discord.File(img, filename="award.png")
                                   )

            if race_in_session:
                media = database.hget(f"race.data:{ctx.channel.id}",
                                      "media").decode("utf-8")

                limit = int(
                    database.hget(f"race.data:{ctx.channel.id}", "limit"))
                first = database.zrevrange(f"race.scores:{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(f"auto sending next bird {media}")
                    filter_int, taxon, state = database.hmget(
                        f"race.data:{ctx.channel.id}",
                        ["filter", "taxon", "state"])
                    birds = self.bot.get_cog("Birds")
                    await birds.send_bird_(
                        ctx,
                        media,
                        Filter.from_int(int(filter_int)),
                        taxon.decode("utf-8"),
                        state.decode("utf-8"),
                    )

        else:
            logger.info("incorrect")

            streak_increment(ctx, None)  # reset streak
            session_increment(ctx, "incorrect", 1)
            incorrect_increment(ctx, str(currentBird), 1)

            if race_in_session:
                await ctx.send("Sorry, that wasn't the right answer.")
            else:
                database.hset(f"channel:{ctx.channel.id}", "bird", "")
                database.hset(f"channel:{ctx.channel.id}", "answered", "1")
                await ctx.send("Sorry, the bird was actually **" +
                               currentBird + "**.")
                url = get_wiki_url(ctx, currentBird)
                await ctx.send(url)
Esempio n. 28
0
    async def edit(self, ctx, *, args_str: str = ""):
        logger.info("command: view session")

        if database.exists(f"session.data:{ctx.author.id}"):
            new_filter = Filter.parse(args_str, defaults=False)

            args = args_str.lower().split(" ")
            logger.info(f"args: {args}")

            new_filter ^= int(
                database.hget(f"session.data:{ctx.author.id}", "filter"))
            database.hset(f"session.data:{ctx.author.id}", "filter",
                          str(new_filter.to_int()))

            if "wiki" in args:
                if database.hget(f"session.data:{ctx.author.id}", "wiki"):
                    logger.info("enabling wiki embeds")
                    database.hset(f"session.data:{ctx.author.id}", "wiki", "")
                else:
                    logger.info("disabling wiki embeds")
                    database.hset(f"session.data:{ctx.author.id}", "wiki",
                                  "wiki")

            if "strict" in args:
                if database.hget(f"session.data:{ctx.author.id}", "strict"):
                    logger.info("disabling strict spelling")
                    database.hset(f"session.data:{ctx.author.id}", "strict",
                                  "")
                else:
                    logger.info("enabling strict spelling")
                    database.hset(f"session.data:{ctx.author.id}", "strict",
                                  "strict")

            states_args = set(states.keys()).intersection(
                {arg.upper()
                 for arg in args})
            if states_args:
                current_states = set(
                    database.hget(f"session.data:{ctx.author.id}",
                                  "state").decode("utf-8").split(" "))
                logger.info(f"toggle states: {states_args}")
                logger.info(f"current states: {current_states}")
                states_args.symmetric_difference_update(current_states)
                logger.info(f"new states: {states_args}")
                database.hset(
                    f"session.data:{ctx.author.id}",
                    "state",
                    " ".join(states_args).strip(),
                )

            taxon_args = set(taxons.keys()).intersection(
                {arg.lower()
                 for arg in args})
            if taxon_args:
                current_taxons = set(
                    database.hget(f"session.data:{ctx.author.id}",
                                  "taxon").decode("utf-8").split(" "))
                logger.info(f"toggle taxons: {taxon_args}")
                logger.info(f"current taxons: {current_taxons}")
                taxon_args.symmetric_difference_update(current_taxons)
                logger.info(f"new taxons: {taxon_args}")
                database.hset(
                    f"session.data:{ctx.author.id}",
                    "taxon",
                    " ".join(taxon_args).strip(),
                )

            await self._send_stats(ctx, "**Session started previously.**\n")
        else:
            await ctx.send(
                "**There is no session running.** *You can start one with `b!session start`*"
            )
Esempio n. 29
0
    async def check(self, ctx, *, arg):
        logger.info("command: check")

        await channel_setup(ctx)
        await user_setup(ctx)

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "bird").decode("utf-8")
        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) or spellcheck(arg, sciBird):
                logger.info("correct")

                database.hset(f"channel:{ctx.channel.id}", "bird", "")
                database.hset(f"channel:{ctx.channel.id}", "answered", "1")

                if database.exists(f"session.data:{ctx.author.id}"):
                    logger.info("session active")
                    session_increment(ctx, "correct", 1)

                database.zincrby("streak:global", 1, str(ctx.author.id))
                # 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:{ctx.channel.id}") else
                               f"**{ctx.author.mention}**, you are correct!")
                url = get_wiki_url(currentBird)
                await ctx.send(url if not database.exists(
                    f"race.data:{ctx.channel.id}") else f"<{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 = f"bot/media/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:{ctx.channel.id}") and str(
                        database.hget(f"race.data:{ctx.channel.id}",
                                      "media"))[2:-1] == "image":

                    limit = int(
                        database.hget(f"race.data:{ctx.channel.id}", "limit"))
                    first = database.zrevrange(f"race.scores:{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, taxon = database.hmget(
                            f"race.data:{ctx.channel.id}",
                            ["addon", "bw", "taxon"])
                        birds = self.bot.get_cog("Birds")
                        await birds.send_bird_(ctx, addon.decode("utf-8"),
                                               bw.decode("utf-8"),
                                               taxon.decode("utf-8"))

            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)

                if database.exists(f"race.data:{ctx.channel.id}"):
                    await ctx.send("Sorry, that wasn't the right answer.")
                else:
                    database.hset(f"channel:{ctx.channel.id}", "bird", "")
                    database.hset(f"channel:{ctx.channel.id}", "answered", "1")
                    await ctx.send("Sorry, the bird was actually " +
                                   currentBird.lower() + ".")
                    url = get_wiki_url(currentBird)
                    await ctx.send(url)
Esempio n. 30
0
    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:{ctx.author.id}"):
            args = args_str.split(" ")
            logger.info(f"args: {args}")
            if "bw" in args:
                if not database.hget(f"session.data:{ctx.author.id}", "bw"):
                    logger.info("adding bw")
                    database.hset(f"session.data:{ctx.author.id}", "bw", "bw")
                else:
                    logger.info("removing bw")
                    database.hset(f"session.data:{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 = database.hget(f"session.data:{ctx.author.id}", "state").decode("utf-8").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:{ctx.author.id}", "state", " ".join(add_states).strip())
            taxon_args = set(taxons.keys()).intersection({arg.lower() for arg in args})
            if taxon_args:
                toggle_taxon = list(taxon_args)
                current_taxons = database.hget(f"session.data:{ctx.author.id}", "taxon").decode("utf-8").split(" ")
                add_taxons = []
                logger.info(f"toggle taxons: {toggle_taxon}")
                logger.info(f"current taxons: {current_taxons}")
                for o in set(toggle_taxon).symmetric_difference(set(current_taxons)):
                    add_taxons.append(o)
                logger.info(f"adding taxons: {add_taxons}")
                database.hset(f"session.data:{ctx.author.id}", "taxon", " ".join(add_taxons).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 not database.hget(f"session.data:{ctx.author.id}", "addon"):
                    logger.info("adding female")
                    database.hset(f"session.data:{ctx.author.id}", "addon", addon)
                else:
                    logger.info("removing female")
                    database.hset(f"session.data:{ctx.author.id}", "addon", "")
            elif juvenile:
                addon = "juvenile"
                if not database.hget(f"session.data:{ctx.author.id}", "addon"):
                    logger.info("adding juvenile")
                    database.hset(f"session.data:{ctx.author.id}", "addon", addon)
                else:
                    logger.info("removing juvenile")
                    database.hset(f"session.data:{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`*")