Как добавить меню в Телеграмм бота

Многоуровневое меню в Telegram bot на Python позволяет пользователям взаимодействовать с ботом через древовидную структуру интерфейса. Для его создания используются inline-кнопки. Inline-кнопки позволяют разместить несколько кнопок в одной строке, в отличие от обычных кнопок, которые устанавливаются под сообщением.

Для создания многоуровневого меню в Telegram bot на Python нужно использовать обработчики CallbackQueryHandler и dict. CallbackQueryHandler вызывается, когда пользователь нажимает на inline-кнопку. Dict использует ключи, чтобы создавать дерево меню: каждый уровень меню обрабатывает каждый ключ как кнопку. Когда пользователь нажимает на кнопку, CallbackQueryHandler возвращает ключ.

Для примера создадим меню, которое имеет два уровня и три кнопки в каждом уровне: Кнопка 1, Кнопка 2 и Кнопка 3.

from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup

data = ‘1’: [‘Кнопка 1’, ‘Кнопка 2’, ‘Кнопка 3’],

Как сделать меню в боте Телеграм | Меню с кнопками в Телеграм


‘2’: [‘Кнопка 1’, ‘Кнопка 2’, ‘Кнопка 3’]
>

def start(update, context):
keyboard = []
for key in data.keys():
keyboard.append([InlineKeyboardButton(key, callback_data=key)])
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text(‘Выберите уровень:’, reply_markup=reply_markup)

def level_one(update, context):
query = update.callback_query
keyboard = []
for button_text in data[query.data]:
keyboard.append([InlineKeyboardButton(button_text, callback_data=button_text)])
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text(‘Выберите кнопку 2 уровня:’, reply_markup=reply_markup)

def level_two(update, context):
query = update.callback_query
query.edit_message_text(‘Вы выбрали кнопку <> уровня’.format(query.data))

def main():
updater = Updater(‘TOKEN’, use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler(‘start’, start))
dp.add_handler(CallbackQueryHandler(level_one))
dp.add_handler(CallbackQueryHandler(level_two))
updater.start_polling()
updater.idle()

if __name__ == ‘__main__’:
main()

Наше меню имеет два уровня, ключи для первого уровня — ‘1’ и ‘2’. Для каждого из этих ключей определены три кнопки для второго уровня. При выборе первого уровня, пользователь получает серию кнопок второго уровня. Когда пользователь выбирает кнопку второго уровня, бот отвечает сообщением о выборе кнопки и возвращает пользователя назад к первому уровню.

Как настроить кнопки и сделать многоуровневое меню

Как сделать меню для Телеграм Бота на Python

Как сделать меню для Телеграм Бота

Telegram бот на python — курс по созданию бота по документации aiogram и Telegram API

Многоуровневая клавиатура как у BotFather в Телеграм для чат бота — multi-level inline keyboard

Телеграм бот: многоуровневое меню, отправка аудиофайла.

BLGPG-3E4E2EFD7F56-23-10-02-05

Новые материалы:

  • Python голосование по большинству
  • Flask наследование шаблонов
  • Медиана в numpy
  • Хахаев практикум по алгоритмизации и программированию на python
  • Как запустить python на mac os
  • Java или python
  • Python selenium обход капчи
  • Как проверить установлен ли pip python 3
  • Info метод python
  • Макграт майк python программирование для начинающих
  • Python сортировка списка словарей
  • Python метод apply
  • Документирование python кода

Источник: pygame.ru

Создание бота в мессенджере Telegram

как сделать бота в телеграмм

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

Как сделать бота в Телеграмм_048

    Откройте мессенджер и либо воспользуйтесь представленной выше ссылкой, либо введите название бота в поисковую строку и откройте чат с ним. Нажмите на кнопку «Запустить».
  • Отправьте указанную ниже команду: /start Как сделать бота в Телеграмм_050
  • Затем либо введите и отправьте вручную, либо выберите в полученном сообщении следующее: /newbot Как сделать бота в Телеграмм_051
  • Придумайте имя (название) для своего бота, введите и отправьте его. В дальнейшем это можно будет изменить. Как сделать бота в Телеграмм_052
  • Теперь придумайте имя пользователя для бота, которое одновременно будет и ссылкой на него. Этот адрес обязательно должен быть уникальным (свободным) и заканчиваться на «_bot». Как сделать бота в Телеграмм_053
  • В ответ вы получите сообщение, содержащее рабочую ссылку на пока еще пустого, ненастроенного бота и токен, который будет использоваться для доступа к HTTP API. Обязательно сохраните его в безопасном месте, так как любой, кто получит доступ к этим данным, сможет управлять вашим ботом. Как сделать бота в Телеграмм_054
  • Шаг 2: Настройка

    Обратите внимание! Данный шаг инструкции подразумевает, что у вас уже есть как минимум основная идея для бота и общее представление о том, как он будет выглядеть и работать. О создании его «внутренней», программной части, будет рассказано в следующем шаге, а потому вы вполне можете начать с разработки и только после этого перейти к настройке.

    Как сделать бота в Телеграмм_066

    Как сделать бота в Телеграмм_067

    КомандаОписание
    /setname Изменение отображаемого имени бота
    /setdescription Добавление описания
    /setuserpic Смена аватара
    /setcommands Установка и редактирование перечня команд, на которые бот должен реагировать
    /deletebot Удаление добавленного бота

    Как сделать бота в Телеграмм_068

  • Помимо указанных выше команд, в меню главного бота Телеграм имеются и другие – с их помощью можно интегрировать в свой проект веб-приложения и игры, изменять многие другие параметры и т.д. (напротив каждого пункта имеется описание на английском). Как сделать бота в Телеграмм_069Рассмотрение каждого из них отдельно существенно усложнит инструкцию, а для многих сделает ее излишне подробной, поэтому данную часть настройки по необходимости можете освоить самостоятельно. Мы же представим ниже еще несколько важных команд и перейдем к следующему шагу.
    КомандаОписание
    /token Создание нового токена или замена старого, если оригинальный скомпрометирован
    /setinline Включение inline-режима, при котором бот будет реагировать на соответствующие команды во всех чатах, куда он добавлен
    /setinlinefeedback Ответ на ввод отображением заданных вариантов (показом сообщения-шаблона, изображения, кнопки и т. д.)
    /setprivacy Активация приватного режима, при котором бот будет распознавать исключительно команды и адресованные ему сообщения
    Еще по теме:  Как сделать твинк в Телеграм на один номер
  • Шаг 3: Разработка

    Наиболее важный и, наверное, сложный, если говорить о малоопытных пользователях, этап в создании собственного Telegram-бота – его непосредственная разработка. В примере далее нами будет использоваться Python.

    Примечание: pyTelegramBotAPI – библиотека, необходимая для обеспечения работы Telegram-бота, но это не единственное такого рода решение. В качестве альтернативы можете использовать telegram-bot – соответствующая команда для установки указана ниже. По этой библиотеке можно найти довольно много инструкций в интернете, но в нашем случае она работала некорректно.

    pip install python-telegram-bot

    Как сделать бота в Телеграмм_076

    Откройте редактор кода и сделайте следующее:

      Прежде всего импортируйте в него установленную на предыдущем шаге библиотеку. В случае с pyTelegramBotAPI запрос должен выглядеть следующим образом: import telebot

    Обратите внимание! Описанное выше, — это обязательная «основа» для будущего бота. Далее – пример простейшего кода команды запуска и ответа с пояснениями, в вашем случае это может и наверняка будет отличаться, так как зависит исключительно от поставленной задачи.

    Пояснение: Это декоратор для функции send_welcome, который указывает, что она должна выполняться в случае, если пользователь отправляет команду /start. Когда это происходит, бот отвечает приветственным сообщением с текстом «Привет! Я простой бот, рад познакомиться!».

    Пояснение: Этот обработчик, обозначенный декоратором echo_message, будет вызываться для всех текстовых сообщений, которые отправляют пользователи. Когда бот получает текстовое сообщение, он просто повторяет это сообщение обратно отправителю с помощью функции bot.reply_to().

    Как сделать бота в Телеграмм_083

    Завершающая команда – запуск бота: if __name__ == «__main__»:
    bot.polling()

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

    Как сделать бота в Телеграмм_084

  • Сохраните проект Телеграм-бота в удобном месте на диске ПК (проследите, чтобы в его названии и на пути к нему не содержалось кириллических символов), в формате .py (в нашем случае, так как использовался Python).
  • Шаг 4: Запуск и использование

    Для того чтобы бот работал и был доступен к использованию в Telegram, его необходимо запустить. Сделать это можно с помощью любого варианта системной консоли, будь то «Командная строка», «PowerShell» или «Терминал».

      Перейдите в папку с проектом вашего бота, зажмите клавишу «Shift» на клавиатуре, не отпуская ее, кликните правой кнопкой мышки (ПКМ) в пустой области и, далее, в зависимости от версии используемой операционной системы (в нашем примере – Windows 11) и/или ваших собственных пожеланий, выберите предпочтительный вариант консоли в контекстном меню.

    Как сделать бота в Телеграмм_085
    Введите команду следующего вида и нажмите «Enter»: python your_telegram_bot.py Как сделать бота в Телеграмм_086‘your_telegram_bot’ – название вашего бота, присвоенное ему при сохранении на последнем шаге предыдущей инструкции. Как сделать бота в Телеграмм_087

    Примечание: Вместо выполнения двух предыдущих шагов вы можете самостоятельно запустить консоль, перейти из нее в папку с проектом и выполнить его запуск. Для этого поочередно введите и выполните следующие команды: cd путь_к_папке_с_проектом
    python your_telegram_bot.py

    Как сделать бота в Телеграмм_088

  • Перейдите в Телеграм и проверьте работоспособность своего проекта. Как сделать бота в Телеграмм_089
  • Бот будет работать и даже станет доступным для других пользователей мессенджера, но только тогда, когда он запущен в консоли. Как сделать бота в Телеграмм_090Для остановки достаточно воспользоваться клавишами «Ctrl+C» или просто закрыть окно, для повторного запуска – выполнить действия из двух первых пунктов текущей инструкции. Как сделать бота в Телеграмм_093
  • Шаг 5: Хостинг

    Для того чтобы Telegram-бот работал постоянно, даже когда ваш компьютер выключен и/или проект не запущен в консоли, его необходимо разместить на хостинге. Это не самая сложная задача, но и откровенно простой ее назвать нельзя. Причем важно отметить, что сделать это бесплатно на сегодняшний день не получится, по крайней мере, если не рассматривать ограниченные по времени и/или функциональности решения. А с учетом того, что использование и настройка в каждом отдельном случае существенно отличается (это может делаться на веб-сайте, в десктопной программе или консоли), предоставить универсальную инструкцию не получиться.

    Как сделать бота в Телеграмм_091

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

    хостинг телеграм бот

    Как сделать бота в Телеграмм_092

    Способ 2: Специализированный сервис

    Альтернативой решению от Telegram и последующей самостоятельной разработке будет один из сторонних сервисов, который позволяет как создавать ботов, так и добавлять к ним дополнительную функциональность, причём последнее не требует навыков программирования. Одним из самых удобных решений такого рода является проект Manybot, которым мы и воспользуемся.

    как сделать бота в телеграмм-11

    1. Воспользуйтесь ссылкой выше, а после загрузки страницы нажмите на кнопку «Создать бота».
    2. Далее кликните «Открыть Manybot в Telegram».

    Важно! Этот сервис работает только с клиентским приложением, веб-версия не поддерживается!

    Источник: lumpics.ru

    Кнопки Aiogram

    Этот вид кнопок появился вместе с Bot API в далёком 2015 году и представляет собой не что иное, как шаблоны сообщений (за исключением нескольких особых случаев, но о них позже). Принцип простой: что написано на кнопке, то и будет отправлено в текущий чат. Соответственно, чтобы обработать нажатие такой кнопки, бот должен распознавать входящие текстовые сообщения.

    Напишем хэндлер, который будет при нажатии на команду /start отправлять сообщение с двумя кнопками:

    Несмотря на то, что Telegram Bot API допускает указывать просто строки вместо объектов KeyboardButton , при попытке использовать строку aiogram 3.x выкинет ошибку валидации и это не баг, а фича.
    Живите теперь с этим

    Еще по теме:  Как восстановить контакты через Телеграмм

    Что ж, запустим бота и обалдеем от громадных кнопок:

    Очень большие обычные кнопки

    Как-то некрасиво. Во-первых, хочется сделать кнопки поменьше, а во-вторых, расположить их горизонтально.
    Почему вообще они такие большие? Дело в том, что по умолчанию «кнопочная» клавиатура должна занимать на смартфонах столько же места, сколько и обычная буквенная. Для уменьшения кнопок к объекту клавиатуры надо указать дополнительный параметр resize_keyboard=True .
    Но как заменить вертикальные кнопки на горизонтальные? С точки зрения Bot API, клавиатура — это массив массивов кнопок, а если говорить проще, массив рядов. Перепишем наш код, чтобы было красиво, а для пущей важности добавим параметр input_field_placeholder , который заменит текст в пустой строке ввода, когда активна обычная клавиатура:

    Смотрим — действительно красиво:

    Кнопки в один ряд

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

    Реакция на нажатие кнопок

    Чтобы удалить кнопки, необходимо отправить новое сообщение со специальной «удаляющей» клавиатурой типа ReplyKeyboardRemove . Например: await message.reply(«Отличный выбор!», reply_markup=types.ReplyKeyboardRemove())

    Keyboard Builder

    Для более динамической генерации кнопок можно воспользоваться сборщиком клавиатур. Нам пригодятся следующие методы:

    • add() — добавляет кнопку в память сборщика;
    • adjust(int1, int2, int3. ) — делает строки по int1, int2, int3. кнопок;
    • as_markup() — возвращает готовый объект клавиатуры;
    • button() — добавляет кнопку с заданными параметрами, тип кнопки (Reply или Inline) определяется автоматически.

    Создадим пронумерованную клавиатуру размером 4×4:

    Результат работы сборщика кнопок

    У объекта обычной клавиатуры есть ещё две полезных опции: one_time_keyboard для автоматического скрытия кнопок после нажатия и selective для показа клавиатуры лишь некоторым участникам группы. Их использование остаётся для самостоятельного изучения.

    Специальные обычные кнопки

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

    • отправки текущей геолокации (флаг request_location );
    • отправки своего контакта с номером телефона (флаг request_contact );
    • создания опроса/викторины (объект KeyboardButtonPollType).

    Для первых двух типов достаточно установить булевый флаг, а для опросов и викторин нужно передать специальный тип KeyboardButtonPollType и, по желанию, указать тип создаваемого объекта.

    Впрочем, проще один раз увидеть код:

    Специальные обычные кнопки

    Инлайн-кнопки

    URL-кнопки¶

    В отличие от обычных кнопок, инлайновые цепляются не к низу экрана, а к сообщению, с которым были отправлены. В этой главе мы рассмотрим два типа таких кнопок: URL и Callback. Ещё один — Switch — будет рассмотрен в главе про инлайн-режим.

    Login- и Pay-кнопки в книге рассматриваться не будут вообще. Если у кого-то есть желание помочь хотя бы с рабочим кодом для авторизации или оплаты, пожалуйста, создайте Pull Request на GitHub. Спасибо!

    Самые простые инлайн-кнопки относятся к типу URL, т.е. «ссылка». Поддерживаются только протоколы HTTP(S) и tg://

    Отдельно остановимся на среднем блоке кода. Дело в том, что в марте 2019 года разработчики Telegram добавили возможность отключать переход к профилю пользователя у пересланного сообщения. При попытке создать URL-кнопку с ID юзера, у которого отключен переход по форварду, бот получит ошибку Bad Request: BUTTON_USER_PRIVACY_RESTRICTED . Соответственно, прежде чем показывать такую кнопку, необходимо выяснить состояние упомянутой настройки. Для этого можно вызвать метод getChat и в ответе проверить состояние поля has_private_forwards . Если оно равно True , значит, попытка добавить URL-ID кнопку приведёт к ошибке.

    Колбэки

    Напишем хэндлер, который по команде /random будет отправлять сообщение с колбэк-кнопкой:

    Но как же обработать нажатие? Если раньше мы использовали хэндлер на message для обработки входящих сообщений, то теперь будем использовать хэндлер на callback_query для обработки колбэков. Ориентироваться будем на «значение» кнопки, т.е. на её data:

    Несмотря на то, что параметр кнопки callback_data , а значение data лежит в одноимённом поле data объекта CallbackQuery, собственный фильтр aiogram называется text .

    Реакция на нажатие колбэк-кнопки

    Ой, а что это за часики? Оказывается, сервер Telegram ждёт от нас подтверждения о доставке колбэка, иначе в течение 30 секунд будет показывать специальную иконку. Чтобы скрыть часики, нужно вызвать метод answer() у колбэка (или использовать метод API answer_callback_query() ). В общем случае, в метод answer() можно ничего не передавать, но можно вызвать специальное окошко (всплывающее сверху или поверх экрана):

    Всплывающее окно при нажатии на колбэк-кнопку

    В функции send_random_value мы вызывали метод answer() не у message , а у callback.message . Это связано с тем, что колбэк-хэндлеры работают не с сообщениями (тип Message), а с колбэками (тип CallbackQuery), у которого другие поля, и само сообщение — всего лишь его часть. Учтите также, что message — это сообщение, к которому была прицеплена кнопка (т.е. отправитель такого сообщения — сам бот). Если хотите узнать, кто нажал на кнопку, смотрите поле from (в вашем коде это будет callback.from_user , т.к. слово from зарезервировано в Python)

    Когда вызывать answer() ?

    В общем случае, главное — просто не забыть сообщить Telegram о получении колбэк-запроса, но я рекомендую ставить вызов answer() в самом конце, и вот почему: если вдруг в процессе обработки колбэка случится какая-то ошибка и бот нарвётся на необработанное исключение, пользователь увидит неубирающиеся полминуты часики и поймёт, что что-то не так. В противном случае, часики исчезнут, а пользователь останется в неведении, выполнился его запрос успешно или нет.

    Еще по теме:  Метод оплаты payeer в Телеграмм

    Перейдём к примеру посложнее. Пусть пользователю предлагается сообщение с числом 0, а внизу три кнопки: +1, -1 и Подтвердить. Первыми двумя он может редактировать число, а последняя удаляет всю клавиатуру, фиксируя изменения. Хранить значения будем в памяти в словаре (про конечные автоматы поговорим как-нибудь в другой раз).

    И, казалось бы, всё работает:

    Всё работает?

    Но теперь представим, что ушлый пользователь сделал следующее: вызвал команду /numbers (значение 0), увеличил значение до 1, снова вызвал /numbers (значение сбросилось до 0) и отредактировал и нажал кнопку “+1” на первом сообщении. Что произойдёт? Бот по-честному отправит запрос на редактирование текста со значением 1, но т.к. на том сообщении уже стоит цифра 1, то Bot API вернёт ошибку, что старый и новый тексты совпадают, а бот словит исключение: Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message

    Всё работает?

    С этой ошибкой вы, скорее всего, будете поначалу часто сталкиваться, пытаясь редактировать сообщения. Вообще говоря, подобная ошибка часто говорит о проблемах с логикой генерации/обновления данных в сообщении, но иногда, как в примере выше, может быть ожидаемым поведением.

    В данном случае проигнорируем ошибку целиком, т.к. нам важен лишь итоговый результат, который точно будет правильным. Ошибка MessageNotModified относится к категории Bad Request, поэтому у нас есть выбор: проигнорировать весь подобный класс ошибок, либо отловить весь класс BadRequest и попытаться по тексту ошибки опознать конкретную причину. Чтобы не слишком усложнять пример, обойдёмся первым способом и немного обновим функцию update_num_text() :

    # Новые импорты! from contextlib import suppress from aiogram.exceptions import TelegramBadRequest async def update_num_text(message: types.Message, new_value: int): with suppress(TelegramBadRequest): await message.edit_text( f»Укажите число: «, reply_markup=get_keyboard() )

    Если теперь вы попробуете повторить пример выше, то указанное исключение в этом блоке кода бот просто-напросто проигнорирует.

    Фабрика колбэков

    Когда вы оперируете какими-то простыми колбэками с общим префиксом, типа order_1 , order_2 … вам может показаться, что довольно легко вызывать split() и делить строку по какому-то разделителю. А теперь представьте, что вам нужно хранить не одно значение, а три: order_1_1994_2731519 . Что здесь артикул, цена, количество? А может быть, тут вообще год выпуска? Да и разбиение строки начинает выглядеть страшно: .split(«_»)[2] . А почему не 1 или 3?

    В какой-то момент возникает необходимость структурировать содержимое таких callback data, и в aiogram есть решение! Вы создаёте объекты типа CallbackData , указываете префикс, описываете структуру, а дальше фреймворк самостоятельно собирает строку с данными колбэка и, что важнее, корректно разбирает входящее значение. Снова разберёмся на конкретном примере; создадим класс NumbersCallbackFactory с префиксом fabnum и двумя полями action и value . Поле action определяет, что делать, менять значение (change) или зафиксировать (finish), а поле value показывает, на сколько изменять значение. Оно помечено как Optional[int] , т.к. если action равен “finish”, то значение указывать бессмысленно. Код:

    # новые импорты! from typing import Optional from aiogram.dispatcher.filters.callback_data import CallbackData class NumbersCallbackFactory(CallbackData, prefix=»fabnum»): action: str value: Optional[int]

    Наш класс обязательно должен наследоваться от CallbackData и принимать значение префикса. Префикс — это общая подстрока в начале, по которой фреймворк будет определять, какая структура лежит в колбэке.

    Теперь напишем функцию генерации клавиатуры. Здесь нам пригодится метод button() , который автоматически будет создавать кнопку с нужным типом, а от нас требуется только передать аргументы. В качестве аргумента callback_data вместо строки будем указывать экземпляр нашего класса NumbersCallbackFactory :

    def get_keyboard_fab(): builder = InlineKeyboardBuilder() builder.button( text=»-2″, callback_data=NumbersCallbackFactory(action=»change», value=-2) ) builder.button( text=»-1″, callback_data=NumbersCallbackFactory(action=»change», value=-1) ) builder.button( text=»+1″, callback_data=NumbersCallbackFactory(action=»change», value=1) ) builder.button( text=»+2″, callback_data=NumbersCallbackFactory(action=»change», value=2) ) builder.button( text=»Подтвердить», callback_data=NumbersCallbackFactory(action=»finish») ) # Выравниваем кнопки по 4 в ряд, чтобы получилось 4 + 1 builder.adjust(4) return builder.as_markup()

    Методы отправки сообщения и его редактирования оставляем теми же (в названиях и командах добавим суффикс _fab ):

    Наконец, переходим к главному — обработке колбэков. Для этого в декоратор надо передать класс, колбэки с которым мы ловим, с вызванным методом filter() . Также появляется дополнительный аргумент с названием callback_data (имя должно быть именно таким!), и имеющим тот же тип, что и фильтруемый класс:

    Ещё немного конкретизируем наши хэндлеры и сделаем отдельный обработчик для числовых кнопок и для кнопки «Подтвердить». Фильтровать будем по значению action и в этом нам помогут «магические фильтры» aiogram 3.x. Серьёзно, они так и называются: Magic Filter. Подробнее сие чародейство рассмотрим в другой главе, а сейчас просто воспользуемся «магией» и примем это на веру:

    Фабрика колбэков

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

    Источник: aiogram.ru

    Рейтинг
    ( Пока оценок нет )
    Загрузка ...