diff --git a/Pipfile b/Pipfile index c35b20e..fa62c9d 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,6 @@ verify_ssl = true name = "pypi" [packages] -pymongo = "*" loguru = "*" "nekos.py" = "*" levenshtein = "*" @@ -19,6 +18,7 @@ simpledemotivators = {file = "https://github.com/Infqq/simpledemotivators/archiv "discord.py" = {extras = ["voice"], version = "*"} pillow = {file = "https://github.com/python-pillow/Pillow/archive/refs/tags/9.5.0.zip"} pretty-errors = "*" +motor = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 76bd41d..60305fd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5fd31ea1728c2767b040091ff943f0048057d157b4d1b66507560fec546b4fff" + "sha256": "3fc195e7fba50262dd6fb8d84b4e94ffef0409cadd3af064a540ac135621cd79" }, "pipfile-spec": 6, "requires": { @@ -863,6 +863,14 @@ "index": "pypi", "version": "==1.2.10" }, + "motor": { + "hashes": [ + "sha256:4bfc65230853ad61af447088527c1197f91c20ee957cfaea3144226907335716", + "sha256:80c08477c09e70db4f85c99d484f2bafa095772f1d29b3ccb253270f9041da9a" + ], + "index": "pypi", + "version": "==3.1.2" + }, "multidict": { "hashes": [ "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9", @@ -1139,7 +1147,7 @@ "sha256:fd7bb378d82b88387dc10227cfd964f6273eb083e05299e9b97cbe075da12d11", "sha256:ffcc8394123ea8d43fff8e5d000095fe7741ce3f8988366c5c919c4f5eb179d3" ], - "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==4.3.3" }, "pynacl": { diff --git a/bot.py b/bot.py index 57f79ae..a42f597 100644 --- a/bot.py +++ b/bot.py @@ -16,7 +16,7 @@ from discord import app_commands from random import randint, shuffle, choice, seed from time import time from inspect import _empty -from pymongo import MongoClient +import motor.motor_asyncio from loguru import logger from discord.ext.commands import HybridCommand @@ -37,7 +37,7 @@ TOKEN = getenv('NATSUKO_TOKEN') my_id = 710089471835504672 -db = MongoClient('localhost', 27017).Koteika +db = motor.motor_asyncio.AsyncIOMotorClient('localhost', 27017).Koteika if os.path.exists('prefixes.json'): with open('prefixes.json', 'r') as f: @@ -86,11 +86,10 @@ def insert_returns(body): def region_to_str(_): return "RU" # TODO: Заменить на нормальный код -_- -def add_user_to_DB(member): +async def add_user_to_DB(member): # if member is not discord.Member: return - ids = [i["id"] for i in db.members.find()] - if member.id not in ids: - db.members.insert_one({"id": member.id, + if not await db.members.find_one({"id": member.id}): + await db.members.insert_one({"id": member.id, "name": member.name, "access_level": "gray", "language": region_to_str("Meow"), # TODO: Ну, очевидно @@ -145,7 +144,7 @@ async def on_ready(): logger.info(f"Загрузка {cog}...") await bot.load_extension(f'cogs.{cog.replace(".py", "")}') - db.members.update_one({"id": 459823895256498186}, {"$set": {"access_level": "secret"}}) + await db.members.update_one({"id": 459823895256498186}, {"$set": {"access_level": "secret"}}) if os.path.isfile('reboot'): with open('reboot', 'r') as f: @@ -181,7 +180,7 @@ async def on_message_handler(message): # Обработка команд (пре-подготовка) if user.name != 'Котейка': - add_user_to_DB(user) + await add_user_to_DB(user) @bot.event @@ -250,7 +249,7 @@ async def change_level(ctx, user: typing.Union[discord.Member, int], level): if not level in ('secret', 'white', 'gray', 'black'): await ctx.message.add_reaction(XX) raise TypeError - db.members.update_one({"id": id_}, {"$set": {"access_level": level}}) + await db.members.update_one({"id": id_}, {"$set": {"access_level": level}}) await ctx.message.add_reaction(check_mark) await asyncio.sleep(3) diff --git a/cogs/activity_counter.py b/cogs/activity_counter.py index 22cc98d..41f39e9 100644 --- a/cogs/activity_counter.py +++ b/cogs/activity_counter.py @@ -7,6 +7,7 @@ from datetime import datetime, timedelta, timezone from matplotlib import pyplot as plt from matplotlib import ticker, markers from loguru import logger +from asyncio import run_coroutine_threadsafe class ActiveCount(commands.Cog): @@ -18,11 +19,11 @@ class ActiveCount(commands.Cog): self.daysoftheweek = ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday") for server in bot.guilds: - self.add_server(server.id) + run_coroutine_threadsafe(self.add_server(server.id), self.bot.loop) - def add_server(self, server_id: int): - if not db.history.find_one({"type": "server", "id": server_id}): - db.history.insert_one({ + async def add_server(self, server_id: int): + if not (await db.history.find_one({"type": "server", "id": server_id})): + await db.history.insert_one({ "type": "server", "id": server_id, "history": { @@ -66,7 +67,7 @@ class ActiveCount(commands.Cog): day = datetime.now().weekday() fig, ax = plt.subplots(figsize=(8, 5)) - server_data = db.history.find_one({"type": "server", "id": inter.guild_id}) + server_data = await db.history.find_one({"type": "server", "id": inter.guild_id}) if server_data is None: await inter.response.send_message("Недостаточно данных! Попробуйте завтра") diff --git a/cogs/economic.py b/cogs/economic.py index 6256070..fb56c26 100644 --- a/cogs/economic.py +++ b/cogs/economic.py @@ -52,8 +52,8 @@ class Economic(commands.Cog, name="Экономика"): @commands.Cog.listener() async def on_message(self, message): if not message.author.bot and message.guild is not None and not message.content.startswith(tuple(await self.bot.command_prefix(self.bot, message))): - data = db.members.find_one({"id": message.author.id}) - flood_channels = db.guild_settings.find_one({"id": message.guild.id}) + data = await db.members.find_one({"id": message.author.id}) + flood_channels = await db.guild_settings.find_one({"id": message.guild.id}) if flood_channels is None: flood_channels = [] else: @@ -62,7 +62,7 @@ class Economic(commands.Cog, name="Экономика"): if time() - 3 >= data["last_mess_time"] and message.channel.id not in flood_channels: delta_exp = len(message.content) + len(message.attachments)*100 - db.history.update_one( + await db.history.update_one( {'type': 'server', 'id': message.guild.id}, {'$inc': {f'current.{datetime.now().hour}': delta_exp}} ) @@ -72,23 +72,23 @@ class Economic(commands.Cog, name="Экономика"): delta_money = rint(1, 5) # Глобальные опыт/уроень - db.members.update_one({"id": message.author.id}, + await db.members.update_one({"id": message.author.id}, {"$inc": {"exp": delta_exp}}) # Изменяем exp - data = db.members.find_one({"id": message.author.id}) + data = await db.members.find_one({"id": message.author.id}) if data is not None: level = data["level"] if level ** 2 * 50 + 5 <= data["exp"]: - db.members.update_one({"id": message.author.id}, + await db.members.update_one({"id": message.author.id}, {"$inc": {"level": 1}}) # Изменяем level if data["level"]+1 >= data["max_level"]: - db.members.update_one({"id": message.author.id}, + await db.members.update_one({"id": message.author.id}, {"$inc": {"money": (level + 1) * delta_money}}) # Изменяем money # Локальные опыт/уровень prefix = f"guild_stat.{message.guild.id}" - if str(message.guild.id) not in db.members.find_one({"id": message.author.id})["guild_stat"].keys(): - db.members.update_many({"id": message.author.id}, + if (await db.members.find_one({"id": message.author.id, f'guild_stat.{message.guild.id}': {'$exists': 0}})): + await db.members.update_many({"id": message.author.id}, {"$set": { f"{prefix}.exp": 0, f"{prefix}.level": 0, @@ -101,15 +101,15 @@ class Economic(commands.Cog, name="Экономика"): } }}) # Создаем в guild_stat поле для сервера - data = db.members.find_one({"id": message.author.id})["guild_stat"][str(message.guild.id)] - db.members.update_one({"id": message.author.id}, + data = (await db.members.find_one({"id": message.author.id}))["guild_stat"][str(message.guild.id)] + await db.members.update_one({"id": message.author.id}, {"$inc": {f"{prefix}.exp": delta_exp}}) - data = db.members.find_one({"id": message.author.id})["guild_stat"][str(message.guild.id)] + data = (await db.members.find_one({"id": message.author.id}))["guild_stat"][str(message.guild.id)] level = data["level"] if level ** 2 * 50 + 5 <= data["exp"]: - db.members.update_one({"id": message.author.id}, + await db.members.update_one({"id": message.author.id}, {"$inc": {f"{prefix}.level": 1}}) - data = db.guild_settings.find_one({"id": message.guild.id}) + data = await db.guild_settings.find_one({"id": message.guild.id}) if data is not None and data['levelup'] == "send": await message.reply( embed=discord.Embed( @@ -120,7 +120,7 @@ class Economic(commands.Cog, name="Экономика"): mention_author=False ) - db.members.update_one({"id": message.author.id}, {"$set": {"last_mess_time": time()}}) + await db.members.update_one({"id": message.author.id}, {"$set": {"last_mess_time": time()}}) @commands.Cog.listener() @@ -142,9 +142,9 @@ class Economic(commands.Cog, name="Экономика"): else: humans = list(filter(lambda x: not x.bot, before.channel.members)) if len(humans) == 1: - self.voice_register(humans[0], before) + await self.voice_register(humans[0], before) if len(humans) != 0: - self.voice_register(member, before) + await self.voice_register(member, before) # При выходе if after.channel is None: @@ -152,7 +152,7 @@ class Economic(commands.Cog, name="Экономика"): except: pass - def voice_register(self, member, voice_state): + async def voice_register(self, member, voice_state): if member.id in self.bot.voice_counter.keys(): secs = (datetime.now() - self.bot.voice_counter[member.id]).seconds else: @@ -171,7 +171,7 @@ class Economic(commands.Cog, name="Экономика"): k *= 2 exp = int(secs // 5 * k) money = exp * rint(1, 5) - db.members.update_one({"id": member.id}, { + await db.members.update_one({"id": member.id}, { "$inc": { f"guild_stat.{member.guild.id}.secs_in_voice": secs, f"guild_stat.{member.guild.id}.exp": exp, @@ -179,7 +179,7 @@ class Economic(commands.Cog, name="Экономика"): "money": money }}) - db.history.update_one( + await db.history.update_one( {'type': 'server', 'id': member.guild.id}, {"$inc": {f'current.{datetime.now().hour}': exp}} ) @@ -196,7 +196,7 @@ class Economic(commands.Cog, name="Экономика"): @commands.Cog.listener() async def on_member_join(self, member): - member_data = db.members.find_one({"id": member.id}) + member_data = await db.members.find_one({"id": member.id}) if member_data is None: logger.warning("Пользователь не найден") @@ -204,30 +204,30 @@ class Economic(commands.Cog, name="Экономика"): if str(member.guild.id) in member_data["guild_stat"].keys(): logger.debug(member_data["guild_stat"][str(member.guild.id)]["exp"], end="\t") - db.members.update_one( + await db.members.update_one( {"id": member.id}, {"$inc": {"exp": member_data["guild_stat"][str(member.guild.id)]["exp"]}} ) @commands.Cog.listener() async def on_member_remove(self, member): - member_data = db.members.find_one({"id": member.id}) + member_data = await db.members.find_one({"id": member.id}) if member_data is None: logger.warning("Пользователь не найден") return if str(member.guild.id) in member_data["guild_stat"].keys(): logger.debug(member_data["guild_stat"][str(member.guild.id)]["exp"], end="\t") - db.members.update_one( + await db.members.update_one( {"id": member.id}, {"$dec": {"exp": member_data["guild_stat"][str(member.guild.id)]["exp"]} }) @commands.Cog.listener() async def on_guild_join(self, guild): - for m in db.members.find({f"guild_stat.{guild.id}": {"$exists": True}}): + async for m in db.members.find({f"guild_stat.{guild.id}": {"$exists": True}}): logger.debug(m["guild_stat"][str(guild.id)]["exp"], end="\t") - db.members.update_one( + await db.members.update_one( {"id": m['id']}, {"$inc": {"exp": m["guild_stat"][str(guild.id)]["exp"]} }) @@ -235,9 +235,9 @@ class Economic(commands.Cog, name="Экономика"): @commands.Cog.listener() async def on_guild_remove(self, guild): - for m in db.members.find({f"guild_stat.{guild.id}": {"$exists": True}}): + async for m in db.members.find({f"guild_stat.{guild.id}": {"$exists": True}}): logger.debug(m["guild_stat"][str(guild.id)]["exp"], end="\t") - db.members.update_one( + await db.members.update_one( {"id": m['id']}, {"$dec": {"exp": m["guild_stat"][str(guild.id)]["exp"]} }) @@ -251,7 +251,7 @@ class Economic(commands.Cog, name="Экономика"): await inter.response.send_message(await get_text(inter, "rank", "Bot hasn't experience")) return - user_data = db.members.find_one({"id": user.id}) + user_data = await db.members.find_one({"id": user.id}) if user_data is None or str(inter.guild.id) not in user_data['guild_stat'].keys(): await inter.response.send_message("Об этом пользователе информации пока нет") return @@ -259,7 +259,7 @@ class Economic(commands.Cog, name="Экономика"): if str(user.id) in self.bot.voice_counter.keys(): prefix = f"guild_stat.{inter.guild.id}" if str(inter.guild.id) not in user_data["guild_stat"].keys(): - db.members.update_many( + await db.members.update_many( {"id": user.id}, {"$set": { f"{prefix}.exp": 0, @@ -272,9 +272,9 @@ class Economic(commands.Cog, name="Экономика"): }} ) # Создаем в guild_stat поле для сервера - self.voice_register(user, user.voice) + await self.voice_register(user, user.voice) - user_data = db.members.find_one({"id": user.id}) + user_data = await db.members.find_one({"id": user.id}) if user_data is None: return if inter.guild is not None: @@ -353,7 +353,7 @@ class Economic(commands.Cog, name="Экономика"): color = discord.Color(0xaaffaa) e = discord.Embed(title="Топ", description=category, color=color) - data_ = list(db.members.find({f"guild_stat.{inter.guild.id}": {"$exists": True}}).sort(categories[category], -1))[:10] + data_ = await db.members.find({f"guild_stat.{inter.guild.id}": {"$exists": True}}).sort(categories[category], -1).to_list(10) if not data_: await inter.response.send_message(await get_text(inter, "top", "Not enough data. Try later")) @@ -374,7 +374,7 @@ class Economic(commands.Cog, name="Экономика"): for place in range(l): m = data_[place] if 'level' not in m['guild_stat'][str(inter.guild.id)].keys(): - db.members.update_one( + await db.members.update_one( {'id': m['id']}, {'$set': {f'guild_stat.{inter.guild.id}.level': 0}} ) @@ -426,10 +426,10 @@ class Economic(commands.Cog, name="Экономика"): db_ = db.members - info1 = db_.find_one({"id": user1})['guild_stat'][str(inter.guild.id)]['history']['hour'] - info2 = db_.find_one({"id": user2})['guild_stat'][str(inter.guild.id)]['history']['hour'] - info1[str(int(ts))] = db_.find_one({"id": user1})['guild_stat'][str(inter.guild.id)]['exp'] - info2[str(int(ts))] = db_.find_one({"id": user2})['guild_stat'][str(inter.guild.id)]['exp'] + info1 = await db_.find_one({"id": user1})['guild_stat'][str(inter.guild.id)]['history']['hour'] + info2 = await db_.find_one({"id": user2})['guild_stat'][str(inter.guild.id)]['history']['hour'] + info1[str(int(ts))] = await db_.find_one({"id": user1})['guild_stat'][str(inter.guild.id)]['exp'] + info2[str(int(ts))] = await db_.find_one({"id": user2})['guild_stat'][str(inter.guild.id)]['exp'] if period == -1: @@ -491,7 +491,7 @@ class Economic(commands.Cog, name="Экономика"): ts = datetime.now().timestamp() db_mem = db.members - data = list(db_mem.find({f"guild_stat.{inter.guild.id}": {"$exists": True}}).sort(f"guild_stat.{inter.guild.id}.exp", -1))[:10] + data = await db_mem.find({f"guild_stat.{inter.guild.id}": {"$exists": True}}).sort(f"guild_stat.{inter.guild.id}.exp", -1).to_list(10) if not data: await inter.response.send_message("Недостаточно данных. Попробуйте завтра") diff --git a/cogs/private_channels.py b/cogs/private_channels.py index 6a2be6e..fad846a 100644 --- a/cogs/private_channels.py +++ b/cogs/private_channels.py @@ -17,22 +17,22 @@ class privateChannels(commands.Cog, name="Приватные комнаты"): @commands.Cog.listener() async def on_voice_state_update(self, member, before, after): - for chan in [i["id"] for i in db.private_channels.find()]: - if not self.bot.get_channel(chan): - db.private_channels.delete_one({"id": chan}) - - v_channels = [i["id"] for i in db.private_channels.find()] - v_categories = [self.bot.get_channel(i).category_id for i in v_channels] + if ( + before.channel and + (await db.private_channels.find_one({'id': before.channel.id})) and + not self.bot.get_channel(before.channel.id) + ): + await db.private_channels.delete_one({'id': before.channel.id}) if ( - before.channel is not None and - len(before.channel.members) == 0 and - before.channel.id not in v_channels and - before.channel.category_id in v_categories + before.channel and + len(before.channel.members) == 0 and + not (await db.private_channels.find_one({'id': before.channel.id})) and + (await db.private_channels.find_one({'category_id': before.channel.category_id})) ): await before.channel.delete() - if after.channel is not None and after.channel.id in v_channels: + if after.channel and (await db.private_channels.find_one({"id": after.channel.id})): #, overwrites={ # member: discord.PermissionOverwrite(manage_channels=True, # move_members=True, @@ -66,11 +66,11 @@ class privateChannels(commands.Cog, name="Приватные комнаты"): "находитесь в главный") @commands.check(is_white) async def set_private(self, ctx): - if ctx.author.voice.channel.id in [i["id"] for i in db.private_channels.find()]: + if (await db.private_channels.find({'id': ctx.author.voice.channel.id})): await ctx.message.delete() message = await ctx.send('Канал уже добавлен') else: - db.private_channels.insert_one({"id": ctx.author.voice.channel.id}) + await db.private_channels.insert_one({"id": ctx.author.voice.channel.id, 'category_id': ctx.author.voice.category.id}) await ctx.message.add_reaction(check_mark) message = ctx.message @@ -91,8 +91,8 @@ class privateChannels(commands.Cog, name="Приватные комнаты"): message = await ctx.send("Зайдите в ГК") await self.bot.wait_for("voice_state_update", check=lambda member, _, after: \ member == ctx.message.author and after.channel is not None) - if ctx.author.voice.channel.id in [i["id"] for i in db.private_channels.find()]: - db.private_channels.delete_one({"id": ctx.author.voice.channel.id}) + if (await db.private_channels.find_one({'id': ctx.author.voice.channel.id})): + await db.private_channels.delete_one({"id": ctx.author.voice.channel.id}) await ctx.message.add_reaction(check_mark) else: await message.edit(content='Этот канал не является приватным') diff --git a/cogs/timeble.py b/cogs/timeble.py index 661aa19..944ed5c 100644 --- a/cogs/timeble.py +++ b/cogs/timeble.py @@ -6,10 +6,10 @@ from loguru import logger daysoftheweek = ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday") -def save_activity(): +async def save_activity(): day = (datetime.now()-timedelta(1)).weekday() - for data in db.history.find({"type": "server"}): - db.history.update_one( + async for data in db.history.find({"type": "server"}): + await db.history.update_one( {"type": "server", "id": data['id']}, { "$push": @@ -18,7 +18,7 @@ def save_activity(): {f'yesterday.{i}': data['current'][str(i)] for i in range(24)} } ) - db.history.update_one( + await db.history.update_one( {"type": "server", "id": data['id']}, { "$push": @@ -28,36 +28,36 @@ def save_activity(): } ) -def db_sync_hour(): +async def db_sync_hour(): logger.info("Регистрация за час") - for member in list(db.members.find()): - db.members.update_one({"_id": member["_id"]}, {"$set": {f"history.hour.{int(datetime.now().timestamp())}": member["exp"]}}) + async for member in db.members.find(): + await db.members.update_one({"_id": member["_id"]}, {"$set": {f"history.hour.{int(datetime.now().timestamp())}": member["exp"]}}) if 'guild_stat' in member.keys(): for guild in member["guild_stat"].keys(): - db.members.update_one({"_id": member["_id"]}, {"$set": {f"guild_stat.{guild}.history.hour.{int(datetime.now().timestamp())}": member["guild_stat"][guild]["exp"]}}) + await db.members.update_one({"_id": member["_id"]}, {"$set": {f"guild_stat.{guild}.history.hour.{int(datetime.now().timestamp())}": member["guild_stat"][guild]["exp"]}}) logger.info("Регистрация завершена") -def db_sync_day(): +async def db_sync_day(): logger.info("Регистрация за день") - for member in list(db.members.find()): - db.members.update_one({"_id": member["_id"]}, {"$set": {f"history.day.{int(datetime.now().timestamp())}": member["exp"]}}) + async for member in db.members.find(): + await db.members.update_one({"_id": member["_id"]}, {"$set": {f"history.day.{int(datetime.now().timestamp())}": member["exp"]}}) for guild in member["guild_stat"].keys(): - db.members.update_one({"_id": member["_id"]}, {"$set": {f"guild_stat.{guild}.history.day.{int(datetime.now().timestamp())}": member["guild_stat"][guild]["exp"]}}) + await db.members.update_one({"_id": member["_id"]}, {"$set": {f"guild_stat.{guild}.history.day.{int(datetime.now().timestamp())}": member["guild_stat"][guild]["exp"]}}) logger.info("Регистрация завершена") # await self.bot.get_user(self.bot.owner_id).send("Завершено за день????") -async def main(): +async def main(bot): clear() - every().day.at('00:00:00').do(save_activity) - every().hours.at("00:00").do(db_sync_hour) - every().day.at("00:00:00").do(db_sync_day) + every().day.at('00:00:00').do(lambda: asyncio.run_coroutine_threadsafe(save_activity(), bot.loop)) + every().hours.at("00:00").do(lambda: asyncio.run_coroutine_threadsafe(db_sync_hour(), bot.loop)) + every().day.at("00:00:00").do(lambda: asyncio.run_coroutine_threadsafe(db_sync_day(), bot.loop)) while True: run_pending() await asyncio.sleep(1) -async def setup(_): - asyncio.create_task(main()) +async def setup(bot): + asyncio.create_task(main(bot))