Удаление предыдущего формата проекта
This commit is contained in:
4
bot.log
4
bot.log
@@ -1,4 +0,0 @@
|
||||
2025-12-08 13:08:26,502:WARNING:discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2025-12-08 13:08:26,504:INFO:discord.client: logging in using static token
|
||||
2025-12-08 14:08:52,657:WARNING:discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2025-12-08 14:08:52,659:INFO:discord.client: logging in using static token
|
||||
405
bot.py
405
bot.py
@@ -1,405 +0,0 @@
|
||||
import discord
|
||||
from discord.ext import commands, tasks
|
||||
from discord.utils import get
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
|
||||
# --- Настройки и константы ---
|
||||
BOT_TOKEN = '11'
|
||||
WELCOME_CHANNEL_ID = 1342797233250107482 # ID канала для приветствий
|
||||
ADMIN_ROLE_NAME = "Администратор"
|
||||
|
||||
WARNINGS_FILE = "warnings.json"
|
||||
REMINDERS_FILE = "reminders.json"
|
||||
BLACKLIST_FILE = "blacklist.json"
|
||||
|
||||
# --- Логирование ---
|
||||
logging.basicConfig(
|
||||
filename='bot.log',
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s:%(levelname)s:%(name)s: %(message)s'
|
||||
)
|
||||
|
||||
# --- Интенты ---
|
||||
intents = discord.Intents.default()
|
||||
intents.message_content = True
|
||||
intents.members = True
|
||||
|
||||
# --- Глобальные переменные ---
|
||||
reminders = []
|
||||
user_warnings = {}
|
||||
blacklist = []
|
||||
|
||||
# --- Хелп команда ---
|
||||
class MyHelpCommand(commands.HelpCommand):
|
||||
async def send_bot_help(self, mapping):
|
||||
channel = self.get_destination()
|
||||
help_text = (
|
||||
"**Доступные команды:**\n"
|
||||
"`!help` — показать это сообщение\n"
|
||||
"`!rules` — показать правила сервера\n"
|
||||
"`!reminder add <минуты> <текст>` — добавить напоминание (только для админов)\n"
|
||||
"`!reminder list` — показать все активные напоминания\n"
|
||||
"`!reminder remove <номер>` — удалить напоминание\n"
|
||||
"`!kick @пользователь [причина]` — исключить участника\n"
|
||||
"`!ban @пользователь [причина]` — забанить участника\n"
|
||||
"`!unban имя#дискриминатор` — разбанить участника\n"
|
||||
"`!mute @пользователь [причина]` — заглушить участника\n"
|
||||
"`!unmute @пользователь` — снять заглушение\n"
|
||||
"`!warn @пользователь [причина]` — выдать предупреждение\n"
|
||||
"`!warnings @пользователь` — посмотреть предупреждения\n"
|
||||
"`!clear <кол-во>` — удалить сообщения\n"
|
||||
"`!blacklist_show` — показать чёрный список (админ)\n"
|
||||
"`!blacklist_add <слово>` — добавить слово в чёрный список (админ)\n"
|
||||
"`!blacklist_remove <слово>` — удалить слово из чёрного списка (админ)\n"
|
||||
)
|
||||
await channel.send(help_text)
|
||||
|
||||
# --- Инициализация бота ---
|
||||
bot = commands.Bot(command_prefix='!', intents=intents, help_command=MyHelpCommand())
|
||||
|
||||
# --- Функции загрузки и сохранения данных ---
|
||||
def load_data():
|
||||
global reminders, user_warnings
|
||||
if os.path.isfile(WARNINGS_FILE):
|
||||
with open(WARNINGS_FILE, 'r', encoding='utf-8') as f:
|
||||
try:
|
||||
user_warnings.update(json.load(f))
|
||||
except json.JSONDecodeError:
|
||||
user_warnings.clear()
|
||||
if os.path.isfile(REMINDERS_FILE):
|
||||
with open(REMINDERS_FILE, 'r', encoding='utf-8') as f:
|
||||
try:
|
||||
reminders.extend(json.load(f))
|
||||
except json.JSONDecodeError:
|
||||
reminders.clear()
|
||||
|
||||
def save_warnings():
|
||||
with open(WARNINGS_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(user_warnings, f, ensure_ascii=False, indent=2)
|
||||
|
||||
def save_reminders():
|
||||
with open(REMINDERS_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(reminders, f, ensure_ascii=False, indent=2)
|
||||
|
||||
def load_blacklist_local():
|
||||
global blacklist
|
||||
if os.path.isfile(BLACKLIST_FILE):
|
||||
try:
|
||||
with open(BLACKLIST_FILE, 'r', encoding='utf-8') as f:
|
||||
blacklist = json.load(f)
|
||||
except Exception:
|
||||
blacklist = []
|
||||
else:
|
||||
blacklist = []
|
||||
|
||||
def save_blacklist_local():
|
||||
with open(BLACKLIST_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(blacklist, f, ensure_ascii=False, indent=2)
|
||||
|
||||
# --- Проверка и создание ролей ---
|
||||
async def ensure_roles_exist():
|
||||
for guild in bot.guilds:
|
||||
muted_role = get(guild.roles, name="Muted")
|
||||
if not muted_role:
|
||||
try:
|
||||
muted_role = await guild.create_role(name="Muted")
|
||||
for channel in guild.channels:
|
||||
await channel.set_permissions(muted_role, send_messages=False, speak=False)
|
||||
logging.info(f"Создана роль 'Muted' в {guild.name}")
|
||||
except Exception as e:
|
||||
logging.error(f"Ошибка при создании роли Muted в {guild.name}: {e}")
|
||||
|
||||
new_member_role = get(guild.roles, name="New Member")
|
||||
if not new_member_role:
|
||||
try:
|
||||
new_member_role = await guild.create_role(name="New Member")
|
||||
logging.info(f"Создана роль 'New Member' в {guild.name}")
|
||||
except Exception as e:
|
||||
logging.error(f"Ошибка при создании роли New Member в {guild.name}: {e}")
|
||||
|
||||
# --- События ---
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print(f'Бот запущен как {bot.user}')
|
||||
if not check_reminders.is_running():
|
||||
check_reminders.start()
|
||||
load_data()
|
||||
load_blacklist_local()
|
||||
await ensure_roles_exist()
|
||||
|
||||
@bot.event
|
||||
async def on_member_join(member):
|
||||
role = get(member.guild.roles, name="New Member")
|
||||
if role:
|
||||
await member.add_roles(role)
|
||||
channel = bot.get_channel(WELCOME_CHANNEL_ID)
|
||||
if channel:
|
||||
await channel.send(f"Приветствуем {member.mention} на сервере!")
|
||||
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
if message.author.bot:
|
||||
return
|
||||
# Проверка на запрещённые слова
|
||||
msg_lower = message.content.lower()
|
||||
if any(word in msg_lower for word in blacklist):
|
||||
try:
|
||||
await message.delete()
|
||||
await message.channel.send(f"{message.author.mention}, ваше сообщение содержит запрещённые слова.")
|
||||
logging.info(f"Удалено сообщение с запрещёнными словами от {message.author} в {message.channel}")
|
||||
except Exception as e:
|
||||
logging.error(f"Ошибка при удалении сообщения: {e}")
|
||||
return
|
||||
|
||||
await bot.process_commands(message)
|
||||
|
||||
# --- Проверка прав администратора ---
|
||||
def is_admin():
|
||||
def predicate(ctx):
|
||||
return get(ctx.author.roles, name=ADMIN_ROLE_NAME) is not None or ctx.author.guild_permissions.administrator
|
||||
return commands.check(predicate)
|
||||
|
||||
# --- Команды модерации и управления ---
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def blacklist_show(ctx):
|
||||
if not blacklist:
|
||||
await ctx.send("Чёрный список пуст.")
|
||||
else:
|
||||
await ctx.send("Чёрный список:\n" + ", ".join(blacklist))
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def blacklist_add(ctx, *, word: str):
|
||||
word = word.lower()
|
||||
if word in blacklist:
|
||||
await ctx.send(f"Слово `{word}` уже в чёрном списке.")
|
||||
else:
|
||||
blacklist.append(word)
|
||||
save_blacklist_local()
|
||||
await ctx.send(f"Слово `{word}` добавлено в чёрный список.")
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def blacklist_remove(ctx, *, word: str):
|
||||
word = word.lower()
|
||||
if word not in blacklist:
|
||||
await ctx.send(f"Слово `{word}` отсутствует в чёрном списке.")
|
||||
else:
|
||||
blacklist.remove(word)
|
||||
save_blacklist_local()
|
||||
await ctx.send(f"Слово `{word}` удалено из чёрного списка.")
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def rules(ctx):
|
||||
rules_text = (
|
||||
"**Правила сервера:**\n"
|
||||
"1. Уважайте других участников.\n"
|
||||
"2. Запрещена реклама и спам.\n"
|
||||
"3. Не используйте запрещённые слова.\n"
|
||||
"4. Соблюдайте тематику каналов.\n"
|
||||
"5. Выполняйте указания модераторов.\n"
|
||||
)
|
||||
await ctx.send(rules_text)
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def kick(ctx, member: discord.Member, *, reason=None):
|
||||
try:
|
||||
await member.kick(reason=reason)
|
||||
await ctx.send(f"{member} был исключён. Причина: {reason}")
|
||||
logging.info(f"{member} был исключён администратором {ctx.author}. Причина: {reason}")
|
||||
except Exception as e:
|
||||
await ctx.send(f"Не удалось исключить {member}.")
|
||||
logging.error(f"Ошибка при исключении: {e}")
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def ban(ctx, member: discord.Member, *, reason=None):
|
||||
try:
|
||||
await member.ban(reason=reason)
|
||||
await ctx.send(f"{member} был забанен. Причина: {reason}")
|
||||
logging.info(f"{member} был забанен администратором {ctx.author}. Причина: {reason}")
|
||||
except Exception as e:
|
||||
await ctx.send(f"Не удалось забанить {member}.")
|
||||
logging.error(f"Ошибка при бане: {e}")
|
||||
|
||||
|
||||
@bot.command()
|
||||
@commands.has_permissions(ban_members=True)
|
||||
async def unban(ctx, *, member_name):
|
||||
banned_users = []
|
||||
async for ban_entry in ctx.guild.bans():
|
||||
banned_users.append(ban_entry)
|
||||
|
||||
# Если указан полный тег с #
|
||||
if '#' in member_name:
|
||||
try:
|
||||
name, discriminator = member_name.split('#')
|
||||
except ValueError:
|
||||
await ctx.send("Неверный формат пользователя. Используйте Имя#Тег.")
|
||||
return
|
||||
|
||||
for ban_entry in banned_users:
|
||||
user = ban_entry.user
|
||||
if (user.name, user.discriminator) == (name, discriminator):
|
||||
try:
|
||||
await ctx.guild.unban(user)
|
||||
await ctx.send(f"Пользователь {user} разбанен.")
|
||||
return
|
||||
except Exception as e:
|
||||
await ctx.send("Ошибка при разбане.")
|
||||
logging.error(f"Ошибка при разбане: {e}")
|
||||
return
|
||||
|
||||
await ctx.send(f"Пользователь {member_name} не найден в бан-листе.")
|
||||
return
|
||||
|
||||
# Если указан только имя без тега — ищем все совпадения по имени
|
||||
matching = [ban_entry.user for ban_entry in banned_users if ban_entry.user.name.lower() == member_name.lower()]
|
||||
|
||||
if not matching:
|
||||
await ctx.send(f"Пользователь с именем `{member_name}` не найден в бан-листе.")
|
||||
return
|
||||
|
||||
if len(matching) == 1:
|
||||
user = matching[0]
|
||||
try:
|
||||
await ctx.guild.unban(user)
|
||||
await ctx.send(f"Пользователь {user} разбанен.")
|
||||
except Exception as e:
|
||||
await ctx.send("Ошибка при разбане.")
|
||||
logging.error(f"Ошибка при разбане: {e}")
|
||||
return
|
||||
|
||||
# Если совпадений несколько — выводим список для выбора
|
||||
msg = "Найдено несколько пользователей с таким именем. Укажите полный тег для разбанивания:\n"
|
||||
for user in matching:
|
||||
msg += f"- {user.name}#{user.discriminator}\n"
|
||||
await ctx.send(msg)
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def mute(ctx, member: discord.Member, *, reason=None):
|
||||
muted_role = get(ctx.guild.roles, name="Muted")
|
||||
if not muted_role:
|
||||
await ctx.send("Роль Muted не найдена.")
|
||||
return
|
||||
try:
|
||||
await member.add_roles(muted_role)
|
||||
await ctx.send(f"{member} заглушен. Причина: {reason}")
|
||||
except Exception as e:
|
||||
await ctx.send("Не удалось выдать мут.")
|
||||
logging.error(f"Ошибка при муте: {e}")
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def unmute(ctx, member: discord.Member):
|
||||
muted_role = get(ctx.guild.roles, name="Muted")
|
||||
if not muted_role:
|
||||
await ctx.send("Роль Muted не найдена.")
|
||||
return
|
||||
try:
|
||||
await member.remove_roles(muted_role)
|
||||
await ctx.send(f"С мутом снято с {member}.")
|
||||
except Exception as e:
|
||||
await ctx.send("Не удалось снять мут.")
|
||||
logging.error(f"Ошибка при снятии мута: {e}")
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def warn(ctx, member: discord.Member, *, reason=None):
|
||||
user_id = str(member.id)
|
||||
if user_id not in user_warnings:
|
||||
user_warnings[user_id] = []
|
||||
user_warnings[user_id].append({"reason": reason or "Без причины", "date": str(datetime.datetime.now())})
|
||||
save_warnings()
|
||||
await ctx.send(f"{member} получил предупреждение. Причина: {reason or 'Без причины'}")
|
||||
|
||||
@bot.command()
|
||||
async def warnings(ctx, member: discord.Member):
|
||||
user_id = str(member.id)
|
||||
warns = user_warnings.get(user_id, [])
|
||||
if not warns:
|
||||
await ctx.send(f"У пользователя {member} нет предупреждений.")
|
||||
return
|
||||
msg = f"Предупреждения пользователя {member}:\n"
|
||||
for i, w in enumerate(warns, 1):
|
||||
msg += f"{i}. {w['reason']} ({w['date']})\n"
|
||||
await ctx.send(msg)
|
||||
|
||||
@bot.command()
|
||||
@is_admin()
|
||||
async def clear(ctx, amount: int):
|
||||
if amount <= 0:
|
||||
await ctx.send("Количество должно быть положительным числом.")
|
||||
return
|
||||
deleted = await ctx.channel.purge(limit=amount + 1)
|
||||
await ctx.send(f"Удалено сообщений: {len(deleted)-1}", delete_after=5)
|
||||
|
||||
# --- Команды напоминаний ---
|
||||
@bot.group()
|
||||
@is_admin()
|
||||
async def reminder(ctx):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send("Используйте `!reminder add <минуты> <текст>`, `!reminder list` или `!reminder remove <номер>`")
|
||||
|
||||
@reminder.command(name="add")
|
||||
async def reminder_add(ctx, minutes: int, *, text: str):
|
||||
if minutes <= 0:
|
||||
await ctx.send("Время должно быть положительным числом минут.")
|
||||
return
|
||||
remind_time = datetime.datetime.now() + datetime.timedelta(minutes=minutes)
|
||||
reminders.append({
|
||||
"time": remind_time.timestamp(),
|
||||
"channel_id": ctx.channel.id,
|
||||
"user_mention": ctx.author.mention,
|
||||
"text": text
|
||||
})
|
||||
save_reminders()
|
||||
await ctx.send(f"Напоминание добавлено через {minutes} минут: {text}")
|
||||
|
||||
@reminder.command(name="list")
|
||||
async def reminder_list(ctx):
|
||||
if not reminders:
|
||||
await ctx.send("Активных напоминаний нет.")
|
||||
return
|
||||
msg = "Активные напоминания:\n"
|
||||
for i, rem in enumerate(reminders, 1):
|
||||
t = datetime.datetime.fromtimestamp(rem["time"]).strftime("%Y-%m-%d %H:%M:%S")
|
||||
msg += f"{i}. Через {t} — {rem['text']} (от {rem['user_mention']})\n"
|
||||
await ctx.send(msg)
|
||||
|
||||
@reminder.command(name="remove")
|
||||
async def reminder_remove(ctx, number: int):
|
||||
if number <= 0 or number > len(reminders):
|
||||
await ctx.send("Неверный номер напоминания.")
|
||||
return
|
||||
removed = reminders.pop(number - 1)
|
||||
save_reminders()
|
||||
await ctx.send(f"Удалено напоминание: {removed['text']}")
|
||||
|
||||
# --- Фоновая задача проверки напоминаний ---
|
||||
@tasks.loop(seconds=30)
|
||||
async def check_reminders():
|
||||
now = datetime.datetime.now().timestamp()
|
||||
to_remove = []
|
||||
for rem in reminders:
|
||||
if rem['time'] <= now:
|
||||
channel = bot.get_channel(rem['channel_id'])
|
||||
if channel:
|
||||
await channel.send(f"{rem['user_mention']} Напоминание: {rem['text']}")
|
||||
to_remove.append(rem)
|
||||
for rem in to_remove:
|
||||
reminders.remove(rem)
|
||||
if to_remove:
|
||||
save_reminders()
|
||||
|
||||
# --- Запуск бота ---
|
||||
bot.run(BOT_TOKEN)
|
||||
Reference in New Issue
Block a user