Добавление автомута

This commit is contained in:
2025-10-12 16:00:02 +03:00
parent 643ad9feda
commit f6b888c6d3
9 changed files with 894 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
## changed at Sun Oct 12 12:00:13 MSK 2025 ## changed at Sun Oct 12 15:29:33 MSK 2025
#Sun Oct 12 12:00:13 MSK 2025 #Sun Oct 12 15:29:33 MSK 2025
com.gigaide.elements.ext.marker.solution.BeanMarkedPsi.shouldMark=true com.gigaide.elements.ext.marker.solution.BeanMarkedPsi.shouldMark=true
com.gigaide.elements.ext.marker.solution.ConfigMarkedPsi.shouldMark=true com.gigaide.elements.ext.marker.solution.ConfigMarkedPsi.shouldMark=true
com.gigaide.elements.ext.marker.solution.DataMarkedPsi.shouldMark=true com.gigaide.elements.ext.marker.solution.DataMarkedPsi.shouldMark=true

167
README.md
View File

@@ -40,4 +40,169 @@ python src/main.py
- Проверит наличие обновлений в git-репозитории - Проверит наличие обновлений в git-репозитории
- Загрузит изменения (`git pull`) - Загрузит изменения (`git pull`)
- Перезапустит службу бота (`systemctl restart LGBot.service`) - Перезапустит службу бота (`systemctl restart LGBot.service`)
- Покажет статус работы бота - Покажет статус работы бота
---
## Система автоматического мьюта
Бот автоматически отслеживает использование нецензурной лексики и применяет прогрессирующие наказания.
### Как работает
1. **Обнаружение нарушений:**
- Каждое текстовое сообщение проверяется на наличие бранных слов
- Проверяются только группы и супергруппы (не личные сообщения)
- Команды (начинающиеся с `/`) не проверяются
2. **При обнаружении мата:**
- Сообщение удаляется автоматически
- Нарушение фиксируется в базе данных
- Пользователь получает мут соответствующего уровня
- Уведомление отправляется в чат и админ-чат
3. **Прогрессирующие наказания:**
| № нарушения | Длительность мута | № нарушения | Длительность мута |
|-------------|-------------------|-------------|-------------------|
| 1 | 5 минут | 9 | 1 день |
| 2 | 15 минут | 10 | 2 дня |
| 3 | 30 минут | 11 | 3 дня |
| 4 | 1 час | 12 | 5 дней |
| 5 | 2 часа | 13 | 7 дней |
| 8 | 12 часов | 16+ | **НАВСЕГДА** |
4. **Накопительный эффект:**
- Нарушения учитываются за последние **30 дней**
- Старые нарушения автоматически удаляются из базы
- Администраторы **освобождены** от автоматических мутов
### Управление списком бранных слов
⚠️ **Все команды доступны только администраторам чата**
#### Основные команды
```bash
# Показать справку
/badwords help
# Показать список бранных слов (первые 50)
/badwords list
# Статистика
/badwords count
# Добавить слово в список
/badwords add <слово>
# Удалить слово из списка
/badwords remove <слово>
```
#### Исключения
Исключения — слова, содержащие бранные корни, но не являющиеся матом (например: "республика", "документ"):
```bash
# Показать исключения
/badwords exceptions
# Добавить исключение
/badwords add_exception <слово>
# Удалить исключение
/badwords remove_exception <слово>
```
#### Служебные команды
```bash
# Перезагрузить списки из файла
/badwords reload
```
### Рекомендации
1. **Используйте корни слов**, а не полные формы:
- ✅ Правильно: `ебал` (поймает все формы)
- ❌ Неправильно: `ебала` (пропустит другие формы)
2. **Избегайте коротких корней** (могут давать ложные срабатывания)
3. **Тестируйте после добавления** нового слова
### Хранение данных
Все списки хранятся в файле `src/data/bad_words.json`:
```json
{
"bad_words": ["слово1", "слово2", ...],
"exceptions": [сключение1", сключение2", ...]
}
```
Изменения через команды применяются **немедленно**, перезапуск бота не требуется.
### Логирование
Все действия записываются в:
- **bot.log** - файл логов
- **Админ-чат** - уведомления о мутах
Примеры логов:
```
[INFO] Пользователь 123456789 получил автоматический мут на 5 минут за нецензурную лексику (нарушение #1)
[INFO] Нарушение пользователя 123456789 зафиксировано в чате -100123456789
[INFO] Администратор 987654321 добавил бранное слово: спам
```
### База данных
Таблица `violations` хранит все нарушения:
- `id` - уникальный идентификатор
- `user_id` - ID пользователя
- `chat_id` - ID чата
- `violation_date` - время нарушения (unix timestamp)
- `violation_type` - тип нарушения ('bad_language')
### Настройка системы
#### Изменение уровней мутов
Откройте `src/modules/auto_mute.py` и измените массив `MUTE_LEVELS`:
```python
MUTE_LEVELS = [
300, # 1. 5 минут
900, # 2. 15 минут
# ... добавьте или измените уровни
None, # Перманентный мут
]
```
#### Изменение периода накопления
Измените `VIOLATIONS_PERIOD` в `src/modules/auto_mute.py`:
```python
VIOLATIONS_PERIOD = 2592000 # 30 дней в секундах
```
### Требования
- Python 3.7+
- pyTelegramBotAPI (telebot)
- SQLite3
- Права бота в чате:
- Удаление сообщений
- Ограничение пользователей
### Устранение проблем
При возникновении проблем проверьте:
1. Логи бота в файле `bot.log`
2. Права бота в чате (удаление сообщений, ограничение пользователей)
3. Корректность настроек в `.env`
4. Наличие файла `src/data/bad_words.json`

153
src/bad_words.py Normal file
View File

@@ -0,0 +1,153 @@
# Система управления бранными словами
# Список слов хранится в JSON файле для возможности управления через команды
import json
import os
import logging
logger = logging.getLogger(__name__)
# Путь к файлу с бранными словами
BAD_WORDS_FILE = os.path.join(os.path.dirname(__file__), 'data', 'bad_words.json')
# Кэш для загруженных слов
_bad_words_cache = None
_exceptions_cache = None
def load_bad_words():
"""
Загружает список бранных слов из JSON файла.
Returns:
tuple: (список бранных слов, список исключений)
"""
global _bad_words_cache, _exceptions_cache
try:
with open(BAD_WORDS_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
_bad_words_cache = data.get('bad_words', [])
_exceptions_cache = data.get('exceptions', [])
logger.info(f"Загружено {len(_bad_words_cache)} бранных слов и {len(_exceptions_cache)} исключений")
return _bad_words_cache, _exceptions_cache
except FileNotFoundError:
logger.error(f"Файл {BAD_WORDS_FILE} не найден")
return [], []
except json.JSONDecodeError as e:
logger.error(f"Ошибка чтения JSON: {e}")
return [], []
def save_bad_words(bad_words: list, exceptions: list):
"""
Сохраняет список бранных слов в JSON файл.
Args:
bad_words: Список бранных слов
exceptions: Список исключений
Returns:
bool: True если успешно, иначе False
"""
global _bad_words_cache, _exceptions_cache
try:
# Создаем директорию, если её нет
os.makedirs(os.path.dirname(BAD_WORDS_FILE), exist_ok=True)
data = {
'bad_words': sorted(list(set(bad_words))), # Убираем дубликаты и сортируем
'exceptions': sorted(list(set(exceptions)))
}
with open(BAD_WORDS_FILE, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# Обновляем кэш
_bad_words_cache = data['bad_words']
_exceptions_cache = data['exceptions']
logger.info(f"Сохранено {len(_bad_words_cache)} бранных слов и {len(_exceptions_cache)} исключений")
return True
except Exception as e:
logger.error(f"Ошибка сохранения: {e}")
return False
def get_bad_words():
"""Возвращает список бранных слов (с кэшированием)"""
global _bad_words_cache
if _bad_words_cache is None:
load_bad_words()
return _bad_words_cache or []
def get_exceptions():
"""Возвращает список исключений (с кэшированием)"""
global _exceptions_cache
if _exceptions_cache is None:
load_bad_words()
return _exceptions_cache or []
def reload_words():
"""Перезагружает списки из файла (сбрасывает кэш)"""
global _bad_words_cache, _exceptions_cache
_bad_words_cache = None
_exceptions_cache = None
return load_bad_words()
# Загружаем слова при импорте модуля
BAD_WORDS, EXCEPTIONS = load_bad_words()
def contains_bad_word(text: str) -> bool:
"""
Проверяет, содержит ли текст бранные слова.
Args:
text: Текст для проверки
Returns:
True, если найдено бранное слово, иначе False
"""
if not text:
return False
# Приводим к нижнему регистру для проверки
text_lower = text.lower()
# Проверяем исключения
for exception in EXCEPTIONS:
if exception in text_lower:
text_lower = text_lower.replace(exception, '')
# Проверяем бранные слова
for bad_word in BAD_WORDS:
if bad_word in text_lower:
return True
return False
def get_bad_words_from_text(text: str) -> list:
"""
Возвращает список найденных бранных слов в тексте.
Args:
text: Текст для проверки
Returns:
Список найденных бранных слов
"""
if not text:
return []
text_lower = text.lower()
found_words = []
# Проверяем исключения
for exception in EXCEPTIONS:
if exception in text_lower:
text_lower = text_lower.replace(exception, '')
# Ищем бранные слова
for bad_word in BAD_WORDS:
if bad_word in text_lower:
found_words.append(bad_word)
return found_words

View File

@@ -96,6 +96,33 @@ COMMAND_MESSAGES = {
'banned': '✅ Пользователь успешно забанен.', 'banned': '✅ Пользователь успешно забанен.',
'unbanned': '✅ Пользователь успешно разбанен.', 'unbanned': '✅ Пользователь успешно разбанен.',
'error': '⚠️ Ошибка: {e}', 'error': '⚠️ Ошибка: {e}',
'general_error': '⚠️ Произошла непредвиденная ошибка.' 'general_error': '⚠️ Произошла непредвиденная ошибка.',
'auto_mute_warning': (
'⚠️ Пользователь <b>{user_name}</b> получил мут на <b>{duration}</b> '
'за использование нецензурной лексики.\n\n'
'📊 Нарушение #{count}\n'
'💡 При повторных нарушениях время мута будет увеличиваться.'
),
'auto_mute_permanent': (
'⛔️ Пользователь <b>{user_name}</b> получил перманентный мут '
'за злостное нарушение правил чата (использование нецензурной лексики).\n\n'
'📊 Количество нарушений: <b>{count}</b>\n'
'🔒 Режим: только чтение (навсегда)'
),
'badwords_help': (
"<b>🔧 Управление списком бранных слов</b>\n\n"
"<u>Основные команды:</u>\n"
"• <code>/badwords list</code> - Показать список слов\n"
"• <code>/badwords count</code> - Статистика\n"
"• <code>/badwords add [слово]</code> - Добавить слово\n"
"• <code>/badwords remove [слово]</code> - Удалить слово\n\n"
"<u>Исключения:</u>\n"
"• <code>/badwords exceptions</code> - Список исключений\n"
"• <code>/badwords add_exception [слово]</code> - Добавить\n"
"• <code>/badwords remove_exception [слово]</code> - Удалить\n\n"
"<u>Прочее:</u>\n"
"• <code>/badwords reload</code> - Перезагрузить из файла\n\n"
"<i>💡 Все изменения применяются немедленно</i>"
)
} }

47
src/data/bad_words.json Normal file
View File

@@ -0,0 +1,47 @@
{
"bad_words": [
"хуй", "хуе", "хуи", "хую", "хуя", "хер",
"пизд", "пизж", "пезд",
"ебал", "ебан", "ебат", "ебу", "ебош", "ебля", "ебет",
"бля", "блядь", "блять",
"сука", "суки", "сучк", "сучар",
"мудак", "мудил", "муди",
"гандон",
"даун",
"дебил",
"долбоеб", "долбаеб",
"уебан", "уебок",
"хуесос",
"пидор", "пидар", "педик", "педр",
"гей", "гомик", "гомос",
"шлюх", "шалав",
"еблан",
"говн",
"срать", "сраль", "серун",
"дрочи", "дроч",
"жоп", "жёп",
"залуп",
"мразь", "мраз",
"козел", "козл",
"урод", "урода",
"ублюдо", "ублюд",
"тварь", "твар",
"падла",
"сволочь", "сволоч",
"гнида", "гнид",
"выблядо",
"хуета", "хуйн",
"охуе", "охуи", "охуя",
"нахуй", "нахер",
"похуй", "похер",
"захуя",
"ахуе",
"впизду",
"попизд"
],
"exceptions": [
"республика",
"документ",
"документы"
]
}

View File

@@ -13,7 +13,7 @@ class Database: # Инициализация класса
self.db_name = db_name self.db_name = db_name
self._init_db() self._init_db()
# Инициализирует базу данных и создает таблицу, если она не существует # Инициализирует базу данных и создает таблицы, если они не существуют
def _init_db(self): def _init_db(self):
with self._get_connection() as connect: with self._get_connection() as connect:
cursor = connect.cursor() cursor = connect.cursor()
@@ -24,6 +24,16 @@ class Database: # Инициализация класса
tag TEXT tag TEXT
) )
''') ''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS violations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
chat_id INTEGER NOT NULL,
violation_date INTEGER NOT NULL,
violation_type TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users (id)
)
''')
connect.commit() connect.commit()
# Возвращает соединение с базой данных # Возвращает соединение с базой данных
@@ -70,15 +80,68 @@ class Database: # Инициализация класса
def get_user_by_username(self, username: str) -> Optional[Tuple]: def get_user_by_username(self, username: str) -> Optional[Tuple]:
if not username: if not username:
return None return None
with self._get_connection() as connect: with self._get_connection() as connect:
cursor = connect.cursor() cursor = connect.cursor()
cursor.execute(''' cursor.execute('''
SELECT id, nickname, tag SELECT id, nickname, tag
FROM users FROM users
WHERE LOWER(tag) = LOWER(?) WHERE LOWER(tag) = LOWER(?)
''', (username,)) ''', (username,))
return cursor.fetchone() return cursor.fetchone()
# Добавляет нарушение в базу данных
def add_violation(self, user_id: int, chat_id: int, violation_type: str = 'bad_language'):
import time
with self._get_connection() as connect:
cursor = connect.cursor()
cursor.execute('''
INSERT INTO violations (user_id, chat_id, violation_date, violation_type)
VALUES (?, ?, ?, ?)
''', (user_id, chat_id, int(time.time()), violation_type))
connect.commit()
logger.info(f"Нарушение пользователя {user_id} зафиксировано в чате {chat_id}")
# Получает количество нарушений за период (по умолчанию - за последний месяц)
def get_violations_count(self, user_id: int, chat_id: int, period_seconds: int = 2592000) -> int:
import time
with self._get_connection() as connect:
cursor = connect.cursor()
cutoff_time = int(time.time()) - period_seconds
cursor.execute('''
SELECT COUNT(*)
FROM violations
WHERE user_id = ? AND chat_id = ? AND violation_date > ?
''', (user_id, chat_id, cutoff_time))
result = cursor.fetchone()
return result[0] if result else 0
# Получает все нарушения пользователя
def get_user_violations(self, user_id: int, chat_id: int):
with self._get_connection() as connect:
cursor = connect.cursor()
cursor.execute('''
SELECT id, violation_date, violation_type
FROM violations
WHERE user_id = ? AND chat_id = ?
ORDER BY violation_date DESC
''', (user_id, chat_id))
return cursor.fetchall()
# Очищает старые нарушения (старше указанного периода)
def clean_old_violations(self, period_seconds: int = 2592000):
import time
with self._get_connection() as connect:
cursor = connect.cursor()
cutoff_time = int(time.time()) - period_seconds
cursor.execute('''
DELETE FROM violations
WHERE violation_date < ?
''', (cutoff_time,))
deleted_count = cursor.rowcount
connect.commit()
logger.info(f"Удалено старых нарушений: {deleted_count}")
return deleted_count
# Создаем экземпляр базы данных для импорта в других модулях # Создаем экземпляр базы данных для импорта в других модулях
db = Database() db = Database()

View File

@@ -121,6 +121,7 @@ async def setup_bot_commands():
BotCommand("unban", "Разбанить пользователя"), BotCommand("unban", "Разбанить пользователя"),
BotCommand("mute", "Замутить пользователя"), BotCommand("mute", "Замутить пользователя"),
BotCommand("unmute", "Размутить пользователя"), BotCommand("unmute", "Размутить пользователя"),
BotCommand("badwords", "Управление списком бранных слов"),
BotCommand("botdata", "Получить данные бота (только админы)"), BotCommand("botdata", "Получить данные бота (только админы)"),
] ]

199
src/modules/auto_mute.py Normal file
View File

@@ -0,0 +1,199 @@
from telebot.async_telebot import AsyncTeleBot
from telebot.types import Message, ChatPermissions
import asyncio
import logging
import time
from database import db
from bad_words import contains_bad_word, get_bad_words_from_text
from action_reporter import action_reporter
from utils import delete_messages, format_mute_time
# Получаем логгер для текущего модуля
logger = logging.getLogger(__name__)
# Система прогрессирующих мутов (в секундах)
# Более плавная прогрессия для накопительного эффекта
MUTE_LEVELS = [
300, # 1. 5 минут (первое нарушение - символический мут)
900, # 2. 15 минут
1800, # 3. 30 минут
3600, # 4. 1 час
7200, # 5. 2 часа
14400, # 6. 4 часа
28800, # 7. 8 часов
43200, # 8. 12 часов
86400, # 9. 1 день
172800, # 10. 2 дня
259200, # 11. 3 дня
432000, # 12. 5 дней
604800, # 13. 7 дней
None, # 16. Перманентный мут (режим только чтения навсегда)
]
# Период для подсчета нарушений (30 дней в секундах)
VIOLATIONS_PERIOD = 2592000
def get_mute_duration(violations_count: int) -> int:
"""
Определяет длительность мута на основе количества нарушений.
Args:
violations_count: Количество нарушений пользователя
Returns:
Длительность мута в секундах (или None для перманентного мута)
"""
if violations_count < 1:
return MUTE_LEVELS[0]
# Индекс уровня мута (количество нарушений - 1, т.к. начинаем с 0)
level_index = violations_count - 1
# Если превысили количество уровней, возвращаем перманентный мут
if level_index >= len(MUTE_LEVELS):
return None
return MUTE_LEVELS[level_index]
async def apply_mute(bot: AsyncTeleBot, message: Message, user_id: int, duration: int, violations_count: int):
"""
Применяет мут к пользователю.
Args:
bot: Экземпляр бота
message: Сообщение, которое вызвало мут
user_id: ID пользователя
duration: Длительность мута в секундах (None для перманентного)
violations_count: Количество нарушений
"""
try:
# Устанавливаем ограничения (только чтение)
permissions = ChatPermissions(
can_send_messages=False,
can_send_media_messages=False,
can_send_polls=False,
can_send_other_messages=False,
can_add_web_page_previews=False,
can_change_info=False,
can_invite_users=False,
can_pin_messages=False,
)
# Вычисляем время окончания мута
until_date = None if duration is None else int(time.time()) + duration
# Выполняем мут
await bot.restrict_chat_member(
chat_id=message.chat.id,
user_id=user_id,
permissions=permissions,
until_date=until_date
)
# Удаляем сообщение с матом
try:
await bot.delete_message(chat_id=message.chat.id, message_id=message.message_id)
except Exception as e:
logger.warning(f"Не удалось удалить сообщение: {e}")
# Формируем сообщение о муте
if duration is None:
time_display = "навсегда"
warning_msg = (
f"⛔️ Пользователь <b>{message.from_user.first_name}</b> получил перманентный мут "
f"за злостное нарушение правил чата (использование нецензурной лексики).\n\n"
f"📊 Количество нарушений: <b>{violations_count}</b>\n"
f"🔒 Режим: только чтение (навсегда)"
)
else:
time_display = format_mute_time(duration)
warning_msg = (
f"⚠️ Пользователь <b>{message.from_user.first_name}</b> получил мут на <b>{time_display}</b> "
f"за использование нецензурной лексики.\n\n"
f"📊 Нарушение #{violations_count}\n"
f"💡 При повторных нарушениях время мута будет увеличиваться."
)
# Отправляем сообщение в чат
await bot.send_message(
chat_id=message.chat.id,
text=warning_msg,
message_thread_id=message.message_thread_id,
)
# Отправляем сообщение-лог в админ-чат
await action_reporter.log_action(
action="АВТОМУТ",
user_id=user_id,
admin_id=None, # Автоматическое действие
reason=f"Использование нецензурной лексики (нарушение #{violations_count})",
duration=time_display,
)
# Записываем действие в логи
logger.info(
f"Пользователь {user_id} получил автоматический мут на {time_display} "
f"за нецензурную лексику (нарушение #{violations_count})"
)
except Exception as e:
logger.error(f"Ошибка при применении мута: {e}")
async def check_message_for_profanity(bot: AsyncTeleBot, message: Message):
"""
Проверяет сообщение на наличие бранных слов и применяет мут при необходимости.
Args:
bot: Экземпляр бота
message: Сообщение для проверки
"""
# Проверяем только текстовые сообщения
if not message.text:
return
# Не проверяем команды
if message.text.startswith('/'):
return
# Проверяем, содержит ли сообщение бранные слова
if not contains_bad_word(message.text):
return
# Получаем ID пользователя и чата
user_id = message.from_user.id
chat_id = message.chat.id
# Проверяем, является ли отправитель администратором
try:
chat_member = await bot.get_chat_member(chat_id, user_id)
if chat_member.status in ['administrator', 'creator']:
logger.info(f"Администратор {user_id} использовал нецензурную лексику, мут не применен")
return
except Exception as e:
logger.error(f"Ошибка проверки статуса пользователя: {e}")
return
# Добавляем нарушение в базу данных
db.add_violation(user_id, chat_id, violation_type='bad_language')
# Получаем количество нарушений за последний месяц
violations_count = db.get_violations_count(user_id, chat_id, VIOLATIONS_PERIOD)
# Определяем длительность мута
mute_duration = get_mute_duration(violations_count)
# Применяем мут
await apply_mute(bot, message, user_id, mute_duration, violations_count)
def register_handlers(bot: AsyncTeleBot):
"""
Регистрирует обработчики для автоматического мута.
"""
# Обработчик всех текстовых сообщений
@bot.message_handler(func=lambda message: message.text and message.chat.type in ['group', 'supergroup'])
async def handle_text_message(message: Message):
await check_message_for_profanity(bot, message)
logger.info("Модуль автоматического мута успешно загружен")

View File

@@ -0,0 +1,231 @@
from telebot.async_telebot import AsyncTeleBot
from telebot.types import Message
import logging
from bad_words import (
get_bad_words,
get_exceptions,
save_bad_words,
reload_words
)
from utils import check_admin_status, delete_messages
from config import COMMAND_MESSAGES
logger = logging.getLogger(__name__)
def register_handlers(bot: AsyncTeleBot):
"""Регистрирует обработчики команд управления бранными словами"""
@bot.message_handler(commands=['badwords'])
async def badwords_command(message: Message):
"""Главная команда управления списком бранных слов"""
# Проверяем права администратора
if await check_admin_status(bot, message) == 1:
return
parts = message.text.split(maxsplit=2)
# /badwords без параметров - показываем help
if len(parts) == 1:
await show_help(bot, message)
return
subcommand = parts[1].lower()
# Обработка подкоманд
if subcommand == 'help':
await show_help(bot, message)
elif subcommand == 'list':
await list_bad_words(bot, message)
elif subcommand == 'count':
await count_words(bot, message)
elif subcommand == 'add':
if len(parts) < 3:
await send_temp_message(bot, message, "❌ Укажите слово для добавления: /badwords add <слово>")
else:
await add_bad_word(bot, message, parts[2])
elif subcommand == 'remove':
if len(parts) < 3:
await send_temp_message(bot, message, "❌ Укажите слово для удаления: /badwords remove <слово>")
else:
await remove_bad_word(bot, message, parts[2])
elif subcommand == 'exceptions':
await list_exceptions(bot, message)
elif subcommand == 'add_exception':
if len(parts) < 3:
await send_temp_message(bot, message, "❌ Укажите слово для добавления в исключения: /badwords add_exception <слово>")
else:
await add_exception(bot, message, parts[2])
elif subcommand == 'remove_exception':
if len(parts) < 3:
await send_temp_message(bot, message, "❌ Укажите слово для удаления из исключений: /badwords remove_exception <слово>")
else:
await remove_exception(bot, message, parts[2])
elif subcommand == 'reload':
await reload_wordlist(bot, message)
else:
await send_temp_message(bot, message, f"❌ Неизвестная команда: {subcommand}\n\nИспользуйте /badwords help")
async def show_help(bot: AsyncTeleBot, message: Message):
"""Показывает справку по командам управления бранными словами"""
help_text = COMMAND_MESSAGES['badwords_help']
await bot.send_message(
chat_id=message.chat.id,
text=help_text,
message_thread_id=message.message_thread_id,
)
await delete_messages(bot, message, time_sleep=60, number_message=2)
async def list_bad_words(bot: AsyncTeleBot, message: Message):
"""Показывает список бранных слов (первые 50)"""
words = get_bad_words()
if not words:
text = "📝 Список бранных слов пуст."
else:
# Показываем только первые 50 слов
display_words = words[:50]
text = f"📝 <b>Бранные слова</b> (всего: {len(words)})\n\n"
text += ", ".join([f"<code>{word}</code>" for word in display_words])
if len(words) > 50:
text += f"\n\n<i>...и ещё {len(words) - 50} слов</i>"
await bot.send_message(
chat_id=message.chat.id,
text=text,
message_thread_id=message.message_thread_id,
)
await delete_messages(bot, message, time_sleep=30, number_message=2)
async def count_words(bot: AsyncTeleBot, message: Message):
"""Показывает статистику по спискам"""
words = get_bad_words()
exceptions = get_exceptions()
text = (
f"📊 <b>Статистика списков</b>\n\n"
f"🚫 Бранных слов: <b>{len(words)}</b>\n"
f"✅ Исключений: <b>{len(exceptions)}</b>"
)
await bot.send_message(
chat_id=message.chat.id,
text=text,
message_thread_id=message.message_thread_id,
)
await delete_messages(bot, message, time_sleep=15, number_message=2)
async def add_bad_word(bot: AsyncTeleBot, message: Message, word: str):
"""Добавляет слово в список бранных"""
word = word.lower().strip()
words = get_bad_words()
exceptions = get_exceptions()
if word in words:
await send_temp_message(bot, message, f"⚠️ Слово '<code>{word}</code>' уже есть в списке.")
return
words.append(word)
if save_bad_words(words, exceptions):
reload_words() # Перезагружаем кэш
await send_temp_message(bot, message, f"✅ Слово '<code>{word}</code>' добавлено в список бранных.")
logger.info(f"Администратор {message.from_user.id} добавил бранное слово: {word}")
else:
await send_temp_message(bot, message, "❌ Ошибка при сохранении файла.")
async def remove_bad_word(bot: AsyncTeleBot, message: Message, word: str):
"""Удаляет слово из списка бранных"""
word = word.lower().strip()
words = get_bad_words()
exceptions = get_exceptions()
if word not in words:
await send_temp_message(bot, message, f"⚠️ Слово '<code>{word}</code>' не найдено в списке.")
return
words.remove(word)
if save_bad_words(words, exceptions):
reload_words() # Перезагружаем кэш
await send_temp_message(bot, message, f"✅ Слово '<code>{word}</code>' удалено из списка бранных.")
logger.info(f"Администратор {message.from_user.id} удалил бранное слово: {word}")
else:
await send_temp_message(bot, message, "❌ Ошибка при сохранении файла.")
async def list_exceptions(bot: AsyncTeleBot, message: Message):
"""Показывает список исключений"""
exceptions = get_exceptions()
if not exceptions:
text = "📝 Список исключений пуст."
else:
text = f"📝 <b>Исключения</b> (всего: {len(exceptions)})\n\n"
text += ", ".join([f"<code>{word}</code>" for word in exceptions])
await bot.send_message(
chat_id=message.chat.id,
text=text,
message_thread_id=message.message_thread_id,
)
await delete_messages(bot, message, time_sleep=30, number_message=2)
async def add_exception(bot: AsyncTeleBot, message: Message, word: str):
"""Добавляет слово в список исключений"""
word = word.lower().strip()
words = get_bad_words()
exceptions = get_exceptions()
if word in exceptions:
await send_temp_message(bot, message, f"⚠️ Слово '<code>{word}</code>' уже есть в исключениях.")
return
exceptions.append(word)
if save_bad_words(words, exceptions):
reload_words() # Перезагружаем кэш
await send_temp_message(bot, message, f"✅ Слово '<code>{word}</code>' добавлено в исключения.")
logger.info(f"Администратор {message.from_user.id} добавил исключение: {word}")
else:
await send_temp_message(bot, message, "❌ Ошибка при сохранении файла.")
async def remove_exception(bot: AsyncTeleBot, message: Message, word: str):
"""Удаляет слово из списка исключений"""
word = word.lower().strip()
words = get_bad_words()
exceptions = get_exceptions()
if word not in exceptions:
await send_temp_message(bot, message, f"⚠️ Слово '<code>{word}</code>' не найдено в исключениях.")
return
exceptions.remove(word)
if save_bad_words(words, exceptions):
reload_words() # Перезагружаем кэш
await send_temp_message(bot, message, f"✅ Слово '<code>{word}</code>' удалено из исключений.")
logger.info(f"Администратор {message.from_user.id} удалил исключение: {word}")
else:
await send_temp_message(bot, message, "❌ Ошибка при сохранении файла.")
async def reload_wordlist(bot: AsyncTeleBot, message: Message):
"""Перезагружает списки слов из файла"""
words, exceptions = reload_words()
text = (
f"🔄 <b>Списки перезагружены</b>\n\n"
f"🚫 Бранных слов: <b>{len(words)}</b>\n"
f"✅ Исключений: <b>{len(exceptions)}</b>"
)
await send_temp_message(bot, message, text)
logger.info(f"Администратор {message.from_user.id} перезагрузил списки слов")
async def send_temp_message(bot: AsyncTeleBot, message: Message, text: str, time_sleep: int = 10):
"""Отправляет временное сообщение, которое удаляется через указанное время"""
await bot.send_message(
chat_id=message.chat.id,
text=text,
message_thread_id=message.message_thread_id,
)
await delete_messages(bot, message, time_sleep=time_sleep, number_message=2)