Persistent View Disnake

Рейтинг: 0Ответов: 1Опубликовано: 07.03.2023

При создании выпадающего списка и перезагрузке бота, перестает работать список. Знаю что нужно использовать timeout=None и bot.add_view. У меня есть dropdown_view=RolesDropdownView(options=options, placeholder=placeholder, min_values=min_value, max_values=max_value) Тоесть это генератор списков по параметрам из слэш команды. Данные динамические. В примере регистрируют view без аргументов и всё получается, но как мне зарегистрировать его когда у меня динамические данные и я незнаю что отправлять туда. Пробовал после отправки сообщения регистрировать view эффекта не дало.

if frequency == 0.0:
        message = await to_channel.send(message.content, files=files, view=dropdown_view, embeds=embeds)  # type: ignore
        inter.bot.add_view(view=dropdown_view, message_id=message.id)  # type: ignore
        await inter.response.send_message("Объявление опубликовано")

И правильно ли то что я для каждого view использую новый custom_id.

UPD: Или мне надо каждый раз где то сохранять данные View и сообщения и отправлять их при старте бота.

UPD: пример: main.py

import disnake
import os
from disnake.ext import commands
from typing import List

intents = disnake.Intents.all()

class Bot(commands.InteractionBot):
    async def on_ready(self):
        print("Bot Started!")

bot = Bot(intents=intents)

bot.load_extension("cogs.cogs")
bot.run(os.environ["discord_bot_token"])

cogs/cogs.py

import disnake
import json
from disnake.ext import commands,
from typing import List
from cogs.views import RolesDropdownView

class UtilsCommand(commands.Cog):
    def __init__(self, bot: commands.Bot) -> None:
        self.bot = bot

    @commands.slash_command(description="Создание меню выбора", dm_permission=False, name="menu_creator")
    @commands.default_member_permissions(administrator=True)
    async def create_dropdown(
        self,
        inter: disnake.GuildCommandInteraction,
        schema: str = commands.Param(description="схема в json формате для меню"),
        to_channel_id: int = commands.Param(name="канал", description="В какой канал отправить", large=True),
        )
    ):
        channel = inter.bot.get_channel(to_channel_id)
        if channel is None:
            await inter.response.send_message("Неверный ID канала")
            return None
        converted_schema = json.loads(schema)
        message = converted_schema["content"]
        options = []
        placeholder = converted_schema["placeholder"]
        min_value = converted_schema["min_value"]
        max_value = converted_schema["max_value"]
        components = converted_schema["components"]
        for component in components:
            emoji_info = component["emoji"]
            emoji = None
            if "name" in emoji_info:
                emoji = disnake.utils.get(inter.guild.emojis, name=emoji_info["name"])
            option = disnake.SelectOption(
                label=component["label"], value=component["value"], default=component["default"], emoji=emoji
            )
            options.append(option)
        dropdown_view = RolesDropdownView(
            options=options, placeholder=placeholder, min_values=min_value, max_values=max_value
        )
        message = await channel.send(content=message, view=dropdown_view)  # type: ignore
        inter.bot.add_view(view=dropdown_view, message_id=message.id)
        await inter.response.send_message("Объявление опубликовано")

def setup(bot: commands.Bot):
    bot.add_cog(UtilsCommand(bot))

cogs/views.py

from typing import List
import disnake
import secrets

class BaseDropdown(disnake.ui.StringSelect):
    def __init__(
        self,
        options: List[disnake.SelectOption],
        placeholder: str,
        custom_id: str,
        max_values: int = -1,
        min_values: int = 1,
    ):

        super().__init__(
            placeholder=placeholder,
            min_values=min_values,
            max_values=len(options) if max_values == -1 else max_values,
            options=options,
            custom_id=custom_id,
        )

class RolesDropdown(BaseDropdown):
    def __init__(
        self, options: List[disnake.SelectOption], placeholder: str, max_values: int = -1, min_values: int = 1
    ):
        custom_id = f"RolesDropdown:{secrets.token_urlsafe(8)}"
        super().__init__(
            options,
            placeholder,
            custom_id,
            max_values,
            min_values,
        )

    async def callback(self, inter: disnake.MessageInteraction) -> None:
        for value in inter.values:
                role = disnake.utils.get(inter.guild.roles, name=value) 
                if role is None:
                    await inter.response.send_message("Роль не найдена", ephemeral=True)
                    return None
                await author.add_roles(role)  # type: ignore
            await inter.response.send_message("Роли успешно обновлены", ephemeral=True)

class RolesDropdownView(disnake.ui.View):
    def __init__(self, options: List[disnake.SelectOption], placeholder: str, min_values: int, max_values: int):
        super().__init__(timeout=None)
        self.add_item(RolesDropdown(options, placeholder, min_values=min_values, max_values=max_values))

json для генерации списка

    {
     "content": "",
     "placeholder": "Выберите роль здесь",
     "min_value": 1,
     "max_value": -1,
     "components": [
       {
         "label": "Удалить все роли",
         "value": "remove all",
         "default": false,
         "emoji": {
           "name": "redcrossmark"
         }
       },
       {
         "label": "Steam",
         "emoji": {
           "name": "Steam"
         },
         "value": "Steam",
         "default": false
       }
     ]
   }

Ответы

▲ 1Принят

Решил проблему тем что сохраняю данные view в словарь с помощью функции to_component_dict() в файл, а после перезагрузки бота загружаю всё из этого файла.

async def on_ready(self):
    views_dict = {'type': 3, 'message_id': 00000, 'custom_id': 
                  'RolesDropdown:LSTMru9w36E', 'min_values': 1, 'max_values': 
                  2, 'disabled': False, 'placeholder': 'Выберите роль здесь', 'options': [{'label': 'Удалить все роли', 'value': 
                  'remove all', 'default': False}, {'label': 'Steam', 'value': 'Steam', 'default': False}]}
    view = RolesDropdownView(options=views_dict["options"], placeholder=views_dict["placeholder"], min_values=views_dict['min_values'], max_values=views_dict['max_values'], custom_id=views_dict['custom_id'])
    self.add_view(view=view, message_id=views_dict["message_id"])

Но так же если есть какие то другие варианты сохранения то укажите их пожалуйста.