diff --git a/database/afk_db.py b/database/afk_db.py index 73cc890e..c44cc9f7 100644 --- a/database/afk_db.py +++ b/database/afk_db.py @@ -1,6 +1,44 @@ +# +# Copyright (C) 2021-2022 by TeamYukki@Github, < https://github.com/TeamYukki >. +# +# This file is part of < https://github.com/TeamYukki/YukkiAFKBot > project, +# and is released under the "GNU v3.0 License Agreement". +# Please see < https://github.com/TeamYukki/YukkiAFKBot/blob/master/LICENSE > +# +# All rights reserved. +# + from database import dbname usersdb = dbname.users +cleandb = dbname.cleanmode +cleanmode = {} + + +async def is_cleanmode_on(chat_id: int) -> bool: + mode = cleanmode.get(chat_id) + if not mode: + user = await cleandb.find_one({"chat_id": chat_id}) + if not user: + cleanmode[chat_id] = True + return True + cleanmode[chat_id] = False + return False + return mode + + +async def cleanmode_on(chat_id: int): + cleanmode[chat_id] = True + user = await cleandb.find_one({"chat_id": chat_id}) + if user: + return await cleandb.delete_one({"chat_id": chat_id}) + + +async def cleanmode_off(chat_id: int): + cleanmode[chat_id] = False + user = await cleandb.find_one({"chat_id": chat_id}) + if not user: + return await cleandb.insert_one({"chat_id": chat_id}) async def is_afk(user_id: int) -> bool: @@ -9,10 +47,9 @@ async def is_afk(user_id: int) -> bool: async def add_afk(user_id: int, mode): - await usersdb.update_one({"user_id": user_id}, {"$set": { - "reason": mode - }}, - upsert=True) + await usersdb.update_one( + {"user_id": user_id}, {"$set": {"reason": mode}}, upsert=True + ) async def remove_afk(user_id: int): diff --git a/misskaty/__main__.py b/misskaty/__main__.py index 295d6284..4c41c847 100644 --- a/misskaty/__main__.py +++ b/misskaty/__main__.py @@ -12,7 +12,7 @@ from misskaty.plugins import ALL_MODULES from misskaty.helper import paginate_modules from misskaty.helper.tools import bot_sys_stats from database.users_chats_db import db -from misskaty.vars import LOG_CHANNEL +from misskaty.vars import LOG_CHANNEL, SUDO from utils import temp from pyrogram.raw.all import layer from pyrogram import idle, __version__, filters @@ -53,10 +53,11 @@ async def start_bot(): try: LOGGER.info("[INFO]: SENDING ONLINE STATUS") - await app.send_message( - 617426792, - f"USERBOT AND BOT STARTED with Pyrogram v{__version__}..\nUserBot: {ubot.first_name}\nBot: {me.first_name}\n\nwith Pyrogram v{__version__} (Layer {layer}) started on @{me.username}.", - ) + for i in SUDO: + await app.send_message( + SUDO, + f"USERBOT AND BOT STARTED with Pyrogram v{__version__}..\nUserBot: {ubot.first_name}\nBot: {me.first_name}\n\nwith Pyrogram v{__version__} (Layer {layer}) started on @{me.username}.", + ) except Exception: pass @@ -336,7 +337,4 @@ General command are: if __name__ == "__main__": - try: - loop.run_until_complete(start_bot()) - except KeyboardInterrupt: - LOGGER.info("----------------------- Service Stopped -----------------------") + loop.run_until_complete(start_bot()) diff --git a/misskaty/plugins/afk.py b/misskaty/plugins/afk.py index 2a7bd9fd..94748dc2 100644 --- a/misskaty/plugins/afk.py +++ b/misskaty/plugins/afk.py @@ -1,14 +1,28 @@ -# Sample menggunakan modul motor mongodb +# +# Copyright (C) 2021-2022 by TeamYukki@Github, < https://github.com/TeamYukki >. +# +# This file is part of < https://github.com/TeamYukki/YukkiAFKBot > project, +# and is released under the "GNU v3.0 License Agreement". +# Please see < https://github.com/TeamYukki/YukkiAFKBot/blob/master/LICENSE > +# +# All rights reserved. +# + +# Modified plugin by me from https://github.com/TeamYukki/YukkiAFKBot to make compatible with pyrogram v2 import time, asyncio from misskaty import app +from utils import put_cleanmode from pyrogram import filters from misskaty.vars import COMMAND_HANDLER -from database.afk_db import remove_afk, is_afk, add_afk +from database.afk_db import remove_afk, is_afk, add_afk, is_cleanmode_on, cleanmode_off, cleanmode_on from misskaty.helper.human_read import get_readable_time2 from misskaty.core.decorator.errors import capture_err +from misskaty.core.decorator.permissions import adminsOnly __MODULE__ = "AFK" __HELP__ = """/afk [Reason > Optional] - Tell others that you are AFK (Away From Keyboard), so that your boyfriend or girlfriend won't look for you 💔. +/afk [reply to media] - AFK with media. +/afkdel - Enable auto delete AFK message in group (Only for group admin). Just type something in group to remove AFK Status.""" @@ -29,46 +43,44 @@ async def active_afk(_, message): reasonafk = reasondb["reason"] seenago = get_readable_time2((int(time.time() - timeafk))) if afktype == "text": - return await message.reply_text( + send = await message.reply_text( f"**{message.from_user.first_name}** is back online and was away for {seenago}", disable_web_page_preview=True, ) if afktype == "text_reason": - return await message.reply_text( - f"**{message.from_user.first_name}** is back online and was away for {seenago}\n\n**Reason:** {reasonafk}", + send = await message.reply_text( + f"**{message.from_user.first_name}** is back online and was away for {seenago}\n\nReason: `{reasonafk}`", disable_web_page_preview=True, ) if afktype == "animation": - return ( - await message.reply_animation( + if str(reasonafk) == "None": + send = await message.reply_animation( data, caption=f"**{message.from_user.first_name}** is back online and was away for {seenago}", ) - if str(reasonafk) == "None" - else await message.reply_animation( + else: + send = await message.reply_animation( data, - caption=f"**{message.from_user.first_name}** is back online and was away for {seenago}\n\n**Reason:** {reasonafk}", + caption=f"**{message.from_user.first_name}** is back online and was away for {seenago}\n\nReason: `{reasonafk}`", ) - ) - - elif afktype == "photo": - return ( - await message.reply_photo( + if afktype == "photo": + if str(reasonafk) == "None": + send = await message.reply_photo( photo=f"downloads/{user_id}.jpg", caption=f"**{message.from_user.first_name}** is back online and was away for {seenago}", ) - if str(reasonafk) == "None" - else await message.reply_photo( + else: + send = await message.reply_photo( photo=f"downloads/{user_id}.jpg", - caption=f"**{message.from_user.first_name}** is back online and was away for {seenago}\n\n**Reason:** {reasonafk}", + caption=f"**{message.from_user.first_name}** is back online and was away for {seenago}\n\nReason: `{reasonafk}`", ) - ) - - except Exception: - return await message.reply_text( - f"**{message.from_user.first_name}** is back online.", + except Exception as e: + send = await message.reply_text( + f"**{message.from_user.first_name}** is back online", disable_web_page_preview=True, ) + await put_cleanmode(message.chat.id, send.message_id) + return if len(message.command) == 1 and not message.reply_to_message: details = { "type": "text", @@ -164,12 +176,26 @@ async def active_afk(_, message): } await add_afk(user_id, details) - pesan = await message.reply_text( + send = await message.reply_text( f"{message.from_user.mention} [{message.from_user.id}] is now AFK! This message will be deleted in 10s." ) - await asyncio.sleep(10) - await pesan.delete() - try: - await message.delete() - except: - pass + await put_cleanmode(message.chat.id, send.message_id) + + +@app.on_message(filters.command("afkdel") & ~filters.private) +@adminsOnly +async def captcha_state(_, message): + usage = "**Usage:**\n/afkdel [ENABLE|DISABLE]" + if len(message.command) == 1: + return await message.reply_text(usage) + chat_id = message.chat.id + state = message.text.split(None, 1)[1].strip() + state = state.lower() + if state == "enable": + await cleanmode_on(chat_id) + await message.reply_text("Enabled auto delete AFK message.") + elif state == "disable": + await cleanmode_off(chat_id) + await message.reply_text("Disabled auto delete AFK message.") + else: + await message.reply_text(usage) diff --git a/misskaty/plugins/detect_afk.py b/misskaty/plugins/detect_afk.py index 151abc9f..09ad538f 100644 --- a/misskaty/plugins/detect_afk.py +++ b/misskaty/plugins/detect_afk.py @@ -1,6 +1,17 @@ +# +# Copyright (C) 2021-2022 by TeamYukki@Github, < https://github.com/TeamYukki >. +# +# This file is part of < https://github.com/TeamYukki/YukkiAFKBot > project, +# and is released under the "GNU v3.0 License Agreement". +# Please see < https://github.com/TeamYukki/YukkiAFKBot/blob/master/LICENSE > +# +# All rights reserved. +# + +# Modified plugin by me from https://github.com/TeamYukki/YukkiAFKBot to make compatible with pyrogram v2 import re import time -import asyncio +from utils import put_cleanmode from misskaty import app from pyrogram import filters, enums from database.afk_db import remove_afk, is_afk @@ -43,23 +54,23 @@ async def chat_watcher_func(_, message): msg += f"**{user_name[:25]}** is back online and was away for {seenago}\n\n**Reason:** {reasonafk}\n\n" if afktype == "animation": if str(reasonafk) == "None": - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{user_name[:25]}** is back online and was away for {seenago}\n\n", ) else: - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{user_name[:25]}** is back online and was away for {seenago}\n\n**Reason:** {reasonafk}\n\n", ) if afktype == "photo": if str(reasonafk) == "None": - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{userid}.jpg", caption=f"**{user_name[:25]}** is back online and was away for {seenago}\n\n", ) else: - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{userid}.jpg", caption=f"**{user_name[:25]}** is back online and was away for {seenago}\n\n**Reason:** {reasonafk}\n\n", ) @@ -85,23 +96,23 @@ async def chat_watcher_func(_, message): msg += f"**{replied_first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n" if afktype == "animation": if str(reasonafk) == "None": - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{replied_first_name[:25]}** is AFK since {seenago} ago.\n\n", ) else: - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{replied_first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n", ) if afktype == "photo": if str(reasonafk) == "None": - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{replied_user_id}.jpg", caption=f"**{replied_first_name[:25]}** is AFK since {seenago} ago.\n\n", ) else: - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{replied_user_id}.jpg", caption=f"**{replied_first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n", ) @@ -140,23 +151,23 @@ async def chat_watcher_func(_, message): msg += f"**{user.first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n" if afktype == "animation": if str(reasonafk) == "None": - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{user.first_name[:25]}** is AFK since {seenago} ago.\n\n", ) else: - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{user.first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason**: {reasonafk}\n\n", ) if afktype == "photo": if str(reasonafk) == "None": - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{user.id}.jpg", caption=f"**{user.first_name[:25]}** is AFK since {seenago} ago.\n\n", ) else: - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{user.id}.jpg", caption=f"**{user.first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n", ) @@ -188,23 +199,23 @@ async def chat_watcher_func(_, message): msg += f"**{first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n" if afktype == "animation": if str(reasonafk) == "None": - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{first_name[:25]}** is AFK since {seenago} ago.\n\n", ) else: - await message.reply_animation( + send = await message.reply_animation( data, caption=f"**{first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n", ) if afktype == "photo": if str(reasonafk) == "None": - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{user_id}.jpg", caption=f"**{first_name[:25]}** is AFK since {seenago} ago.\n\n", ) else: - await message.reply_photo( + send = await message.reply_photo( photo=f"downloads/{user_id}.jpg", caption=f"**{first_name[:25]}** is AFK since {seenago} ago.\n\n**Reason:** {reasonafk}\n\n", ) @@ -213,8 +224,10 @@ async def chat_watcher_func(_, message): j += 1 if msg != "": try: - pesan = await message.reply_text(msg, disable_web_page_preview=True) - await asyncio.sleep(20) - await pesan.delete() + send = await message.reply_text(msg, disable_web_page_preview=True) except: return + try: + await put_cleanmode(message.chat.id, send.message_id) + except: + return diff --git a/utils.py b/utils.py index 16c0d183..e58dd95a 100644 --- a/utils.py +++ b/utils.py @@ -11,11 +11,44 @@ from typing import Union import os import emoji from database.users_chats_db import db +from database.afk_db import is_cleanmode_on +from misskaty import app LOGGER = getLogger(__name__) BANNED = {} +async def put_cleanmode(chat_id, message_id): + if chat_id not in cleanmode: + cleanmode[chat_id] = [] + time_now = datetime.now() + put = { + "msg_id": message_id, + "timer_after": time_now + timedelta(minutes=1), + } + cleanmode[chat_id].append(put) + + +async def auto_clean(): + while not await asyncio.sleep(30): + try: + for chat_id in cleanmode: + if not await is_cleanmode_on(chat_id): + continue + for x in cleanmode[chat_id]: + if datetime.now() > x["timer_after"]: + try: + await app.delete_messages(chat_id, x["msg_id"]) + except FloodWait as e: + await asyncio.sleep(e.x) + except: + continue + else: + continue + except: + continue + + # temp db for banned class temp(object): BANNED_USERS = [] @@ -110,3 +143,6 @@ def extract_user(message: Message) -> Union[int, str]: user_id = message.from_user.id user_first_name = message.from_user.first_name return (user_id, user_first_name) + + +asyncio.create_task(auto_clean())