commands, deeplinks, link_preview

This commit is contained in:
vasilytray 2025-03-10 22:13:15 +07:00
parent 5f587980e1
commit 046c47cd68
3 changed files with 229 additions and 7 deletions

132
README.md
View File

@ -251,3 +251,135 @@ async def extract_data(message: Message):
f"Пароль: {html.quote(data['code'])}" f"Пароль: {html.quote(data['code'])}"
) )
``` ```
#### Команды и их аргументы
В составе aiogram есть фильтр Command(), упрощающий жизнь разработчика.
Реализуем последний пример в коде:
```py
@dp.message(Command("settimer", prefix="/!")) # добавим дополнительные префиксы для оперделения команды
async def cmd_settimer(
message: Message,
command: CommandObject
):
# Если не переданы никакие аргументы, то
# command.args будет None
if command.args is None:
await message.answer(
"Ошибка: не переданы аргументы"
)
return
# Пробуем разделить аргументы на две части по первому встречному пробелу
try:
delay_time, text_to_send = command.args.split(" ", maxsplit=1)
# Если получилось меньше двух частей, вылетит ValueError
except ValueError:
await message.answer(
"Ошибка: неправильный формат команды. Пример:\n"
"/settimer <time> <message>"
)
return
await message.answer(
"Таймер добавлен!\n"
f"Время: {delay_time}\n"
f"Текст: {text_to_send}"
)
```
Проблема кастомных префиксов в группах только в том, что боты не-админы со включенным Privacy Mode (по умолчанию) могут не увидеть такие команды из-за особенностей логики сервера.
Самый частый use-case — боты-модераторы групп, которые уже являются администраторами.
#### Диплинки
Существует одна команда в **Telegram**, у которой есть чуть больше возможностей. Это **/start**. Дело в том, что можно сформировать ссылку вида t.me/bot?start=xxx и пре переходе по такой ссылке пользователю покажут кнопку «Начать», при нажатии которой бот получит сообщение **/start xxx**.
Учтите, что диплинки через start отправляют пользователя в личку с ботом. Чтобы выбрать группу и отправить диплинк туда, замените start на startgroup. Также у aiogram существует удобная функция для создания диплинков прямо из вашего кода.
Первый дииплинк https://t.me/your_bot?start=help выведет сообщение, соответсвующее команде /help
Второй диплиинк https://t.me/your_bot?start=book_2 выведет соответствующее
сообщение, полученное из регулярного выражения
```
Sending book №2
```
*Больше диплинков, но не для ботов:*
В документации **Telegram** есть подробное описание всевозможных диплинков для клиентских приложений: https://core.telegram.org/api/links
#### Предпросмотр ссылок
Обычно при отправке текстового сообщения со ссылками **Telegram** пытается найти и показать предпросмотр первой по порядку ссылки. Это поведение можно настроить по своему желанию, передав в качестве аргумента **link_preview_options** метода **send_message()** объект L**inkPreviewOptions**
```py
# Новый импорт
from aiogram.types import LinkPreviewOptions
@dp.message(Command("links"))
async def cmd_links(message: Message):
links_text = (
"https://nplus1.ru/news/2024/05/23/voyager-1-science-data"
"\n"
"https://t.me/telegram"
)
# Ссылка отключена
options_1 = LinkPreviewOptions(is_disabled=True)
await message.answer(
f"Нет превью ссылок\n{links_text}",
link_preview_options=options_1
)
# -------------------- #
# Маленькое превью
# Для использования prefer_small_media обязательно указывать ещё и url
options_2 = LinkPreviewOptions(
url="https://nplus1.ru/news/2024/05/23/voyager-1-science-data",
prefer_small_media=True
)
await message.answer(
f"Маленькое превью\n{links_text}",
link_preview_options=options_2
)
# -------------------- #
# Большое превью
# Для использования prefer_large_media обязательно указывать ещё и url
options_3 = LinkPreviewOptions(
url="https://nplus1.ru/news/2024/05/23/voyager-1-science-data",
prefer_large_media=True
)
await message.answer(
f"Большое превью\n{links_text}",
link_preview_options=options_3
)
# -------------------- #
# Можно сочетать: маленькое превью и расположение над текстом
options_4 = LinkPreviewOptions(
url="https://nplus1.ru/news/2024/05/23/voyager-1-science-data",
prefer_small_media=True,
show_above_text=True
)
await message.answer(
f"Маленькое превью над текстом\n{links_text}",
link_preview_options=options_4
)
# -------------------- #
# Можно выбрать, какая ссылка будет использоваться для предпосмотра,
options_5 = LinkPreviewOptions(
url="https://t.me/telegram"
)
await message.answer(
f"Предпросмотр не первой ссылки\n{links_text}",
link_preview_options=options_5
)
```
Также некоторые параметры предпросмотра можно указать по умолчанию в DefaultBotProperties

42
bot.py
View File

@ -5,13 +5,15 @@ from datetime import datetime
from aiogram import Bot, Dispatcher, types from aiogram import Bot, Dispatcher, types
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.enums.dice_emoji import DiceEmoji from aiogram.enums.dice_emoji import DiceEmoji
from aiogram import F, html from aiogram import F, html
from aiogram.types import Message from aiogram.types import Message
from aiogram.filters import Command from aiogram.filters import Command, CommandObject
from aiogram.utils.formatting import Text, Bold, as_list, as_marked_section, as_key_value, HashTag from aiogram.utils.formatting import Text, Bold, as_list, as_marked_section, as_key_value, HashTag
from aiogram.enums import ParseMode
from aiogram.client.default import DefaultBotProperties
from config_reader import config from config_reader import config
# Включаем логирование, чтобы не пропустить важные сообщения # Включаем логирование, чтобы не пропустить важные сообщения
@ -84,9 +86,9 @@ async def cmd_more(message: types.Message):
"адрес сайта,", "адрес сайта,",
"e-mail,", "e-mail,",
"Номер телефона,", "Номер телефона,",
"Какой нибудь код или пароль", "Я распознаю их и напишу что нашел",
"Я распознаю из и напишу что нашел",
"/dice - Подкину для тебя кубик, загадай число ;)", "/dice - Подкину для тебя кубик, загадай число ;)",
"/settime <time> <message> - через установленное время сообще Message ;)",
marker="", marker="",
), ),
HashTag("#еще"), HashTag("#еще"),
@ -185,7 +187,7 @@ async def echo_with_time(message: Message):
await message.answer(f"{message.html_text}\n\n{not_anderstand}!!! Я не понимаю эту команду :(\nДля получения списка известных мне команд напиши /start \n{added_text}", parse_mode="HTML") await message.answer(f"{message.html_text}\n\n{not_anderstand}!!! Я не понимаю эту команду :(\nДля получения списка известных мне команд напиши /start \n{added_text}", parse_mode="HTML")
# Извлекаем из сообщений пользователя данные url, email, телефон и код # Извлекаем из сообщений пользователя данные url, email, телефон и код
@dp.message(F.text) #@dp.message(F.text)
async def extract_data(message: Message): async def extract_data(message: Message):
data = { data = {
"url": "<N/A>", "url": "<N/A>",
@ -208,6 +210,34 @@ async def extract_data(message: Message):
# f"Пароль: {html.quote(data['code'])}" # f"Пароль: {html.quote(data['code'])}"
) )
@dp.message(Command("settimer", prefix="/!")) # добавим дополнительные префиксы для оперделения команды
async def cmd_settimer(
message: Message,
command: CommandObject
):
# Если не переданы никакие аргументы, то
# command.args будет None
if command.args is None:
await message.answer(
"Ошибка: не переданы аргументы"
)
return
# Пробуем разделить аргументы на две части по первому встречному пробелу
try:
delay_time, text_to_send = command.args.split(" ", maxsplit=1)
# Если получилось меньше двух частей, вылетит ValueError
except ValueError:
await message.answer(
"Ошибка: неправильный формат команды. Пример:\n"
"/settimer <time> <message>"
)
return
await message.answer(
"Таймер добавлен!\n"
f"Время: {delay_time}\n"
f"Текст: {text_to_send}"
)
# Запуск процесса поллинга новых апдейтов # Запуск процесса поллинга новых апдейтов
async def main(): async def main():
# Регистрируем хэндлер cmd_test2 по команде /start # Регистрируем хэндлер cmd_test2 по команде /start

60
bot2.py Normal file
View File

@ -0,0 +1,60 @@
import re
import asyncio
import logging
from datetime import datetime
from aiogram import F
from aiogram.types import Message
from aiogram.filters import Command, CommandObject, CommandStart
from aiogram import Bot, Dispatcher, types
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from config_reader import config
# Включаем логирование, чтобы не пропустить важные сообщения
logging.basicConfig(level=logging.INFO)
# Для записей с типом Secret* необходимо
# вызывать метод get_secret_value(),
# чтобы получить настоящее содержимое вместо '*******'
bot = Bot(
token=config.bot_token.get_secret_value(),
default=DefaultBotProperties(
parse_mode=ParseMode.HTML
# тут ещё много других интересных настроек
))
# Объект бота напрямую из .env
# bot = Bot(token=os.getenv("BOT_TOKEN"))
# Диспетчер
dp = Dispatcher()
dp["started_at"] = datetime.now().strftime("%Y-%m-%d %H:%M")
@dp.message(Command("help"))
@dp.message(CommandStart(
deep_link=True, magic=F.args == "help"
))
async def cmd_start_help(message: Message):
await message.answer("Это сообщение со справкой")
@dp.message(CommandStart(
deep_link=True,
magic=F.args.regexp(re.compile(r'book_(\d+)'))
))
async def cmd_start_book(
message: Message,
command: CommandObject
):
book_number = command.args.split("_")[1]
await message.answer(f"Sending book №{book_number}")
# Запуск процесса поллинга новых апдейтов
async def main():
# Регистрируем хэндлер cmd_test2 по команде /start
# Запускаем бота
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())