Версия 1.0
This commit is contained in:
179
BotCode/handlers/inline.py
Normal file
179
BotCode/handlers/inline.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# BotCode/handlers/inline.py
|
||||
from aiogram import Router
|
||||
from aiogram.types import (
|
||||
InlineKeyboardButton,
|
||||
InlineKeyboardMarkup,
|
||||
InlineQuery,
|
||||
InputTextMessageContent,
|
||||
InlineQueryResultArticle,
|
||||
SwitchInlineQueryChosenChat,
|
||||
CopyTextButton,
|
||||
)
|
||||
from aiogram.utils.markdown import hide_link
|
||||
|
||||
from BotCode.core.storage import storage
|
||||
from BotCode.utils import textmd2
|
||||
from BotCode.config import PARSE_MODE
|
||||
from BotCode.loggers import logs
|
||||
|
||||
router = Router(name="inline_send")
|
||||
|
||||
|
||||
|
||||
def build_markup(buttons_def: list[list[dict]]) -> InlineKeyboardMarkup | None:
|
||||
"""
|
||||
Создаёт InlineKeyboardMarkup из списка описаний кнопок.
|
||||
Поддерживает URL, callback, inline-моды.
|
||||
Обрабатывает "void"-кнопки как callback_data="void".
|
||||
Для switch_inline_query_chosen_chat устанавливает хотя бы один allow_* True.
|
||||
"""
|
||||
if not buttons_def:
|
||||
return None
|
||||
|
||||
rows: list[list[InlineKeyboardButton]] = []
|
||||
for row_idx, row in enumerate(buttons_def):
|
||||
if not isinstance(row, list):
|
||||
logs.warning(f"Некорректный формат ряда кнопок: {row}")
|
||||
continue
|
||||
|
||||
kb_row: list[InlineKeyboardButton] = []
|
||||
for col_idx, b in enumerate(row):
|
||||
if not isinstance(b, dict):
|
||||
logs.warning(f"Некорректный формат кнопки в ряду {row_idx}: {b}")
|
||||
continue
|
||||
|
||||
text = b.get("text", "")
|
||||
if not text:
|
||||
logs.warning(f"Пустой текст кнопки в ряду {row_idx}, колонке {col_idx}")
|
||||
continue
|
||||
|
||||
btn = None
|
||||
try:
|
||||
if "url" in b:
|
||||
url = b["url"]
|
||||
if url.lower().endswith("void"):
|
||||
btn = InlineKeyboardButton(text=text, callback_data="void")
|
||||
else:
|
||||
btn = InlineKeyboardButton(text=text, url=url)
|
||||
elif "switch_inline_query" in b:
|
||||
btn = InlineKeyboardButton(
|
||||
text=text,
|
||||
switch_inline_query=b["switch_inline_query"]
|
||||
)
|
||||
elif "switch_inline_query_current_chat" in b:
|
||||
btn = InlineKeyboardButton(
|
||||
text=text,
|
||||
switch_inline_query_current_chat=b["switch_inline_query_current_chat"]
|
||||
)
|
||||
elif "switch_inline_query_chosen_chat" in b:
|
||||
query = b["switch_inline_query_chosen_chat"]
|
||||
if isinstance(query, dict):
|
||||
siqcc = SwitchInlineQueryChosenChat(
|
||||
query=query.get("query", ""),
|
||||
allow_user_chats=query.get("allow_user_chats", True),
|
||||
allow_group_chats=query.get("allow_group_chats", True),
|
||||
allow_channel_chats=query.get("allow_channel_chats", True),
|
||||
allow_bot_chats=query.get("allow_bot_chats", False),
|
||||
)
|
||||
else:
|
||||
siqcc = SwitchInlineQueryChosenChat(
|
||||
query=query,
|
||||
allow_user_chats=True,
|
||||
allow_group_chats=True,
|
||||
allow_channel_chats=True,
|
||||
allow_bot_chats=False,
|
||||
)
|
||||
btn = InlineKeyboardButton(
|
||||
text=text,
|
||||
switch_inline_query_chosen_chat=siqcc
|
||||
)
|
||||
elif "copy_text" in b:
|
||||
btn = InlineKeyboardButton(
|
||||
text=text,
|
||||
copy_text=CopyTextButton(text=b["copy_text"])
|
||||
)
|
||||
elif "callback_data" in b:
|
||||
btn = InlineKeyboardButton(
|
||||
text=text,
|
||||
callback_data=b["callback_data"]
|
||||
)
|
||||
except Exception as e:
|
||||
logs.error(f"Ошибка при создании кнопки в ряду {row_idx}, колонке {col_idx}: {e}")
|
||||
continue
|
||||
|
||||
if btn:
|
||||
kb_row.append(btn)
|
||||
|
||||
if kb_row:
|
||||
rows.append(kb_row)
|
||||
|
||||
if not rows:
|
||||
return None
|
||||
|
||||
return InlineKeyboardMarkup(inline_keyboard=rows)
|
||||
|
||||
|
||||
@router.inline_query()
|
||||
async def inline_query_handler(inline_query: InlineQuery):
|
||||
"""
|
||||
Обрабатывает инлайн-запросы для поиска и отправки постов.
|
||||
Фильтрует посты по приватности и поисковому запросу.
|
||||
"""
|
||||
# Перезагружаем все посты из файлов на случай изменений
|
||||
storage.load_all_posts()
|
||||
|
||||
query = inline_query.query or ""
|
||||
user_id = inline_query.from_user.id
|
||||
username = inline_query.from_user.username or f"user_{user_id}"
|
||||
|
||||
logs.debug(f"Получен инлайн-запрос от {username} (ID: {user_id}): {query}")
|
||||
|
||||
results = []
|
||||
for post_id, post in storage.global_posts.items():
|
||||
try:
|
||||
# Проверка приватности
|
||||
if post.get("private") and post.get("user_id") != user_id:
|
||||
continue
|
||||
|
||||
# Проверка поискового запроса
|
||||
if query and query.lower() not in post_id.lower():
|
||||
continue
|
||||
|
||||
# Тело сообщения
|
||||
text = textmd2(post.get("text", ""))
|
||||
image = post.get("image", "")
|
||||
if image and image.startswith("http"):
|
||||
text = f"{hide_link(image)}{text}"
|
||||
|
||||
# Клавиатура
|
||||
markup = build_markup(post.get("buttons", []))
|
||||
|
||||
results.append(
|
||||
InlineQueryResultArticle(
|
||||
id=post_id,
|
||||
title=f"Пост {post_id}",
|
||||
description=(post.get("text", "")[:100] + "...") if len(post.get("text", "")) > 100 else post.get(
|
||||
"text", ""),
|
||||
input_message_content=InputTextMessageContent(
|
||||
message_text=text,
|
||||
parse_mode=PARSE_MODE
|
||||
),
|
||||
reply_markup=markup
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logs.error(f"Ошибка при обработке поста {post_id}: {e}")
|
||||
continue
|
||||
|
||||
logs.info(f"Отправлено {len(results)} результатов для запроса '{query}' от {username} (ID: {user_id})")
|
||||
|
||||
try:
|
||||
await inline_query.answer(results, cache_time=0, is_personal=True)
|
||||
except Exception as e:
|
||||
logs.error(f"Ошибка при отправке результатов инлайн-запроса: {e}")
|
||||
|
||||
|
||||
__all__ = [
|
||||
'router',
|
||||
'inline_query_handler'
|
||||
]
|
||||
Reference in New Issue
Block a user