Пример #1
0
async def is_banned(client, event, user: ('user', 'Who should I check?')):
    """Checks whether the user is banned."""
    if (not event.user.has_role(ROLE__NEKO_DUNGEON__TESTER)) and (
            not event.user_permissions.can_ban_users):
        abort('You need to have `ban users` permissions to do this.')

    if not event.channel.cached_permissions_for(client).can_ban_users:
        abort('I need to have `ban users` permissions to do this.')

    yield  # acknowledge the event

    try:
        ban_entry = await client.guild_ban_get(event.guild, user)
    except DiscordException as err:
        if err.code == ERROR_CODES.unknown_ban:
            ban_entry = None
        else:
            raise

    embed = Embed(f'Ban entry for {user:f}').add_thumbnail(user.avatar_url)

    if ban_entry is None:
        embed.description = 'The user **NOT YET** banned.'

    else:
        embed.description = 'The user is banned.'

        reason = ban_entry.reason
        if reason is None:
            reason = '*No reason was specified.*'

        embed.add_field('Reason:', reason)

    yield embed
Пример #2
0
async def latest_users(
    client,
    event,
):
    """Shows the new users of the guild."""
    if not event.user.has_role(ROLE__NEKO_DUNGEON__MODERATOR):
        abort('Hacker trying to hack Discord.')

    date_limit = datetime.now() - timedelta(days=7)

    users = []
    guild = event.guild
    for user in guild.users.values():
        # Use created at and not `joined_at`, we can ignore lurkers.
        created_at = user.guild_profiles[guild].created_at
        if created_at > date_limit:
            users.append((created_at, user))

    users.sort(reverse=True)
    del users[10:]

    embed = Embed('Recently joined users')
    if users:
        for index, (joined_at, user) in enumerate(users, 1):
            add_user_field(embed, index, joined_at, user)

    else:
        embed.description = '*none*'

    return InteractionResponse(embed=embed, allowed_mentions=None)
Пример #3
0
async def latest_users(event):
    """Shows the new users of the guild."""
    date_limit = datetime.now() - timedelta(days=7)

    users = []
    guild = event.guild
    for user in guild.users.values():
        # `joined_at` might be set as `None` if the user is a lurker.
        # We can ignore lurkers, so use `created_at` which defaults to Discord epoch.
        created_at = user.guild_profiles[guild].created_at
        if created_at > date_limit:
            users.append((created_at, user))

    users.sort(reverse=True)
    del users[10:]

    embed = Embed('Recently joined users')
    if users:
        for index, (joined_at, user) in enumerate(users, 1):
            created_at = user.created_at
            embed.add_field(
                f'{index}. {user.full_name}',
                f'Id: {user.id}\n'
                f'Mention: {user.mention}\n'
                '\n'
                f'Joined : {joined_at:{DATETIME_FORMAT_CODE}} [*{elapsed_time(joined_at)} ago*]\n'
                f'Created : {created_at:{DATETIME_FORMAT_CODE}} [*{elapsed_time(created_at)} ago*]\n'
                f'Difference : {elapsed_time(relativedelta(created_at, joined_at))}',
            )

    else:
        embed.description = '*none*'

    return InteractionResponse(embed=embed, allowed_mentions=None)
Пример #4
0
async def show_auto_react_roles(client, message):
    guild = message.guild
    if guild is None:
        return

    managers = client.events.guild_delete.get_waiters(guild,
                                                      AutoReactRoleManager,
                                                      by_type=True,
                                                      is_method=True)

    embed = Embed(f'Auto role managers for: {guild}',
                  color=AUTO_REACT_ROLE_COLOR)
    if not managers:
        embed.description = '*none*'
        await Pagination(client, message.channel, [embed])
        return

    results = []
    for manager in managers:
        message_ = manager.message
        title = f'{message_.channel:m} {message.id}'
        results.append((title, manager), )

    await ChooseMenu(client,
                     message.channel,
                     results,
                     select_auto_react_role_gui,
                     embed=embed,
                     prefix='¤')
Пример #5
0
async def queue(client, message):
    guild = message.guild
    if guild is None:
        return
    
    voice_client = client.voice_client_for(message)
    color = VOICE_COLORS.get(client)
    
    title = f'Playing queue for {guild}'
    page = Embed(title, color=color)
    pages = [page]
    while True:
        if voice_client is None:
            page.description = '*none*'
            break
        
        source = voice_client.source
        if (source is not None):
            page.add_field('Actual:', source.title)
        
        queue = voice_client.queue
        limit = len(queue)
        if limit:
            index = 0
            while True:
                source = queue[index]
                index += 1
                page.add_field(f'Track {index}.:', source.title)
                
                if index == limit:
                    break
                
                if index%10 == 0:
                    page = Embed(title, color=color)
                    pages.append(page)
            
        else:
            if source is None:
                page.description = '*none*'
        
        break
    
    await Pagination(client, message.channel, pages)
Пример #6
0
async def edit_(
    client,
    event,
    sticker_name: ('str', 'The sticker\'s name to delete', 'sticker'),
    new_name: (
        'str',
        'New name for the sticker',
    ) = None,
    new_emoji_value: (str, 'Emoji representation of the sticker.',
                      'new_emoji') = None,
    new_description: (str, 'Description for the sticker.') = None,
):
    """Edits the given sticker. (You must have emoji-council role)"""
    if not event.user.has_role(ROLE__NEKO_DUNGEON__EMOJI_MANAGER):
        abort(
            f'You must have {ROLE__NEKO_DUNGEON__EMOJI_MANAGER:m} role to invoke this command.'
        )

    sticker = event.guild.get_sticker_like(sticker_name)
    if (sticker is None):
        abort(f'No sticker matched the given name: {sticker_name!r}.')

    anything_to_edit = False

    if (new_name is not None):
        if (sticker.name != new_name):
            name_length = len(new_name)
            if (name_length < 2) or (name_length > 32):
                abort(
                    f'Sticker name\'s length can be in range [2:32], got {name_length!r}, {new_name!r}.'
                )

            anything_to_edit = True
        else:
            new_name = None

    if (new_emoji_value is not None):
        new_emoji = parse_emoji(new_emoji_value)

        if new_emoji is None:
            abort(f'{new_emoji_value} cannot be interpreted as an emoji.')

        if new_emoji.is_custom_emoji():
            abort(f'Only unicode can be used, got {new_emoji:e}')

        tags = sticker.tags
        if (tags is None) or (len(tags) != 1) or (next(iter(tags)) !=
                                                  new_emoji.name):
            anything_to_edit = True
        else:
            new_emoji = None
    else:
        new_emoji = None

    if (new_description is not None):
        description_length = len(new_description)
        if (description_length > 100):
            abort(
                f'Sticker description\'s length can be in range [0:100], got {description_length!r}, '
                f'{new_description!r}.')

        if (sticker.description != new_description):
            anything_to_edit = True
        else:
            new_description = None

    if not anything_to_edit:
        abort('No differences were provided.')

    embed = Embed('Confirmation',
                  f'Are you sure to edit {sticker.name!r} sticker?')

    if (new_name is not None):
        embed.add_field('Name', f'{sticker.name} -> {new_name}')

    if (new_emoji is not None):
        embed.add_field('Tags',
                        f'{", ".join(sticker.tags)} -> {new_emoji.name}')

    if (new_description is not None):
        embed.add_field('Description',
                        f'{sticker.description} -> {new_description}')

    message = yield InteractionResponse(embed=embed,
                                        components=STICKER_EDIT_COMPONENTS,
                                        allowed_mentions=None)

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=partial_func(check_sticker_editor, event.user))

    except TimeoutError:
        embed.title = 'Timeout'
        embed.description = f'Sticker {sticker.name!r} was not edited.'

        # Edit the source message with the source interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  message=message)
        return

    if component_interaction.interaction == STICKER_EDIT_BUTTON_CANCEL:
        embed.title = 'Cancelled'
        embed.description = f'Sticker {sticker.name!r} was not edited.'

        # Edit the source message with the component interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  event=component_interaction)
        return

    # Acknowledge the event
    await client.interaction_component_acknowledge(component_interaction)

    kwargs = {}

    if (new_name is not None):
        kwargs['name'] = new_name

    if (new_emoji is not None):
        kwargs['emoji_representation'] = new_emoji

    if (new_description is not None):
        kwargs['description'] = new_description

    try:
        await client.sticker_guild_edit(sticker, **kwargs)
    except ConnectionError:
        # No internet, let it be
        return

    except DiscordException as err:
        if err.code == ERROR_CODES.unknown_sticker:
            failure = False
        else:
            failure = True
            embed.title = 'Failure'
            embed.description = repr(err)
    else:
        failure = False

    if not failure:
        embed.title = 'Success'
        embed.description = f'Sticker {sticker.name!r} has been successfully edited.'

    # Edit the source message
    yield InteractionResponse(embed=embed, message=message, components=None)
Пример #7
0
async def delete_(
        client,
        event,
        sticker_name: ('str', 'The sticker\'s name to delete', 'sticker'),
):
    """Deletes the given sticker. (You must have emoji-council role)"""
    if not event.user.has_role(ROLE__NEKO_DUNGEON__EMOJI_MANAGER):
        abort(
            f'You must have {ROLE__NEKO_DUNGEON__EMOJI_MANAGER:m} role to invoke this command.'
        )

    sticker = event.guild.get_sticker_like(sticker_name)
    if (sticker is None):
        abort(f'No sticker matched the given name: {sticker_name!r}.')

    embed = Embed(
        'Confirmation',
        f'Are you sure to delete {sticker.name!r} ({sticker.id}) sticker forever?'
    )

    message = yield InteractionResponse(embed=embed,
                                        components=STICKER_DELETE_COMPONENTS,
                                        allowed_mentions=None)

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=partial_func(check_sticker_deleter, event.user))

    except TimeoutError:
        embed.title = 'Timeout'
        embed.description = f'Sticker {sticker.name!r} was not deleted.'

        # Edit the source message with the source interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  message=message)
        return

    if component_interaction.interaction == STICKER_DELETE_BUTTON_CANCEL:
        embed.title = 'Cancelled'
        embed.description = f'Sticker {sticker.name!r} was not deleted.'

        # Edit the source message with the component interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  event=component_interaction)
        return

    # Acknowledge the event
    await client.interaction_component_acknowledge(component_interaction)

    try:
        await client.sticker_guild_delete(sticker)
    except ConnectionError:
        # No internet, let it be
        return

    except DiscordException as err:
        if err.code == ERROR_CODES.unknown_sticker:
            failure = False
        else:
            failure = True
            embed.title = 'Failure'
            embed.description = repr(err)
    else:
        failure = False

    if not failure:
        embed.title = 'Success'
        embed.description = f'Sticker {sticker.name!r} has been deleted successfully.'

    # Edit the source message
    yield InteractionResponse(embed=embed, message=message, components=None)
Пример #8
0
async def user_top(
    event,
    user: ('user', 'By who?') = None,
    count: (range(10, 61, 10), 'The maximal amount of emojis to show') = 30,
    months: (range(1, 13), 'The months to get') = 1,
):
    """List the most used stickers at ND by you or by the selected user."""
    if user is None:
        user = event.user

    async with DB_ENGINE.connect() as connector:
        response = await connector.execute(
            select([
                sticker_counter_model.sticker_id,
                alchemy_function.count(sticker_counter_model.sticker_id).label('total'),
            ]). \
            where(and_(
                sticker_counter_model.user_id == user.id,
                sticker_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months,
            )). \
            limit(count). \
            group_by(sticker_counter_model.sticker_id). \
            order_by(desc('total'))
        )

        results = await response.fetchall()

    embed = Embed(
        f'Most used stickers by {user.full_name}',
        color=user.color_at(GUILD__NEKO_DUNGEON),
    ).add_thumbnail(user.avatar_url)

    if results:
        description_parts = []
        limit = len(results)
        index = 0
        start = 1

        while True:
            sticker_id, count = results[index]

            index += 1

            try:
                sticker = STICKERS[sticker_id]
            except KeyError:
                continue

            description_parts.append(str(index))
            description_parts.append('.: **')
            description_parts.append(str(count))
            description_parts.append('** x ')
            description_parts.append(sticker.name)

            if (not index % 10) or (index == limit):
                description = ''.join(description_parts)
                description_parts.clear()
                embed.add_field(f'{start} - {index}', description, inline=True)

                if (index == limit):
                    break

                start = index + 1
                continue

            description_parts.append('\n')
            continue
    else:
        embed.description = '*No recorded data.*'

    return embed
Пример #9
0
async def yeet(
    client,
    event,
    user: ('user', 'Select the user to yeet!'),
    reason: ('str', 'Any reason why you would want to yeet?') = None,
    delete_message_days: (range(8), 'Delete previous messages?') = 0,
    notify_user: ('bool',
                  'Whether the user should get DM about the ban.') = True,
):
    """Yeets someone out of the guild. You must have ban users permission."""
    # Check permissions
    guild = event.guild
    if guild is None:
        abort('Guild only command.')

    if guild not in client.guild_profiles:
        abort('I must be in the guild to do this.')

    if not event.user_permissions.can_ban_users:
        abort('You must have yeet users permission to use this command.')

    if not guild.cached_permissions_for(client).can_ban_users:
        abort(f'{client.name_at(guild)} cannot yeet in the guild.')

    if not event.user.has_higher_role_than_at(user, guild):
        abort('You must have higher role than the person to be yeeted.')

    if not client.has_higher_role_than_at(user, guild):
        abort('I must have higher role than the person to yeeted.')

    # Ask, whether the user should be banned.
    if (reason is not None) and (not reason):
        reason = None

    embed = Embed('Confirmation', f'Are you sure to yeet {user.mention} from {guild.name}?'). \
        add_field('Delete message day', str(delete_message_days), inline=True). \
        add_field('Notify user', 'true' if notify_user else 'false', inline=True). \
        add_field('Reason', '*No reason provided.*' if reason is None else reason)

    message = yield InteractionResponse(embed=embed,
                                        components=BAN_COMPONENTS,
                                        allowed_mentions=None)

    # Wait for user input

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=partial_func(check_banner, event.user))

    except TimeoutError:
        embed.title = 'Timeout'
        embed.description = f'{user.mention} was not yeeted from {guild.name}.'

        # Edit the source message with the source interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  message=message)
        return

    if component_interaction.interaction == BAN_BUTTON_CANCEL:
        embed.title = 'Cancelled'
        embed.description = f'{user.mention} was not yeeted from {guild.name}.'

        # Edit the source message with the component interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  event=component_interaction)
        return

    # Acknowledge the event
    await client.interaction_component_acknowledge(component_interaction)

    # Try to notify the user. Ignore bot notifications.
    if notify_user:
        if user.is_bot:
            notify_note = None
        else:

            try:
                channel = await client.channel_private_create(user)
            except BaseException as err:
                if isinstance(err, ConnectionError):
                    return  # We cannot help no internet

                raise

            embed = Embed('Yeeted', f'You were yeeted from {guild.name}.'). \
                add_field('Reason', '*No reason provided.*' if reason is None else reason)

            try:
                await client.message_create(channel, embed=embed)
            except BaseException as err:
                if isinstance(err, ConnectionError):
                    return  # We cannot help no internet

                elif isinstance(err, DiscordException) and (
                        err.code == ERROR_CODES.cannot_message_user):
                    notify_note = 'Notification cannot be delivered: user has DM disabled.'
                else:
                    raise
            else:
                notify_note = None
    else:
        notify_note = None

    if reason is None:
        caller = event.user
        reason = f'Requested by: {caller.full_name} [{caller.id}]'

    await client.guild_ban_add(guild,
                               user,
                               delete_message_days=delete_message_days,
                               reason=reason)

    embed = Embed('Hecatia yeah!', f'{user.full_name} has been yeeted.')
    if (notify_note is not None):
        embed.add_footer(notify_note)

    # Edit the source message
    yield InteractionResponse(embed=embed, message=message, components=None)
Пример #10
0
    async def runner(self):
        client = self.client
        channel = self.channel
        answers = self.answers
        buffer = ReuBytesIO()
        embed = Embed(color=KANAKO_COLOR).add_image(
            'attachment://guess_me.png').add_footer('')

        time_till_notify = CIRCLE_TIME - 10

        for index, (question, answer) in enumerate(self.map, 1):
            embed.footer.text = f'{index} / {len(self.map)}'
            if self.possibilities:
                self.options = self.generate_options(answer)
                embed.description = '\n'.join([
                    f'**{index}.: {value}**'
                    for index, value in enumerate(self.options, 1)
                ])

            try:
                await client.message_create(channel,
                                            embed=embed,
                                            file=('guess_me.png',
                                                  draw(buffer, question)))
            except BaseException as err:
                self.cancel()
                if isinstance(err, ConnectionError):
                    return

                if isinstance(err, DiscordException):
                    if err.code in (
                            ERROR_CODES.unknown_channel,  # channel deleted
                            ERROR_CODES.missing_access,  # client removed
                            ERROR_CODES.
                            missing_permissions,  # permissions changed meanwhile
                    ):
                        return

                await client.events.error(client,
                                          f'{self.__class__.__name__}.runner',
                                          err)
                return

            circle_start = LOOP_TIME()
            self.waiter = waiter = Future(KOKORO)
            future_or_timeout(waiter, time_till_notify)

            try:
                await waiter
            except TimeoutError:
                Task(self.notify_late_users(), KOKORO)

                self.waiter = waiter = Future(KOKORO)
                future_or_timeout(waiter, 10)

                try:
                    await waiter
                except TimeoutError:
                    leavers = []

                    users = self.users

                    for index in reversed(range(len(users))):
                        user = users[index]
                        if user in answers:
                            continue

                        leavers.append(user)
                        del users[index]

                        for element in self.history:
                            del element.answers[index]

                    if len(self.users) == 0:
                        self.cancel()
                        embed = Embed(
                            None,
                            'No-one gave answer in time, cancelling the game.',
                            color=KANAKO_COLOR)
                    else:
                        embed = Embed(None,
                                      '\n'.join([
                                          'Users timed out:',
                                          *(user.full_name for user in leavers)
                                      ]),
                                      color=KANAKO_COLOR)

                    try:
                        await client.message_create(channel, embed=embed)
                    except BaseException as err:
                        self.cancel()
                        if isinstance(err, ConnectionError):
                            return

                        if isinstance(err, DiscordException):
                            if err.code in (
                                    ERROR_CODES.
                                    unknown_channel,  # channel deleted
                                    ERROR_CODES.
                                    missing_access,  # client removed
                                    ERROR_CODES.
                                    missing_permissions,  # permissions changed meanwhile
                            ):
                                return

                        await client.events.error(
                            client, f'{self.__class__.__name__}.runner', err)
                        return

            if self.cancelled:
                return

            self.waiter = None

            element = HistoryElement()
            element.question = question
            element.answer = answer
            element.options = self.options
            element.answers = [(value[0], value[1] - circle_start)
                               for value in (answers[user.id]
                                             for user in self.users)]
            self.history.append(element)

            answers.clear()

            embed.title = f'Last answer: {answer}'

        self.cancel()

        embed = Embed(embed.title, color=KANAKO_COLOR)
        try:
            await client.message_create(channel, embed=embed)
        except BaseException as err:
            self.cancel()
            if isinstance(err, ConnectionError):
                return

            if isinstance(err, DiscordException):
                if err.code in (
                        ERROR_CODES.unknown_channel,  # channel deleted
                        ERROR_CODES.missing_access,  # client removed
                        ERROR_CODES.
                        missing_permissions,  # permissions changed meanwhile
                ):
                    return

            await client.events.error(client,
                                      f'{self.__class__.__name__}.runner', err)
            return

        await GameStatistics(self)
Пример #11
0
async def buy(client, event,
        item : ([(item.name, item.id) for item in BUYABLE], 'Select the item to buy nya!'),
        amount : (int, 'How much items would you want to buy?'),
            ):
    """Buy?"""
    try:
        item = ITEMS[item]
    except KeyError:
        abort('Item not available.')
    
    permissions = event.channel.cached_permissions_for(client)
    if (not permissions.can_send_messages) or (not permissions.can_add_reactions):
        abort('I need `send messages` and `add reactions` permissions to execute the command.')
    
    yield
    
    user = event.user
    async with DB_ENGINE.connect() as connector:
        response = await connector.execute(
            select([currency_model.total_love]). \
                where(currency_model.user_id==user.id))
        
        results = await response.fetchall()
        if results:
            total_love = results[0]
        else:
            total_love = 0
    
    embed = Embed('Confirm buying',
        f'Selected item: {item.emoji:e} **{item.name}**\n'
        f'Amount: **{amount}**\n'
        f'\n'
        f'Price: {calculate_buy_cost(item.market_cost, amount)} {EMOJI__HEART_CURRENCY:e}\n'
        f'Budget: {total_love} {EMOJI__HEART_CURRENCY:e}'
    )
    
    embed.add_author(user.avaar_url, user.full_name)
    embed.add_footer('The prices of context of demand and supply.')
    
    message = await client.message_create(event.channel, embed=embed)
    await client.reaction_add(message, item.emoji)
    await client.reaction_add(message, CONFIRM_NAH)
    
    try:
        event = await wait_for_reaction(client, message, partial_func(check_confirm_emoji, item.emoji), 300.0)
    except TimeoutError:
        return
    
    if event.emoji is CONFIRM_NAH:
        embed.title = 'Buying cancelled'
    else:
        user = event.user
        async with DB_ENGINE.connect() as connector:
            response = await connector.execute(
                select([currency_model.total_love, currency_model.total_allocated]). \
                    where(currency_model.user_id==user.id))
            
            results = await response.fetchall()
            if results:
                total_love, total_allocated = results[0]
            else:
                total_love = total_allocated = 0
            
            if total_love == 0:
                amount = cost = 0
            else:
                amount, cost = calculate_buyable_and_cost(item.market_cost, amount, total_love-total_allocated)
                
                item.market_cost += amount
            
            if cost == 0:
                new_love = total_love
            else:
                new_love = total_love-cost
                await connector.execute(update(currency_model.user_id==user.id). \
                    values(total_love = new_love))
                
                response = await connector.execute(select([item_model.id, item_model.amount]). \
                    where(item_model.user_id==user.id).where(item_model.type==item.id))
                
                results = await response.fetchall()
                if results:
                    row_id, actual_amount = results[0]
                    new_amount = actual_amount+amount
                    to_execute = ITEM_TABLE.update().values(
                        amount=new_amount
                            ).where(item_model.id==row_id)
                else:
                    to_execute = ITEM_TABLE.insert().values(
                        user_id = user.id,
                        amount  = amount,
                        type    = item.id
                    )
                
                await connector.execute(to_execute)
        
        embed.title = 'Buying confirmed'
        embed.description = (
            f'Selected item: {item.emoji:e} **{item.name}**\n'
            f'Bought mount: **{amount}**\n'
            f'\n'
            f'Hearts: {total_love} {EMOJI__HEART_CURRENCY:e} -> {new_love} {EMOJI__HEART_CURRENCY:e}'
        )
    
    await client.message_edit(message, embed=embed)
Пример #12
0
async def handle_waifu_select(client, event):
    # We filter out 3rd party users based on original and current invoking user.
    if event.message.interaction.user is not event.user:
        return

    # Second we filter out incorrect selected values.
    # You can change the command over time and the can return bad option as well.
    selected_waifu_types = event.interaction.options
    if (selected_waifu_types is None):
        return

    selected_waifu_type = selected_waifu_types[0]
    if (selected_waifu_type not in WAIFU_TYPES):
        return

    # Try to get url from cache
    cache = WAIFU_CACHE_BY_KEY[selected_waifu_type]
    if cache:
        url = cache.pop()
    else:
        # We could not get url from cache

        # Do 1 yield to acknowledge the event.
        yield

        # We could use a Lock to avoid parallel requests, but that would expose us to other edge cases.
        async with client.http.post(
            f'{WAIFU_API_BASE_URL}/many/sfw/{selected_waifu_type}',
            headers=WAIFU_API_HEADERS,
            data=WAIFU_API_REQUEST_DATA,
        ) as response:

            if response.status == 200:
                data = await response.json()
            else:
                data = None

        url = None

        if (data is not None):
            try:
                files = data['files']
            except KeyError:
                pass
            else:
                cache.extend(files)

                if cache:
                    url = cache.pop()

    # Url defaults to `None`, so passing it to `url` field is fine.
    embed = Embed('Please select a waifu type to ship.', url=url)

    if url is None:
        embed.description = (
            f'*Could not find any free {selected_waifu_type} now.\n'
            f'Please try again later.*')
    else:
        embed.add_image(url)

    # We re-build the select again with one difference, we mark the used one as default.
    select = Select(
        [
            Option(waifu_type,
                   waifu_type,
                   default=(waifu_type == selected_waifu_type))
            for waifu_type in WAIFU_TYPES
        ],
        custom_id=WAIFU_CUSTOM_ID,
    )

    yield InteractionResponse(embed=embed, components=select)
Пример #13
0
    async def run(self):
        client = self.client
        channel = self.channel
        answers = self.answers
        buffer = ReuBytesIO()
        embed = Embed(color=KANAKO_COLOR)
        embed.add_image('attachment://guessme.png')
        embed.add_footer('')
        time_till_notify = CIRCLE_TIME - 10

        for index, (question, answer) in enumerate(self.map, 1):
            embed.footer.text = f'{index} / {len(self.map)}'
            if self.possibilities:
                self.options = self.generate_options(answer)
                embed.description = '\n'.join([
                    f'**{index}.: {value}**'
                    for index, value in enumerate(self.options, 1)
                ])

            try:
                await client.message_create(channel,
                                            embed=embed,
                                            file=('guessme.png',
                                                  draw(buffer, question)))
            except DiscordException:
                return self.cancel()

            circle_start = LOOP_TIME()
            waiter = sleep(time_till_notify, client.loop)
            self.waiter = waiter
            try:
                await waiter
                Task(
                    self.send_or_except(
                        Embed(
                            'Hurry! Only 10 seconds left!', '\n'.join([
                                user.full_name for user in self.users
                                if user.id not in answers
                            ]), KANAKO_COLOR)), client.loop)
                waiter = sleep(time_till_notify, client.loop)
                self.waiter = waiter
                await waiter
                self.calculate_leavers()
            except CancelledError:
                pass
            except InterruptedError as err:
                return self.cancel()

            element = history_element()
            element.question = question
            element.answer = answer
            element.options = self.options
            element.answers = [(value[0], value[1] - circle_start)
                               for value in (answers[user.id]
                                             for user in self.users)]
            self.history.append(element)

            answers.clear()

            embed.title = f'Last answer: {answer}'

        await self.send_or_except(Embed(embed.title, '', KANAKO_COLOR))

        del ACTIVE_GAMES[channel.id]
        client.events.message_create.remove(self.channel, self)
        self.running = False

        await game_statistics(self)