216 lines
7.9 KiB
Python
216 lines
7.9 KiB
Python
"""
|
||
Обработчик команды /emoji для извлечения ID премиум эмодзи
|
||
"""
|
||
from aiogram import Router
|
||
from aiogram.filters import Command
|
||
from aiogram.types import Message
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
|
||
from bot.filters.admin import IsAdmin
|
||
from configs import settings, COMMANDS
|
||
from middleware.loggers import logger
|
||
|
||
__all__ = ("router",)
|
||
|
||
router: Router = Router(name="emoji_extractor_router")
|
||
|
||
|
||
# ================= ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ =================
|
||
|
||
def extract_custom_emojis(message: Message) -> list[dict]:
|
||
"""
|
||
Извлекает все кастомные эмодзи из сообщения.
|
||
|
||
Args:
|
||
message: Сообщение для анализа
|
||
|
||
Returns:
|
||
Список словарей с информацией об эмодзи
|
||
"""
|
||
if not message.entities and not message.caption_entities:
|
||
return []
|
||
|
||
# Определяем текст и entities
|
||
text = message.text or message.caption
|
||
entities = message.entities or message.caption_entities
|
||
|
||
if not text or not entities:
|
||
return []
|
||
|
||
custom_emojis = []
|
||
|
||
for entity in entities:
|
||
if entity.type == "custom_emoji":
|
||
# Извлекаем символ эмодзи
|
||
emoji_char = text[entity.offset:entity.offset + entity.length]
|
||
|
||
custom_emojis.append({
|
||
"char": emoji_char,
|
||
"id": entity.custom_emoji_id,
|
||
"offset": entity.offset
|
||
})
|
||
|
||
return custom_emojis
|
||
|
||
|
||
def format_emoji_html(emoji_char: str, emoji_id: str) -> str:
|
||
"""
|
||
Форматирует эмодзи в HTML-тег.
|
||
|
||
Args:
|
||
emoji_char: Символ эмодзи (fallback)
|
||
emoji_id: ID кастомного эмодзи
|
||
|
||
Returns:
|
||
HTML-строка
|
||
"""
|
||
return f'<tg-emoji emoji-id="{emoji_id}">{emoji_char}</tg-emoji>'
|
||
|
||
|
||
def escape_html(text: str) -> str:
|
||
"""Экранирует HTML символы"""
|
||
return (
|
||
text.replace("&", "&")
|
||
.replace("<", "<")
|
||
.replace(">", ">")
|
||
)
|
||
|
||
|
||
# ================= КОМАНДА /EMOJI =================
|
||
|
||
@router.message(
|
||
Command(*COMMANDS.get("emoji", ["emoji"]), prefix=settings.PREFIX, ignore_case=True),
|
||
IsAdmin()
|
||
)
|
||
async def emoji_extractor_cmd(message: Message) -> None:
|
||
"""
|
||
Извлекает кастомные эмодзи из сообщения.
|
||
|
||
Доступно только администраторам.
|
||
|
||
Использование: /emoji (в ответ на сообщение)
|
||
"""
|
||
# Проверяем, что команда в ответ на сообщение
|
||
if not message.reply_to_message:
|
||
await message.answer(
|
||
"❌ <b>Используйте команду в ответ на сообщение</b>\n\n"
|
||
"📝 Как использовать:\n"
|
||
"1. Ответьте на сообщение с премиум эмодзи\n"
|
||
"2. Напишите <code>/emoji</code>\n\n"
|
||
"💡 <i>Бот извлечёт все кастомные эмодзи и покажет HTML-код</i>",
|
||
parse_mode="HTML"
|
||
)
|
||
return
|
||
|
||
replied_message = message.reply_to_message
|
||
|
||
# Извлекаем кастомные эмодзи
|
||
custom_emojis = extract_custom_emojis(replied_message)
|
||
|
||
if not custom_emojis:
|
||
# Нет кастомных эмодзи
|
||
await message.answer(
|
||
"⚠️ <b>Кастомные эмодзи не найдены</b>\n\n"
|
||
"В этом сообщении нет премиум эмодзи.\n\n"
|
||
"💡 <i>Попробуйте ответить на сообщение с анимированными эмодзи</i>",
|
||
parse_mode="HTML"
|
||
)
|
||
return
|
||
|
||
# === ФОРМИРУЕМ ОТВЕТ ===
|
||
|
||
output = f"✨ <b>НАЙДЕНО ЭМОДЗИ: {len(custom_emojis)}</b>\n\n"
|
||
|
||
for idx, emoji_data in enumerate(custom_emojis, 1):
|
||
emoji_char = emoji_data["char"]
|
||
emoji_id = emoji_data["id"]
|
||
|
||
output += f"<b>{idx}.</b> Эмодзи: {emoji_char}\n"
|
||
output += f"📋 <b>ID:</b> <code>{emoji_id}</code>\n\n"
|
||
|
||
# HTML-код (экранированный для отображения)
|
||
html_code = format_emoji_html(emoji_char, emoji_id)
|
||
html_escaped = escape_html(html_code)
|
||
|
||
output += f"📝 <b>HTML-код:</b>\n"
|
||
output += f"<code>{html_escaped}</code>\n\n"
|
||
|
||
# Пример использования
|
||
output += f"🎨 <b>Превью:</b> {html_code}\n"
|
||
|
||
if idx < len(custom_emojis):
|
||
output += "\n" + "─" * 30 + "\n\n"
|
||
|
||
output += "💡 <i>Скопируйте HTML-код и используйте в своих сообщениях</i>"
|
||
|
||
# Создаём клавиатуру
|
||
ikb = InlineKeyboardBuilder()
|
||
ikb.button(text="✖️ Закрыть", callback_data="emoji_close")
|
||
|
||
# Отправляем
|
||
try:
|
||
await message.answer(
|
||
text=output,
|
||
parse_mode="HTML",
|
||
reply_markup=ikb.as_markup()
|
||
)
|
||
|
||
logger.info(
|
||
f"Извлечено {len(custom_emojis)} кастомных эмодзи админом {message.from_user.id}",
|
||
log_type="EMOJI_EXTRACT"
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка отправки эмодзи: {e}", log_type="ERROR")
|
||
await message.answer(
|
||
"❌ <b>Ошибка извлечения эмодзи</b>\n\n"
|
||
"Попробуйте позже или обратитесь к разработчику.",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
|
||
# ================= ОБРАБОТЧИК КНОПКИ ЗАКРЫТИЯ =================
|
||
|
||
@router.callback_query(lambda c: c.data == "emoji_close", IsAdmin())
|
||
async def emoji_close_callback(callback) -> None:
|
||
"""Закрывает сообщение с эмодзи"""
|
||
try:
|
||
await callback.message.delete()
|
||
await callback.answer("✅ Закрыто")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка удаления сообщения с эмодзи: {e}", log_type="ERROR")
|
||
await callback.answer("❌ Не удалось удалить", show_alert=True)
|
||
|
||
|
||
# ================= ДОПОЛНИТЕЛЬНАЯ КОМАНДА /EMOJIHELP =================
|
||
|
||
@router.message(
|
||
Command(*COMMANDS.get("emojihelp", ["emojihelp"]), prefix=settings.PREFIX, ignore_case=True),
|
||
IsAdmin()
|
||
)
|
||
async def emoji_help_cmd(message: Message) -> None:
|
||
"""
|
||
Справка по работе с кастомными эмодзи.
|
||
"""
|
||
text = (
|
||
"🎨 <b>РАБОТА С КАСТОМНЫМИ ЭМОДЗИ</b>\n\n"
|
||
"📝 <b>Команда /emoji</b>\n"
|
||
"Извлекает ID премиум эмодзи из сообщения\n\n"
|
||
"🔧 <b>Как использовать:</b>\n"
|
||
"1️⃣ Ответьте на сообщение с эмодзи\n"
|
||
"2️⃣ Напишите <code>/emoji</code>\n"
|
||
"3️⃣ Скопируйте HTML-код\n\n"
|
||
"💻 <b>Формат HTML-кода:</b>\n"
|
||
"<code><tg-emoji emoji-id=\"ID\">fallback</tg-emoji></code>\n\n"
|
||
"📌 <b>Пример использования в коде:</b>\n"
|
||
"<code>text = 'Привет <tg-emoji emoji-id=\"5368324170671202286\">👍</tg-emoji>'\n"
|
||
"await message.answer(text, parse_mode=\"HTML\")</code>\n\n"
|
||
"⚠️ <b>Важно:</b>\n"
|
||
"├─ Используйте <code>parse_mode=\"HTML\"</code>\n"
|
||
"├─ Пользователи без Premium видят fallback\n"
|
||
"└─ Работает только с кастомными эмодзи\n\n"
|
||
"💡 <i>Попробуйте отправить эмодзи и ответить командой /emoji</i>"
|
||
)
|
||
|
||
await message.answer(text, parse_mode="HTML")
|