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

134
README.md
View File

@ -250,4 +250,136 @@ async def extract_data(message: Message):
f"E-mail: {html.quote(data['email'])}\n"
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.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.enums.dice_emoji import DiceEmoji
from aiogram import F, html
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.enums import ParseMode
from aiogram.client.default import DefaultBotProperties
from config_reader import config
# Включаем логирование, чтобы не пропустить важные сообщения
@ -84,9 +86,9 @@ async def cmd_more(message: types.Message):
"адрес сайта,",
"e-mail,",
"Номер телефона,",
"Какой нибудь код или пароль",
"Я распознаю из и напишу что нашел",
"Я распознаю их и напишу что нашел",
"/dice - Подкину для тебя кубик, загадай число ;)",
"/settime <time> <message> - через установленное время сообще Message ;)",
marker="",
),
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")
# Извлекаем из сообщений пользователя данные url, email, телефон и код
@dp.message(F.text)
#@dp.message(F.text)
async def extract_data(message: Message):
data = {
"url": "<N/A>",
@ -208,6 +210,34 @@ async def extract_data(message: Message):
# 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():
# Регистрируем хэндлер 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())