Версия 1.0

This commit is contained in:
Whyverum
2025-05-20 09:12:05 +07:00
commit 0b3b957c0a
34 changed files with 1964 additions and 0 deletions

179
BotCode/handlers/inline.py Normal file
View 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'
]