Code Monkey home page Code Monkey logo

kutana's People

Contributors

daeeros avatar dependabot[bot] avatar fossabot avatar merded avatar michaelkryukov avatar nm17 avatar sakost avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kutana's Issues

on_commands does not ignore prefix when bot mentioned in private messages

on_commands ignores prefix when bot mentioned in group chats, but not in private messages

Expected Behavior

on_commands ignores prefix when bot mentioned in private messages

Actual Behavior

only in group chats on_commands ignores prefix when bot mentioned

Context

Bot users try to use mention as command prefix in private messages as they use it in group chats

Your Environment

  • Python vesion: 3.9
  • Kutana version: 5.1.0.dev0
  • Platform: not matter
  • Country: not matter

Добавить новый декоратор "schedule"

Довольно часто требуется запускать постоянные coroutines эное-кол-во раз в несколько секунд. Текущий подход всегда выглядел так, несомненно работает нет проблем. Но как бы это удобно выглядело с декоратором?

from kutana import Plugin
import asyncio

plugin = Plugin("TestPlugin")

@plugin.on_start()
async def _():
    asyncio.create_task(egg_printer())

# Prints egg every 5 seconds
async def egg_printer():
    while True:
        print("Its Egg!")
        await asyncio.sleep(5)

Вот как бы это выглядело с помощью декоратора, красиво а самое главное удобно. И мы избавляемся от лишних импортов и лишних блоков кода.

from kutana import Plugin

plugin = Plugin("TestPlugin")

# Prints egg every 5 seconds
@plugin.schedule(5)
async def egg_printer():
    print("Its Egg!")

Обновить метод рекурсивной загрузки плагинов

Сейчас он обходит все *.py файлы, но хочется, чтобы он умел адекватно импортировать модули. При этом просто лежащие рядом файлы-модули всё-равно надо оставить импортируемыми. Т.е. поиграть с определением папок как модулей и т.д.

VK Callback buttons support

Special decorator for handling callback buttons events
(VK Docs)

Expected Behavior

Something like:
@vk.on_callback(payload=...)

Actual Behavior

Possible Solution

Make similar to @vk.on_payloads(...) but with callback buttons

Context

It's difficult to use callback buttons in current kutana api's

Bot commands with alias

Commands like /command@BotUsername don't work as expected.

Example code:

@plugin.on_commands(commands=["command"])
async def _(msg, ctx):
    await ctx.reply("Works!!!")

@plugin.on_any_unprocessed_message()
async def _(msg, ctx):
    await ctx.reply("Doesn't work :-(")

Expected Behavior

/command => Works!!!
/command@BotUsername => Works!!!

Actual Behavior

/command => Works!!!
/command@BotUsername => Doesn't work :-(

Possible Solution

Strip anything after @ in commands.

Steps to Reproduce (for bugs)

  1. Run example code
  2. Write to a bot
  3. Cry

Context

This feature is quite useful if there're multiple bots in one chat.

Your Environment

  • Python vesion: 3.8.5
  • Kutana version: 4.2.0
  • Platform: Arch Linux 5.7.11-arch1-1
  • Country: Russia

Более гибкая система команд

Я беру во внимание Red (Discord bot). В нем используется более гибкая система команд, которая позволяет очень легко и просто создавать подкоманды (subcommands) в плагинах с помощью декораторов. Также было бы удобно передавать аргументы, которые пользователь передает вместе с командой в *args.

Ожидаемое поведение

Просто посмотрите, как легко и просто в Red создаются команды:

    @commands.group(alias=["nf"])
    async def nickforcer(self, ctx:commands.Context):
        """Nickname Forcer related commands"""

        pass

    @nickforcer.command()
    @commands.admin()
    async def set(self, ctx: commands.Context, user: discord.Member, nick: commands.UserInputOptional[str]):
        """Sets the user to Nickname Forcer"""
        await self.config.user(user).nickname.set(nick)
        current_users = await self.config.guild(ctx.guild).users_to_force()
        if user.id not in current_users:
            current_users.append(user.id)
            await self.config.guild(ctx.guild).users_to_force.set(current_users)
        await ctx.send(_("This user now will be forced with this nickname: **{nickname}**").format(nickname=nick))
        try:
            await user.edit(nick=nick)
        except discord.errors.Forbidden:
            await ctx.send(_("So I've tried to do this, but i have no permission to change nicknames of other users, "
                             "add it to me, please."))

    @nickforcer.command()
    @commands.admin()
    async def unset(self, ctx: commands.context, user: discord.Member):
        """Unsets the user to Nickname Forcer"""
        current_users = await self.config.guild(ctx.guild).users_to_force()
        if user.id not in current_users:
            await ctx.send(_("Nothing to unset..."))
        else:
            current_users.remove(user.id)
            await ctx.send(_("User {mention} has been removed from forcing!").format(mention=user.mention))

Как вы можете заметить, самая первая функция - назовём её "мастер-командой", с которой начинается вся магия. Использовав ее как декоратор, вторая функция становится после нее и получается так, что чтобы вызвать эту команду нужно набрать /nickforcer set [аргументы]. Ведь просто же? И что самое главное логично - вторая команда как-бы наследует мастер-команду.

Также обратите внимание, что у функций после ctx объявлены еще несколько параметров. Red передает в них, аргументы, который спарсил из полученной команды. Разработчику плагинов при этом больше не нужно заниматься парсингом body, достаточно доверить все фреймворку, просто объявив аргументы разного типа. Также, если им задать значение по умолчанию None, можно сделать их необязательными. Было бы здорово позаимствовать такой мощный парсер команд у Red и добавить в Kutana, не так ли?

И ещё один ключевой фактор, который здесь присутствует - это docstring. У каждой команды есть свой комментарий, который находится там не просто так. Это справка по команде, которую использует встроенный плагин help в Red. Также, эти комментарии, как и все строки внутри функции перевода _("string") замечательно извлекается с помощью форка gettext от Red, который называется redgettext (есть в PyPI). Хотелось бы еще, чтобы Kutana отошла от использования yml в i18n и использовала специальные форматы, такие как po и mo. Все системы перевода заточены именно под эти форматы файлов.

Текущее поведение

На данный момент Kutana очень скудно обрабатывает команды. Да, конечно сейчас можно сделать подкоманды вот так:

@plugin.on_commands(['settings set'])
async def __(message, context):
    ...

Но делать их с помощью декораторов гораздо приятнее и красивее. Ну и, кстати говоря, Kutana не умеет парсить аргументы, приходится самостоятельно парсить их из body, что не очень удобно и выглядит несколько кустарно.

Также сейчас Kutana использует yml для i18n, что неудобно для перевода плагинов, так как все системы перевода используют форматы файлов po и mo.

Возможные решения

Red - открытый фреймворк для построения ботов для Discord. Вооружившись его открытым исходным кодом, из него можно позаимствовать различные идеи и наработки, с помощью которых можно сделать Kutana лучшим фреймворком для создания мультиплатформенных ботов.

Контекст

Контекст не требуется. Всё было сказано выше. Если у вас есть какие-то вопросы, прошу связаться со мной:
ВКонтакте, Telegram

Webhook support

Expected Behavior

app.run(webhook=True)

or

Vkontakte(webhook=True)

Actual Behavior

Webhooks save a lot of resources, and it would also be possible to deploy bots to services like Heroku.

Possible Solution

We could make an aiohttp server to serve webhooks.

I can implement it, but I need your approval and any suggestions on how it could be implemented better.

Context

Both Telegram and Vkontakte, as well as most popular messengers, support WebHooks.

I guess it could be easily done with aiohttp.

I'm okay with both English and Russian.

Use bot mention (example: "@bot_name") as default prefix

Now when bot only has access to messages with mentions (example: "@bot_name") it's also necessary to use prefix. In this case to execute command user should write something like:

  • @bot_name prefix command_name ("@bot_name / echo")
  • @bot_name prefixcommand_name ("@bot_name /echo")

VK Docs

Expected Behavior

"@bot_name echo" should work
"@bot_name, echo" should work too (mobile clients add a comma by default)

Actual Behavior

"@bot_name echo" and "@bot_name, echo" don't works (only "@bot_name / echo" or "@bot_name /echo")

Possible Solution

Context

Users try to execute the bot command with a mention, but they do not expect that you also need to specify the prefix

Идея

Добавить базу данных, не файловую, желательно peewee

Добавьте больше декораторов - модификаторов доступа

Когда разработчики разрабатывают плагины, они хотят видеть больше возможностей для разграничения доступа для различных пользователей. К примеру, разработчик пишет плагин для модерации мультичата (беседы). Ему необходимо ограничить доступ к командам, например к команде, которая банит участника. Было бы здорово не писать условие внутри функции, а просто импортировать готовый декоратор для нее. И декоратор, который проверяет, является ли отправитель (sender) администратором мультичата, этакий @plugin.is_chat_admin().

Ожидаемое поведение

Хотелось бы видеть следующие декораторы:

  • @is_solo() - является ли чат диалогом
  • @is_multi() - является ли чат мультичатом (беседой)
  • @is_owner() - является ли отправитель создателем бота
  • @is_chat_owner() - является ли отправитель создателем чата (да, если диалог)
  • @is_chat_admin() - является ли отправитель администратором чата (да, если диалог)
  • @is_backend(backend) - проверка бэкенда, через который пришло сообщение

Возможно удастся придумать их больше, но я столкнулся с необходимость иметь хотя-бы эти.

Текущее поведение

Приведенных выше декораторов не существует в Kutana.

Возможные решения

Нужно - всего-то - ничего, просто добавить эти декораторы в kutana.Plugin.

Контекст

Эти декораторы мне очень сильно понадобились, когда я писал своего бота. Пришлось писать их с нуля, потому что в моем боте есть очень много плагинов с разграничением доступа.

[Вопрос] Реализация проверки триггера определенного декоратора во всех плагинах.

Возник такой вопрос, каким образом можно реализовать проверку - когда хотя бы один из декораторов on_commands во всех плагинах стригерился. Но, при этом проверять это в декораторе у которого приоритет выше всех и срабатывает он в первую очередь, в нашем случае on_messages(priority=10). Подскажите правильный ход реализации данной конструкции. Спасибо :3

Ошибка при обработке update

2024-01-04 19:50:54,281 [ ERROR ] Task exception was never retrieved
future: <Task finished name='Task-4' coro=<Telegram.acquire_updates() done, defined at /root/kutana/kutana/backends/telegram.py:215> exception=KeyError('file_name')>
Traceback (most recent call last):
  File "/root/kutana/kutana/backends/telegram.py", line 229, in acquire_updates
    await queue.put((self._make_update(raw_update), self))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/kutana/kutana/backends/telegram.py", line 198, in _make_update
    attachments.append(self._make_attachment(raw_update["message"][kind], kind))
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/kutana/kutana/backends/telegram.py", line 147, in _make_attachment
    title=raw_attachment["file_name"],
          ~~~~~~~~~~~~~~^^^^^^^^^^^^^
KeyError: 'file_name'

a

a

Support for signals is not available on Windows

Expected Behavior

App need to start.

Actual Behavior

App shooting down with NotImplementedError in add_signal_handler (file > kutana.py > line(203) > (add_signal_handler)

Possible Solution

Make the correct exception handler in the event loop.

Steps to Reproduce (for bugs)

  1. Install all requirements
  2. Try to run runer.py
  3. We geting the NotImplementedError in add_signal_handler (file > kutana.py > line(203) > (add_signal_handler) will Windows no't support signals.

Context

Your Environment

  • Python vesion: 3.6
  • Kutana version: 4.1.3
  • Platform: Windows 10 x64 (1809)
  • Country: Turkey

Принцип работы плагинов

На сколько я понимаю, сейчас принцип работы ядра при выборе плагина примерно следующий - проходится по всем плагинам, пока не найдёт плагин с нужной командой, если нашёл - выполнил, если не нашёл - не выполнил ничего.

Expected Behavior

Как насчёт, такого варианта работы:

  1. Перед стартом регистрировать все имеющиеся плагины в отдельной моделе в созданной юзером БД(указывать в моделе название плагина + команды + ещё что-нибудь)
  2. При поступлении команды от юзера в ядро - обращаться к БД и искать там подходящую команду(при помощи LIKE/ILIKE всяких), ну а дальше действовать, как и сейчас - вначале вызывать те плагины, которые помечены для предварительного вызова, а потом уже тот, для которого пришла команда.

Actual Behavior

Я так понимаю, для этого потребуется немного переработать ядро.

Context

Столкнулся с проблемой, когда хотел для плагинов добавить просто свои декораторы, оказалось что перед тем как добраться до нужного плагина, вызываются все мои декораторы, которые находятся у предыдущих плагинов.
И, на сколько я знаю, подобный принцип регистрации плагинов в ядре присутствует у многих систем(в которых реализована модульность), к примеру Odoo.

P.S. Если в реализации потребуется помощь - готов заняться этим.

Спасибо.

Добавить дополнительную защиту от лимита в групповых чатах.

У телеграма существует лимит в 30 сообщений в секунду, но это действует на личные сообщения пользователям, так же есть и другой лимит, 20 сообщений в минуту в групповых чатах, и на каждый чат свой лимит, и бот довольно часто может упираться в него и в итоге сообщения попросту теряются. Было бы не плохо добавить и для него обход лимитов, в виде какой-нибудь очереди, и в случае превышения кол-ва в 20 штук за минуту пихать их туда а потом уже высчитать и отправить по новой когда таймер спадёт.

image

Упразднить и удалить части библиотеки, связанные с i18n

Упразднить и удалить части библиотеки, связанные с i18n. Реализация получается слишком специфичной, и поддержка этой части будет требовать много ресурсов. Простои использование gettext пользователями (и нами) должно закрыть проблему более адекватной и поддерживаемой не нами реализацией.

Создание инфраструктуры

Предупреждение: это не Feature Request! Можете считать это предложением по созданию платформы/фреймворка. Если это произойдет, я обязательно впишусь.

Обдумав ответы на 3 моих предыдущих issue, я пришел к очень интересному умозаключению, которое может положить начало новому проекту. Давайте по порядку.

Проект Kutana действительно может остаться собой, не потеряв при этом ничего. Однако, его всё еще мало для того, что хочет видеть народ. Я предлагаю начать разработку мощного фреймворка для построения self-hosted ботов. Давайте пока что, как эскиз, назовём его Katuna, в противовес Kutana.

Зачем?

Упростить разработку ботов, конечно же! И дать разработчикам обширный перечень инструментов для этого. В моей голове я это вижу, как аналог Red Discord Bot, только гораздо мощнее.

Архитектура

В плане архитектуры я вижу это, как реализацию Kutana. То есть, полу-готовый бот, который нужно лишь настроить и из коробки он будет обладать некоторым базовым функционалом, который я опишу в отдельном пункте. Но это будет не просто бот, как я уже говорил, он даст набор инструментов, не доступный в Kutana из коробки и более конкретную архитектуру плагинов для их стандартизации.

Базовый функционал

В качестве базового функционала я рассматриваю пока два краеугольных базовых плагина:
help - как понятно из названия, встроенный плагин справки. Этот плагин будет автоматически собирать из других загруженных плагинов справочную информацию, чтобы отдать её пользователю бота. Разработчикам сторонних плагинов нужно будет лишь рассказать, как оставить эту справочную информацию в командах их плагинов.
plugin - этот плагин и его команды будут отвечать за получение/обновление плагинов из репозитория. В качестве репозитория, Red (если грубо говоря) использует github-репозиторий, в котором хранится файл со ссылками на сторонние github-репозитории с плагинами. Сторонние разработчики смогут добавлять свои репозитории в этот файл с помощью пулл реквестов. Удобно, не правда ли? Для установки или обновления, этому плагину нужно будет просто использовать утилиту git и просто клонировать или обновлять локальные репозитории. Вкратце, так устроена дистрибуция плагинов в Red.

Что мы получим?

Прежде всего мы получим платформу для создания ботов. Прекрасный инструмент, который позволит создавать ботов и вовсе без навыков программирования. Буквально, ввел пару-тройку команд, настроил, запустил и мгновение спустя отдаешь боту команды на установку плагинов на свое усмотрение. Грубо говоря, собираешь своего бота, как конструктор. Могу привести аналогию: словно ты установил игру и не зная ни одного языка программирования, устанавливаешь в него различные моды.

Заключение

Если вам интересна эта идея, я обязательно в нее впишусь. Маякните мне, я дам данные для связи со мной.

Инкапсулируйте плагины в поддиректории

Почему это нужно? Опираясь на опыт Red (Discord bot), разделение плагинов над поддиректории поможет избежать путаницы, удобно дистрибутировать и распространять плагины, как это сделано в вышеприведенном фреймворке. Также в последствии можно будет создать репозиторий с плагинами.

Ожидаемое поведение

Я предлагаю сделать структуру плагинов такой: внутри папки plugins/ будут находиться подпапки, названные как плагины. Внутри каждой папки будет находится __init__.py, который будет создавать плагин, подпапка i18n с переводами для каждого конкретного плагина. Структура должна получится примерно такой:
image

Текущее поведение

Плагины расположены в виде файлов внутри папки plugins/, инкапсулированы на уровне файлов. Переводы слиты в один файл, что неудобно переводчикам и разработчикам.

Решение

Нужно просто немного изменить несколько функций внутри класса "Kutana", изменить то, как загружает переводы модуль i18n - и начало будет положено.

Контекст

В моей реализации бота я решил инкапсулировать плагины в поддиректории самостоятельно. Для это написал небольшую функцию:

def load_plugins_from_dir(bot: Kutana, directory="plugins") -> None:
    """Loads all plugins from subdirectories in current working directory's subdirectory using reflection"""

    path = Path.cwd() / directory

    if not path.exists():
        raise FileNotFoundError("Directory doesn't exist!")
    if not path.is_dir():
        raise NotADirectoryError("Path is not a directory!")

    for subdir in path.glob("*"):
        if subdir.is_dir():
            # from plugins.ping import plugins
            module = __import__(f"{directory}.{subdir.name}")
            plugin = getattr(module, subdir.name)
            plugin = getattr(plugin, "plugin")

            if isinstance(plugin, kutana.Plugin):
                bot.add_plugin(plugin)

[BUG] Перестает тригериться один из декораторов on_payloads

Для воспроивзедения потребуется создать 2 плагина, отдельным файлом друг от друга.
plugin_first.py:

import json
from kutana import Plugin


plugin = Plugin("kb2")

ac_name = "accept"
dc_name = "decline"

@plugin.vk.on_payloads([ac_name, dc_name])
@plugin.on_commands(["kb2"])
async def __(msg, ctx):

    if hasattr(ctx, "payload"):
        return await ctx.reply("TRIGGERED")

    await ctx.reply("hey", keyboard=json.dumps({
        "inline": True,
        "buttons": [
            [
                {
                    "action": {"type": "text", "payload": f"\"{ac_name}\"", "label": "✅ Принять"},
                    "color": "positive",
                },
                {
                    "action": {"type": "text", "payload": f"\"{dc_name}\"", "label": "❌ Отказать"},
                    "color": "negative",
                },
            ],
        ],
    }))

plugin_second.py:

import json
from kutana import Plugin


plugin = Plugin("kb")


@plugin.vk.on_payloads([{"kind": "1"}])
async def __(msg, ctx):
    await ctx.reply(f"Handler for kind (1), your meta is '{ctx.payload['meta']}'")


@plugin.vk.on_payloads([{"kind": "2"}])
async def __(msg, ctx):
    await ctx.reply(f"Handler for kind (2), your meta is '{ctx.payload['meta']}'")


@plugin.on_commands(["kb"])
async def __(msg, ctx):
    await ctx.reply("hey", keyboard=json.dumps({
        "one_time": True,
        "buttons": [
            [
                {"action": {
                        "type":"text",
                        "label": "kind=1, meta=2", "payload": "{\"kind\": \"1\", \"meta\": \"2\"}"
                }}
            ],
            [
                {"action": {
                        "type":"text",
                        "label": "kind=1, meta=4", "payload": "{\"kind\": \"1\", \"meta\": \"4\"}"
                }}
            ],
            [
                {"action": {
                        "type":"text",
                        "label": "kind=2, meta=4", "payload": "{\"kind\": \"1\", \"meta\": \"4\"}"
                }}
            ],
        ]
    }))

При использовании конструкции on_payloads в plugin_first, в следующем нашем plugin_second перестает срабатывать тригер @plugin.vk.on_payloads([{"kind": "1"}]) и @plugin.vk.on_payloads([{"kind": "2"}]) но если не использовать кострукцию из первого плагина, все срабатывает нормально.

[Вопрос] Ожидаемая кнопка

Приветствую, такой вопрос возник, к примеру у нас есть куча кнопок по типу u_1_2, u_0_6, u_9_1 и тд, такой вопрос, как можно вызвать vk.on_payload что бы он откликался на все кнопки которые начинаются допустим в нашем примере на u_?

Возможность добавлять описание аттачей при их загрузке (Telegram)

При выводе изображения иногда нужно и написать кое-что, но телеграм отправляет это отдельным сообщением, было бы гораздо удобнее если бы при загрузке аттачей была бы возможность указывать их описание - caption

К примеру:

from kutana import Attachment

with open("assets/pizza.png", "rb") as f:
    image = Attachment.new(f.read(), caption="А вот и твоя пицца!")

Это было бы очень удобно :3

Производительность httpx почти в 2 раза ниже чем aiohttp

Решил на проде всё же замерить скорость обработки запросов как аио так и httpx, делаем 500 запросов. Как итог, httpx справляется в 2 раза дольше нежели aiohttp. Когда бот разрастется это будет уже критично, но пока что не заметно на маленьких кол-вах запросов.

import asyncio
import time
import httpx
import aiohttp

httpx_client = httpx.AsyncClient()
aiohttp_client = aiohttp.ClientSession()

try:
    text = ""
    
    start_time = time.perf_counter()
    tasks = [httpx_client.get("https://daeeros.ru") for _ in range(500)]
    await asyncio.gather(*tasks)
    end_time = time.perf_counter()
    text += f"HTTPX: {end_time - start_time:.2f} seconds"

    start_time = time.perf_counter()
    tasks = [aiohttp_client.get("https://daeeros.ru") for _ in range(500)]
    await asyncio.gather(*tasks)
    end_time = time.perf_counter()
    text += f"AIOHTTP: {end_time - start_time:.2f} seconds"
finally:
    await aiohttp_client.close()
    await httpx_client.aclose()

print(text)

Итоговый резлуьтат теста:
image

Ошибка в Context.reply() при длинном (больше 4096) сообщении в vk

Actual Behavior

вылетает при вызове reply для vk, если сообщение для ответа больше, чем 4096

File "C:\Python38\lib\site-packages\kutana\context.py", line 137, in reply
return await self.send_message(
File "C:\Python38\lib\site-packages\kutana\context.py", line 158, in send_message
responses.append(await self.backend.perform_send(
File "C:\Python38\lib\site-packages\kutana\backends\vkontakte\backend.py", line 427, in perform_send
true_kwargs.update(kwargs)
TypeError: 'NoneType' object is not iterable

Possible Solution

    for part in parts[:-1]:
        responses.append(await self.backend.perform_send(
            target_id,
            part,
            (),
            None,
        ))

может быть, заменить None

Add the ability to trigger commands without a prefix

It would be convenient to add the is_prefix = False parameter to the usual on_commands decorator, after which it would be triggered on commands with or without a prefix, instead of crutches with on_messages

use:

#prefixes (".",)

@plugin.on_commands(["test"])

.test - work

test - not work

@plugin.on_commands(["test"], is_prefix=False)

.test - work

test - work

[Вопрос] Не делать ожидание в некоторых плагинах.

У нас есть такой плагин рассылки, но при его работе все остальные пользователи так же ждут пока он завершится, тк как бот не будет обрабатывать их учитывая что он асинхронный, подскажите как можно не делать ожидание завершения в некоторых плагинах и сразу же давать возможность боту обрабатывать следующие сообщения/плагины?

from kutana import Plugin, RequestException


plugin = Plugin()

@plugin.on_commands(["test"])
async def __(msg, ctx):

    await ctx.reply("Начинаю рассылку.")

    members = []
    offset = 1000

    data = await ctx.request("groups.getMembers", sort="time_asc", group_id="1")
    members += data['items']

    steps = int(data['count'] / 1000)

    for _ in range(steps):
        data = await ctx.request("groups.getMembers", sort="time_asc", group_id="1", offset=offset)
        members += data['items']
        offset += 1000

    sended = 0
    for u in members:
        try:
            await ctx.send_message(u, text="У нас тут новая запись!", attachment="wall-1_1")
            sended += 1
        except RequestException:
            continue

    return await ctx.reply("Рассылка завершена! Всего отправлено: {}".format(sended))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.