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

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

View File

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

View File

@@ -1,7 +1,8 @@
from telebot.async_telebot import AsyncTeleBot from telebot.async_telebot import AsyncTeleBot
from telebot.types import Message from telebot.types import Message, MessageReactionUpdated, ReactionTypeEmoji
import asyncio import asyncio
import logging import logging
from collections import OrderedDict
from database import db from database import db
from thank_words import contains_thank_word from thank_words import contains_thank_word
@@ -10,10 +11,126 @@ from config import THANK_COOLDOWN
logger = logging.getLogger(__name__) 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): def register_handlers(bot: AsyncTeleBot):
"""Регистрирует обработчики для отслеживания благодарностей""" """Регистрирует обработчики для отслеживания благодарностей"""
logger.info("Регистрация обработчика благодарностей (karma_tracker)") 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('/')) @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): async def handle_thank_message(message: Message):
""" """