import datetime from os import name from typing import Text from discord.ext.commands.core import cooldown from requests.api import delete START_TIME = datetime.datetime.utcnow() import locale locale.setlocale(locale.LC_NUMERIC, ('ru_RU', 'UTF-8')) import sys sys.tracebacklimit = 0 import discord import discord_slash import vk_api import json import random import asyncio import requests import threading import logging import time import re from string import Template from discord import utils from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType from discord_slash.utils.manage_commands import create_choice, create_option, create_permission from PIL import Image, ImageDraw, ImageFont root_logger = logging.getLogger() factory = logging.getLogRecordFactory() def add_secs(*args, **kwargs): record = factory(*args, **kwargs) record.secs = record.relativeCreated/1000 return record logging.setLogRecordFactory(add_secs) root_logger.setLevel(logging.INFO) try: log_path = f'logs/bot_log{str(START_TIME)}.log' handler = logging.FileHandler(log_path, 'w', 'utf-8') except: log_path = 'bot.log' handler = logging.FileHandler(log_path, 'w', 'utf-8') ch = logging.StreamHandler() f = logging.Formatter('[{secs:10.2f}] [{levelname:s}] {message:s} [{name:s}]', style="{") handler.setFormatter(f) ch.setFormatter(f) root_logger.addHandler(handler) root_logger.addHandler(ch) def log(text): logging.info(text) log(f"Script started {START_TIME.strftime('%d.%m.%Y %H:%M:%S.%f UTC')}") STRING_TRUE = ['true', '1', 't', 'y', 'yes', 'д', 'да', 'ага', 'тирания'] STRING_FALSE = ['false', '0', 'f', 'n', 'no', 'н', 'нет', 'неа', 'террор'] ACTIVE_TOTAL = 0 USERS_LAST_MESSAGE = {} USERS_LAST_ACTIVE = {} USERS_FLOOD_COUNTER = {} INIT_SETUP_CHANNEL = {} TO_VERIFY = {} NEW_YEAR_STATS = {} NEW_YEAR_NOTIFYED = {} intents = discord.Intents.default() intents.members = True client = discord.Client(guild_subscriptions=True, chunk_guilds_at_startup=True, intents=intents) slash = discord_slash.SlashCommand(client, sync_commands=True) def num4(num): """Number in 4 symbols and postfix (5 symbols)""" num = int(num) if len(str(num)) <= 4: return str(num) postfixs = ["k", "M", "B", "T", "q", "Q", "s", "S"] nl = len(str(num))-1 scale = min(int(nl / 3), len(postfixs)) num /= 10**(3*scale) decimal_length = 2 - nl % 3 if int(nl / 3) <= len(postfixs) else 0 return f"{num:.{decimal_length}f}{postfixs[scale-1]}" try: with open("data.json", "r") as jsn: data = json.load(jsn) except Exception as e: logging.critical(f"Some problem with 'data.json': {e}") exit("Some problem with 'data.json'") for g in data['bot-data']: if g != "counters" and g != "new_year_event": for m in data['bot-data'][g]['active']: ACTIVE_TOTAL += data['bot-data'][g]['active'][m] class Counters: def __init__(self): self.SESSION = {'vk_msg_recived': 0, 'vk_msg_sended': 0, 'exceptions': 0, 'dc_msg_recived': 0, 'dc_msg_sended': 0} try: self.COUNTERS = data['bot-data']['counters'] except: self.COUNTERS = {'start_stats_timestamp': datetime.datetime.now().timestamp(), 'uptime_secs': 0, 'start_ups': 0, 'vk_msg_recived': 0, 'vk_msg_sended': 0, 'exceptions': 0, 'dc_msg_recived': 0, 'dc_msg_sended': 0} self.uptime_from = self.COUNTERS['uptime_secs'] self.COUNTERS['start_ups'] += 1 def incriment(self, case: str): if case == "e": self.SESSION['exceptions'] += 1 self.COUNTERS['exceptions'] += 1 elif case == "vk-r": self.SESSION['vk_msg_recived'] += 1 self.COUNTERS['vk_msg_recived'] += 1 elif case == "vk-s": self.SESSION['vk_msg_sended'] += 1 self.COUNTERS['vk_msg_sended'] += 1 elif case == "dc-r": self.SESSION['dc_msg_recived'] += 1 self.COUNTERS['dc_msg_recived'] += 1 elif case == "dc-s": self.SESSION['dc_msg_sended'] += 1 self.COUNTERS['dc_msg_sended'] += 1 data['bot-data']['counters'] = self.COUNTERS def show(self, which: str): if which == "session": return self.SESSION elif which == "counters": return self.COUNTERS def incriment_uptime(self): self.COUNTERS['uptime_secs'] = self.uptime_from + ( datetime.datetime.utcnow().timestamp() - START_TIME.timestamp()) data['bot-data']['counters'] = self.COUNTERS counters = Counters() class MyVkLongPoll(VkBotLongPoll): def listen(self): while True: try: for event in self.check(): yield event except Exception as e: counters.incriment("e") err = "A problem with VK LongPull: " + str(e) log(err) continue def debug(): numbers = counters.show("session") return f"Последний запуск: {START_TIME.strftime('%d.%m.%Y %H:%M:%S.%f UTC')}\n\ Поймано исключений: {numbers['exceptions']}\n\n\ **ВК**\n\ - Отправлено сообщений: {numbers['vk_msg_sended']}\n\ - Получено сообщений: {numbers['vk_msg_recived']}\n\n\ **Дискорд**\n\ - Отправлено сообщений: {numbers['dc_msg_sended']}\n\ - Получено сообщений: {numbers['dc_msg_recived']}\n" def counters_print(): numbers = counters.show("counters") return f"**Значения накопительных счётчиков \ (созданы {datetime.datetime.fromtimestamp(numbers['start_stats_timestamp']).strftime('%d.%m.%Y %H:%M:%S UTC')})**\n\ Запусков: {numbers['start_ups']}\n\ Всего поймано исключений: {numbers['exceptions']}\n\n\ *ВК*\n\ Всего сообщений: {numbers['vk_msg_sended'] + numbers['vk_msg_recived']}\n\ - прослушано: {numbers['vk_msg_recived']}\n\ - отправлено: {numbers['vk_msg_sended']}\n\n\ *Discord*\n\ Всего сообщений: {numbers['dc_msg_recived'] + numbers['dc_msg_sended']}\n\ - прослушано: {numbers['dc_msg_recived']}\n\ - отправлено: {numbers['dc_msg_sended']}\n\ " def uptime_rate(): now = datetime.datetime.utcnow() session_up = datetime.datetime.utcnow() - START_TIME start_time = datetime.datetime.fromtimestamp(counters.show("counters")['start_stats_timestamp']) all_up = session_up + datetime.timedelta(seconds=counters.uptime_from) time_from_init = now - start_time uptime_r = (all_up.total_seconds() / time_from_init.total_seconds()) * 100 return f'Время работы бота: {strfdelta(datetime.datetime.utcnow(), START_TIME, True, "%D:%H:%M:%S")}\n\ Начиная с {start_time.strftime("%d.%m.%Y")}:\n\ - Проработал: {strfdelta(datetime.datetime.utcnow(), START_TIME - datetime.timedelta(seconds=counters.uptime_from), True, "%D:%H:%M:%S")}\n\ - Простаивал: {strfdelta(now, start_time + all_up, True, "%D:%H:%M:%S")}\n\n\ **UPTIME РЕЙТИНГ: {locale.format_string("%.6f", uptime_r, grouping=True)} %**' class DeltaTemplate(Template): delimiter = "%" def strfdelta(zero:datetime.datetime, dtfrom:datetime.datetime, show_days:bool, temp=None) -> str: if zero < dtfrom: tdelta = dtfrom - zero negative = True else: tdelta = zero - dtfrom negative = False if tdelta.days == 0 and temp is None: show_days = False if show_days: d = {"D": tdelta.days} hours, rem = divmod(tdelta.seconds, 3600) minutes, seconds = divmod(rem, 60) d["H"] = '{:02d}'.format(hours) d["M"] = '{:02d}'.format(minutes) d["S"] = '{:02d}'.format(seconds) if temp is None: if negative: t = DeltaTemplate('- %D дн. %H:%M:%S') else: t = DeltaTemplate('%D дн. %H:%M:%S') else: if negative: t = DeltaTemplate('-'+temp) else: t = DeltaTemplate(temp) return t.substitute(**d) else: d = {"D": tdelta.days} hours, rem = divmod(tdelta.seconds, 3600) minutes, seconds = divmod(rem, 60) hours += d["D"]*24 d["H"] = hours d["M"] = '{:02d}'.format(minutes) d["S"] = '{:02d}'.format(seconds) if temp is None: if negative: t = DeltaTemplate('-%H:%M:%S') else: t = DeltaTemplate('%H:%M:%S') else: if negative: t = DeltaTemplate('-'+temp) else: t = DeltaTemplate(temp) return t.substitute(**d) def hi_msg_temp(user_mention, full_username, temp): d = {"user_mention": user_mention, "full_username": full_username} return DeltaTemplate(temp).substitute(**d) def widget_temp(temp): d = {"until_new_year": strfdelta(datetime.datetime(year=datetime.datetime.utcnow().year, month=12, day=31, hour=21, minute=0), datetime.datetime.utcnow(), False, "%Hч%Mм"), "next_year": str(datetime.datetime.now().year + 1)} return DeltaTemplate(temp).substitute(**d) def can_use_it(dude, guild_id): has_role = False if data['bot-data'][str(guild_id)].get("role_access"): for i in dude.roles: if i.id == data['bot-data'][str(guild_id)]["role_access"]: has_role = True if dude.id == data['main-data']['owner_id'] or dude.id == data['bot-data'][str(guild_id)]['access'] or has_role: return True else: return False def count_active(dude_id, guild_id, len_of_message, len_of_attachment): global ACTIVE_TOTAL if not data['bot-data'][str(guild_id)]['active'].get(str(dude_id)): data['bot-data'][str(guild_id)]['active'][str(dude_id)] = len_of_message + len_of_attachment*10 else: message_limit = 30 if len_of_message > message_limit: data['bot-data'][str(guild_id)]['active'][str(dude_id)] += message_limit + len_of_attachment*10 ACTIVE_TOTAL += message_limit + len_of_attachment*10 else: data['bot-data'][str(guild_id)]['active'][str(dude_id)] += len_of_message + len_of_attachment*10 ACTIVE_TOTAL += len_of_message + len_of_attachment*10 async def get_image_stats(msg): avatar = await msg.author.avatar_url_as(format="png", size=256).read() image_file = open("av.png", "wb") image_file.write(avatar) image_file.close() X = 1000 Y = 400 a = str(msg.author.id) active_role_level = -1 if data['bot-data'][str(msg.guild.id)].get("roles") and data['bot-data'][str(msg.guild.id)].get("active_roles"): if len(data['bot-data'][str(msg.guild.id)]['roles']) == len(data['bot-data'][str(msg.guild.id)]['active_roles']): for i in msg.author.roles: for ar in data['bot-data'][str(msg.guild.id)]["roles"]: if i.id == ar: active_role_level = data['bot-data'][str(msg.guild.id)]["roles"].index(ar) show_progress_to_next_role = True if active_role_level != len(data['bot-data'][str(msg.guild.id)]["roles"])-1: string_next_role = f'До роли "{utils.get(msg.guild.roles, id=data["bot-data"][str(msg.guild.id)]["roles"][active_role_level+1]).name}"' user_next_role_active = data['bot-data'][str(msg.guild.id)]["active_roles"][active_role_level+1] if active_role_level == -1: user_currect_role = "Неактивный" user_currect_role_active = 0 else: user_currect_role = utils.get(msg.guild.roles, id=data['bot-data'][str(msg.guild.id)]["roles"][active_role_level]).name user_currect_role_active = data['bot-data'][str(msg.guild.id)]["active_roles"][active_role_level] else: show_progress_to_next_role = False user_next_role_active = data['bot-data'][str(msg.guild.id)]["active"][a] user_currect_role = utils.get(msg.guild.roles, id=data['bot-data'][str(msg.guild.id)]["roles"][active_role_level]).name user_currect_role_active = 0 else: show_progress_to_next_role = False user_next_role_active = data['bot-data'][str(msg.guild.id)]["active"][a] user_currect_role = f"Ролей: {len(data['bot-data'][str(msg.guild.id)]['roles'])}, требований: {len(data['bot-data'][str(msg.guild.id)]['active_roles'])}. Настройте бота!" user_currect_role_active = 0 else: show_progress_to_next_role = False user_next_role_active = data['bot-data'][str(msg.guild.id)]["active"][a] user_currect_role = "" user_currect_role_active = 0 place = sorted(data['bot-data'][str(msg.guild.id)]["active"], key=lambda i: data['bot-data'][str(msg.guild.id)]["active"][i], reverse=True).index(a)+1 bar_offset = ((user_next_role_active - user_currect_role_active) - (data['bot-data'][str(msg.guild.id)]['active'][a] - user_currect_role_active)) / (user_next_role_active - user_currect_role_active) * (X - 100) im = Image.new("RGB", (X, Y), (25, 25, 25)) draw = ImageDraw.Draw(im) av_pil = Image.open("av.png") av_r = av_pil.resize((164, 164)) font = ImageFont.truetype("19471.ttf", 50) big_font = ImageFont.truetype("19471.ttf", 130) small_font = ImageFont.truetype("19471.ttf", 30) draw.line((50, Y - 50, X - 50, Y - 50), (0, 0, 0), 33) draw.line((50, Y - 50, X - 50 - bar_offset, Y - 50), (255, 255, 255), 33) draw.text((230, 50), msg.author.display_name, font=font) draw.text((230, 160), user_currect_role, font=font) draw.text((230, 100), f"#{place} на сервере {msg.guild.name}\nПрисоединился {strfdelta(datetime.datetime.utcnow(), msg.author.joined_at, data['bot-data'][str(msg.guild.id)]['days_in_timedelta'])} назад", font=small_font) size3 = font.getsize(locale.format_string("%d", user_next_role_active - data['bot-data'][str(msg.guild.id)]['active'][a], grouping=True)) if show_progress_to_next_role: size1 = small_font.getsize(string_next_role) draw.text((X - size1[0] - 50 , Y-135), string_next_role, font=small_font, align="right") draw.text((X - size3[0] - 50 , Y-110), locale.format_string("%d", user_next_role_active - data['bot-data'][str(msg.guild.id)]['active'][a], grouping=True), font=font, align="right") im.paste(av_r, (50, 50, 214, 214)) draw.text((50, Y - 170), locale.format_string("%d", data['bot-data'][str(msg.guild.id)]['active'][a], grouping=True), font=big_font) im.save("stats.png", "png") async def get_image_stats_all(msg): Y = 145 font = ImageFont.truetype("19471.ttf", 50) lower_hat_font = ImageFont.truetype("19471.ttf", 30) longest_name_size_x = font.getsize(msg.guild.name)[0] for u in data['bot-data'][str(msg.guild.id)]["active"]: try: name = client.get_guild(msg.guild.id).get_member(int(u)).display_name except Exception: member = requests.get(f"https://discordapp.com/api/users/{u}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}) if member.ok: member = member.json() name = f"{member['username']}#{member['discriminator']}" else: name = f"id{u}" name_size_x = lower_hat_font.getsize(name)[0] Y += 30 longest_name_size_x = max(longest_name_size_x, name_size_x) X = longest_name_size_x + 140 + lower_hat_font.getsize("Актив")[0] + 10 im = Image.new("RGB", (X, Y), (25, 25, 25)) draw = ImageDraw.Draw(im) title = msg.guild.name draw.text((X / 2 - font.getsize(title)[0] / 2, 5), title, font=font) draw.text((10, 60), "Пользователь", font=lower_hat_font) draw.text((longest_name_size_x + 140, 60), "Актив", font=lower_hat_font) start_table_y = 100 to_draw = sorted(data['bot-data'][str(msg.guild.id)]["active"], key=lambda i: data['bot-data'][str(msg.guild.id)]["active"][i], reverse=True) all_a = 0 for u in to_draw: try: name = client.get_guild(msg.guild.id).get_member(int(u)).display_name except Exception: member = requests.get(f"https://discordapp.com/api/users/{u}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}) if member.ok: member = member.json() name = f"{member['username']}#{member['discriminator']}" else: name = f"id{u}" draw.text((10, start_table_y), name, font=lower_hat_font) size_a = lower_hat_font.getsize(locale.format_string("%d", data['bot-data'][str(msg.guild.id)]["active"][u], grouping=True)) draw.text((longest_name_size_x + 140 + lower_hat_font.getsize("Актив")[0] - size_a[0], start_table_y), locale.format_string("%d", data['bot-data'][str(msg.guild.id)]["active"][u], grouping=True), font=lower_hat_font) start_table_y += 30 all_a += data['bot-data'][str(msg.guild.id)]["active"][u] start_table_y += 10 draw.text((10, start_table_y), "Весь сервер:", font=lower_hat_font) size_a = lower_hat_font.getsize(locale.format_string("%d", all_a, grouping=True)) draw.text((longest_name_size_x + 140 + lower_hat_font.getsize("Актив")[0] - size_a[0], start_table_y), locale.format_string("%d", all_a, grouping=True), font=lower_hat_font) im.save("stats_all.png", "png") async def get_image_stats_all_guilds(msg): Y = 145 font = ImageFont.truetype("19471.ttf", 50) lower_hat_font = ImageFont.truetype("19471.ttf", 30) longest_name_size_x = font.getsize("Актив всех серверов")[0] guilds = {} for g in data['bot-data']: if g != "counters": name = client.get_guild(int(g)).name name_size_x = lower_hat_font.getsize(name)[0] Y += 30 longest_name_size_x = max(longest_name_size_x, name_size_x) active = sum( data['bot-data'][g]["active"][m] for m in data["bot-data"][g]["active"] ) guilds[g] = {'name': name, 'active': active} X = longest_name_size_x + 140 + lower_hat_font.getsize("Актив")[0] + 10 im = Image.new("RGB", (X, Y), (25, 25, 25)) draw = ImageDraw.Draw(im) title = "Актив всех серверов" draw.text((X / 2 - font.getsize(title)[0] / 2, 5), title, font=font) draw.text((10, 60), "Сервер", font=lower_hat_font) draw.text((longest_name_size_x + 140, 60), "Актив", font=lower_hat_font) start_table_y = 100 to_draw = sorted(guilds, key=lambda i: guilds[i]["active"], reverse=True) all_a = 0 for u in to_draw: draw.text((10, start_table_y), guilds[u]["name"], font=lower_hat_font) size_a = lower_hat_font.getsize(locale.format_string("%d", guilds[u]["active"], grouping=True)) draw.text((longest_name_size_x + 140 + lower_hat_font.getsize("Актив")[0] - size_a[0], start_table_y), locale.format_string("%d", guilds[u]["active"], grouping=True), font=lower_hat_font) start_table_y += 30 all_a += guilds[u]["active"] start_table_y += 10 draw.text((10, start_table_y), "Все сервера:", font=lower_hat_font) size_a = lower_hat_font.getsize(locale.format_string("%d", all_a, grouping=True)) draw.text((longest_name_size_x + 140 + lower_hat_font.getsize("Актив")[0] - size_a[0], start_table_y), locale.format_string("%d", all_a, grouping=True), font=lower_hat_font) im.save("stats_all_guilds.png", "png") @client.event async def on_ready(): log(f'Logged in Discord as {client.user}') global NEW_YEAR_STATS NEW_YEAR_STATS = data['bot-data']["new_year_event"] for g in data['bot-data']: if g != "counters" and g != "new_year_event": if data['bot-data'][g]['state'] != 'normal': data['bot-data'][g]['state'] = 'normal' NEW_YEAR_NOTIFYED[g] = False if not NEW_YEAR_STATS.get(g): NEW_YEAR_STATS[g] = {'cooldown': 1638835200, "times_used": {}, "type_used":{"ban": 0, "not_ban": 0}, "victums": {}, "longest_mute":None, "shortest_mute":None} @client.event async def on_message(message): if isinstance(message.channel, discord.TextChannel): if message.author == client.user: counters.incriment("dc-s") m = message.content.replace("\n", "⁞") log(f'Bot in {message.guild} #{message.channel}: "{m}", attachments: {message.attachments}') else: m = message.content.replace("\n", "⁞") log(f'{message.author} in {message.guild} #{message.channel}: "{m}", attachments: {message.attachments}') counters.incriment("dc-r") if not data['bot-data'].get(str(message.guild.id)): data['bot-data'][str(message.guild.id)] = {"active": {}, "muted": {}, "banned": {}, "count_channel": 1, "access": message.guild.owner_id, "state": "normal", "command_prefix": "$", 'can_ban': False, 'react_on_join_leave_members': False, 'days_in_timedelta': True, "days_for_spam": 1} if not data.get("game"): data['game'] = {} if not USERS_LAST_ACTIVE.get(str(message.guild.id)): USERS_LAST_ACTIVE[str(message.guild.id)] = {str(message.author.id): datetime.datetime(2020, 1, 1)} if not USERS_LAST_MESSAGE.get(str(message.guild.id)): USERS_LAST_MESSAGE[str(message.guild.id)] = {str(message.author.id): ""} if not USERS_FLOOD_COUNTER.get(str(message.guild.id)): USERS_FLOOD_COUNTER[str(message.guild.id)] = {str(message.author.id): 0} if not USERS_LAST_ACTIVE[str(message.guild.id)].get(str(message.author.id)): USERS_LAST_ACTIVE[str(message.guild.id)][str(message.author.id)] = datetime.datetime(2020, 1, 1) if not USERS_LAST_MESSAGE[str(message.guild.id)].get(str(message.author.id)): USERS_LAST_MESSAGE[str(message.guild.id)][str(message.author.id)] = "" if not USERS_FLOOD_COUNTER[str(message.guild.id)].get(str(message.author.id)): USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] = 0 if not message.author.bot and (message.content != "" or len(message.attachments) > 0) and (USERS_LAST_MESSAGE[str(message.guild.id)][str(message.author.id)] != message.content or len(message.attachments) > 0): count_active(message.author.id, message.guild.id, len(message.content), len(message.attachments)) if data['bot-data'][str(message.guild.id)].get("mute_role") and data['bot-data'][str(message.guild.id)].get('flood_limit'): invite_search = re.search(r"discord\.gg\/\w+", message.content) if invite_search is not None and not can_use_it(message.author, message.guild.id): USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] = data['bot-data'][str(message.guild.id)]['flood_limit'] await message.delete() elif 747797669648269364 in message.raw_role_mentions: USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] += 3 elif len(message.attachments) == 0 and (USERS_LAST_MESSAGE[str(message.guild.id)][str(message.author.id)] == message.content or (message.created_at - USERS_LAST_ACTIVE[str(message.guild.id)][str(message.author.id)]) < datetime.timedelta(0, 2,5)): USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] += 1 elif USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] > 0: USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] -= 1 if USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] >= data['bot-data'][str(message.guild.id)]['flood_limit']: role = utils.get(message.guild.roles, id=data['bot-data'][str(message.guild.id)]['mute_role']) await message.author.add_roles(role) now = datetime.datetime.utcnow() mute = datetime.timedelta(days=1) mute_time = now + mute data['bot-data'][str(message.guild.id)]['muted'][str(message.author.id)] = {"timestamp": mute_time.timestamp(), "reason": "Спам", "by_id": client.user.id, "done": datetime.datetime.utcnow().timestamp()} emb = discord.Embed(description=f"От {client.user.mention} специально для {message.author.mention}\n**Срок молчалки:** {strfdelta(now+mute, now, data['bot-data'][str(message.guild.id)]['days_in_timedelta'])}", title=f"Молчалка за спам", timestamp=mute_time, colour=0x0000ff) emb.set_author(name=f"{message.author.name} (Ник: {message.author.nick})", icon_url=message.author.avatar_url) await message.channel.send(f"Ты в муте за спам {message.author.mention}", embed=emb) USERS_FLOOD_COUNTER[str(message.guild.id)][str(message.author.id)] = 0 USERS_LAST_MESSAGE[str(message.guild.id)][str(message.author.id)] = message.content USERS_LAST_ACTIVE[str(message.guild.id)][str(message.author.id)] = message.created_at if data['bot-data'][str(message.guild.id)].get("roles") and data['bot-data'][str(message.guild.id)].get("active_roles") and not message.author.bot: if len(data['bot-data'][str(message.guild.id)]['roles']) == len(data['bot-data'][str(message.guild.id)]['active_roles']): active_role_level = -1 for i in message.author.roles: for ar in data['bot-data'][str(message.guild.id)]["roles"]: if i.id == ar: active_role_level = data['bot-data'][str(message.guild.id)]["roles"].index(ar) for ari in data['bot-data'][str(message.guild.id)]['roles']: if active_role_level != len(data['bot-data'][str(message.guild.id)]['roles'])-1: if data['bot-data'][str(message.guild.id)]["active"][str(message.author.id)] >= int(data['bot-data'][str(message.guild.id)]['active_roles'][data['bot-data'][str(message.guild.id)]['roles'].index(ari)]) and active_role_level < data['bot-data'][str(message.guild.id)]['roles'].index(ari): role = utils.get(message.guild.roles, id=ari) await message.author.add_roles(role) text = f"{message.author.mention}, вы проявили достаточно актива для получения роли \"{role.name}\", поздравляю" if data['bot-data'][str(message.guild.id)].get('notify_channel'): await message.guild.get_channel(data['bot-data'][str(message.guild.id)]['notify_channel']).send(text) else: await message.channel.send(text) role = utils.get(message.guild.roles, id=data['bot-data'][str(message.guild.id)]['roles'][active_role_level]) await message.author.remove_roles(role) if data['bot-data'][str(message.guild.id)].get("count_log"): if message.channel.id == data['bot-data'][str(message.guild.id)]["count_log"] and message.author != client.user: try: if int(message.content) == data['bot-data'][str(message.guild.id)]["count_channel"]: data['bot-data'][str(message.guild.id)]["count_channel"] += 1 if data['bot-data'][str(message.guild.id)].get("roles_count"): if (data['bot-data'][str(message.guild.id)]["count_channel"]-1) % 10000 == 0: role = utils.get(message.guild.roles, id=data['bot-data'][str(message.guild.id)]["roles_count"][3]) await message.author.add_roles(role) await message.pin() elif (data['bot-data'][str(message.guild.id)]["count_channel"]-1) % 1000 == 0: role = utils.get(message.guild.roles, id=data['bot-data'][str(message.guild.id)]["roles_count"][2]) await message.author.add_roles(role) await message.pin() elif (data['bot-data'][str(message.guild.id)]["count_channel"]-1) == 500: role = utils.get(message.guild.roles, id=data['bot-data'][str(message.guild.id)]["roles_count"][1]) await message.author.add_roles(role) await message.pin() elif (data['bot-data'][str(message.guild.id)]["count_channel"]-1) == 100: role = utils.get(message.guild.roles, id=data['bot-data'][str(message.guild.id)]["roles_count"][0]) await message.author.add_roles(role) await message.pin() else: if (data['bot-data'][str(message.guild.id)]["count_channel"]-1) % 10000 == 0: await message.pin() elif (data['bot-data'][str(message.guild.id)]["count_channel"]-1) % 1000 == 0: await message.pin() elif (data['bot-data'][str(message.guild.id)]["count_channel"]-1) == 500: await message.pin() elif (data['bot-data'][str(message.guild.id)]["count_channel"]-1) == 100: await message.pin() else: await message.delete() except ValueError: await message.delete() if message.content.lower() == "бот дай денег": await message.channel.send("Иди нахуй") with open("data.json", "w") as jsn: json.dump(data, jsn) elif isinstance(message.channel, discord.DMChannel): log(f'Message in {message.channel} by "{message.author}": "{message.content}", attachments: {message.attachments}') if message.content == "reboot" and message.author.id == data['main-data']['owner_id']: await message.channel.send(f"Перезагружаюсь") exit("Got command to exit") if message.content == "ъ": await message.channel.send(f"ь") else: log(message) @client.event async def on_error(event, *args, **kwargs): counters.incriment("e") exc = sys.exc_info() logging.error(f"Exception {exc[0]} in {event}: {exc[1]}", exc_info=exc) @client.event async def on_guild_join(guild): log(f"We joined to {guild}") data['bot-data'][str(guild.id)] = {"active": {}, "muted": {}, "banned": {}, "count_channel": 1, "access": guild.owner_id, "state": "normal", 'can_ban': False, 'react_on_join_leave_members': False, 'days_in_timedelta': True, "days_for_spam": 1} await guild.system_channel.send(f"Доброго времени суток. Спасибо, что пригласили меня на свой сервер. Используйте команду /help, чтобы узнать о моих возможностях") with open("data.json", "w") as jsn: json.dump(data, jsn) @client.event async def on_member_join(member): log(f"Joined member {member} to guild {member.guild}") muted = False banned = False for u in data['bot-data'][str(member.guild.id)]["muted"]: if u == str(member.id): role = utils.get(member.guild.roles, id=data['bot-data'][str(member.guild.id)]['mute_role']) await member.add_roles(role) muted = True for u in data['bot-data'][str(member.guild.id)]["banned"]: if u == str(member.id): banned = True if banned: mesg = await member.guild.system_channel.send(f'Персонаж из бан листа {member.name}#{member.discriminator} осмелился ступить на сервер. Что-ж, банхаммер на готове.') await member.ban(reason=data['bot-data'][str(member.guild.id)]["banned"][str(member.id)]['reason']) elif muted: strtimediff = strfdelta(datetime.datetime.fromtimestamp(data["bot-data"][str(member.guild.id)]["muted"][str(member.id)]["timestamp"]), datetime.datetime.utcnow(), data['bot-data'][str(member.guild.id)]['days_in_timedelta']) mesg = await member.guild.system_channel.send(f'Ку, {member.mention}. На этом сервере ты получил мут от <@{data["bot-data"][str(member.guild.id)]["muted"][str(member.id)]["by_id"]}> за "{data["bot-data"][str(member.guild.id)]["muted"][str(member.id)]["reason"]}" и он истекает через {strtimediff}') elif data['bot-data'][str(member.guild.id)].get("role_for_verification"): if not data['bot-data'][str(member.guild.id)].get('hi_msg'): mesg = await member.guild.system_channel.send(f'Добро пожаловать, {member.mention}. Чтобы получить роль участника "{utils.get(member.guild.roles, id=data["bot-data"][str(member.guild.id)]["role_for_verification"]).name}" и получить доступ к серверу, поставьте реакцию на это сообщение.') else: mesg = await member.guild.system_channel.send(hi_msg_temp(member.mention, f"{member.name}#{member.discriminator}", data['bot-data'][str(member.guild.id)]['hi_msg']) + f'\nЧтобы получить роль участника "{utils.get(member.guild.roles, id=data["bot-data"][str(member.guild.id)]["role_for_verification"]).name}" и получить доступ к серверу, поставьте реакцию на это сообщение.') elif data['bot-data'][str(member.guild.id)]["react_on_join_leave_members"]: if not data['bot-data'][str(member.guild.id)].get('hi_msg'): await member.guild.system_channel.send(f'Добро пожаловать, {member.mention}') else: await member.guild.system_channel.send(hi_msg_temp(member.mention, f"{member.name}#{member.discriminator}", data['bot-data'][str(member.guild.id)]['hi_msg'])) if data['bot-data'][str(member.guild.id)].get("role_for_verification"): await mesg.add_reaction("✅") if not TO_VERIFY.get(str(member.guild.id)): TO_VERIFY[str(member.guild.id)] = [] TO_VERIFY[str(member.guild.id)].append(member.id) if data['bot-data'][str(member.guild.id)].get("admin_log"): emb = discord.Embed(description=f"**Дата регистрации:** {member.created_at.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**Cуществует уже:** {strfdelta(datetime.datetime.utcnow(), member.created_at, data['bot-data'][str(member.guild.id)]['days_in_timedelta'])}", title=f"Новый пользователь на сервере", timestamp=member.joined_at, colour=0xd1e9ef) emb.set_author(name=f"{member.name}#{member.discriminator}", icon_url=member.avatar_url) emb.set_footer(text=f"User ID: {member.id}, Bot: {member.bot}") await client.get_channel(data['bot-data'][str(member.guild.id)]['admin_log']).send(embed=emb) @client.event async def on_member_remove(member): log(f"Removed member {member} from guild {member.guild}") if data['bot-data'][str(member.guild.id)].get("admin_log"): emb = discord.Embed(description=f"**Дата регистрации:** {member.created_at.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**Cуществует уже:** {strfdelta(datetime.datetime.utcnow(), member.created_at, data['bot-data'][str(member.guild.id)]['days_in_timedelta'])}\n**Пробыл на сервере**: {strfdelta(datetime.datetime.utcnow(), member.joined_at, data['bot-data'][str(member.guild.id)]['days_in_timedelta'])}", title=f"Пользователь покинул сервер", timestamp=member.joined_at, colour=0xff0000) emb.set_author(name=f"{member.name}#{member.discriminator}", icon_url=member.avatar_url) emb.set_footer(text=f"User ID: {member.id}, Bot: {member.bot}") await client.get_channel(data['bot-data'][str(member.guild.id)]['admin_log']).send(embed=emb) if data['bot-data'][str(member.guild.id)]["react_on_join_leave_members"]: await member.guild.system_channel.send(f'{member} покинул сервер. Он пробыл здесь всего {strfdelta(datetime.datetime.utcnow(), member.joined_at, data["bot-data"][str(member.guild.id)]["days_in_timedelta"])}') @client.event async def on_raw_reaction_add(payload): if TO_VERIFY.get(str(payload.guild_id)) and data['bot-data'][str(payload.guild_id)].get("role_for_verification"): for i in TO_VERIFY[str(payload.guild_id)]: if i == payload.user_id: TO_VERIFY[str(payload.guild_id)].remove(i) await payload.member.add_roles(utils.get(client.get_guild(payload.guild_id).roles, id=data['bot-data'][str(payload.guild_id)]["role_for_verification"])) @client.event async def on_raw_message_delete(payload): if data['bot-data'][str(payload.guild_id)].get("admin_log"): if payload.cached_message: emb = discord.Embed(title="Было удалено сообщение", description=payload.cached_message.content, timestamp=payload.cached_message.created_at, colour=0xff0000) emb.set_author(name=f"{payload.cached_message.author.name} (Ник: {payload.cached_message.author.nick}) #{payload.cached_message.channel}", icon_url=payload.cached_message.author.avatar_url) if payload.cached_message.attachments: for i in payload.cached_message.attachments: emb.add_field(name="Прикреплено", value=i.filename, inline=False) if payload.cached_message.reactions: reactions = "" for i in payload.cached_message.reactions: if reactions == "": reactions += f"{i.emoji} **{i.count}**" else: reactions += f", {i.emoji} **{i.count}**" emb.add_field(name=f"Реакций: {len(payload.cached_message.reactions)}", value=reactions, inline=False) else: emb = discord.Embed(title="Было удалено сообщение", description="Сообщения не было в кеше бота", colour=0xff0000) await client.get_channel(data['bot-data'][str(payload.guild_id)]['admin_log']).send(embed=emb) @client.event async def on_member_update(before, after): if data['bot-data'][str(before.guild.id)].get("admin_log"): if after.nick != before.nick: emb = discord.Embed(title="Пользователь изменил свой ник на сервере", colour=0x00ff00) if before.nick is not None: emb.add_field(name="Старый ник", value=before.nick) else: emb.add_field(name="Старый ник", value="**Нет ника**") if after.nick is not None: emb.add_field(name="Новый ник", value=after.nick) else: emb.add_field(name="Новый ник", value="**Нет ника**") emb.set_author(name=after.name, icon_url=after.avatar_url) await client.get_channel(data['bot-data'][str(before.guild.id)]['admin_log']).send(embed=emb) @client.event async def on_member_ban(guild, user): log(f"Banned in {guild}: {user}") if data['bot-data'][str(guild.id)].get("admin_log"): emb = discord.Embed(title="Пользователь был забанен", description=f"**Дата регистрации:** {user.created_at.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**Cуществует уже:** {strfdelta(datetime.datetime.utcnow(), user.created_at, data['bot-data'][str(guild.id)]['mute_role'])}\n**Пробыл на сервере**: {strfdelta(datetime.datetime.utcnow(), user.joined_at, data['bot-data'][str(guild.id)]['mute_role'])}", colour=0xff0000) emb.set_author(name=f"{user.name}#{user.discriminator}", icon_url=user.avatar_url) emb.set_footer(text=f"User ID: {user.id}, Bot: {user.bot}") await client.get_channel(data['bot-data'][str(guild.id)]['admin_log']).send(embed=emb) @client.event async def on_member_unban(guild, user): log(f"Unbanned in {guild}: {user}") if data['bot-data'][str(guild.id)].get("admin_log"): emb = discord.Embed(title="Пользователь был разбанен", description=f"**Дата регистрации:** {user.created_at.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**Cуществует уже:** {strfdelta(datetime.datetime.utcnow(), user.created_at, data['bot-data'][str(guild.id)]['mute_role'])}", colour=0x00ff00) emb.set_author(name=f"{user.name}#{user.discriminator}", icon_url=user.avatar_url) emb.set_footer(text=f"User ID: {user.id}, Bot: {user.bot}") await client.get_channel(data['bot-data'][str(guild.id)]['admin_log']).send(embed=emb) @client.event async def on_invite_create(invite): if data['bot-data'][str(invite.guild.id)].get("admin_log"): emb = discord.Embed(title="Была создана ссылка-приглашение", description=invite.url, timestamp=invite.created_at, colour=0x0000ff) emb.add_field(name="Канал", value=invite.channel.mention) if invite.max_age > 0 and invite.max_age != None: emb.add_field(name="Срок действия", value=f"{strfdelta(invite.created_at+datetime.timedelta(0, invite.max_age), invite.created_at, data['bot-data'][str(invite.guild.id)]['mute_role'])}\n(до {(invite.created_at+datetime.timedelta(0, invite.max_age)).strftime('%d.%m.%Y %H:%M:%S UTC')})") else: emb.add_field(name="Срок действия", value="Вечная ссылка") if invite.max_uses > 0 and invite.max_uses != None: emb.add_field(name="Лимит на использование", value=f"{invite.max_uses} раз") if invite.temporary: emb.add_field(name="Ссылка предоставляет временное членство", value="Если временным учасникам не выдадут роль, они автоматически будут кикнуты") emb.set_author(name=invite.inviter.display_name, icon_url=invite.inviter.avatar_url) await client.get_channel(data['bot-data'][str(invite.guild.id)]['admin_log']).send(embed=emb) @client.event async def on_invite_delete(invite): if data['bot-data'][str(invite.guild.id)].get("admin_log"): emb = discord.Embed(title="Была удалена ссылка-приглашение", description=invite.url, colour=0xff0000) emb.add_field(name="Канал", value=invite.channel.mention) await client.get_channel(data['bot-data'][str(invite.guild.id)]['admin_log']).send(embed=emb) @client.event async def on_raw_message_edit(payload): if data['bot-data'][payload.data['guild_id']].get("admin_log"): emb = discord.Embed(title="Было отредактировано сообщение", description=f"**Отредактировано:** {datetime.datetime.strptime(payload.data['edited_timestamp'], '%Y-%m-%dT%H:%M:%S.%f%z').strftime('%d.%m.%Y %H:%M:%S UTC')}", timestamp=datetime.datetime.strptime(payload.data['timestamp'], "%Y-%m-%dT%H:%M:%S.%f%z"), colour=0x0000ff) if payload.cached_message: emb.set_author(name=f"{payload.cached_message.author.name} (Ник: {payload.cached_message.author.nick}) #{payload.cached_message.channel}", icon_url=payload.cached_message.author.avatar_url) emb.add_field(name="Старый текст", value=payload.cached_message.content, inline=True) else: emb.set_author(name=f"{payload.data['author']['username']}") emb.add_field(name="Сообщения не было в кеше бота", value="Невозможно показать разницу", inline=True) emb.add_field(name="Новый текст", value=payload.data['content'], inline=True) await client.get_channel(data['bot-data'][payload.data['guild_id']]['admin_log']).send(embed=emb) @client.event async def on_guild_remove(guild): log(f"We left from {guild}") global ACTIVE_TOTAL for m in data['bot-data'][str(guild.id)]['active']: ACTIVE_TOTAL -= data['bot-data'][str(guild.id)]['active'][m] del data['bot-data'][str(guild.id)] @slash.slash(name="help", description="Справочный материал с описанием команд бота") async def help(ctx): emb = discord.Embed(title="Справочный материал с описанием команд бота", description="Эта справка призвана помочь разобраться в командах бота") emb.add_field(name=f"/random *X* *Y*", value="Генерирует рандомное число от *X* до *Y*. Если *Y* нету, то тогда от 0 до *X*. Если и *X* нет, то тогда от 0 до 10") emb.add_field(name=f"/stats *choice*", value="Посмотреть актив, который насчитал бот для вас, а если после команды написать *all*, то можно посмотреть актив, который насчитал бот для всего сервера") #emb.add_field(name=f"{data['bot-data'][str(ctx.guild.id)]['command_prefix']}кнб *камень/ножницы/бумага/стат*", value='Сыграть в "Камень, ножницы, бумага" с ботом, если приписать аргумент *стат*, можно увидеть количесво побед, поражений и ничей') emb.add_field(name=f"/slap *@user*", value='Шлёпнуть *@user* или рандомного персонажа на сервере, если не упомянут') if can_use_it(ctx.author, ctx.guild.id): emb.add_field(name=f"/settings", value="Даёт возможность перенастроить бота") if data['bot-data'][str(ctx.guild.id)].get("mute_role"): emb.add_field(name=f"/mute *@user* *[s, m, h, d, w]/DD.MM.YYYY* *reason*", value="Выдать молчалку пользователю. Команда имеет 2 обязательных аргумента: *@user* - упоминание персоны; *[s, m, h, d, w]/DD.MM.YYYY* - либо срок в относительном формате (30m - 30 минут, 7d - 7 дней), либо дата. Есть также 3-ий необязательный аргумент: *reason* - причина мута.") emb.add_field(name=f"/unmute *@user*", value="Cнять молчалку с пользователя. *@user* - упоминание персоны") emb.add_field(name=f"/mute_list", value="Показать активные на сервере молчалки") if data['bot-data'][str(ctx.guild.id)]["can_ban"]: emb.add_field(name=f"/ban *@user* *[s, m, h, d, w]/DD.MM.YYYY* *reason*", value="Забанить пользователя. Команда имеет 2 обязательных аргумента: *@user* - упоминание персоны; *[s, m, h, d, w]/DD.MM.YYYY* - либо срок в относительном формате (30m - 30 минут, 7d - 7 дней), либо дата. Есть также 3-ий необязательный аргумент: *reason* - причина бана.") emb.add_field(name=f"/unban *id*", value="Разбанить пользователя, которого забанили командой /ban. *id* - его цифровой id") emb.add_field(name=f"/ban_list", value="Показать активные на сервере баны") await ctx.send(embed=emb) @slash.slash(name="random", description="Отправляет рандомное число от X до Y", options=[create_option(name="x_int", description="Наименьшее число если используется вместе с y_int, иначе число больше нуля", option_type=4, required=False), create_option(name="y_int", description="Наибольшее число", option_type=4, required=False)]) async def randon(ctx, **kwargs): if "y_int" in kwargs and "x_int" in kwargs: emb = discord.Embed(title="Рандомное число") emb.add_field(name="От", value=kwargs["x_int"], inline=True) emb.add_field(name="До", value=kwargs["y_int"], inline=True) emb.add_field(name="**Результат**", value=locale.format_string('**%d**', random.randint(kwargs["x_int"], kwargs["y_int"]), grouping=True), inline=False) elif "x_int" in kwargs: emb = discord.Embed(title="Рандомное число") emb.add_field(name="От", value="0", inline=True) emb.add_field(name="До", value=kwargs["x_int"], inline=True) emb.add_field(name="**Результат**", value=locale.format_string('**%d**', random.randint(0, kwargs["x_int"]), grouping=True), inline=False) else: emb = discord.Embed(title="Рандомное число") emb.add_field(name="От", value="0", inline=True) emb.add_field(name="До", value="10", inline=True) emb.add_field(name="**Результат**", value=locale.format_string('**%d**', random.randint(0, 10), grouping=True), inline=False) await ctx.send(embed=emb) # , permissions={ # 747583006322983053:[ # create_permission(747583006322983053, discord_slash.model.SlashCommandPermissionType.ROLE, False), # create_permission(747879784364769331, discord_slash.model.SlashCommandPermissionType.ROLE, True) # ] #} @slash.slash(name="debug", description="Позволяет узнать состояние бота", options=[ create_option(name="applet", description="Название конкретной штуки, информацию о которой надо узнать", option_type=3, required=True, choices=[ create_choice(name="Общая информация", value="default"), create_choice(name="Антиспам система", value="spam"), create_choice(name="Cчётчики", value="counters"), create_choice(name="Время работы бота", value="uptime") ]) ]) async def deb(ctx, applet): if applet == "default": await ctx.send(debug()) elif applet == "spam": answer = f"**Работа антиспам системы**\nДанный массив - то, как видит ситуацию антиспам система бота. На уровне *{data['bot-data'][str(ctx.guild.id)]['flood_limit']}* или выше - выдаёт мут на 1 день.\n" for u in USERS_FLOOD_COUNTER[str(ctx.guild.id)]: member = ctx.guild.get_member(u) answer += f"\n{member} - {USERS_FLOOD_COUNTER[str(ctx.guild.id)][u]}" await ctx.send(answer) elif applet == "counters": await ctx.send(counters_print()) elif applet == "uptime": await ctx.send(uptime_rate()) @slash.slash(name="stats", description="Бот отправит информацию о набранных очках актива", options=[ create_option(name="choice", description=" Количество очков актива чего вам нужно узнать?", option_type=3, required=True, choices=[ create_choice(name="Обо мне", value="me"), create_choice(name="О сервере", value="server"), create_choice(name="Таблица серверов", value="all servers") ]) ]) async def stats(ctx, choice): if choice == "me": await get_image_stats(ctx) await ctx.send(file=discord.File("stats.png")) elif choice == "server": await get_image_stats_all(ctx) await ctx.send(file=discord.File("stats_all.png")) elif choice == "all servers": await get_image_stats_all_guilds(ctx) await ctx.send(file=discord.File("stats_all_guilds.png")) @slash.slash(name="slap", description="Шлёпнуть кого-нибудь))))))", options=[ create_option(name="user", description="Выберите пользователя для шлепка, иначе будет выбран рандомный", option_type=6, required=False) ]) async def slap(ctx, **kwargs): guy = kwargs['user'] if "user" in kwargs else random.choice(ctx.guild.members) await ctx.send(f"{ctx.author.mention} шлёпнул {guy.mention}") @slash.slash(name="gift", description="Подарить либо мешочек с нихуя, либо мут от 1 секунды до 2 часов") async def new_year_present(ctx): START_TIME = 1638835200 END_TIME = 1641513600 dt_now = datetime.datetime.utcnow() now = dt_now.timestamp() global NEW_YEAR_STATS global NEW_YEAR_NOTIFYED if not NEW_YEAR_STATS.get(str(ctx.guild.id)): NEW_YEAR_STATS[str(ctx.guild.id)] = {'cooldown': START_TIME, "times_used": {}, "type_used":{"ban": 0, "not_ban": 0}, "victums": {}, "longest_mute":None, "shortest_mute":None} if NEW_YEAR_STATS[str(ctx.guild.id)]["cooldown"] <= now: victim = random.choice(ctx.guild.members) mute = random.randint(0, 1) if mute: reason = "Новогодний подарок" for_ban = victim if data['bot-data'][str(ctx.guild.id)].get('mute_role'): role = utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['mute_role']) await for_ban.add_roles(role) mute_time = random.randint(1, 7200) data['bot-data'][str(ctx.guild.id)]['muted'][str(for_ban.id)] = {"timestamp": now + mute_time, "reason": reason, "by_id": ctx.author.id, "done": now} emb = discord.Embed(description=f"От <@{ctx.author.id}> рандомному персонажу на сервере, которым оказался <@{for_ban.id}>\n**Подарок:** молчалка сроком {strfdelta(datetime.datetime.utcfromtimestamp(now + mute_time), dt_now, False)}", title=f"Новогодний подарок", timestamp=datetime.datetime.fromtimestamp(now + mute_time), colour=0x0000ff) emb.set_author(name=f"{for_ban.name} (Ник: {for_ban.nick})", icon_url=for_ban.avatar_url) emb.set_footer(text="Действует до") else: emb = discord.Embed(description=f"От <@{ctx.author.id}> рандомному персонажу на сервере, которым оказался <@{victim.id}>\n**Подарок:** мешочек с нихуя", title=f"Новогодний подарок", colour=0x0000ff, image="https://sun9-41.userapi.com/impf/c849128/v849128784/b0a1/GXEDUAUp-3A.jpg?size=200x200&quality=96&sign=3bb33aaba78a34581f46ed63e11c4725&type=album") emb.set_author(name=f"{victim.name} (Ник: {victim.nick})", icon_url=victim.avatar_url) if not NEW_YEAR_STATS[str(ctx.guild.id)]["times_used"].get(str(ctx.author.id)): NEW_YEAR_STATS[str(ctx.guild.id)]["times_used"][str(ctx.author.id)] = 1 else: NEW_YEAR_STATS[str(ctx.guild.id)]["times_used"][str(ctx.author.id)] += 1 if not NEW_YEAR_STATS[str(ctx.guild.id)]["victums"].get(str(victim.id)): NEW_YEAR_STATS[str(ctx.guild.id)]["victums"][str(victim.id)] = 1 else: NEW_YEAR_STATS[str(ctx.guild.id)]["victums"][str(victim.id)] += 1 if mute: NEW_YEAR_STATS[str(ctx.guild.id)]["type_used"]["ban"] += 1 if NEW_YEAR_STATS[str(ctx.guild.id)]["longest_mute"] == None or NEW_YEAR_STATS[str(ctx.guild.id)]["longest_mute"][0] < mute_time: NEW_YEAR_STATS[str(ctx.guild.id)]["longest_mute"] = [mute_time, victim.id, ctx.author.id] if NEW_YEAR_STATS[str(ctx.guild.id)]["shortest_mute"] == None or NEW_YEAR_STATS[str(ctx.guild.id)]["shortest_mute"][0] > mute_time: NEW_YEAR_STATS[str(ctx.guild.id)]["shortest_mute"] = [mute_time, victim.id, ctx.author.id] else: NEW_YEAR_STATS[str(ctx.guild.id)]["type_used"]["not_ban"] += 1 if (dt_now.day == 31 and dt_now.month == 12) or (dt_now.day == 1 and dt_now.month == 1): cooldown = now + 900 text_cd = "Команда снова будет доступна через 15 минут" elif dt_now.day == 30 and dt_now.month == 12: cooldown = now + 3600 text_cd = "Команда снова будет доступна через 60 минут" elif dt_now.day >= 25 and dt_now.month == 12: cooldown = now + 7200 text_cd = "Команда снова будет доступна через 2 часа" elif dt_now.day >= 20 and dt_now.month == 12: cooldown = now + 10800 text_cd = "Команда снова будет доступна через 3 часа" elif dt_now.day >= 15 and dt_now.month == 12: cooldown = now + 14400 text_cd = "Команда снова будет доступна через 4 часа" elif dt_now.day >= 10 and dt_now.month == 12: cooldown = now + 18000 text_cd = "Команда снова будет доступна через 5 часов" elif dt_now.day >= 7 and (dt_now.month == 12 or dt_now.month == 1): cooldown = now + 21600 text_cd = "Команда снова будет доступна через 6 часов" if cooldown >= END_TIME: text_cd += ". Это будет последний подарок" else: cooldown = datetime.datetime(dt_now.year, 12, 7).timestamp() text_cd = f'Ивент завершён. Статистика за {dt_now.year-1}-{dt_now.year} года:\nВсего было подарков: {NEW_YEAR_STATS[str(ctx.guild.id)]["type_used"]["ban"]+NEW_YEAR_STATS[str(ctx.guild.id)]["type_used"]["not_ban"]}, из которых было молчалок: {NEW_YEAR_STATS[str(ctx.guild.id)]["type_used"]["ban"]}, мешочков с нихуя: {NEW_YEAR_STATS[str(ctx.guild.id)]["type_used"]["not_ban"]}' NEW_YEAR_STATS[str(ctx.guild.id)]["cooldown"] = cooldown await ctx.send(f"Держи, {victim.mention}. {text_cd}", embed=emb) data['bot-data']["new_year_event"] = NEW_YEAR_STATS with open("data.json", "w") as jsn: json.dump(data, jsn) NEW_YEAR_NOTIFYED[str(ctx.guild.id)] = False else: await ctx.send(f"Новый сюрприз можно будет устроить через {strfdelta(datetime.datetime.fromtimestamp(NEW_YEAR_STATS[str(ctx.guild.id)]['cooldown']), dt_now, False)}", delete_after=15) @slash.slash(name="settings", description="Настройте бота на вашем сервере", options=[ create_option(name="setting", description="Выберите необходимую настройку", option_type=3, required=True, choices=[ create_choice(name="Роль доступа к боту", value="access_role"), create_choice(name="Канал уведомлений", value="notify_channel"), create_choice(name="Дни в отображении разницы времени", value="days_in_timedelta"), create_choice(name="Роль мута", value="mute_role"), create_choice(name="Лимит антифлуд системы", value="flood_limit"), create_choice(name="Бан командой", value="can_ban"), create_choice(name="Реагировать на приход/уход участников", value="join_leave"), create_choice(name="Шаблон приветствия нового пользователя", value="hi_msg"), create_choice(name="Роль верификации", value="role_for_verification"), create_choice(name="Канал для лога событий сервера", value="admin_log"), create_choice(name="Список ролей за актив", value="active_roles"), create_choice(name="Список требований за роли актива", value="active_for_roles"), create_choice(name="Канал для счёта", value="counting"), create_choice(name="Список ролей в канале счёта", value="roles_for_count") ]), create_option(name="value", description="Укажите, чтобы изменить настройку, иначе бот отправит значение настройки", option_type=3, required=False) ]) async def sett(ctx, **kwargs): # sourcery skip: merge-else-if-into-elif if can_use_it(ctx.author, ctx.guild.id): if kwargs['setting'] == "access_role": if "value" in kwargs: if kwargs['value'].lower() == "clear": if data['bot-data'][str(ctx.guild.id)].get("role_access"): del data['bot-data'][str(ctx.guild.id)]['role_access'] await ctx.send(f"Особый доступ к боту будете иметь только вы") else: try: data['bot-data'][str(ctx.guild.id)]['role_access'] = int(kwargs['value']) await ctx.send(f"Роль {utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['role_access']).mention} будет использоваться для доступа к боту.") except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("role_access"): await ctx.send(f"Особый доступ к боту есть только у {ctx.author}\nЧтобы установить роль с особым доступом, напишите её id в аргументе *value*") else: await ctx.send(f"Особый досуп к боту имеют все, у кого есть роль \"{utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['role_access'])}\"\nЧтобы установить роль с особым доступом, напишите её id в аргументе *value*\n Чтобы удалить роль, в аргументе *value* напишите \"clear\"") elif kwargs["setting"] == "notify_channel": if "value" in kwargs: if kwargs["value"].lower() == "clear": del data['bot-data'][str(ctx.guild.id)]['notify_channel'] await ctx.send(f"Уведомления о размуте, разбане и повышении роли выключены") else: try: data['bot-data'][str(ctx.guild.id)]['notify_channel'] = int(kwargs['value']) await ctx.send(f"Канал {utils.get(ctx.guild.channels, id=data['bot-data'][str(ctx.guild.id)]['notify_channel'])} будет использоваться для уведомлений о размуте, разбане и повышении роли") except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("notify_channel"): await ctx.send(f"Канал для уведомлений о размуте, разбане и повышении роли не указан\nЧтобы включить, напишите его id в аргументе *value*") else: await ctx.send(f"Канал для уведомлений о размуте, разбане и повышении роли: {utils.get(ctx.guild.channels, id=data['bot-data'][str(ctx.guild.id)]['notify_channel'])}\nЧтобы изменить канал для админ-лога, напишите его id в аргументе *value*\nЧтобы выключить админ-лог, в аргументе *value* напишите \"clear\"") elif kwargs["setting"] == "days_in_timedelta": if "value" in kwargs: if kwargs["value"] in STRING_TRUE: data['bot-data'][str(ctx.guild.id)]['days_in_timedelta'] = True await ctx.send(f"Формат разницы времени: *дни* дн. *часы*:*минуты*:*секунды*") elif kwargs["value"] in STRING_FALSE: data['bot-data'][str(ctx.guild.id)]['days_in_timedelta'] = False await ctx.send(f"Формат разницы времени: *дни в часах+часы*:*минуты*:*секунды*") else: await ctx.send(f"Некорректное значение", delete_after=10) else: await ctx.send(f"Флаг формата разницы времени: {data['bot-data'][str(ctx.guild.id)]['days_in_timedelta']}\nЧтобы изменить, укажите в аргументе *value* булево значение (True или False)") elif kwargs["setting"] == "mute_role": if "value" in kwargs: if kwargs['value'].lower() == "clear": if data['bot-data'][str(ctx.guild.id)].get("mute_role"): del data['bot-data'][str(ctx.guild.id)]['mute_role'] await ctx.send(f"Молчалка отключена") else: try: data['bot-data'][str(ctx.guild.id)]['mute_role'] = int(kwargs['value']) await ctx.send(f"Роль {utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['mute_role']).mention} будет использоваться для молчалки.") except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("mute_role"): await ctx.send(f"Молчалка отключена\nЧтобы включить, напишите id роли, которая запрещает отправлять сообщения, в аргументе *value*") else: await ctx.send(f"Роль молчалки: \"{utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['mute_role'])}\"\nЧтобы изменить роль молчалки, напишите id роли, которая запрещает отправлять сообщения, в аргументе *value*\n Чтобы удалить роль, в аргументе *value* напишите \"clear\"") elif kwargs["setting"] == "flood_limit": if not data['bot-data'][str(ctx.guild.id)].get("mute_role"): await ctx.send("Молчалка отключена\nОна нужна в качестве наказания за флуд") elif "value" in kwargs: try: if int(kwargs['value']) > 0: data['bot-data'][str(ctx.guild.id)]['flood_limit'] = int(kwargs['value']) await ctx.send(f"Лимит на флуд: {data['bot-data'][str(ctx.guild.id)]['flood_limit']} одинаковых/быстро отправленных сообщений подряд") elif int(kwargs['value']) == 0: del data['bot-data'][str(ctx.guild.id)]['flood_limit'] await ctx.send("Лимит на флуд выключен") else: await ctx.send("Лимит должен быть больше нуля или ноль, если хотите выключить", delete_after=10) except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get('flood_limit'): await ctx.send("Наказание отключено\nЧтобы включить, укажите в аргументе *value*, сколько сообщений флуда можно написать перед полученем наказания") else: await ctx.send(f"Лимит анти-флуд системы: {data['bot-data'][str(ctx.guild.id)]['flood_limit']} одинаковых/быстро отправленных сообщений\nЧтобы изменить, укажите в аргументе *value*, сколько сообщений флуда можно написать перед полученем наказания, или 0, чтобы отключить систему") elif kwargs["setting"] == "can_ban": if "value" in kwargs: if kwargs["value"] in STRING_TRUE: data['bot-data'][str(ctx.guild.id)]['can_ban'] = True await ctx.send(f"Теперь можно банить людей через команду `/ban`") elif kwargs["value"] in STRING_FALSE: data['bot-data'][str(ctx.guild.id)]['can_ban'] = False await ctx.send(f"Команда `/ban` выключена") else: await ctx.send(f"Некорректное значение", delete_after=10) else: await ctx.send(f"Можно банить через команду бота: {data['bot-data'][str(ctx.guild.id)]['can_ban']}\nЧтобы изменить, укажите в аргументе *value* булево значение (True или False)") elif kwargs["setting"] == "join_leave": if "value" in kwargs: if kwargs["value"] in STRING_TRUE: data['bot-data'][str(ctx.guild.id)]['react_on_join_leave_members'] = True await ctx.send(f"Бот будет реагировать на приход/уход участников") elif kwargs["value"] in STRING_FALSE: data['bot-data'][str(ctx.guild.id)]['react_on_join_leave_members'] = False await ctx.send(f"Бот не будет реагировать на приход/уход участников") else: await ctx.send(f"Некорректное значение", delete_after=10) else: await ctx.send(f"Реагировать на приход на сервер и уход с него участников: {data['bot-data'][str(ctx.guild.id)]['react_on_join_leave_members']}\nЧтобы изменить, укажите в аргументе *value* булево значение (True или False)") elif kwargs["setting"] == "hi_msg": if "value" in kwargs: if kwargs["value"].lower() == "clear": del data['bot-data'][str(ctx.guild.id)]['hi_msg'] await ctx.send("Будет использоваться стандартный шаблон приветствия") else: data['bot-data'][str(ctx.guild.id)]['hi_msg'] = kwargs["value"] await ctx.send(f"Новый шаблон приветствия: {data['bot-data'][str(ctx.guild.id)]['hi_msg']}") else: if not data['bot-data'][str(ctx.guild.id)].get('hi_msg'): await ctx.send(f"Используется стандартный шаблон приветствия\nЧтобы изменить, в аргументе *value* напишите шаблон сообщения. В нём могут быть такие элементы, как `%user_mention` (упоминание новичка) и `%full_username` (полный ник новичка)") else: await ctx.send(f"Шаблон приветствия: {data['bot-data'][str(ctx.guild.id)]['hi_msg']}\nЧтобы изменить, в аргументе *value* напишите шаблон сообщения. В нём могут быть такие элементы, как `%user_mention` (упоминание новичка) и `%full_username` (полный ник новичка)\nЕсли он больше не нужен, после аргумента напишите \"clear\"") elif kwargs["setting"] == "role_for_verification": if "value" in kwargs: if kwargs['value'].lower() == "clear": if data['bot-data'][str(ctx.guild.id)].get("role_for_verification"): del data['bot-data'][str(ctx.guild.id)]['role_for_verification'] await ctx.send(f"Верификация отключена") else: try: data['bot-data'][str(ctx.guild.id)]['role_for_verification'] = int(kwargs['value']) await ctx.send(f"Роль {utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['role_for_verification'])} будет использоваться для верификации.") except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("role_for_verification"): await ctx.send(f"Верификация отключена\nЧтобы включить, напишите id роли верификации в аргументе *value*") else: await ctx.send(f"Роль верификации: \"{utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['role_for_verification']).name}\"\nЧтобы изменить роль верификации, напишите её id в аргументе *value*\nЧтобы выключить верификацию, в аргументе *value* напишите \"clear\"") elif kwargs["setting"] == "admin_log": if "value" in kwargs: if kwargs["value"].lower() == "clear": del data['bot-data'][str(ctx.guild.id)]['admin_log'] await ctx.send(f"Уведомления о размуте, разбане и повышении роли выключены") else: try: data['bot-data'][str(ctx.guild.id)]['admin_log'] = int(kwargs['value']) await ctx.send(f"Канал {utils.get(ctx.guild.channels, id=data['bot-data'][str(ctx.guild.id)]['admin_log'])} будет использоваться для уведомлений о размуте, разбане и повышении роли") except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("admin_log"): await ctx.send(f"Канал админ-лога не указан\nЧтобы включить, напишите id канала для админ-лога в аргументе *value*") else: await ctx.send(f"Канал админ-лога: \"{utils.get(ctx.guild.channels, id=data['bot-data'][str(ctx.guild.id)]['admin_log'])}\"\nЧтобы изменить канал для админ-лога, напишите его id в аргументе *value*\nЧтобы выключить админ-лог, в аргументе *value* напишите \"clear\"") elif kwargs["setting"] == "active_roles": if "value" in kwargs: lst = kwargs["value"].split(" ") try: for l in lst: int(l) data['bot-data'][str(ctx.guild.id)]['roles'] = lst answer = "Новый порядок ролей:" for role in data['bot-data'][str(ctx.guild.id)]['roles']: answer += f" <@&{role}>" if data['bot-data'][str(ctx.guild.id)].get('active_roles'): if len(data['bot-data'][str(ctx.guild.id)]['roles']) != len(data['bot-data'][str(ctx.guild.id)]['active_roles']): answer += "\nРекомендую также изменить требуемый актив за роли, так как кол-во ролей и требований за них не совпадает" else: answer += "\nРекомендую также изменить награды за актив, так как они не назначены" await ctx.send(answer) except Exception as e: await ctx.send(f"Ошибка\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("roles"): await ctx.send("Роли за актив не установлены\nЧтобы это сделать, в аргументе *value* напишите id ролей по очереди, от самой менее значимой до самой крутой роли за актив через пробел") else: answer = "Порядок ролей:" for role in data['bot-data'][str(ctx.guild.id)]['roles']: answer += f" <@&{role}>" answer +="\nЧтобы изменить, в аргументе *value* напишите id ролей по очереди, от самой менее значимой до самой крутой роли за актив через пробел\nЛибо после аргумента напишите \"clear\"" await ctx.send(answer) elif kwargs["setting"] == "active_for_roles": if not data['bot-data'][str(ctx.guild.id)].get("roles"): await ctx.send("Роли за актив не установлены\nИспользуйте `/settings setting:Список ролей за актив` чтобы узнать подробнее") elif "value" in kwargs: lst = kwargs["value"].split(" ") try: for l in lst: int(l) data['bot-data'][str(ctx.guild.id)]['active_roles'] = lst answer = "Требуемый вами актив:" for n in data['bot-data'][str(ctx.guild.id)]['active_roles']: answer += f" {n}" await ctx.send(answer) except Exception as e: await ctx.send(f"Ошибка\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("active_roles"): await ctx.send("Требования для ролей за актив не установлены\nЧтобы это сделать, напишите в аргументе *value* требуемый актив за роли по очереди через пробел, от самой менее значимой до самой крутой роли за актив") else: answer = "Требуемый актив за роли:" for role in data['bot-data'][str(ctx.guild.id)]['active_roles']: answer += f" {role}" answer +="\nЧтобы изменить, напишите в аргументе *value* требуемый актив за роли по очереди через пробел, от самой менее значимой до самой крутой роли за актив\nЛибо после аргумента напишите \"clear\"" await ctx.send(answer) elif kwargs["setting"] == "counting": if "value" in kwargs: if kwargs["value"].lower() == "clear": del data['bot-data'][str(ctx.guild.id)]['count_log'] await ctx.send(f"Бот теперь не следит за счётом в этом канале") else: try: data['bot-data'][str(ctx.guild.id)]['count_log'] = int(kwargs['value']) await ctx.send(f"Канал {utils.get(ctx.guild.channels, id=data['bot-data'][str(ctx.guild.id)]['count_log'])} будет использоваться для счёта\nСледующее число: {data['bot-data'][str(ctx.guild.id)]['count_channel']}") except Exception as e: await ctx.send(f"Некорректное значение\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("count_log"): await ctx.send(f"Канал для счёта не установлен.\nЧтобы включить, напишите id канала для админ-лога в аргументе *value*") else: await ctx.send(f"Канал для счёта: \"{utils.get(ctx.guild.channels, id=data['bot-data'][str(ctx.guild.id)]['count_log'])}\"\nЧтобы изменить канал для админ-лога, напишите его id в аргументе *value*\nЧтобы выключить админ-лог, в аргументе *value* напишите \"clear\"") elif kwargs["setting"] == "roles_for_count": if not data['bot-data'][str(ctx.guild.id)].get("count_log"): await ctx.send("Канал для счёта не установлен.\nИспользуйте `/settings setting:Канал для счёта` чтобы узнать подробнее") elif "value" in kwargs: lst = kwargs["value"].split(" ") try: for l in lst: int(l) data['bot-data'][str(ctx.guild.id)]['roles'] = lst answer = "Новый порядок ролей:" for role in data['bot-data'][str(ctx.guild.id)]['roles']: answer += f" <@&{role}>" await ctx.send(answer) except Exception as e: await ctx.send(f"Ошибка\n\n`{e}`", delete_after=10) else: if not data['bot-data'][str(ctx.guild.id)].get("active_roles"): await ctx.send("Роли для канала счёта не установлны\nЧтобы это сделать, напишите в аргументе *value* id ролей по порядку за число 100, 500, круглое число с 3 нолями на конце и круглое число с 4 нолями на конце") else: answer = "Требуемый актив за роли:" for role in data['bot-data'][str(ctx.guild.id)]['active_roles']: answer += f" {role}" answer +="\nЧтобы изменить, напишите в аргументе *value* id ролей по порядку за число 100, 500, круглое число с 3 нолями на конце и круглое число с 4 нолями на конце\nЛибо после аргумента напишите \"clear\"" await ctx.send(answer) else: await ctx.send("Вам нельзя использовать эту команду", delete_after=10) @slash.slash(name="mute", description="Лишить кого-нибудь права отправлять сообщения на определённый срок", options=[ create_option(name="user", description="Пользователь, в отношении которого будет применена санкция", option_type=6, required=True), create_option(name="term", description="Либо срок в формате [s, m, h, d, w], либо дата в формате DD.MM.YYYY", option_type=3, required=True), create_option(name="reason", description="Причина приминения санкции", option_type=3, required=False) ]) async def mute(ctx, **kwargs): if not can_use_it(ctx.author, ctx.guild.id): await ctx.send("Вам нельзя использовать эту команду", delete_after=10) return if not data['bot-data'][str(ctx.guild.id)].get("mute_role"): await ctx.send("Команда отключена", delete_after=10) return try: if re.search(r"\d\d\.\d\d.\d\d\d\d", kwargs["term"]) and datetime.datetime.strptime(kwargs["term"], "%d.%m.%Y") >= datetime.datetime.utcnow(): mute_time = datetime.datetime.strptime(kwargs["term"], "%d.%m.%Y") elif ( kwargs["term"][-1:] in ["s", "m", "h", "d", "w"] and int(kwargs["term"][:-1]) > 0 ): valve_time_ban = int(kwargs["term"][:-1]) type_time_ban = kwargs["term"][-1:] now = datetime.datetime.utcnow() if type_time_ban == "s": mute = datetime.timedelta(seconds=valve_time_ban) elif type_time_ban == "m": mute = datetime.timedelta(minutes=valve_time_ban) elif type_time_ban == "h": mute = datetime.timedelta(hours=valve_time_ban) elif type_time_ban == "d": mute = datetime.timedelta(days=valve_time_ban) elif type_time_ban == "w": mute = datetime.timedelta(weeks=valve_time_ban) mute_time = now + mute else: await ctx.send(f"Неправильное значения аргумента `term`: `{kwargs['term']}`", delete_after=10) return reason = kwargs["reason"] if "reason" in kwargs else "Не указана" for_ban = kwargs["user"] role = utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['mute_role']) await for_ban.add_roles(role) data['bot-data'][str(ctx.guild.id)]['muted'][str(for_ban.id)] = {"timestamp": mute_time.timestamp(), "reason": reason, "by_id": ctx.author.id, "done": datetime.datetime.utcnow().timestamp()} emb = discord.Embed(description=f"От <@{ctx.author.id}> специально для <@{for_ban.id}>\n**Причина:** {reason}\n**Срок молчалки:** {strfdelta(now+mute, now, data['bot-data'][str(ctx.guild.id)]['days_in_timedelta'])}", title=f"Молчалка", timestamp=mute_time, colour=0x0000ff) emb.set_author(name=f"{for_ban.name} (Ник: {for_ban.nick})", icon_url=for_ban.avatar_url) emb.set_footer(text="Действует до") await ctx.send(embed=emb) except Exception as e: await ctx.send(f"Я сломался: `{e}`", delete_after=10) @slash.slash(name="ban", description="Лишить кого-нибудь права быть на этом сервере на определённый срок", options=[ create_option(name="user", description="Пользователь, в отношении которого будет применена санкция", option_type=6, required=True), create_option(name="term", description="Либо срок в формате [s, m, h, d, w], либо дата в формате DD.MM.YYYY", option_type=3, required=True), create_option(name="reason", description="Причина приминения санкции", option_type=3, required=False) ]) async def ban(ctx, **kwargs): if not can_use_it(ctx.author, ctx.guild.id): await ctx.send("Вам нельзя использовать эту команду", delete_after=10) return if not data['bot-data'][str(ctx.guild.id)]["can_ban"]: await ctx.send("Команда отключена", delete_after=10) return try: if re.search(r"\d\d\.\d\d.\d\d\d\d", kwargs["term"]) and datetime.datetime.strptime(kwargs["term"], "%d.%m.%Y") >= datetime.datetime.utcnow(): mute_time = datetime.datetime.strptime(kwargs["term"], "%d.%m.%Y") elif ( kwargs["term"][-1:] in ["s", "m", "h", "d", "w"] and int(kwargs["term"][:-1]) > 0 ): valve_time_ban = int(kwargs["term"][:-1]) type_time_ban = kwargs["term"][-1:] now = datetime.datetime.utcnow() if type_time_ban == "s": mute = datetime.timedelta(seconds=valve_time_ban) elif type_time_ban == "m": mute = datetime.timedelta(minutes=valve_time_ban) elif type_time_ban == "h": mute = datetime.timedelta(hours=valve_time_ban) elif type_time_ban == "d": mute = datetime.timedelta(days=valve_time_ban) elif type_time_ban == "w": mute = datetime.timedelta(weeks=valve_time_ban) mute_time = now + mute else: await ctx.send(f"Неправильное значения аргумента `term`: `{kwargs['term']}`", delete_after=10) return reason = kwargs["reason"] if "reason" in kwargs else "Не указана" for_ban = kwargs["user"] await for_ban.ban(reason=reason) data['bot-data'][str(ctx.guild.id)]['banned'][str(for_ban.id)] = {"timestamp": mute_time.timestamp(), "reason": reason, "by_id": ctx.author.id, "done": datetime.datetime.utcnow().timestamp()} emb = discord.Embed(description=f"<@{ctx.author.id}> бьёт <@{for_ban.id}> банхаммером\n**Причина:** {reason}\n**Срок бана:** {strfdelta(now+mute, now, data['bot-data'][str(ctx.guild.id)]['days_in_timedelta'])}", title="Бан", timestamp=mute_time, colour=0x0000ff) emb.set_author(name=f"{for_ban.name} (Ник: {for_ban.nick})", icon_url=for_ban.avatar_url) emb.set_footer(text="Действует до") await ctx.send(embed=emb) except Exception as e: await ctx.send(f"Я сломался: `{e}`", delete_after=10) @slash.slash(name="unmute", description="Вернуть кому-нибудь право отправлять сообщения", options=[ create_option(name="user", description="Пользователь, в отношении которого будет снята санкция", option_type=6, required=True) ]) async def unmute(ctx, user): if not can_use_it(ctx.author, ctx.guild.id): await ctx.send("Вам нельзя использовать эту команду", delete_after=10) return if not data['bot-data'][str(ctx.guild.id)].get("mute_role"): await ctx.send("Команда отключена", delete_after=10) return try: for u in data['bot-data'][str(ctx.guild.id)]['muted']: if int(u) == user.id: role = utils.get(ctx.guild.roles, id=data['bot-data'][str(ctx.guild.id)]['mute_role']) await user.remove_roles(role) await ctx.send(f"Молчалка снята с {user.mention}") del data['bot-data'][str(ctx.guild.id)]['muted'][u] return await ctx.send(f"У пользователя нет молчалки", delete_after=10) except Exception as e: await ctx.send(f"Я сломался: `{e}`", delete_after=10) @slash.slash(name="unban", description="Вернуть кому-нибудь право быть на этом сервере", options=[ create_option(name="userid", description="ID пользователя, в отношении которого будет снята санкция", option_type=4, required=True) ]) async def unban(ctx, userID): if not can_use_it(ctx.author, ctx.guild.id): await ctx.send("Вам нельзя использовать эту команду", delete_after=10) return if not data['bot-data'][str(ctx.guild.id)]["can_ban"]: await ctx.send("Команда отключена", delete_after=10) return try: for_ban = str(userID) for u in data['bot-data'][str(ctx.guild.id)]['banned']: if u == for_ban: ban_list = await ctx.guild.bans() for i in ban_list: if i.user.id == int(u): unban = i.user await ctx.guild.unban(unban) await ctx.send(f"{unban} разбанен") del data['bot-data'][str(ctx.guild.id)]['banned'][u] return await ctx.send("Пользователь не найден", delete_after=10) except Exception as e: await ctx.send(f"Я сломался: `{e}`", delete_after=10) @slash.slash(name="mute_list", description="Посмотреть список активных на сервере молчалок") async def mute_list(ctx): if not can_use_it(ctx.author, ctx.guild.id): await ctx.send("Вам нельзя использовать эту команду", delete_after=10) return if not data['bot-data'][str(ctx.guild.id)].get("mute_role"): await ctx.send("Команда отключена", delete_after=10) return if len(data['bot-data'][str(ctx.guild.id)]['muted']) > 0: desc_text = f"**Активных молчалок**: {len(data['bot-data'][str(ctx.guild.id)]['muted'])}" if len(data['bot-data'][str(ctx.guild.id)]['muted']) > 25: desc_text += f"\n**Embed может показать только 25 строк**" emb = discord.Embed(title="Действующие молчалки", description=desc_text, color=0x0000ff) for_cout = sorted(data['bot-data'][str(ctx.guild.id)]['muted'], key=lambda i:data['bot-data'][str(ctx.guild.id)]['muted'][i]["timestamp"]) for u in for_cout: unmute_time = datetime.datetime.fromtimestamp(data['bot-data'][str(ctx.guild.id)]['muted'][u]["timestamp"]) mute_time = datetime.datetime.fromtimestamp(data['bot-data'][str(ctx.guild.id)]['muted'][u]["done"]) strtimediff = strfdelta(unmute_time, datetime.datetime.utcnow(), data["bot-data"][str(ctx.guild.id)]["days_in_timedelta"]) nick = ctx.guild.get_member(int(u)) bnick = ctx.guild.get_member(int(data['bot-data'][str(ctx.guild.id)]['muted'][u]['by_id'])) if nick is None: try: member = requests.get(f"https://discordapp.com/api/users/{u}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}).json() nick = f"{member['username']}#{member['discriminator']}" except: nick = f"id{u}" else: nick = nick.display_name if bnick is None: try: muted_by = requests.get(f"https://discordapp.com/api/users/{data['bot-data'][str(ctx.guild.id)]['muted'][u]['by_id']}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}).json() bnick = f"{muted_by['username']}#{muted_by['discriminator']}" except: bnick = f"id{data['bot-data'][str(ctx.guild.id)]['muted'][u]['by_id']}" else: bnick = bnick.display_name emb.add_field(name=nick, value=f"**От**: {mute_time.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**До**: {unmute_time.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**Ост. срок**: {strtimediff}\n**Причина**: {data['bot-data'][str(ctx.guild.id)]['muted'][u]['reason']}\n**Выдал**: {bnick}") await ctx.send(embed=emb) else: await ctx.send("Нет действующих молчалок") @slash.slash(name="ban_list", description="Посмотреть список активныx на сервере временных банов") async def ban_list(ctx): if not can_use_it(ctx.author, ctx.guild.id): await ctx.send("Вам нельзя использовать эту команду", delete_after=10) return if not data['bot-data'][str(ctx.guild.id)]["can_ban"]: await ctx.send("Команда отключена", delete_after=10) return if len(data['bot-data'][str(ctx.guild.id)]['banned']) > 0: emb = discord.Embed(title="Действующие баны", description=f"**Активных банов**: {len(data['bot-data'][str(ctx.guild.id)]['banned'])}", color=0x0000ff) for u in data['bot-data'][str(ctx.guild.id)]['banned']: unmute_time = datetime.datetime.utcfromtimestamp(data['bot-data'][str(ctx.guild.id)]['banned'][u]["timestamp"]) mute_time = datetime.datetime.fromtimestamp(data['bot-data'][str(ctx.guild.id)]['banned'][u]["done"]) strtimediff = strfdelta(unmute_time, datetime.datetime.utcnow(), data["bot-data"][str(ctx.guild.id)]["days_in_timedelta"]) nick = ctx.guild.get_member(int(u)) bnick = ctx.guild.get_member(int(data['bot-data'][str(ctx.guild.id)]['banned'][u]['by_id'])) if nick is None: try: member = requests.get(f"https://discordapp.com/api/users/{u}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}).json() nick = f"{member['username']}#{member['discriminator']}" except: nick = f"id{u}" else: nick = nick.display_name if bnick is None: try: muted_by = requests.get(f"https://discordapp.com/api/users/{data['bot-data'][str(ctx.guild.id)]['banned'][u]['by_id']}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}).json() bnick = f"{muted_by['username']}#{muted_by['discriminator']}" except: bnick = f"id{data['bot-data'][str(ctx.guild.id)]['banned'][u]['by_id']}" else: bnick = bnick.display_name emb.add_field(name=nick, value=f"**От**: {mute_time.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**До**: {unmute_time.strftime('%d.%m.%Y %H:%M:%S UTC')}\n**Ост. срок**: {strtimediff}\n**Причина**: {data['bot-data'][str(ctx.guild.id)]['banned'][u]['reason']}\n**Выдал**: {bnick}") await ctx.send(embed=emb) else: await ctx.send("Нет действующих банов") async def time_unmute(member_id, guild_id): response = requests.delete(f'https://discordapp.com/api/guilds/{guild_id}/members/{member_id}/roles/{data["bot-data"][guild_id]["mute_role"]}', headers={'Authorization': f'Bot {data["main-data"]["token"]}'}) log(f"Discord API answer: {response.status_code} {response.reason}") if response.ok and data['bot-data'][guild_id].get('notify_channel'): await client.get_channel(data['bot-data'][guild_id]['notify_channel']).send(f"Молчалка снята с <@{member_id}>: Срок молчалки истёк") async def ny_notif(g): await client.get_channel(data['bot-data'][g]['notify_channel']).send(f"Новый сюрприз готов. Жду того, кто готов его вручить (/gift)") async def time_unban(member_id, guild_id): try: ban_list = await client.get_guild(guild_id).bans() for i in ban_list: if i.user.id == int(member_id): unban = i.user await client.get_guild(int(guild_id)).unban(unban) if data['bot-data'][guild_id].get('notify_channel'): await client.get_channel(data['bot-data'][guild_id]['notify_channel']).send(f"{unban} разбанен: Срок бана истёк") except: member = requests.get(f"https://discordapp.com/api/users/{member_id}", headers={'Authorization': f'Bot {data["main-data"]["token"]}'}) if member.ok: member = member.json() if data['bot-data'][guild_id].get('notify_channel'): await client.get_channel(data['bot-data'][guild_id]['notify_channel']).send( f"{member['username']}#{member['discriminator']} вычеркнут из бан-листа: срок бана истёк") else: if data['bot-data'][guild_id].get('notify_channel'): await client.get_channel(data['bot-data'][guild_id]['notify_channel']).send(f"id{member_id} вычеркнут из бан-листа: срок бана истёк") vk = vk_api.VkApi(token="redacted") vk_mda = vk_api.VkApi(token="redacted") longpoll = VkBotLongPoll(vk, 190322075) vkcall = vk.get_api() async def new_post(vk_event): group = vkcall.groups.getById(group_id=str(vk_event.object.from_id)[1:], fields='photo_200') emb = discord.Embed(description=vk_event.object.text, url=f"https://vk.com/{group[0]['screen_name']}?w=wall-{group[0]['id']}_{vk_event.object.id}", title="Вышел новый пост", timestamp=datetime.datetime.fromtimestamp(vk_event.object.date), colour=0xF0A020) emb.set_author(name=group[0]['name'], url=f"https://vk.com/{group[0]['screen_name']}", icon_url=group[0]['photo_200']) if vk_event.object.attachments: photo = False attachments = "" for i in vk_event.object.attachments: try: if i['type'] == 'photo': attachments += f"🖼 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" if not photo: emb.set_image(url=i['photo']['sizes'][-1]['url']) photo = True elif i['type'] == 'wall': attachments += f"📰 {i['type']}{i[i['type']]['from_id']}_{i[i['type']]['id']}\n" elif i['type'] == 'link': attachments += f"🔗 {i['type']} {i[i['type']]['title']}\n" elif i['type'] == 'doc': attachments += f"📄 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" elif i['type'] == 'poll': attachments += f"📊 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" elif i['type'] == 'album': attachments += f"🎨 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" elif i['type'] == 'video': attachments += f"🎞 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" elif i['type'] == 'audio': attachments += f"🎵 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" else: attachments += f"🎩 {i['type']}{i[i['type']]['owner_id']}_{i[i['type']]['id']}\n" except: attachments += f"🎩 {i['type']}\n" emb.add_field(name="Прикреплено", value=attachments) emb.set_footer(text=f"wall{str(vk_event.object['from_id'])}_{str(vk_event.object['id'])}") await client.get_channel(747588017543446568).send(embed=emb) def send(to, message=None, attachment=None): try: random_id = random.randint(-9223372036854775808, 9223372036854775807) message = vk.method('messages.send', {'peer_id': int(to), 'message': message, 'random_id': random_id, 'attachment': attachment}) counters.incriment("vk-s") except Exception as e: counters.incriment("e") logging.error(f'Failed to send VK message: {str(e)}') def vk_longpull(): for event in MyVkLongPoll.listen(longpoll): try: if event.type == VkBotEventType.MESSAGE_NEW: counters.incriment("vk-r") if event.message.text.lower() == "бот дай денег": send(event.message.peer_id, "Иди нахуй") if event.message.text.lower() == "бот дай денег": send(event.message.peer_id, "Иди нахуй") if event.message.text.lower() == "бот дай": send(event.message.peer_id, "Мне денег") if event.message.text.lower() == "бот иди": send(event.message.peer_id, "Ты нахуй") if event.message.text.lower() == "бот нахуй": send(event.message.peer_id, "Ты иди") if event.message.text.lower() == "бот деньги": send(event.message.peer_id, "Мне дай") if event.message.text.lower() == "бот иди нахуй": from_obj = vk.method("users.get", {'user_ids': event.message.from_id}) send(event.message.peer_id, f"{from_obj[0]['first_name']}, дай денег") if event.message.text == "!debug" and event.message.from_id == 276193568: send(event.message.peer_id, debug()) elif event.type == VkBotEventType.WALL_POST_NEW: if event.object.post_type == "post": log(f"New post! id{event.object['id']}") post = f"wall{str(event.object['from_id'])}_{str(event.object['id'])}" send(2000000003, f"Вышел новый пост", post) coro = new_post(event) fut = asyncio.run_coroutine_threadsafe(coro, client.loop) try: fut.result() except: counters.incriment("e") continue except Exception as kek: log(f"Беды с ботом: {str(kek)}") continue def bot_status(): while True: try: time.sleep(1) l = round(client.latency*1000) up = strfdelta(datetime.datetime.utcnow(), START_TIME, False, "%Hч%Mм") asyncio.run_coroutine_threadsafe(client.change_presence(activity=discord.Game(name=f"{num4(ACTIVE_TOTAL)} актива на {len(client.guilds)} серверах (пинг {l} мс, проработал {up})")), client.loop).result() if datetime.datetime.utcnow().second == 0: vk_widget = {"title": "Discord бот dan63047Bot#0924", "title_counter": ACTIVE_TOTAL, "text": widget_temp(data['main-data']['vk_widget_text']), "descr": f"Обслуживает серверов: {len(client.guilds)}\nАптайм: {up}\nПинг до Discord API: {l} мс."} vk_mda.method("appWidgets.update", {"type": "text", "code": f'return {json.dumps(vk_widget, ensure_ascii=False)};'}) global NEW_YEAR_NOTIFYED global NEW_YEAR_STATS for g in NEW_YEAR_NOTIFYED: if NEW_YEAR_NOTIFYED[g] is False and datetime.datetime.utcnow().timestamp() >= NEW_YEAR_STATS[g]["cooldown"]: # coro = ny_notif(g) # fut = asyncio.run_coroutine_threadsafe(coro, client.loop) try: # fut.result() NEW_YEAR_NOTIFYED[g] = True except: counters.incriment("e") continue except Exception as e: logging.error(f"Some activity tread shit {e}") time.sleep(1) continue counters.incriment_uptime() def bot_bans(): while True: try: time.sleep(1) now = datetime.datetime.utcnow() for g in data['bot-data']: if g != "counters" and g != "new_year_event": for b in data['bot-data'][g]['banned']: if data['bot-data'][g]['banned'][b]['timestamp'] < now.timestamp(): try: asyncio.run_coroutine_threadsafe(time_unban(b, g), client.loop).result() del data['bot-data'][g]['banned'][b] except: log("Time unban shit") except: logging.error("Some unban tread shit") time.sleep(1) continue def bot_muts(): while True: try: time.sleep(1) now = datetime.datetime.utcnow() for g in data['bot-data']: if g != "counters" and g != "new_year_event": for m in data['bot-data'][g]['muted']: if data['bot-data'][g]['muted'][m]['timestamp'] < now.timestamp(): try: asyncio.run_coroutine_threadsafe(time_unmute(m, g), client.loop).result() del data['bot-data'][g]['muted'][m] except: log("Time unmute shit") except: logging.error("Some unmute tread shit") time.sleep(1) continue try: threading.Thread(target=vk_longpull, name=vk_longpull, daemon=True).start() threading.Thread(target=bot_status, name=bot_status, daemon=True).start() threading.Thread(target=bot_bans, name=bot_bans, daemon=True).start() threading.Thread(target=bot_muts, name=bot_muts, daemon=True).start() client.run(data['main-data']['token']) finally: with open("data.json", "w") as jsn: json.dump(data, jsn) up = strfdelta(datetime.datetime.utcnow(), START_TIME, True, "%D:%H:%M:%S") log(f"Data saved, script ended, uptime: {up}")