Добавление кармы за реакцию большого пальца

This commit is contained in:
2025-10-19 13:34:56 +03:00
parent 61e9d31a75
commit be64915e9b
3 changed files with 123 additions and 4 deletions

View File

@@ -187,10 +187,12 @@ COMMAND_MESSAGES = {
"3. Ответ на сообщение:\n"
" Ответьте на сообщение: <code>/karma</code>\n\n"
"<b>💡 Как начислить карму?</b>\n"
"Ответьте на сообщение пользователя словами благодарности:\n"
"<u>Способ 1: Ответить на сообщение</u>\n"
"• спасибо → +1 карма\n"
"• благодарю → +1 карма\n"
"• спс, сенкс, thanks и др. → +1 карма\n\n"
"<u>Способ 2: Поставить реакцию 👍</u>\n"
"• Нажмите на сообщение и выберите 👍 → +1 карма\n\n"
"<b>🔥 БОНУС: Благодарность с восклицательным знаком даёт x2 кармы!</b>\n"
"• спасибо! → +2 кармы 👍👍\n"
"• thanks! → +2 кармы 👍👍\n\n"

View File

@@ -200,8 +200,8 @@ async def main():
# Устанавливаем команды бота
await setup_bot_commands()
# Запускаем бота
await bot.infinity_polling()
# Запускаем бота с обработкой реакций
await bot.infinity_polling(allowed_updates=['message', 'message_reaction', 'chat_member'])
except Exception as e:

View File

@@ -1,7 +1,8 @@
from telebot.async_telebot import AsyncTeleBot
from telebot.types import Message
from telebot.types import Message, MessageReactionUpdated, ReactionTypeEmoji
import asyncio
import logging
from collections import OrderedDict
from database import db
from thank_words import contains_thank_word
@@ -10,10 +11,126 @@ from config import THANK_COOLDOWN
logger = logging.getLogger(__name__)
# Кэш для хранения message_id -> user_id (последние 1000 сообщений)
# Используем OrderedDict для автоматического удаления старых записей
_message_cache = OrderedDict()
_MAX_CACHE_SIZE = 1000
def _cache_message(chat_id: int, message_id: int, user_id: int):
"""Добавляет сообщение в кэш"""
key = f"{chat_id}:{message_id}"
_message_cache[key] = user_id
# Удаляем старые записи, если кэш переполнен
if len(_message_cache) > _MAX_CACHE_SIZE:
_message_cache.popitem(last=False)
def _get_cached_user(chat_id: int, message_id: int) -> int:
"""Получает user_id из кэша"""
key = f"{chat_id}:{message_id}"
return _message_cache.get(key)
def register_handlers(bot: AsyncTeleBot):
"""Регистрирует обработчики для отслеживания благодарностей"""
logger.info("Регистрация обработчика благодарностей (karma_tracker)")
@bot.message_reaction_handler(func=lambda reaction: True)
async def handle_reaction(reaction: MessageReactionUpdated):
"""
Обрабатывает реакции на сообщения.
Если пользователь поставил 👍, начисляет карму автору сообщения.
"""
try:
logger.info(f"[KARMA] Получена реакция от {reaction.user.id}")
# Проверяем, что это групповой чат
if reaction.chat.type not in ['group', 'supergroup']:
logger.info(f"[KARMA] Пропуск реакции - не групповой чат")
return
# Проверяем, что есть новые реакции (не удаление)
if not reaction.new_reaction:
logger.info(f"[KARMA] Пропуск - удаление реакции")
return
# Ищем реакцию 👍 среди новых реакций
thumbs_up_found = False
for react in reaction.new_reaction:
if isinstance(react, ReactionTypeEmoji) and react.emoji == "👍":
thumbs_up_found = True
break
if not thumbs_up_found:
logger.info(f"[KARMA] Нет реакции 👍")
return
logger.info(f"[KARMA] Обнаружена реакция 👍 от {reaction.user.id}")
from_user = reaction.user
chat_id = reaction.chat.id
# Получаем автора сообщения из кэша
to_user_id = _get_cached_user(chat_id, reaction.message_id)
if not to_user_id:
logger.warning(f"[KARMA] Сообщение {reaction.message_id} не найдено в кэше")
return
# Защита от самоблагодарности
if from_user.id == to_user_id:
logger.info(f"Пользователь {from_user.id} попытался поблагодарить сам себя реакцией")
return
# Получаем информацию о пользователе из БД
to_user_info = db.get_user(to_user_id)
if not to_user_info:
logger.warning(f"[KARMA] Пользователь {to_user_id} не найден в БД")
return
# Атомарно проверяем кулдаун и записываем благодарность
if not db.try_add_karma_thank(from_user.id, to_user_id, chat_id, THANK_COOLDOWN):
logger.info(f"Пользователь {from_user.id} уже благодарил {to_user_id} недавно (реакция)")
return
# Начисляем +1 карму за реакцию
db.add_karma(to_user_id, chat_id, 1)
# Получаем новую карму
new_karma = db.get_karma(to_user_id, chat_id)
logger.info(f"Пользователь {from_user.id} поблагодарил {to_user_id} реакцией 👍, карма: {new_karma}")
# Формируем имя пользователя (из БД: id, nickname, tag)
to_user_display = f"@{to_user_info[2]}" if to_user_info[2] else to_user_info[1]
response = f"👍 Карма пользователя {to_user_display} увеличена (+1)! Текущая карма: {new_karma}"
sent_message = await bot.send_message(
chat_id,
response,
message_thread_id=getattr(reaction, 'message_thread_id', None)
)
# Удаляем уведомление через 15 секунд
await asyncio.sleep(15)
try:
await bot.delete_message(chat_id, sent_message.message_id)
except Exception as e:
logger.error(f"Не удалось удалить уведомление о карме: {e}")
except Exception as e:
logger.error(f"Ошибка при обработке реакции: {e}", exc_info=True)
# Обработчик всех текстовых сообщений для кэширования
@bot.message_handler(content_types=['text'])
async def cache_messages(message: Message):
"""Кэширует все текстовые сообщения для возможности обработки реакций"""
try:
# Кэшируем только сообщения в групповых чатах
if message.chat.type in ['group', 'supergroup']:
_cache_message(message.chat.id, message.message_id, message.from_user.id)
logger.debug(f"[CACHE] Сообщение {message.message_id} от {message.from_user.id} добавлено в кэш")
except Exception as e:
logger.error(f"Ошибка кэширования сообщения: {e}")
@bot.message_handler(func=lambda message: message.reply_to_message is not None and message.text and not message.text.startswith('/'))
async def handle_thank_message(message: Message):
"""