diff --git a/plugins/__init__.py b/plugins/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..45d1e4d76d93978bf394c0da906e3c286ea1bfe9 --- /dev/null +++ b/plugins/__init__.py @@ -0,0 +1,102 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import asyncio +import os +import time +from random import choice + +import requests +from telethon import Button, events +from telethon.tl import functions, types # pylint:ignore +from telethon.tl.custom.message import CustomMarkdown + +from pyUltroid import * +from pyUltroid._misc._assistant import asst_cmd, callback, in_pattern +from pyUltroid._misc._decorators import ultroid_cmd +from pyUltroid._misc._wrappers import eod, eor +from pyUltroid.dB import DEVLIST, ULTROID_IMAGES +from pyUltroid.fns.helper import * +from pyUltroid.fns.misc import * +from pyUltroid.fns.tools import * +from pyUltroid.startup._database import _BaseDatabase as Database +from pyUltroid.version import __version__, ultroid_version +from strings import get_help, get_string + +udB: Database + +Redis = udB.get_key +con = TgConverter +quotly = Quotly() +OWNER_NAME = ultroid_bot.full_name +OWNER_ID = ultroid_bot.uid + +ultroid_bot: UltroidClient +asst: UltroidClient + +LOG_CHANNEL = udB.get_key("LOG_CHANNEL") + +ultroid_bot.parse_mode = CustomMarkdown() + +def inline_pic(): + INLINE_PIC = udB.get_key("INLINE_PIC") + if INLINE_PIC is None: + INLINE_PIC = choice(ULTROID_IMAGES) + elif INLINE_PIC == False: + INLINE_PIC = None + return INLINE_PIC + + +Telegraph = telegraph_client() + +List = [] +Dict = {} +InlinePlugin = {} +N = 0 +cmd = ultroid_cmd +STUFF = {} + +# Chats, which needs to be ignore for some cases +# Considerably, there can be many +# Feel Free to Add Any other... + +NOSPAM_CHAT = [ + -1001361294038, # UltroidSupportChat + -1001387666944, # PyrogramChat + -1001109500936, # TelethonChat + -1001050982793, # Python + -1001256902287, # DurovsChat + -1001473548283, # SharingUserbot +] + +KANGING_STR = [ + "Using Witchery to kang this sticker...", + "Plagiarising hehe...", + "Inviting this sticker over to my pack...", + "Kanging this sticker...", + "Hey that's a nice sticker!\nMind if I kang?!..", + "Hehe me stel ur stiker...", + "Ay look over there (☉。☉)!→\nWhile I kang this...", + "Roses are red violets are blue, kanging this sticker so my pack looks cool", + "Imprisoning this sticker...", + "Mr.Steal-Your-Sticker is stealing this sticker... ", +] + +ATRA_COL = [ + "DarkCyan", + "DeepSkyBlue", + "DarkTurquoise", + "Cyan", + "LightSkyBlue", + "Turquoise", + "MediumVioletRed", + "Aquamarine", + "Lightcyan", + "Azure", + "Moccasin", + "PowderBlue", +] diff --git a/plugins/_chatactions.py b/plugins/_chatactions.py new file mode 100644 index 0000000000000000000000000000000000000000..be6379a6c2c673b4134f842a8935321ef95c5a9d --- /dev/null +++ b/plugins/_chatactions.py @@ -0,0 +1,350 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import asyncio + +from telethon import events +from telethon.errors.rpcerrorlist import UserNotParticipantError +from telethon.tl.functions.channels import GetParticipantRequest +from telethon.utils import get_display_name + +from pyUltroid.dB import stickers +from pyUltroid.dB.echo_db import check_echo +from pyUltroid.dB.forcesub_db import get_forcesetting +from pyUltroid.dB.gban_mute_db import is_gbanned +from pyUltroid.dB.greetings_db import get_goodbye, get_welcome, must_thank +from pyUltroid.dB.nsfw_db import is_profan +from pyUltroid.fns.helper import check_reply_to, inline_mention +from pyUltroid.fns.tools import ( + async_searcher, + create_tl_btn, + get_chatbot_reply, + get_oracle_reply, +) + +try: + from ProfanityDetector import detector +except ImportError: + detector = None +from . import LOG_CHANNEL, LOGS, asst, get_string, types, udB, ultroid_bot +from ._inline import something + +if not udB.get_key("ORACLE_USERS"): + udB.set_key("ORACLE_USERS", {}) +if not udB.get_key("CHATBOT_USERS"): + udB.set_key("CHATBOT_USERS", {}) + +@ultroid_bot.on(events.ChatAction()) +async def Function(event): + try: + await DummyHandler(event) + except Exception as er: + LOGS.exception(er) + + +async def DummyHandler(ult): + # clean chat actions + key = udB.get_key("CLEANCHAT") or [] + if ult.chat_id in key: + try: + await ult.delete() + except BaseException: + pass + + # thank members + if must_thank(ult.chat_id): + chat_count = (await ult.client.get_participants(ult.chat_id, limit=0)).total + if chat_count % 100 == 0: + stik_id = chat_count / 100 - 1 + sticker = stickers[stik_id] + await ult.respond(file=sticker) + # force subscribe + if ( + udB.get_key("FORCESUB") + and ((ult.user_joined or ult.user_added)) + and get_forcesetting(ult.chat_id) + ): + user = await ult.get_user() + if not user.bot: + joinchat = get_forcesetting(ult.chat_id) + try: + await ultroid_bot(GetParticipantRequest(int(joinchat), user.id)) + except UserNotParticipantError: + await ultroid_bot.edit_permissions( + ult.chat_id, user.id, send_messages=False + ) + res = await ultroid_bot.inline_query( + asst.me.username, f"fsub {user.id}_{joinchat}" + ) + await res[0].click(ult.chat_id, reply_to=ult.action_message.id) + + if ult.user_joined or ult.added_by: + user = await ult.get_user() + chat = await ult.get_chat() + # gbans and @UltroidBans checks + if udB.get_key("ULTROID_BANS"): + try: + is_banned = await async_searcher( + "https://bans.ultroid.tech/api/status", + json={"userId": user.id}, + post=True, + re_json=True, + ) + if is_banned["is_banned"]: + await ult.client.edit_permissions( + chat.id, + user.id, + view_messages=False, + ) + await ult.respond( + f'**@UltroidBans:** Banned user detected and banned!\n`{str(is_banned)}`.\nBan reason: {is_banned["reason"]}', + ) + + except BaseException: + pass + reason = is_gbanned(user.id) + if reason and chat.admin_rights: + try: + await ult.client.edit_permissions( + chat.id, + user.id, + view_messages=False, + ) + gban_watch = get_string("can_1").format(inline_mention(user), reason) + await ult.reply(gban_watch) + except Exception as er: + LOGS.exception(er) + + # greetings + elif get_welcome(ult.chat_id): + user = await ult.get_user() + chat = await ult.get_chat() + title = chat.title or "this chat" + count = ( + chat.participants_count + or (await ult.client.get_participants(chat, limit=0)).total + ) + mention = inline_mention(user) + name = user.first_name + fullname = get_display_name(user) + uu = user.username + username = f"@{uu}" if uu else mention + wel = get_welcome(ult.chat_id) + msgg = wel["welcome"] + med = wel["media"] or None + userid = user.id + msg = None + if msgg: + msg = msgg.format( + mention=mention, + group=title, + count=count, + name=name, + fullname=fullname, + username=username, + userid=userid, + ) + if wel.get("button"): + btn = create_tl_btn(wel["button"]) + await something(ult, msg, med, btn) + elif msg: + send = await ult.reply( + msg, + file=med, + ) + await asyncio.sleep(150) + await send.delete() + else: + await ult.reply(file=med) + elif (ult.user_left or ult.user_kicked) and get_goodbye(ult.chat_id): + user = await ult.get_user() + chat = await ult.get_chat() + title = chat.title or "this chat" + count = ( + chat.participants_count + or (await ult.client.get_participants(chat, limit=0)).total + ) + mention = inline_mention(user) + name = user.first_name + fullname = get_display_name(user) + uu = user.username + username = f"@{uu}" if uu else mention + wel = get_goodbye(ult.chat_id) + msgg = wel["goodbye"] + med = wel["media"] + userid = user.id + msg = None + if msgg: + msg = msgg.format( + mention=mention, + group=title, + count=count, + name=name, + fullname=fullname, + username=username, + userid=userid, + ) + if wel.get("button"): + btn = create_tl_btn(wel["button"]) + await something(ult, msg, med, btn) + elif msg: + send = await ult.reply( + msg, + file=med, + ) + await asyncio.sleep(150) + await send.delete() + else: + await ult.reply(file=med) + + +@ultroid_bot.on(events.NewMessage(incoming=True)) +async def chatBot_replies(e): + if e.sender_id in udB.get_key("CHATBOT_USERS"): + xxrep = await check_reply_to(e) + else: + return + + if xxrep: + sender = await e.get_sender() + if not isinstance(sender, types.User) or sender.bot: + return + if check_echo(e.chat_id, e.sender_id): + try: + await e.respond(e.message) + except Exception as er: + LOGS.exception(er) + key = udB.get_key("CHATBOT_USERS") or {} + if e.text and key.get(e.chat_id) and sender.id in key[e.chat_id]: + # Simulate typing indicator + async with e.client.action(e.chat_id, "typing"): + msg = await get_chatbot_reply(e.message.message) + if msg: + sleep = udB.get_key("CHATBOT_SLEEP") or 1.5 + await asyncio.sleep(sleep) + + # Check if the message length exceeds a certain threshold + if len(msg) > 4096: + # Create a temporary text file + with tempfile.NamedTemporaryFile( + mode="w+", delete=False + ) as temp_file: + temp_file.write(msg) + + # Send the text file with a caption + await e.client.send_file( + e.chat_id, + temp_file.name, + caption="Here is the response in a text file.", + ) + + # Delete the temporary text file + os.remove(temp_file.name) + else: + # Send the message directly + await e.reply(msg) + + chat = await e.get_chat() + if e.is_group and sender.username: + await uname_stuff(e.sender_id, sender.username, sender.first_name) + elif e.is_private and chat.username: + await uname_stuff(e.sender_id, chat.username, chat.first_name) + if detector and is_profan(e.chat_id) and e.text: + x, y = detector(e.text) + if y: + await e.delete() + + +@ultroid_bot.on(events.NewMessage(incoming=True)) +async def oracleBot_replies(e): + if e.sender_id in udB.get_key("ORACLE_USERS"): + xxxrep = await check_reply_to(e) + else: + return + + if xxxrep: + sender = await e.get_sender() + if not isinstance(sender, types.User) or sender.bot: + return + if check_echo(e.chat_id, e.sender_id): + try: + await e.respond(e.message) + except Exception as er: + LOGS.exception(er) + key = udB.get_key("ORACLE_USERS") or {} + if e.text and key.get(e.chat_id) and sender.id in key[e.chat_id]: + # Simulate typing indicator + async with e.client.action(e.chat_id, "typing"): + msg = await get_oracle_reply( + e.message.message, user_id=sender.id, mongo_url=MONGO_URI + ) + if msg: + sleep = udB.get_key("ORACLE_SLEEP") or 1.5 + await asyncio.sleep(sleep) + + # Check if the message length exceeds a certain threshold + if len(msg) > 4096: + # Create a temporary text file + with tempfile.NamedTemporaryFile( + mode="w+", delete=False + ) as temp_file: + temp_file.write(msg) + + # Send the text file with a caption + await e.client.send_file( + e.chat_id, + temp_file.name, + caption="Here is the response in a text file", + ) + + # Delete the temporary text file + os.remove(temp_file.name) + else: + # Send the message directly + await e.reply(msg) + + chat = await e.get_chat() + if e.is_group and sender.username: + await uname_stuff(e.sender_id, sender.username, sender.first_name) + elif e.is_private and chat.username: + await uname_stuff(e.sender_id, chat.username, chat.first_name) + if detector and is_profan(e.chat_id) and e.text: + x, y = detector(e.text) + if y: + await e.delete() + + +@ultroid_bot.on(events.Raw(types.UpdateUserName)) +async def uname_change(e): + await uname_stuff(e.user_id, e.usernames[0] if e.usernames else None, e.first_name) + + +async def uname_stuff(id, uname, name): + if udB.get_key("USERNAME_LOG"): + old_ = udB.get_key("USERNAME_DB") or {} + old = old_.get(id) + # Ignore Name Logs + if old and old == uname: + return + if old and uname: + await asst.send_message( + LOG_CHANNEL, + get_string("can_2").format(old, uname), + ) + elif old: + await asst.send_message( + LOG_CHANNEL, + get_string("can_3").format(f"[{name}](tg://user?id={id})", old), + ) + elif uname: + await asst.send_message( + LOG_CHANNEL, + get_string("can_4").format(f"[{name}](tg://user?id={id})", uname), + ) + + old_[id] = uname + udB.set_key("USERNAME_DB", old_) diff --git a/plugins/_help.py b/plugins/_help.py new file mode 100644 index 0000000000000000000000000000000000000000..b36101e7f5d5769f2c309797905e265bdc7e8f1a --- /dev/null +++ b/plugins/_help.py @@ -0,0 +1,136 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from telethon.errors.rpcerrorlist import ( + BotInlineDisabledError, + BotMethodInvalidError, + BotResponseTimeoutError, +) +from telethon.tl.custom import Button + +from pyUltroid.dB._core import HELP, LIST +from pyUltroid.fns.tools import cmd_regex_replace + +from . import HNDLR, LOGS, OWNER_NAME, asst, get_string, inline_pic, udB, ultroid_cmd + +_main_help_menu = [ + [ + Button.inline(get_string("help_4"), data="uh_Official_"), + Button.inline(get_string("help_5"), data="uh_Addons_"), + ], + [ + Button.inline(get_string("help_6"), data="uh_VCBot_"), + Button.inline(get_string("help_7"), data="inlone"), + ], + [ + Button.inline(get_string("help_8"), data="ownr"), + Button.url( + get_string("help_9"), url=f"https://t.me/{asst.me.username}?start=set" + ), + ], + [Button.inline(get_string("help_10"), data="close")], +] + + +@ultroid_cmd(pattern="help( (.*)|$)") +async def _help(ult): + plug = ult.pattern_match.group(1).strip() + chat = await ult.get_chat() + if plug: + try: + if plug in HELP["Official"]: + output = f"**Plugin** - `{plug}`\n" + for i in HELP["Official"][plug]: + output += i + output += "\n© @TeamUltroid" + await ult.eor(output) + elif HELP.get("Addons") and plug in HELP["Addons"]: + output = f"**Plugin** - `{plug}`\n" + for i in HELP["Addons"][plug]: + output += i + output += "\n© @TeamUltroid" + await ult.eor(output) + elif HELP.get("VCBot") and plug in HELP["VCBot"]: + output = f"**Plugin** - `{plug}`\n" + for i in HELP["VCBot"][plug]: + output += i + output += "\n© @TeamUltroid" + await ult.eor(output) + else: + try: + x = get_string("help_11").format(plug) + for d in LIST[plug]: + x += HNDLR + d + x += "\n" + x += "\n© @TeamUltroid" + await ult.eor(x) + except BaseException: + file = None + compare_strings = [] + for file_name in LIST: + compare_strings.append(file_name) + value = LIST[file_name] + for j in value: + j = cmd_regex_replace(j) + compare_strings.append(j) + if j.strip() == plug: + file = file_name + break + if not file: + # the enter command/plugin name is not found + text = f"`{plug}` is not a valid plugin!" + best_match = None + for _ in compare_strings: + if plug in _ and not _.startswith("_"): + best_match = _ + break + if best_match: + text += f"\nDid you mean `{best_match}`?" + return await ult.eor(text) + output = f"**Command** `{plug}` **found in plugin** - `{file}`\n" + if file in HELP["Official"]: + for i in HELP["Official"][file]: + output += i + elif HELP.get("Addons") and file in HELP["Addons"]: + for i in HELP["Addons"][file]: + output += i + elif HELP.get("VCBot") and file in HELP["VCBot"]: + for i in HELP["VCBot"][file]: + output += i + output += "\n© @TeamUltroid" + await ult.eor(output) + except BaseException as er: + LOGS.exception(er) + await ult.eor("Error 🤔 occured.") + else: + try: + results = await ult.client.inline_query(asst.me.username, "ultd") + except BotMethodInvalidError: + z = [] + for x in LIST.values(): + z.extend(x) + cmd = len(z) + 10 + if udB.get_key("MANAGER") and udB.get_key("DUAL_HNDLR") == "/": + _main_help_menu[2:3] = [[Button.inline("• Manager Help •", "mngbtn")]] + return await ult.reply( + get_string("inline_4").format( + OWNER_NAME, + len(HELP["Official"]), + len(HELP["Addons"] if "Addons" in HELP else []), + cmd, + ), + file=inline_pic(), + buttons=_main_help_menu, + ) + except BotResponseTimeoutError: + return await ult.eor( + get_string("help_2").format(HNDLR), + ) + except BotInlineDisabledError: + return await ult.eor(get_string("help_3")) + await results[0].click(chat.id, reply_to=ult.reply_to_msg_id, hide_via=True) + await ult.delete() diff --git a/plugins/_inline.py b/plugins/_inline.py new file mode 100644 index 0000000000000000000000000000000000000000..bcda7ee726539e975a10ad783b401be2f6677a49 --- /dev/null +++ b/plugins/_inline.py @@ -0,0 +1,451 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import re +import time +from datetime import datetime +from os import remove + +from git import Repo +from telethon import Button +from telethon.tl.types import InputWebDocument, Message +from telethon.utils import resolve_bot_file_id + +from pyUltroid._misc._assistant import callback, in_pattern +from pyUltroid.dB._core import HELP, LIST +from pyUltroid.fns.helper import gen_chlog, time_formatter, updater +from pyUltroid.fns.misc import split_list + +from . import ( + HNDLR, + LOGS, + OWNER_NAME, + InlinePlugin, + asst, + get_string, + inline_pic, + split_list, + start_time, + udB, +) +from ._help import _main_help_menu + +# ================================================# + +helps = get_string("inline_1") + +add_ons = udB.get_key("ADDONS") + +zhelps = get_string("inline_3") if add_ons is False else get_string("inline_2") +PLUGINS = HELP.get("Official", []) +ADDONS = HELP.get("Addons", []) +upage = 0 +# ============================================# + +# --------------------BUTTONS--------------------# + +SUP_BUTTONS = [ + [ + Button.url("• Repo •", url="https://github.com/TeamUltroid/Ultroid"), + Button.url("• Support •", url="t.me/UltroidSupportChat"), + ], +] + +# --------------------BUTTONS--------------------# + + +@in_pattern(owner=True, func=lambda x: not x.text) +async def inline_alive(o): + TLINK = inline_pic() or "https://graph.org/file/74d6259983e0642923fdb.jpg" + MSG = "• **Ultroid Userbot •**" + WEB0 = InputWebDocument( + "https://graph.org/file/acd4f5d61369f74c5e7a7.jpg", 0, "image/jpg", [] + ) + RES = [ + await o.builder.article( + type="photo", + text=MSG, + include_media=True, + buttons=SUP_BUTTONS, + title="Ultroid Userbot", + description="Userbot | Telethon", + url=TLINK, + thumb=WEB0, + content=InputWebDocument(TLINK, 0, "image/jpg", []), + ) + ] + await o.answer( + RES, + private=True, + cache_time=300, + switch_pm="👥 ULTROID PORTAL", + switch_pm_param="start", + ) + + +@in_pattern("ultd", owner=True) +async def inline_handler(event): + z = [] + for x in LIST.values(): + z.extend(x) + text = get_string("inline_4").format( + OWNER_NAME, + len(HELP.get("Official", [])), + len(HELP.get("Addons", [])), + len(z), + ) + if inline_pic(): + result = await event.builder.photo( + file=inline_pic(), + link_preview=False, + text=text, + buttons=_main_help_menu, + ) + else: + result = await event.builder.article( + title="Ultroid Help Menu", text=text, buttons=_main_help_menu + ) + await event.answer([result], private=True, cache_time=300, gallery=True) + + +@in_pattern("pasta", owner=True) +async def _(event): + ok = event.text.split("-")[1] + link = f"https://spaceb.in/{ok}" + raw = f"https://spaceb.in/api/{ok}/raw" + result = await event.builder.article( + title="Paste", + text="Pasted to Spacebin 🌌", + buttons=[ + [ + Button.url("SpaceBin", url=link), + Button.url("Raw", url=raw), + ], + ], + ) + await event.answer([result]) + + +@callback("ownr", owner=True) +async def setting(event): + z = [] + for x in LIST.values(): + z.extend(x) + await event.edit( + get_string("inline_4").format( + OWNER_NAME, + len(HELP.get("Official", [])), + len(HELP.get("Addons", [])), + len(z), + ), + file=inline_pic(), + link_preview=False, + buttons=[ + [ + Button.inline("•Pɪɴɢ•", data="pkng"), + Button.inline("•Uᴘᴛɪᴍᴇ•", data="upp"), + ], + [ + Button.inline("•Stats•", data="alive"), + Button.inline("•Uᴘᴅᴀᴛᴇ•", data="doupdate"), + ], + [Button.inline("« Bᴀᴄᴋ", data="open")], + ], + ) + + +_strings = {"Official": helps, "Addons": zhelps, "VCBot": get_string("inline_6")} + + +@callback(re.compile("uh_(.*)"), owner=True) +async def help_func(ult): + key, count = ult.data_match.group(1).decode("utf-8").split("_") + if key == "VCBot" and HELP.get("VCBot") is None: + return await ult.answer(get_string("help_12"), alert=True) + elif key == "Addons" and HELP.get("Addons") is None: + return await ult.answer(get_string("help_13").format(HNDLR), alert=True) + if "|" in count: + _, count = count.split("|") + count = int(count) if count else 0 + text = _strings.get(key, "").format(OWNER_NAME, len(HELP.get(key))) + await ult.edit(text, buttons=page_num(count, key), link_preview=False) + + +@callback(re.compile("uplugin_(.*)"), owner=True) +async def uptd_plugin(event): + key, file = event.data_match.group(1).decode("utf-8").split("_") + index = None + if "|" in file: + file, index = file.split("|") + key_ = HELP.get(key, []) + hel_p = f"Plugin Name - `{file}`\n" + help_ = "" + try: + for i in key_[file]: + help_ += i + except BaseException: + if file in LIST: + help_ = get_string("help_11").format(file) + for d in LIST[file]: + help_ += HNDLR + d + help_ += "\n" + if not help_: + help_ = f"{file} has no Detailed Help!" + help_ += "\n© @TeamUltroid" + buttons = [] + if inline_pic(): + data = f"sndplug_{key}_{file}" + if index is not None: + data += f"|{index}" + buttons.append( + [ + Button.inline( + "« Sᴇɴᴅ Pʟᴜɢɪɴ »", + data=data, + ) + ] + ) + data = f"uh_{key}_" + if index is not None: + data += f"|{index}" + buttons.append( + [ + Button.inline("« Bᴀᴄᴋ", data=data), + ] + ) + try: + await event.edit(help_, buttons=buttons) + except Exception as er: + LOGS.exception(er) + help = f"Do `{HNDLR}help {key}` to get list of commands." + await event.edit(help, buttons=buttons) + + +@callback(data="doupdate", owner=True) +async def _(event): + if not await updater(): + return await event.answer(get_string("inline_9"), cache_time=0, alert=True) + if not inline_pic(): + return await event.answer(f"Do '{HNDLR}update' to update..") + repo = Repo.init() + changelog, tl_chnglog = await gen_chlog( + repo, f"HEAD..upstream/{repo.active_branch}" + ) + changelog_str = changelog + "\n\n" + get_string("inline_8") + if len(changelog_str) > 1024: + await event.edit(get_string("upd_4")) + with open("ultroid_updates.txt", "w+") as file: + file.write(tl_chnglog) + await event.edit( + get_string("upd_5"), + file="ultroid_updates.txt", + buttons=[ + [Button.inline("• Uᴘᴅᴀᴛᴇ Nᴏᴡ •", data="updatenow")], + [Button.inline("« Bᴀᴄᴋ", data="ownr")], + ], + ) + remove("ultroid_updates.txt") + else: + await event.edit( + changelog_str, + buttons=[ + [Button.inline("Update Now", data="updatenow")], + [Button.inline("« Bᴀᴄᴋ", data="ownr")], + ], + parse_mode="html", + ) + + +@callback(data="pkng", owner=True) +async def _(event): + start = datetime.now() + end = datetime.now() + ms = (end - start).microseconds + pin = f"🌋Pɪɴɢ = {ms} microseconds" + await event.answer(pin, cache_time=0, alert=True) + + +@callback(data="upp", owner=True) +async def _(event): + uptime = time_formatter((time.time() - start_time) * 1000) + pin = f"🙋Uᴘᴛɪᴍᴇ = {uptime}" + await event.answer(pin, cache_time=0, alert=True) + + +@callback(data="inlone", owner=True) +async def _(e): + _InButtons = [ + Button.switch_inline(_, query=InlinePlugin[_], same_peer=True) + for _ in list(InlinePlugin.keys()) + ] + InButtons = split_list(_InButtons, 2) + + button = InButtons.copy() + button.append( + [ + Button.inline("« Bᴀᴄᴋ", data="open"), + ], + ) + await e.edit(buttons=button, link_preview=False) + + +@callback(data="open", owner=True) +async def opner(event): + z = [] + for x in LIST.values(): + z.extend(x) + await event.edit( + get_string("inline_4").format( + OWNER_NAME, + len(HELP.get("Official", [])), + len(HELP.get("Addons", [])), + len(z), + ), + buttons=_main_help_menu, + link_preview=False, + ) + + +@callback(data="close", owner=True) +async def on_plug_in_callback_query_handler(event): + await event.edit( + get_string("inline_5"), + buttons=Button.inline("Oᴘᴇɴ Aɢᴀɪɴ", data="open"), + ) + + +def page_num(index, key): + rows = udB.get_key("HELP_ROWS") or 5 + cols = udB.get_key("HELP_COLUMNS") or 2 + loaded = HELP.get(key, []) + emoji = udB.get_key("EMOJI_IN_HELP") or "✘" + List = [ + Button.inline(f"{emoji} {x} {emoji}", data=f"uplugin_{key}_{x}|{index}") + for x in sorted(loaded) + ] + all_ = split_list(List, cols) + fl_ = split_list(all_, rows) + try: + new_ = fl_[index] + except IndexError: + new_ = fl_[0] if fl_ else [] + index = 0 + if index == 0 and len(fl_) == 1: + new_.append([Button.inline("« Bᴀᴄᴋ »", data="open")]) + else: + new_.append( + [ + Button.inline( + "« Pʀᴇᴠɪᴏᴜs", + data=f"uh_{key}_{index-1}", + ), + Button.inline("« Bᴀᴄᴋ »", data="open"), + Button.inline( + "Nᴇxᴛ »", + data=f"uh_{key}_{index+1}", + ), + ] + ) + return new_ + + +# --------------------------------------------------------------------------------- # + + +STUFF = {} + + +@in_pattern("stf(.*)", owner=True) +async def ibuild(e): + n = e.pattern_match.group(1).strip() + builder = e.builder + if not (n and n.isdigit()): + return + ok = STUFF.get(int(n)) + txt = ok.get("msg") + pic = ok.get("media") + btn = ok.get("button") + if not (pic or txt): + txt = "Hey!" + if pic: + try: + include_media = True + mime_type, _pic = None, None + cont, results = None, None + try: + ext = str(pic).split(".")[-1].lower() + except BaseException: + ext = None + if ext in ["img", "jpg", "png"]: + _type = "photo" + mime_type = "image/jpg" + elif ext in ["mp4", "mkv", "gif"]: + mime_type = "video/mp4" + _type = "gif" + else: + try: + if "telethon.tl.types" in str(type(pic)): + _pic = pic + else: + _pic = resolve_bot_file_id(pic) + except BaseException: + pass + if _pic: + results = [ + await builder.document( + _pic, + title="Ultroid Op", + text=txt, + description="@TeamUltroid", + buttons=btn, + link_preview=False, + ) + ] + else: + _type = "article" + include_media = False + if not results: + if include_media: + cont = InputWebDocument(pic, 0, mime_type, []) + results = [ + await builder.article( + title="Ultroid Op", + type=_type, + text=txt, + description="@TeamUltroid", + include_media=include_media, + buttons=btn, + thumb=cont, + content=cont, + link_preview=False, + ) + ] + return await e.answer(results) + except Exception as er: + LOGS.exception(er) + result = [ + await builder.article("Ultroid Op", text=txt, link_preview=False, buttons=btn) + ] + await e.answer(result) + + +async def something(e, msg, media, button, reply=True, chat=None): + if e.client._bot: + return await e.reply(msg, file=media, buttons=button) + num = len(STUFF) + 1 + STUFF.update({num: {"msg": msg, "media": media, "button": button}}) + try: + res = await e.client.inline_query(asst.me.username, f"stf{num}") + return await res[0].click( + chat or e.chat_id, + reply_to=bool(isinstance(e, Message) and reply), + hide_via=True, + silent=True, + ) + + except Exception as er: + LOGS.exception(er) diff --git a/plugins/_ultroid.py b/plugins/_ultroid.py new file mode 100644 index 0000000000000000000000000000000000000000..b2a3e2a6fb4bbf30e35f0fe5979307c2b3c145e2 --- /dev/null +++ b/plugins/_ultroid.py @@ -0,0 +1,66 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from telethon.errors import ( + BotMethodInvalidError, + ChatSendInlineForbiddenError, + ChatSendMediaForbiddenError, +) + +from . import LOG_CHANNEL, LOGS, Button, asst, eor, get_string, ultroid_cmd + +REPOMSG = """ +• **ULTROID USERBOT** •\n +• Repo - [Click Here](https://github.com/TeamUltroid/Ultroid) +• Addons - [Click Here](https://github.com/TeamUltroid/UltroidAddons) +• Support - @UltroidSupportChat +""" + +RP_BUTTONS = [ + [ + Button.url(get_string("bot_3"), "https://github.com/TeamUltroid/Ultroid"), + Button.url("Addons", "https://github.com/TeamUltroid/UltroidAddons"), + ], + [Button.url("Support Group", "t.me/UltroidSupportChat")], +] + +ULTSTRING = """🎇 **Thanks for Deploying Ultroid Userbot!** + +• Here, are the Some Basic stuff from, where you can Know, about its Usage.""" + + +@ultroid_cmd( + pattern="repo$", + manager=True, +) +async def repify(e): + try: + q = await e.client.inline_query(asst.me.username, "") + await q[0].click(e.chat_id) + return await e.delete() + except ( + ChatSendInlineForbiddenError, + ChatSendMediaForbiddenError, + BotMethodInvalidError, + ): + pass + except Exception as er: + LOGS.info(f"Error while repo command : {str(er)}") + await e.eor(REPOMSG) + + +@ultroid_cmd(pattern="ultroid$") +async def useUltroid(rs): + button = Button.inline("Start >>", "initft_2") + msg = await asst.send_message( + LOG_CHANNEL, + ULTSTRING, + file="https://graph.org/file/54a917cc9dbb94733ea5f.jpg", + buttons=button, + ) + if not (rs.chat_id == LOG_CHANNEL and rs.client._bot): + await eor(rs, f"**[Click Here]({msg.message_link})**") diff --git a/plugins/_userlogs.py b/plugins/_userlogs.py new file mode 100644 index 0000000000000000000000000000000000000000..0696ce5b2edfe0b7dad6b98b6ea7e9f8ae499abb --- /dev/null +++ b/plugins/_userlogs.py @@ -0,0 +1,297 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import os +import re + +from telethon.errors.rpcerrorlist import ( + ChannelPrivateError, + ChatWriteForbiddenError, + MediaCaptionTooLongError, + MediaEmptyError, + MessageTooLongError, + PeerIdInvalidError, + UserNotParticipantError, +) +from telethon.tl.types import MessageEntityMention, MessageEntityMentionName, User +from telethon.utils import get_display_name + +from pyUltroid.dB.botchat_db import tag_add, who_tag + +from . import ( + LOG_CHANNEL, + LOGS, + Button, + asst, + callback, + events, + get_string, + inline_mention, + udB, + ultroid_bot, +) + +CACHE_SPAM = {} +TAG_EDITS = {} + + +@ultroid_bot.on( + events.NewMessage( + incoming=True, + func=lambda e: (e.mentioned), + ), +) +async def all_messages_catcher(e): + x = await e.get_sender() + if isinstance(x, User) and (x.bot or x.verified): + return + if not udB.get_key("TAG_LOG"): + return + NEEDTOLOG = udB.get_key("TAG_LOG") + buttons = await parse_buttons(e) + try: + sent = await asst.send_message(NEEDTOLOG, e.message, buttons=buttons) + if TAG_EDITS.get(e.chat_id): + TAG_EDITS[e.chat_id].update({e.id: {"id": sent.id, "msg": e}}) + else: + TAG_EDITS.update({e.chat_id: {e.id: {"id": sent.id, "msg": e}}}) + tag_add(sent.id, e.chat_id, e.id) + except MediaEmptyError as er: + LOGS.debug(f"handling {er}.") + try: + msg = await asst.get_messages(e.chat_id, ids=e.id) + sent = await asst.send_message(NEEDTOLOG, msg, buttons=buttons) + if TAG_EDITS.get(e.chat_id): + TAG_EDITS[e.chat_id].update({e.id: {"id": sent.id, "msg": e}}) + else: + TAG_EDITS.update({e.chat_id: {e.id: {"id": sent.id, "msg": e}}}) + tag_add(sent.id, e.chat_id, e.id) + except Exception as me: + if not isinstance(me, (PeerIdInvalidError, ValueError)): + LOGS.exception(me) + if e.photo or e.sticker or e.gif: + try: + media = await e.download_media() + sent = await asst.send_message( + NEEDTOLOG, e.message.text, file=media, buttons=buttons + ) + if TAG_EDITS.get(e.chat_id): + TAG_EDITS[e.chat_id].update({e.id: {"id": sent.id, "msg": e}}) + else: + TAG_EDITS.update({e.chat_id: {e.id: {"id": sent.id, "msg": e}}}) + return os.remove(media) + except Exception as er: + LOGS.exception(er) + await asst.send_message(NEEDTOLOG, get_string("com_4"), buttons=buttons) + except (PeerIdInvalidError, ValueError) as er: + LOGS.exception(er) + try: + CACHE_SPAM[NEEDTOLOG] + except KeyError: + await asst.send_message( + udB.get_key("LOG_CHANNEL"), get_string("userlogs_1") + ) + CACHE_SPAM.update({NEEDTOLOG: True}) + except ChatWriteForbiddenError: + try: + await asst.get_permissions(NEEDTOLOG, "me") + MSG = get_string("userlogs_4") + except UserNotParticipantError: + MSG = get_string("userlogs_2") + try: + CACHE_SPAM[NEEDTOLOG] + except KeyError: + await asst.send_message(LOG_CHANNEL, MSG) + CACHE_SPAM.update({NEEDTOLOG: True}) + except Exception as er: + LOGS.exception(er) + + +if udB.get_key("TAG_LOG"): + + @ultroid_bot.on(events.MessageEdited(func=lambda x: not x.out)) + async def upd_edits(event): + x = event.sender + if isinstance(x, User) and (x.bot or x.verified): + return + if event.chat_id not in TAG_EDITS: + if event.sender_id == udB.get_key("TAG_LOG"): + return + if event.is_private: + return + if entities := event.get_entities_text(): + is_self = False + username = event.client.me.username + if username: + username = username.lower() + for ent, text in entities: + if isinstance(ent, MessageEntityMention): + is_self = text[1:].lower() == username + elif isinstance(ent, MessageEntityMentionName): + is_self = ent.user_id == event.client.me.id + if is_self: + text = f"**#Edited & #Mentioned**\n\n{event.text}" + try: + sent = await asst.send_message( + udB.get_key("TAG_LOG"), + text, + buttons=await parse_buttons(event), + ) + except Exception as er: + return LOGS.exception(er) + if TAG_EDITS.get(event.chat_id): + TAG_EDITS[event.chat_id].update({event.id: {"id": sent.id}}) + else: + TAG_EDITS.update({event.chat_id: {event.id: {"id": sent.id}}}) + return + d_ = TAG_EDITS[event.chat_id] + if not d_.get(event.id): + return + d_ = d_[event.id] + if d_["msg"].text == event.text: + return + msg = None + if d_.get("count"): + d_["count"] += 1 + else: + msg = True + d_.update({"count": 1}) + if d_["count"] > 10: + return # some limit to take edits + try: + MSG = await asst.get_messages(udB.get_key("TAG_LOG"), ids=d_["id"]) + except Exception as er: + return LOGS.exception(er) + TEXT = MSG.text + if msg: + TEXT += "\n\n🖋 **Later Edited to !**" + strf = event.edit_date.strftime("%H:%M:%S") + if "\n" not in event.text: + TEXT += f"\n• `{strf}` : {event.text}" + else: + TEXT += f"\n• `{strf}` :\n-> {event.text}" + if d_["count"] == 10: + TEXT += "\n\n• __Only the first 10 Edits are shown.__" + try: + msg = await MSG.edit(TEXT, buttons=await parse_buttons(event)) + d_["msg"] = msg + except (MessageTooLongError, MediaCaptionTooLongError): + del TAG_EDITS[event.chat_id][event.id] + except Exception as er: + LOGS.exception(er) + + @ultroid_bot.on( + events.NewMessage( + outgoing=True, + chats=[udB.get_key("TAG_LOG")], + func=lambda e: e.reply_to, + ) + ) + async def idk(e): + id = e.reply_to_msg_id + chat, msg = who_tag(id) + if chat and msg: + try: + await ultroid_bot.send_message(chat, e.message, reply_to=msg) + except BaseException as er: + LOGS.exception(er) + + +# log for assistant/user joins/add + + +async def when_added_or_joined(event): + user = await event.get_user() + chat = await event.get_chat() + if not (user and user.is_self): + return + if getattr(chat, "username", None): + chat = f"[{chat.title}](https://t.me/{chat.username}/{event.action_message.id})" + else: + chat = f"[{chat.title}](https://t.me/c/{chat.id}/{event.action_message.id})" + key = "bot" if event.client._bot else "user" + buttons = Button.inline( + get_string("userlogs_3"), data=f"leave_ch_{event.chat_id}|{key}" + ) + if event.user_added: + tmp = event.added_by + text = f"#ADD_LOG\n\n{inline_mention(tmp)} just added {inline_mention(user)} to {chat}." + elif event.from_request: + text = f"#APPROVAL_LOG\n\n{inline_mention(user)} just got Chat Join Approval to {chat}." + else: + text = f"#JOIN_LOG\n\n{inline_mention(user)} just joined {chat}." + await asst.send_message(udB.get_key("LOG_CHANNEL"), text, buttons=buttons) + + +asst.add_event_handler( + when_added_or_joined, events.ChatAction(func=lambda x: x.user_added) +) +ultroid_bot.add_event_handler( + when_added_or_joined, + events.ChatAction(func=lambda x: x.user_added or x.user_joined), +) +_client = {"bot": asst, "user": ultroid_bot} + + +@callback( + re.compile( + "leave_ch_(.*)", + ), + from_users=[ultroid_bot.uid], +) +async def leave_ch_at(event): + cht = event.data_match.group(1).decode("UTF-8") + ch_id, client = cht.split("|") + try: + client = _client[client] + except KeyError: + return + try: + name = (await client.get_entity(int(ch_id))).title + await client.delete_dialog(int(ch_id)) + except UserNotParticipantError: + pass + except ChannelPrivateError: + return await event.edit( + "`[CANT_ACCESS_CHAT]` `Maybe already left or got banned.`" + ) + except Exception as er: + LOGS.exception(er) + return await event.answer(str(er)) + await event.edit(get_string("userlogs_5").format(name)) + + +@callback("do_nothing") +async def _(event): + await event.answer() + + +async def parse_buttons(event): + y, x = event.chat, event.sender + where_n, who_n = get_display_name(y), get_display_name(x) + where_l = event.message_link + buttons = [[Button.url(where_n, where_l)]] + if isinstance(x, User) and x.username: + try: + buttons.append( + [Button.mention(who_n, await asst.get_input_entity(x.username))] + ) + except Exception as er: + LOGS.exception(er) + buttons.append([Button.url(who_n, f"t.me/{x.username}")]) + elif getattr(x, "username"): + buttons.append([Button.url(who_n, f"t.me/{x.username}")]) + else: + buttons.append([Button.url(who_n, where_l)]) + replied = await event.get_reply_message() + if replied and replied.out: + button = Button.url("Replied to", replied.message_link) + if len(who_n) > 7: + buttons.append([button]) + else: + buttons[-1].append(button) + return buttons diff --git a/plugins/_wspr.py b/plugins/_wspr.py new file mode 100644 index 0000000000000000000000000000000000000000..f46def7dadebbc0e02e845fe53070f99224aac0a --- /dev/null +++ b/plugins/_wspr.py @@ -0,0 +1,204 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import re + +from telethon import Button +from telethon.errors.rpcerrorlist import ( + BotInlineDisabledError, + BotResponseTimeoutError, + MessageNotModifiedError, +) +from telethon.tl import types +from telethon.tl.functions.users import GetFullUserRequest as gu + +from . import ( + HNDLR, + LOGS, + asst, + callback, + get_string, + in_pattern, + inline_mention, + ultroid_bot, + ultroid_cmd, +) + +buddhhu = {} + + +@ultroid_cmd( + pattern="wspr( (.*)|$)", +) +async def _(e): + if e.reply_to_msg_id: + okk = await e.get_reply_message() + put = f"@{okk.sender.username}" if okk.sender.username else okk.sender_id + else: + put = e.pattern_match.group(1).strip() + if put: + try: + results = await e.client.inline_query(asst.me.username, f"msg {put}") + except BotResponseTimeoutError: + return await e.eor( + get_string("help_2").format(HNDLR), + ) + except BotInlineDisabledError: + return await e.eor(get_string("help_3")) + await results[0].click(e.chat_id, reply_to=e.reply_to_msg_id, hide_via=True) + return await e.delete() + await e.eor(get_string("wspr_3")) + + +@in_pattern("wspr", owner=True) +async def _(e): + iuser = e.query.user_id + zzz = e.text.split(maxsplit=2) + try: + query = zzz[1] + if query.isdigit(): + query = int(query) + logi = await ultroid_bot.get_entity(query) + if not isinstance(logi, types.User): + raise ValueError("Invalid Username.") + except IndexError: + sur = await e.builder.article( + title="Give Username", + description="You Didn't Type Username or id.", + text="You Didn't Type Username or id.", + ) + return await e.answer([sur]) + except ValueError as er: + LOGS.exception(er) + sur = await e.builder.article( + title="User Not Found", + description="Make sure username or id is correct.", + text="Make sure username or id is correct.", + ) + return await e.answer([sur]) + try: + desc = zzz[2] + except IndexError: + sur = await e.builder.article( + title="Type ur msg", text="You Didn't Type Your Msg" + ) + return await e.answer([sur]) + button = [ + [ + Button.inline("Secret Msg", data=f"dd_{e.id}"), + Button.inline("Delete Msg", data=f"del_{e.id}"), + ], + [ + Button.switch_inline( + "New", query=f"wspr {logi.username or logi.id}", same_peer=True + ) + ], + ] + us = logi.username or logi.first_name + sur = await e.builder.article( + title=logi.first_name, + description=desc, + text=get_string("wspr_1").format(us), + buttons=button, + ) + buddhhu.update({e.id: [logi.id, iuser, desc]}) + await e.answer([sur]) + + +@in_pattern("msg", owner=True) +async def _(e): + zzz = e.text.split(maxsplit=1) + desc = "Touch me" + try: + query = zzz[1] + if query.isdigit(): + query = int(query) + logi = await ultroid_bot(gu(id=query)) + user = logi.users[0] + mention = inline_mention(user) + x = user.status + if isinstance(x, types.UserStatusOnline): + status = "Online" + elif isinstance(x, types.UserStatusOffline): + status = "Offline" + elif isinstance(x, types.UserStatusRecently): + status = "Last Seen Recently" + elif isinstance(x, types.UserStatusLastMonth): + status = "Last seen months ago" + elif isinstance(x, types.UserStatusLastWeek): + status = "Last seen weeks ago" + else: + status = "Can't Tell" + text = f"**Name:** `{user.first_name}`\n" + text += f"**Id:** `{user.id}`\n" + if user.username: + text += f"**Username:** `{user.username}`\n" + url = f"https://t.me/{user.username}" + else: + text += f"**Mention:** `{mention}`\n" + url = f"tg://user?id={user.id}" + text += f"**Status:** `{status}`\n" + text += f"**About:** `{logi.full_user.about}`" + button = [ + Button.url("Private", url=url), + Button.switch_inline( + "Secret msg", + query=f"wspr {query} Hello 👋", + same_peer=True, + ), + ] + sur = e.builder.article( + title=user.first_name, + description=desc, + text=text, + buttons=button, + ) + except IndexError: + sur = e.builder.article( + title="Give Username", + description="You Didn't Type Username or id.", + text="You Didn't Type Username or id.", + ) + except BaseException as er: + LOGS.exception(er) + name = get_string("wspr_4").format(query) + sur = e.builder.article( + title=name, + text=name, + ) + + await e.answer([sur]) + + +@callback( + re.compile( + "dd_(.*)", + ), +) +async def _(e): + ids = int(e.pattern_match.group(1).strip().decode("UTF-8")) + if buddhhu.get(ids): + if e.sender_id in buddhhu[ids]: + await e.answer(buddhhu[ids][-1], alert=True) + else: + await e.answer("Not For You", alert=True) + else: + await e.answer(get_string("wspr_2"), alert=True) + + +@callback(re.compile("del_(.*)")) +async def _(e): + ids = int(e.pattern_match.group(1).strip().decode("UTF-8")) + if buddhhu.get(ids): + if e.sender_id in buddhhu[ids]: + buddhhu.pop(ids) + try: + await e.edit(get_string("wspr_2")) + except MessageNotModifiedError: + pass + else: + await e.answer(get_string("wspr_5"), alert=True) diff --git a/plugins/admintools.py b/plugins/admintools.py new file mode 100644 index 0000000000000000000000000000000000000000..0d402ff2d6a220a1d884460ae595012a97d4e47a --- /dev/null +++ b/plugins/admintools.py @@ -0,0 +1,472 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_admintools") + +import asyncio + +from telethon.errors import BadRequestError +from telethon.errors.rpcerrorlist import ChatNotModifiedError, UserIdInvalidError +from telethon.tl.functions.channels import EditAdminRequest, GetFullChannelRequest +from telethon.tl.functions.messages import GetFullChatRequest, SetHistoryTTLRequest +from telethon.tl.types import InputMessagesFilterPinned +from telethon.utils import get_display_name + +from pyUltroid.dB import DEVLIST +from pyUltroid.fns.admins import ban_time +from pyUltroid.fns.info import get_uinfo + +from . import HNDLR, LOGS, eod, eor, get_string, inline_mention, types, ultroid_cmd + + +@ultroid_cmd( + pattern="promote( (.*)|$)", + admins_only=True, + manager=True, + require="add_admins", + fullsudo=True, +) +async def prmte(ult): + xx = await ult.eor(get_string("com_1")) + user, rank = await get_uinfo(ult) + rank = rank or "Admin" + FullRight = False + if not user: + return await xx.edit(get_string("pro_1")) + if rank.split()[0] == "-f": + try: + rank = rank.split(maxsplit=1)[1] + except IndexError: + rank = "Admin" + FullRight = True + try: + if FullRight: + await ult.client( + EditAdminRequest(ult.chat_id, user.id, ult.chat.admin_rights, rank) + ) + else: + await ult.client.edit_admin( + ult.chat_id, + user.id, + invite_users=True, + ban_users=True, + delete_messages=True, + pin_messages=True, + manage_call=True, + title=rank, + ) + await eod( + xx, get_string("pro_2").format(inline_mention(user), ult.chat.title, rank) + ) + except Exception as ex: + return await xx.edit(f"`{ex}`") + + +@ultroid_cmd( + pattern="demote( (.*)|$)", + admins_only=True, + manager=True, + require="add_admins", + fullsudo=True, +) +async def dmote(ult): + xx = await ult.eor(get_string("com_1")) + user, rank = await get_uinfo(ult) + if not rank: + rank = "Not Admin" + if not user: + return await xx.edit(get_string("de_1")) + try: + await ult.client.edit_admin( + ult.chat_id, + user.id, + invite_users=None, + ban_users=None, + delete_messages=None, + pin_messages=None, + manage_call=None, + title=rank, + ) + await eod(xx, get_string("de_2").format(inline_mention(user), ult.chat.title)) + except Exception as ex: + return await xx.edit(f"`{ex}`") + + +@ultroid_cmd( + pattern="ban( (.*)|$)", + admins_only=True, + manager=True, + require="ban_users", + fullsudo=True, +) +async def bban(ult): + something = await get_uinfo(ult) + if not something: + return + user, reason = something + if not user: + return await eod(ult, get_string("ban_1")) + if user.id in DEVLIST: + return await eod(ult, get_string("ban_2")) + try: + await ult.client.edit_permissions(ult.chat_id, user.id, view_messages=False) + except UserIdInvalidError: + return await eod(ult, get_string("adm_1")) + except BadRequestError: + return await eod(ult, get_string("ban_3")) + senderme = inline_mention(await ult.get_sender()) + userme = inline_mention(user) + text = get_string("ban_4").format(userme, senderme, ult.chat.title) + if reason: + text += get_string("ban_5").format(reason) + await eod(ult, text) + + +@ultroid_cmd( + pattern="unban( (.*)|$)", + admins_only=True, + manager=True, + require="ban_users", + fullsudo=True, +) +async def uunban(ult): + xx = await ult.eor(get_string("com_1")) + if ult.text[1:].startswith("unbanall"): + return + something = await get_uinfo(ult) + if not something: + return + user, reason = something + if not user: + return await xx.edit(get_string("unban_1")) + try: + await ult.client.edit_permissions(ult.chat_id, user.id, view_messages=True) + except UserIdInvalidError: + return await eod(ult, get_string("adm_1")) + except BadRequestError: + return await xx.edit(get_string("adm_2")) + sender = inline_mention(await ult.get_sender()) + text = get_string("unban_3").format(inline_mention(user), sender, ult.chat.title) + if reason: + text += get_string("ban_5").format(reason) + await xx.edit(text) + + +@ultroid_cmd( + pattern="kick( (.*)|$)", + manager=True, + require="ban_users", + fullsudo=True, +) +async def kck(ult): + if "kickme" in ult.text: + return + if ult.is_private: + return await ult.eor("`Use this in Group/Channel.`", time=5) + ml = ult.text.split(" ", maxsplit=1)[0] + xx = await ult.eor(get_string("com_1")) + something = await get_uinfo(ult) + if not something: + return + user, reason = something + if not user: + return await xx.edit(get_string("adm_1")) + if user.id in DEVLIST: + return await xx.edit(get_string("kick_2")) + if getattr(user, "is_self", False): + return await xx.edit(get_string("kick_3")) + try: + await ult.client.kick_participant(ult.chat_id, user.id) + except BadRequestError as er: + LOGS.info(er) + return await xx.edit(get_string("kick_1")) + except Exception as e: + LOGS.exception(e) + return + text = get_string("kick_4").format( + inline_mention(user), inline_mention(await ult.get_sender()), ult.chat.title + ) + if reason: + text += get_string("ban_5").format(reason) + await xx.edit(text) + + +@ultroid_cmd( + pattern="tban( (.*)|$)", + admins_only=True, + manager=True, + require="ban_users", + fullsudo=True, +) +async def tkicki(e): + huh = e.text.split() + inputt = None + try: + tme = huh[1] + except IndexError: + return await e.eor(get_string("adm_3"), time=15) + try: + inputt = huh[2] + except IndexError: + if e.reply_to_msg_id: + inputt = (await e.get_reply_message()).sender_id + if not inputt: + return await e.eor(get_string("tban_1")) + userid = await e.client.parse_id(inputt) + try: + user = await e.client.get_entity(userid) + except Exception as ex: + return await eor(e, f"`{ex}`") + try: + bun = ban_time(tme) + await e.client.edit_permissions( + e.chat_id, user.id, until_date=bun, view_messages=False + ) + await eod( + e, + get_string("tban_2").format(inline_mention(user), e.chat.title, tme), + time=15, + ) + except Exception as m: + return await e.eor(str(m)) + + +@ultroid_cmd(pattern="pin$", manager=True, require="pin_messages", fullsudo=True) +async def pin(msg): + if not msg.is_reply: + return await eor(msg, get_string("pin_1")) + me = await msg.get_reply_message() + if me.is_private: + text = "`Pinned.`" + else: + text = f"Pinned [This Message]({me.message_link}) !" + try: + await msg.client.pin_message(msg.chat_id, me.id, notify=False) + except BadRequestError: + return await eor(msg, get_string("adm_2")) + except Exception as e: + return await eor(msg, f"**ERROR:**`{e}`") + await eor(msg, text) + + +@ultroid_cmd( + pattern="unpin($| (.*))", + manager=True, + require="pin_messages", + fullsudo=True, +) +async def unp(ult): + xx = await ult.eor(get_string("com_1")) + ch = (ult.pattern_match.group(1).strip()).strip() + msg = None + if ult.is_reply: + msg = ult.reply_to_msg_id + elif ch != "all": + return await xx.edit(get_string("unpin_1").format(HNDLR)) + try: + await ult.client.unpin_message(ult.chat_id, msg) + except BadRequestError: + return await xx.edit(get_string("adm_2")) + except Exception as e: + return await xx.edit(f"**ERROR:**`{e}`") + await xx.edit("`Unpinned!`") + + +@ultroid_cmd( + pattern="tpin( (.*)|$)", + admins_only=True, + manager=True, + require="pin_messages", + fullsudo=True, +) +async def pin_message(ult): + match = ult.pattern_match.group(1).strip() + if not ult.is_reply: + return await ult.eor("`Reply to message..`", time=6) + if not match: + return await ult.eor("`Please provide time..`", time=8) + msg = await ult.eor(get_string("com_1")) + msg_id = ult.reply_to_msg_id + try: + time = ban_time(match) + await ult.client.pin_message(ult.chat_id, msg_id) + await msg.eor(f"`pinned for time` `{time}`", time=8) + except Exception as er: + return await msg.edit(str(er)) + await asyncio.sleep(time) + try: + await ult.client.unpin_message(ult.chat_id, msg_id) + except Exception as er: + LOGS.exception(er) + + +@ultroid_cmd(pattern="purge( (.*)|$)", manager=True, require="delete_messages") +async def fastpurger(purg): + match = purg.pattern_match.group(1).strip() + try: + ABC = purg.text[6] + except IndexError: + ABC = None + if ABC and purg.text[6] in ["m", "a"]: + return + if not purg._client._bot and ( + (match) + or (purg.is_reply and (purg.is_private or isinstance(purg.chat, types.Chat))) + ): + p = 0 + async for msg in purg.client.iter_messages( + purg.chat_id, + limit=int(match) if match else None, + min_id=purg.reply_to_msg_id if purg.is_reply else None, + ): + await msg.delete() + p += 0 + return await eor(purg, f"Purged {p} Messages! ", time=5) + if not purg.reply_to_msg_id: + return await eor(purg, get_string("purge_1"), time=10) + try: + await purg.client.delete_messages( + purg.chat_id, list(range(purg.reply_to_msg_id, purg.id)) + ) + + except Exception as er: + LOGS.info(er) + await purg.eor("__Fast purge complete!__", time=5) + + +@ultroid_cmd( + pattern="purgeme( (.*)|$)", +) +async def fastpurgerme(purg): + if num := purg.pattern_match.group(1).strip(): + try: + nnt = int(num) + except BaseException: + await eor(purg, get_string("com_3"), time=5) + return + mp = 0 + async for mm in purg.client.iter_messages( + purg.chat_id, limit=nnt, from_user="me" + ): + await mm.delete() + mp += 1 + await eor(purg, f"Purged {mp} Messages!", time=5) + return + elif not purg.reply_to_msg_id: + return await eod( + purg, + "`Reply to a message to purge from or use it like ``purgeme `", + time=10, + ) + chat = await purg.get_input_chat() + msgs = [] + async for msg in purg.client.iter_messages( + chat, + from_user="me", + min_id=purg.reply_to_msg_id, + ): + msgs.append(msg) + if msgs: + await purg.client.delete_messages(chat, msgs) + await purg.eor( + "__Fast purge complete!__\n**Purged** `" + str(len(msgs)) + "` **messages.**", + time=5, + ) + + +@ultroid_cmd( + pattern="purgeall$", +) +async def _(e): + if not e.is_reply: + return await eod( + e, + get_string("purgeall_1"), + ) + + msg = await e.get_reply_message() + name = msg.sender + try: + await e.client.delete_messages(e.chat_id, from_user=msg.sender_id) + await e.eor(get_string("purgeall_2").format(name.first_name), time=5) + except Exception as er: + return await e.eor(str(er), time=5) + + +@ultroid_cmd(pattern="pinned", manager=True, groups_only=True) +async def djshsh(event): + chat = await event.get_chat() + if isinstance(chat, types.Chat): + FChat = await event.client(GetFullChatRequest(chat.id)) + elif isinstance(chat, types.Channel): + FChat = await event.client(GetFullChannelRequest(chat.id)) + else: + return + msg_id = FChat.full_chat.pinned_msg_id + if not msg_id: + return await event.eor(get_string("pinned_1")) + msg = await event.client.get_messages(chat.id, ids=msg_id) + if msg: + await event.eor(get_string("pinned_2").format(msg.message_link)) + + +@ultroid_cmd( + pattern="listpinned$", +) +async def get_all_pinned(event): + x = await event.eor(get_string("com_1")) + chat_id = (str(event.chat_id)).replace("-100", "") + chat_name = get_display_name(event.chat) + a = "" + c = 1 + async for i in event.client.iter_messages( + event.chat_id, filter=InputMessagesFilterPinned + ): + if i.message: + t = " ".join(i.message.split()[:4]) + txt = f"{t}...." + else: + txt = "Go to message." + a += f"{c}. {txt}\n" + c += 1 + + if c == 1: + m = f"The pinned message in {chat_name}:\n\n" + else: + m = f"List of pinned message(s) in {chat_name}:\n\n" + + if not a: + return await eor(x, get_string("listpin_1"), time=5) + + await x.edit(m + a, parse_mode="html") + + +@ultroid_cmd( + pattern="autodelete( (.*)|$)", + admins_only=True, +) +async def autodelte(ult): + match = ult.pattern_match.group(1).strip() + if not match or match not in ["24h", "7d", "1m", "off"]: + return await ult.eor("`Please Use in Proper Format..`", time=5) + if match == "24h": + tt = 3600 * 24 + elif match == "7d": + tt = 3600 * 24 * 7 + elif match == "1m": + tt = 3600 * 24 * 31 + else: + tt = 0 + try: + await ult.client(SetHistoryTTLRequest(ult.chat_id, period=tt)) + except ChatNotModifiedError: + return await ult.eor( + f"Auto Delete Setting is Already same to `{match}`", time=5 + ) + await ult.eor(f"Auto Delete Status Changed to `{match}` !") diff --git a/plugins/afk.py b/plugins/afk.py new file mode 100644 index 0000000000000000000000000000000000000000..830136a449f960298a7a45fe2f4e6c717df31615 --- /dev/null +++ b/plugins/afk.py @@ -0,0 +1,166 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_afk") + + +import asyncio + +from telegraph import upload_file as uf +from telethon import events + +from pyUltroid.dB.afk_db import add_afk, del_afk, is_afk +from pyUltroid.dB.base import KeyManager + +from . import ( + LOG_CHANNEL, + NOSPAM_CHAT, + Redis, + asst, + get_string, + mediainfo, + udB, + ultroid_bot, + ultroid_cmd, +) + +old_afk_msg = [] + +is_approved = KeyManager("PMPERMIT", cast=list).contains + + +@ultroid_cmd(pattern="afk( (.*)|$)", owner_only=True) +async def set_afk(event): + if event.client._bot or is_afk(): + return + text, media, media_type = None, None, None + if event.pattern_match.group(1).strip(): + text = event.text.split(maxsplit=1)[1] + reply = await event.get_reply_message() + if reply: + if reply.text and not text: + text = reply.text + if reply.media: + media_type = mediainfo(reply.media) + if media_type.startswith(("pic", "gif")): + file = await event.client.download_media(reply.media) + iurl = uf(file) + media = f"https://graph.org{iurl[0]}" + else: + media = reply.file.id + await event.eor("`Done`", time=2) + add_afk(text, media_type, media) + ultroid_bot.add_handler(remove_afk, events.NewMessage(outgoing=True)) + ultroid_bot.add_handler( + on_afk, + events.NewMessage( + incoming=True, func=lambda e: bool(e.mentioned or e.is_private) + ), + ) + msg1, msg2 = None, None + if text and media: + if "sticker" in media_type: + msg1 = await ultroid_bot.send_file(event.chat_id, file=media) + msg2 = await ultroid_bot.send_message( + event.chat_id, get_string("afk_5").format(text) + ) + else: + msg1 = await ultroid_bot.send_message( + event.chat_id, get_string("afk_5").format(text), file=media + ) + elif media: + if "sticker" in media_type: + msg1 = await ultroid_bot.send_file(event.chat_id, file=media) + msg2 = await ultroid_bot.send_message(event.chat_id, get_string("afk_6")) + else: + msg1 = await ultroid_bot.send_message( + event.chat_id, get_string("afk_6"), file=media + ) + elif text: + msg1 = await event.respond(get_string("afk_5").format(text)) + else: + msg1 = await event.respond(get_string("afk_6")) + old_afk_msg.append(msg1) + if msg2: + old_afk_msg.append(msg2) + return await asst.send_message(LOG_CHANNEL, msg2.text) + await asst.send_message(LOG_CHANNEL, msg1.text) + + +async def remove_afk(event): + if event.is_private and udB.get_key("PMSETTING") and not is_approved(event.chat_id): + return + elif "afk" in event.text.lower(): + return + elif event.chat_id in NOSPAM_CHAT: + return + if is_afk(): + _, _, _, afk_time = is_afk() + del_afk() + off = await event.reply(get_string("afk_1").format(afk_time)) + await asst.send_message(LOG_CHANNEL, get_string("afk_2").format(afk_time)) + for x in old_afk_msg: + try: + await x.delete() + except BaseException: + pass + await asyncio.sleep(10) + await off.delete() + + +async def on_afk(event): + if event.is_private and Redis("PMSETTING") and not is_approved(event.chat_id): + return + elif "afk" in event.text.lower(): + return + elif not is_afk(): + return + if event.chat_id in NOSPAM_CHAT: + return + sender = await event.get_sender() + if sender.bot or sender.verified: + return + text, media_type, media, afk_time = is_afk() + msg1, msg2 = None, None + if text and media: + if "sticker" in media_type: + msg1 = await event.reply(file=media) + msg2 = await event.reply(get_string("afk_3").format(afk_time, text)) + else: + msg1 = await event.reply( + get_string("afk_3").format(afk_time, text), file=media + ) + elif media: + if "sticker" in media_type: + msg1 = await event.reply(file=media) + msg2 = await event.reply(get_string("afk_4").format(afk_time)) + else: + msg1 = await event.reply(get_string("afk_4").format(afk_time), file=media) + elif text: + msg1 = await event.reply(get_string("afk_3").format(afk_time, text)) + else: + msg1 = await event.reply(get_string("afk_4").format(afk_time)) + for x in old_afk_msg: + try: + await x.delete() + except BaseException: + pass + old_afk_msg.append(msg1) + if msg2: + old_afk_msg.append(msg2) + + +if udB.get_key("AFK_DB"): + ultroid_bot.add_handler(remove_afk, events.NewMessage(outgoing=True)) + ultroid_bot.add_handler( + on_afk, + events.NewMessage( + incoming=True, func=lambda e: bool(e.mentioned or e.is_private) + ), + ) diff --git a/plugins/afscrp.py b/plugins/afscrp.py new file mode 100644 index 0000000000000000000000000000000000000000..56f02a5de24c38bbb0dd38879a80457f4eda6bc5 --- /dev/null +++ b/plugins/afscrp.py @@ -0,0 +1,95 @@ +import logging +from bs4 import BeautifulSoup +from googleapiclient.discovery import build +from . import ultroid_cmd, async_searcher, run_async, LOGS +import asyncio +from io import BytesIO + +logging.getLogger("googleapiclient.discovery_cache").setLevel(logging.WARNING) + +async def fetch_full_content(url): + try: + api_url = f"https://scraper.api.airforce/scrape?url={url}" + response = await async_searcher(api_url) + + soup = BeautifulSoup(response, "html.parser") + main_content = soup.select_one("article") or soup.select_one("main") or soup + paragraphs = [ + para.get_text(separator=" ").strip() + for para in main_content.find_all("p") + if len(para.get_text(strip=True)) > 30 + and not any( + keyword in para.get_text().lower() + for keyword in [ + "privacy", + "cookie", + "subscribe", + "sign up", + "terms", + "all rights reserved", + "see all", + "see more", + ] + ) + ] + full_text = ( + " ".join(paragraphs[:5]) if paragraphs else "No main content available." + ) + return full_text + except Exception as e: + return f"Error fetching content: {e}" + +async def google_search(query): + api_key = " AIzaSyCDOnsWu0cF8W-6jnWceUSHeuSmpC7b2g0 " + cse_id = "a44275f02ca2946da" + service = build("customsearch", "v1", developerKey=api_key) + + results = service.cse().list(q=query, cx=cse_id, gl="AU").execute() + search_items = results.get("items", []) + + search_results = await asyncio.gather( + *(fetch_search_result(item) for item in search_items) + ) + + return search_results + +async def fetch_search_result(item): + title = item.get("title") + link = item.get("link") + snippet = item.get("snippet") + full_content = await fetch_full_content(link) + return (title, link, snippet, full_content) + +async def display_readable_results(results): + readable_res = "" + for idx, result in enumerate(results, start=1): + title, link, snippet, full_content = result + full_content = ( + full_content if full_content else "No additional content available." + ) + readable_res += f"Result {idx}:\n" + readable_res += f"Title: {title}\n" + readable_res += f"Link: {link}\n" + readable_res += f"Snippet: {snippet}\n" + readable_res += f"Full Content: {full_content.strip()}\n" + readable_res += "\n" + "=" * 80 + "\n" + return readable_res + +@ultroid_cmd(pattern="afscrp(?: (.*)|$)") +async def google_search_cmd(event): + query = event.pattern_match.group(1) + if not query: + return await event.eor("Please provide a query to search.") + moi = await event.eor("Searching Google...") + results = await google_search(query) + readable_results = await display_readable_results(results) + + if len(readable_results) < 4095: + await moi.edit(readable_results) + else: + with BytesIO(readable_results.encode()) as file: + file.name = "google_search_results.txt" + await event.client.send_file( + event.chat_id, file, caption=f"Search results for: {query}", reply_to=event.reply_to_msg_id + ) + await moi.delete() diff --git a/plugins/antiflood.py b/plugins/antiflood.py new file mode 100644 index 0000000000000000000000000000000000000000..82225c16956e7096bb3e05457ef1892fa14541ef --- /dev/null +++ b/plugins/antiflood.py @@ -0,0 +1,121 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_antiflood") + + +import re + +from telethon.events import NewMessage as NewMsg + +from pyUltroid.dB import DEVLIST +from pyUltroid.dB.antiflood_db import get_flood, get_flood_limit, rem_flood, set_flood +from pyUltroid.fns.admins import admin_check + +from . import Button, Redis, asst, callback, eod, get_string, ultroid_bot, ultroid_cmd + +_check_flood = {} + +if Redis("ANTIFLOOD"): + + @ultroid_bot.on( + NewMsg( + chats=list(get_flood().keys()), + ), + ) + async def flood_checm(event): + count = 1 + chat = (await event.get_chat()).title + if event.chat_id in _check_flood.keys(): + if event.sender_id == list(_check_flood[event.chat_id].keys())[0]: + count = _check_flood[event.chat_id][event.sender_id] + _check_flood[event.chat_id] = {event.sender_id: count + 1} + else: + _check_flood[event.chat_id] = {event.sender_id: count} + else: + _check_flood[event.chat_id] = {event.sender_id: count} + if await admin_check(event, silent=True) or getattr(event.sender, "bot", None): + return + if event.sender_id in DEVLIST: + return + if _check_flood[event.chat_id][event.sender_id] >= int( + get_flood_limit(event.chat_id) + ): + try: + name = event.sender.first_name + await event.client.edit_permissions( + event.chat_id, event.sender_id, send_messages=False + ) + del _check_flood[event.chat_id] + await event.reply(f"#AntiFlood\n\n{get_string('antiflood_3')}") + await asst.send_message( + int(Redis("LOG_CHANNEL")), + f"#Antiflood\n\n`Muted `[{name}](tg://user?id={event.sender_id})` in {chat}`", + buttons=Button.inline( + "Unmute", data=f"anti_{event.sender_id}_{event.chat_id}" + ), + ) + except BaseException: + pass + + +@callback( + re.compile( + "anti_(.*)", + ), +) +async def unmuting(e): + ino = (e.data_match.group(1)).decode("UTF-8").split("_") + user = int(ino[0]) + chat = int(ino[1]) + user_name = (await ultroid_bot.get_entity(user)).first_name + chat_title = (await ultroid_bot.get_entity(chat)).title + await ultroid_bot.edit_permissions(chat, user, send_messages=True) + await e.edit( + f"#Antiflood\n\n`Unmuted `[{user_name}](tg://user?id={user})` in {chat_title}`" + ) + + +@ultroid_cmd( + pattern="setflood ?(\\d+)", + admins_only=True, +) +async def setflood(e): + input_ = e.pattern_match.group(1).strip() + if not input_: + return await e.eor("`What?`", time=5) + if not input_.isdigit(): + return await e.eor(get_string("com_3"), time=5) + if m := set_flood(e.chat_id, input_): + return await eod(e, get_string("antiflood_4").format(input_)) + + +@ultroid_cmd( + pattern="remflood$", + admins_only=True, +) +async def remove_flood(e): + hmm = rem_flood(e.chat_id) + try: + del _check_flood[e.chat_id] + except BaseException: + pass + if hmm: + return await e.eor(get_string("antiflood_1"), time=5) + await e.eor(get_string("antiflood_2"), time=5) + + +@ultroid_cmd( + pattern="getflood$", + admins_only=True, +) +async def getflood(e): + if ok := get_flood_limit(e.chat_id): + return await e.eor(get_string("antiflood_5").format(ok), time=5) + await e.eor(get_string("antiflood_2"), time=5) diff --git a/plugins/asstcmd.py b/plugins/asstcmd.py new file mode 100644 index 0000000000000000000000000000000000000000..b88446ef7d5e50d4578c2f59e6742e90fd06f89e --- /dev/null +++ b/plugins/asstcmd.py @@ -0,0 +1,107 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_asstcmd") + +import os + +from pyUltroid.dB.asstcmd_db import add_cmd, cmd_reply, list_cmds, rem_cmd +from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button + +try: + from telegraph import upload_file as uf +except ImportError: + uf = None +from telethon import events, utils + +from . import asst, get_string, mediainfo, udB, ultroid_cmd + + +@ultroid_cmd(pattern="addcmd( (.*)|$)") +async def ac(e): + wrd = (e.pattern_match.group(1).strip()).lower() + wt = await e.get_reply_message() + if not (wt and wrd): + return await e.eor(get_string("asstcmd_1"), time=5) + if "/" in wrd: + wrd = wrd.replace("/", "") + btn = format_btn(wt.buttons) if wt.buttons else None + if wt and wt.media: + wut = mediainfo(wt.media) + if wut.startswith(("pic", "gif")): + dl = await e.client.download_media(wt.media) + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + elif wut == "video": + if wt.media.document.size > 8 * 1000 * 1000: + return await e.eor(get_string("com_4"), time=5) + dl = await e.client.download_media(wt.media) + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + else: + m = utils.pack_bot_file_id(wt.media) + if wt.text: + txt = wt.text + if not btn: + txt, btn = get_msg_button(wt.text) + add_cmd(wrd, txt, m, btn) + else: + add_cmd(wrd, None, m, btn) + else: + txt = wt.text + if not btn: + txt, btn = get_msg_button(wt.text) + add_cmd(wrd, txt, None, btn) + asst.add_handler( + astcmds, + events.NewMessage( + func=lambda x: x.text.startswith("/") and x.text[1:] in list(list_cmds()) + ), + ) + await e.eor(get_string("asstcmd_4").format(wrd)) + + +@ultroid_cmd(pattern="remcmd( (.*)|$)") +async def rc(e): + wrd = (e.pattern_match.group(1).strip()).lower() + if not wrd: + return await e.eor(get_string("asstcmd_2"), time=5) + wrd = wrd.replace("/", "") + rem_cmd(wrd) + await e.eor(get_string("asstcmd_3").format(wrd)) + + +@ultroid_cmd(pattern="listcmd$") +async def lscmd(e): + if list_cmds(): + ok = get_string("asstcmd_6") + for x in list_cmds(): + ok += f"/{x}" + "\n" + return await e.eor(ok) + return await e.eor(get_string("asstcmd_5")) + + +async def astcmds(e): + xx = (e.text.replace("/", "")).lower().split()[0] + if cmd_reply(xx): + msg, media, bt = cmd_reply(xx) + if bt: + bt = create_tl_btn(bt) + await e.reply(msg, file=media, buttons=bt) + + +if udB.get_key("ASST_CMDS"): + asst.add_handler( + astcmds, + events.NewMessage( + func=lambda x: x.text.startswith("/") and x.text[1:] in list(list_cmds()) + ), + ) diff --git a/plugins/audiotools.py b/plugins/audiotools.py new file mode 100644 index 0000000000000000000000000000000000000000..f8c0b52558cc3642647a2145d8693182305a6c98 --- /dev/null +++ b/plugins/audiotools.py @@ -0,0 +1,160 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +import os +import time +from datetime import datetime as dt + +from pyUltroid.fns.tools import set_attributes + +from . import ( + LOGS, + ULTConfig, + bash, + downloader, + eod, + eor, + genss, + get_help, + get_string, + humanbytes, + mediainfo, + stdr, + time_formatter, + ultroid_cmd, + uploader, +) + +__doc__ = get_help("help_audiotools") + + +@ultroid_cmd(pattern="makevoice$") +async def vnc(e): + if not e.reply_to: + return await eod(e, get_string("audiotools_1")) + r = await e.get_reply_message() + if not mediainfo(r.media).startswith(("audio", "video")): + return await eod(e, get_string("spcltool_1")) + xxx = await e.eor(get_string("com_1")) + file, _ = await e.client.fast_downloader( + r.document, + ) + await xxx.edit(get_string("audiotools_2")) + await bash( + f"ffmpeg -i '{file.name}' -map 0:a -codec:a libopus -b:a 100k -vbr on out.opus" + ) + try: + await e.client.send_message( + e.chat_id, file="out.opus", force_document=False, reply_to=r + ) + except Exception as er: + LOGS.exception(er) + return await xxx.edit("`Failed to convert in Voice...`") + await xxx.delete() + os.remove(file.name) + os.remove("out.opus") + + +@ultroid_cmd(pattern="atrim( (.*)|$)") +async def trim_aud(e): + sec = e.pattern_match.group(1).strip() + if not sec or "-" not in sec: + return await eod(e, get_string("audiotools_3")) + a, b = sec.split("-") + if int(a) >= int(b): + return await eod(e, get_string("audiotools_4")) + vido = await e.get_reply_message() + if vido and vido.media and mediainfo(vido.media).startswith(("video", "audio")): + if hasattr(vido.media, "document"): + vfile = vido.media.document + name = vido.file.name + else: + vfile = vido.media + name = "" + if not name: + name = dt.now().isoformat("_", "seconds") + ".mp4" + xxx = await e.eor(get_string("audiotools_5")) + c_time = time.time() + file = await downloader( + f"resources/downloads/{name}", + vfile, + xxx, + c_time, + f"Downloading {name}...", + ) + + o_size = os.path.getsize(file.name) + d_time = time.time() + diff = time_formatter((d_time - c_time) * 1000) + file_name = (file.name).split("/")[-1] + out = file_name.replace(file_name.split(".")[-1], "_trimmed.aac") + if int(b) > int(await genss(file.name)): + os.remove(file.name) + return await eod(xxx, get_string("audiotools_6")) + ss, dd = stdr(int(a)), stdr(int(b)) + xxx = await xxx.edit( + f"Downloaded `{file.name}` of `{humanbytes(o_size)}` in `{diff}`.\n\nNow Trimming Audio from `{ss}` to `{dd}`..." + ) + cmd = f'ffmpeg -i "{file.name}" -preset ultrafast -ss {ss} -to {dd} -vn -acodec copy "{out}" -y' + await bash(cmd) + os.remove(file.name) + f_time = time.time() + mmmm = await uploader(out, out, f_time, xxx, f"Uploading {out}...") + attributes = await set_attributes(out) + + caption = get_string("audiotools_7").format(ss, dd) + await e.client.send_file( + e.chat_id, + mmmm, + thumb=ULTConfig.thumb, + caption=caption, + attributes=attributes, + force_document=False, + reply_to=e.reply_to_msg_id, + ) + await xxx.delete() + else: + await e.eor(get_string("audiotools_1"), time=5) + + +@ultroid_cmd(pattern="extractaudio$") +async def ex_aud(e): + reply = await e.get_reply_message() + if not (reply and reply.media and mediainfo(reply.media).startswith("video")): + return await e.eor(get_string("audiotools_8")) + name = reply.file.name or "video.mp4" + vfile = reply.media.document + msg = await e.eor(get_string("com_1")) + c_time = time.time() + file = await downloader( + f"resources/downloads/{name}", + vfile, + msg, + c_time, + f"Downloading {name}...", + ) + + out_file = f"{file.name}.aac" + cmd = f"ffmpeg -i {file.name} -vn -acodec copy {out_file}" + o, err = await bash(cmd) + os.remove(file.name) + attributes = await set_attributes(out_file) + + f_time = time.time() + try: + fo = await uploader(out_file, out_file, f_time, msg, f"Uploading {out_file}...") + + except FileNotFoundError: + return await eor(msg, get_string("audiotools_9")) + await e.reply( + get_string("audiotools_10"), + file=fo, + thumb=ULTConfig.thumb, + attributes=attributes, + ) + await msg.delete() diff --git a/plugins/autoban.py b/plugins/autoban.py new file mode 100644 index 0000000000000000000000000000000000000000..597323213b309398b1f2a8f047f095aa904dc0df --- /dev/null +++ b/plugins/autoban.py @@ -0,0 +1,59 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_autoban") + +from telethon import events + +from pyUltroid.dB.base import KeyManager + +from . import LOGS, asst, ultroid_bot, ultroid_cmd + +Keym = KeyManager("DND_CHATS", cast=list) + + +def join_func(e): + return e.user_joined and Keym.contains(e.chat_id) + + +async def dnd_func(event): + for user in event.users: + try: + await (await event.client.kick_participant(event.chat_id, user)).delete() + except Exception as ex: + LOGS.error("Error in DND:") + LOGS.exception(ex) + await event.delete() + + +@ultroid_cmd( + pattern="autokick (on|off)$", + admins_only=True, + manager=True, + require="ban_users", + fullsudo=True, +) +async def _(event): + match = event.pattern_match.group(1) + if match == "on": + if Keym.contains(event.chat_id): + return await event.eor("`Chat already in do not disturb mode.`", time=3) + Keym.add(event.chat_id) + event.client.add_handler(dnd_func, events.ChatAction(func=join_func)) + await event.eor("`Do not disturb mode activated for this chat.`", time=3) + elif match == "off": + if not Keym.contains(event.chat_id): + return await event.eor("`Chat is not in do not disturb mode.`", time=3) + Keym.remove(event.chat_id) + await event.eor("`Do not disturb mode deactivated for this chat.`", time=3) + + +if Keym.get(): + ultroid_bot.add_handler(dnd_func, events.ChatAction(func=join_func)) + asst.add_handler(dnd_func, events.ChatAction(func=join_func)) diff --git a/plugins/autopic.py b/plugins/autopic.py new file mode 100644 index 0000000000000000000000000000000000000000..f6e5127662bc1aaf78bf85ba4bcda347ffc841a3 --- /dev/null +++ b/plugins/autopic.py @@ -0,0 +1,84 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +import asyncio +import os +import random +from random import shuffle + +from telethon.tl.functions.photos import UploadProfilePhotoRequest + +from pyUltroid.fns.helper import download_file +from pyUltroid.fns.tools import get_google_images + +from . import LOGS, get_help, get_string, udB, ultroid_bot, ultroid_cmd + +__doc__ = get_help("help_autopic") + + +@ultroid_cmd(pattern="autopic( (.*)|$)") +async def autopic(e): + search = e.pattern_match.group(1).strip() + if udB.get_key("AUTOPIC") and not search: + udB.del_key("AUTOPIC") + return await e.eor(get_string("autopic_5")) + if not search: + return await e.eor(get_string("autopic_1"), time=5) + e = await e.eor(get_string("com_1")) + gi = googleimagesdownload() + args = { + "keywords": search, + "limit": 50, + "format": "jpg", + "output_directory": "./resources/downloads/", + } + try: + pth = await gi.download(args) + ok = pth[0][search] + except Exception as er: + LOGS.exception(er) + return await e.eor(str(er)) + if not ok: + return await e.eor(get_string("autopic_2").format(search), time=5) + await e.eor(get_string("autopic_3").format(search)) + udB.set_key("AUTOPIC", search) + SLEEP_TIME = udB.get_key("SLEEP_TIME") or 1221 + while True: + for lie in ok: + if udB.get_key("AUTOPIC") != search: + return + file = await e.client.upload_file(lie) + await e.client(UploadProfilePhotoRequest(file)) + await asyncio.sleep(SLEEP_TIME) + shuffle(ok) + + +if search := udB.get_key("AUTOPIC"): + images = {} + sleep = udB.get_key("SLEEP_TIME") or 1221 + + async def autopic_func(): + search = udB.get_key("AUTOPIC") + if images.get(search) is None: + images[search] = await get_google_images(search) + if not images.get(search): + return + img = random.choice(images[search]) + filee = await download_file(img["original"], "resources/downloads/autopic.jpg") + file = await ultroid_bot.upload_file(filee) + await ultroid_bot(UploadProfilePhotoRequest(file)) + os.remove(filee) + + try: + from apscheduler.schedulers.asyncio import AsyncIOScheduler + + schedule = AsyncIOScheduler() + schedule.add_job(autopic_func, "interval", seconds=sleep) + schedule.start() + except ModuleNotFoundError as er: + LOGS.error(f"autopic: '{er.name}' not installed.") diff --git a/plugins/beautify.py b/plugins/beautify.py new file mode 100644 index 0000000000000000000000000000000000000000..efe307d26d6557212168df78c8e333673d802e14 --- /dev/null +++ b/plugins/beautify.py @@ -0,0 +1,210 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_beautify") + + +import os +import random + +from telethon.utils import get_display_name +from urllib.parse import urlencode +from . import Carbon, ultroid_cmd, get_string, inline_mention, LOGS +from secrets import token_hex + +_colorspath = "resources/colorlist.txt" + +if os.path.exists(_colorspath): + with open(_colorspath, "r") as f: + all_col = f.read().split() +else: + all_col = [] + + +@ultroid_cmd( + pattern="(rc|c)arbon", +) +async def cr_bn(event): + xxxx = await event.eor(get_string("com_1")) + te = event.pattern_match.group(1) + col = random.choice(all_col) if te[0] == "r" else "White" + if event.reply_to_msg_id: + temp = await event.get_reply_message() + if temp.media: + b = await event.client.download_media(temp) + with open(b) as a: + code = a.read() + os.remove(b) + else: + code = temp.message + else: + try: + code = event.text.split(" ", maxsplit=1)[1] + except IndexError: + return await xxxx.eor(get_string("carbon_2")) + xx = await Carbon(code=code, file_name="ultroid_carbon", backgroundColor=col) + if isinstance(xx, dict): + await xxxx.edit(f"`{xx}`") + return + await xxxx.delete() + await event.reply( + f"Carbonised by {inline_mention(event.sender)}", + file=xx, + ) + + +@ultroid_cmd( + pattern="ccarbon( (.*)|$)", +) +async def crbn(event): + match = event.pattern_match.group(1).strip() + if not match: + return await event.eor(get_string("carbon_3")) + msg = await event.eor(get_string("com_1")) + if event.reply_to_msg_id: + temp = await event.get_reply_message() + if temp.media: + b = await event.client.download_media(temp) + with open(b) as a: + code = a.read() + os.remove(b) + else: + code = temp.message + else: + try: + match = match.split(" ", maxsplit=1) + code = match[1] + match = match[0] + except IndexError: + return await msg.eor(get_string("carbon_2")) + xx = await Carbon(code=code, backgroundColor=match) + await msg.delete() + await event.reply( + f"Carbonised by {inline_mention(event.sender)}", + file=xx, + ) + + +RaySoTheme = [ + "meadow", + "breeze", + "raindrop", + "candy", + "crimson", + "falcon", + "sunset", + "noir", + "midnight", + "bitmap", + "ice", + "sand", + "forest", + "mono" +] + + +@ultroid_cmd(pattern="rayso") +async def pass_on(ult): + try: + from playwright.async_api import async_playwright + except ImportError: + await ult.eor("`playwright` is not installed!\nPlease install it to use this command..") + return + + proc = await ult.eor(get_string("com_1")) + spli = ult.text.split() + theme, dark, title, text = None, True, get_display_name(ult.chat), None + + if len(spli) > 2: + if spli[1] in RaySoTheme: + theme = spli[1] + dark = spli[2].lower().strip() in ["true", "t"] + elif len(spli) > 1: + if spli[1] in RaySoTheme: + theme = spli[1] + elif spli[1] == "list": + text = "**List of Rayso Themes:**\n" + "\n".join([f"- `{th_}`" for th_ in RaySoTheme]) + await proc.eor(text) + return + else: + try: + text = ult.text.split(maxsplit=1)[1] + except IndexError: + pass + + if not theme or theme not in RaySoTheme: + theme = random.choice(RaySoTheme) + + if ult.is_reply: + try: + msg = await ult.get_reply_message() + text = msg.message + title = get_display_name(msg.sender) + except Exception as sam: + ErrInfo(sam) + + if not text: + await proc.eor("No text to beautify!") + return + + cleaned_text = "\n".join([line.strip() for line in text.splitlines()]) + + name = token_hex(8) + ".png" + data = {"darkMode": dark, "theme": theme, "title": title} + url = f"https://ray.so/#{urlencode(data)}" + + async with async_playwright() as play: + try: +# browser = await play.chromium.launch(headless=False) # Set to False for debugging + browser = await play.chromium.launch(headless=True, args=["--disable-crash-reporter"]) + page = await browser.new_page() + await page.goto(url, timeout=60000) # Increase timeout + await page.wait_for_load_state("networkidle") + + try: + await page.wait_for_selector("div[class*='Editor_editor__']", timeout=60000) + editor = await page.query_selector("div[class*='Editor_editor__']") + await editor.focus() + await editor.click() + + for line in cleaned_text.split("\n"): + await page.keyboard.type(line) + await page.keyboard.press("Enter") + + await page.evaluate("""() => { + const button = document.querySelector('button[aria-label="Export as PNG"]'); + button.click(); + }""") + + async with page.expect_download() as download_info: + download = await download_info.value + await download.save_as(name) + + except playwright._impl._errors.TimeoutError: + LOGS.info("Timeout error: Selector not found within 60 seconds.") + await proc.eor("Failed to find the editor within 60 seconds.") + return + + except Exception as e: + LOGS.info(f"Error occurred during playwright operation: {e}") + await proc.eor("An error occurred during the operation.") + return + + finally: + if os.path.exists(name): + try: + await ult.reply(file=name) + await proc.try_delete() + os.remove(name) + except Exception as e: + LOGS.info(f"Error occurred while replying with the file: {e}") + await proc.eor("Failed to send the file.") + else: + LOGS.info(f"Error: File {name} not found or inaccessible.") + await proc.eor("Failed to save the file.") diff --git a/plugins/blacklist.py b/plugins/blacklist.py new file mode 100644 index 0000000000000000000000000000000000000000..78f2d42afe65f3cf377a7b28654333fa806446ba --- /dev/null +++ b/plugins/blacklist.py @@ -0,0 +1,69 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_blacklist") + + +from pyUltroid.dB.blacklist_db import ( + add_blacklist, + get_blacklist, + list_blacklist, + rem_blacklist, +) + +from . import events, get_string, udB, ultroid_bot, ultroid_cmd + + +@ultroid_cmd(pattern="blacklist( (.*)|$)", admins_only=True) +async def af(e): + wrd = e.pattern_match.group(1).strip() + chat = e.chat_id + if not (wrd): + return await e.eor(get_string("blk_1"), time=5) + wrd = e.text[11:] + heh = wrd.split(" ") + for z in heh: + add_blacklist(int(chat), z.lower()) + ultroid_bot.add_handler(blacklist, events.NewMessage(incoming=True)) + await e.eor(get_string("blk_2").format(wrd)) + + +@ultroid_cmd(pattern="remblacklist( (.*)|$)", admins_only=True) +async def rf(e): + wrd = e.pattern_match.group(1).strip() + chat = e.chat_id + if not wrd: + return await e.eor(get_string("blk_3"), time=5) + wrd = e.text[14:] + heh = wrd.split(" ") + for z in heh: + rem_blacklist(int(chat), z.lower()) + await e.eor(get_string("blk_4").format(wrd)) + + +@ultroid_cmd(pattern="listblacklist$", admins_only=True) +async def lsnote(e): + if x := list_blacklist(e.chat_id): + sd = get_string("blk_5") + return await e.eor(sd + x) + await e.eor(get_string("blk_6")) + + +async def blacklist(e): + if x := get_blacklist(e.chat_id): + text = e.text.lower().split() + if any((z in text) for z in x): + try: + await e.delete() + except BaseException: + pass + + +if udB.get_key("BLACKLIST_DB"): + ultroid_bot.add_handler(blacklist, events.NewMessage(incoming=True)) diff --git a/plugins/bot.py b/plugins/bot.py new file mode 100644 index 0000000000000000000000000000000000000000..2209c64b66ee550c74bcf0c991428b02b8e9eb02 --- /dev/null +++ b/plugins/bot.py @@ -0,0 +1,358 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_bot") + +import os +import sys +import time +from platform import python_version as pyver +from random import choice + +from telethon import __version__ +from telethon.errors.rpcerrorlist import ( + BotMethodInvalidError, + ChatSendMediaForbiddenError, +) + +from pyUltroid.version import __version__ as UltVer + +from . import HOSTED_ON, LOGS + +try: + from git import Repo +except ImportError: + LOGS.error("bot: 'gitpython' module not found!") + Repo = None + +from telethon.utils import resolve_bot_file_id + +from . import ( + ATRA_COL, + LOGS, + OWNER_NAME, + ULTROID_IMAGES, + Button, + Carbon, + Telegraph, + Var, + allcmds, + asst, + bash, + call_back, + callback, + def_logs, + eor, + get_string, + heroku_logs, + in_pattern, + inline_pic, + restart, + shutdown, + start_time, + time_formatter, + udB, + ultroid_cmd, + ultroid_version, + updater, +) + + +def ULTPIC(): + return inline_pic() or choice(ULTROID_IMAGES) + + +buttons = [ + [ + Button.url(get_string("bot_3"), "https://github.com/TeamUltroid/Ultroid"), + Button.url(get_string("bot_4"), "t.me/UltroidSupportChat"), + ] +] + +# Will move to strings +alive_txt = """ +The Ultroid Userbot + + ◍ Version - {} + ◍ Py-Ultroid - {} + ◍ Telethon - {} +""" + +in_alive = "{}\n\n🌀 Ultroid Version -> {}\n🌀 PyUltroid -> {}\n🌀 Python -> {}\n🌀 Uptime -> {}\n🌀 Branch ->[ {} ]\n\n• Join @TeamUltroid" + + +@callback("alive") +async def alive(event): + text = alive_txt.format(ultroid_version, UltVer, __version__) + await event.answer(text, alert=True) + + +@ultroid_cmd( + pattern="alive( (.*)|$)", +) +async def lol(ult): + match = ult.pattern_match.group(1).strip() + inline = None + if match in ["inline", "i"]: + try: + res = await ult.client.inline_query(asst.me.username, "alive") + return await res[0].click(ult.chat_id) + except BotMethodInvalidError: + pass + except BaseException as er: + LOGS.exception(er) + inline = True + pic = udB.get_key("ALIVE_PIC") + if isinstance(pic, list): + pic = choice(pic) + uptime = time_formatter((time.time() - start_time) * 1000) + header = udB.get_key("ALIVE_TEXT") or get_string("bot_1") +# y = Repo().active_branch + y = "main" +# xx = Repo().remotes[0].config_reader.get("url") + xx = "https://github.com/ufoptg/UltroidBackup.git" + rep = xx.replace(".git", f"/tree/{y}") + kk = f" `[{y}]({rep})` " + if inline: + kk = f"{y}" + parse = "html" + als = in_alive.format( + header, + f"{ultroid_version} [{HOSTED_ON}]", + UltVer, + pyver(), + uptime, + kk, + ) + + if _e := udB.get_key("ALIVE_EMOJI"): + als = als.replace("🌀", _e) + else: + parse = "md" + als = (get_string("alive_1")).format( + header, + OWNER_NAME, + f"{ultroid_version} [{HOSTED_ON}]", + UltVer, + uptime, + pyver(), + __version__, + kk, + ) + + if a := udB.get_key("ALIVE_EMOJI"): + als = als.replace("✵", a) + if pic: + try: + await ult.reply( + als, + file=pic, + parse_mode=parse, + link_preview=False, + buttons=buttons if inline else None, + ) + return await ult.try_delete() + except ChatSendMediaForbiddenError: + pass + except BaseException as er: + LOGS.exception(er) + try: + await ult.reply(file=pic) + await ult.reply( + als, + parse_mode=parse, + buttons=buttons if inline else None, + link_preview=False, + ) + return await ult.try_delete() + except BaseException as er: + LOGS.exception(er) + await eor( + ult, + als, + parse_mode=parse, + link_preview=False, + buttons=buttons if inline else None, + ) + + +@ultroid_cmd(pattern="ping$", chats=[], type=["official", "assistant"]) +async def _(event): + start = time.time() + x = await event.eor("Pong !") + end = round((time.time() - start) * 1000) + uptime = time_formatter((time.time() - start_time) * 1000) + await x.edit(get_string("ping").format(end, uptime)) + + +@ultroid_cmd( + pattern="cmds$", +) +async def cmds(event): + await allcmds(event, Telegraph) + + +heroku_api = Var.HEROKU_API + + +@ultroid_cmd( + pattern="restart$", + fullsudo=True, +) +async def restartbt(ult): + ok = await ult.eor(get_string("bot_5")) + call_back() + who = "bot" if ult.client._bot else "user" + udB.set_key("_RESTART", f"{who}_{ult.chat_id}_{ok.id}") + if heroku_api: + return await restart(ok) + await bash("git pull && pip3 install -r requirements.txt") + if len(sys.argv) > 1: + os.execl(sys.executable, sys.executable, "main.py") + else: + os.execl(sys.executable, sys.executable, "-m", "pyUltroid") + + +@ultroid_cmd( + pattern="shutdown$", + fullsudo=True, +) +async def shutdownbot(ult): + await shutdown(ult) + + +@ultroid_cmd( + pattern="logs( (.*)|$)", + chats=[], +) +async def _(event): + opt = event.pattern_match.group(1).strip() + file = f"ultroid{sys.argv[-1]}.log" if len(sys.argv) > 1 else "ultroid.log" + if opt == "heroku": + await heroku_logs(event) + elif opt == "carbon" and Carbon: + event = await event.eor(get_string("com_1")) + with open(file, "r") as f: + code = f.read()[-2500:] + file = await Carbon( + file_name="ultroid-logs", + code=code, + backgroundColor=choice(ATRA_COL), + ) + if isinstance(file, dict): + await event.eor(f"`{file}`") + return + await event.reply("**Ultroid Logs.**", file=file) + elif opt == "open": + with open("ultroid.log", "r") as f: + file = f.read()[-4000:] + return await event.eor(f"`{file}`") + else: + await def_logs(event, file) + await event.try_delete() + + +@in_pattern("alive", owner=True) +async def inline_alive(ult): + pic = udB.get_key("ALIVE_PIC") + if isinstance(pic, list): + pic = choice(pic) + uptime = time_formatter((time.time() - start_time) * 1000) + header = udB.get_key("ALIVE_TEXT") or get_string("bot_1") + y = Repo().active_branch + xx = Repo().remotes[0].config_reader.get("url") + rep = xx.replace(".git", f"/tree/{y}") + kk = f"{y}" + als = in_alive.format( + header, f"{ultroid_version} [{HOSTED_ON}]", UltVer, pyver(), uptime, kk + ) + + if _e := udB.get_key("ALIVE_EMOJI"): + als = als.replace("🌀", _e) + builder = ult.builder + if pic: + try: + if ".jpg" in pic: + results = [ + await builder.photo( + pic, text=als, parse_mode="html", buttons=buttons + ) + ] + else: + if _pic := resolve_bot_file_id(pic): + pic = _pic + buttons.insert( + 0, [Button.inline(get_string("bot_2"), data="alive")] + ) + results = [ + await builder.document( + pic, + title="Inline Alive", + description="@TeamUltroid", + parse_mode="html", + buttons=buttons, + ) + ] + return await ult.answer(results) + except BaseException as er: + LOGS.exception(er) + result = [ + await builder.article( + "Alive", text=als, parse_mode="html", link_preview=False, buttons=buttons + ) + ] + await ult.answer(result) + + +@ultroid_cmd(pattern="update( (.*)|$)") +async def _(e): + xx = await e.eor(get_string("upd_1")) + if e.pattern_match.group(1).strip() and ( + "fast" in e.pattern_match.group(1).strip() + or "soft" in e.pattern_match.group(1).strip() + ): + await bash("git pull -f && pip3 install -r requirements.txt") + call_back() + await xx.edit(get_string("upd_7")) + os.execl(sys.executable, "python3", "-m", "pyUltroid") + # return + m = await updater() + branch = (Repo.init()).active_branch + if m: + x = await asst.send_file( + udB.get_key("LOG_CHANNEL"), + ULTPIC(), + caption="• **Update Available** •", + force_document=False, + buttons=Button.inline("Changelogs", data="changes"), + ) + Link = x.message_link + await xx.edit( + f'[ChangeLogs]', + parse_mode="html", + link_preview=False, + ) + else: + await xx.edit( + f'Your BOT is up-to-date with [{branch}]', + parse_mode="html", + link_preview=False, + ) + + +@callback("updtavail", owner=True) +async def updava(event): + await event.delete() + await asst.send_file( + udB.get_key("LOG_CHANNEL"), + ULTPIC(), + caption="• **Update Available** •", + force_document=False, + buttons=Button.inline("Changelogs", data="changes"), + ) diff --git a/plugins/broadcast.py b/plugins/broadcast.py new file mode 100644 index 0000000000000000000000000000000000000000..f8aedf2f086d04c9a54d45d90b9d031af2ad66ae --- /dev/null +++ b/plugins/broadcast.py @@ -0,0 +1,216 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +from . import get_help + +__doc__ = get_help("help_broadcast") + +import asyncio +import io + +from telethon.utils import get_display_name + +from pyUltroid.dB.base import KeyManager + +from . import HNDLR, LOGS, eor, get_string, udB, ultroid_bot, ultroid_cmd + +KeyM = KeyManager("BROADCAST", cast=list) + + +@ultroid_cmd( + pattern="addch( (.*)|$)", + allow_sudo=False, +) +async def broadcast_adder(event): + msgg = event.pattern_match.group(1).strip() + x = await event.eor(get_string("bd_1")) + if msgg == "all": + await x.edit(get_string("bd_2")) + chats = [ + e.entity + for e in await event.client.get_dialogs() + if (e.is_group or e.is_channel) + ] + new = 0 + for i in chats: + try: + if ( + i.broadcast + and (i.creator or i.admin_rights) + and not KeyM.contains(i.id) + ): + new += 1 + cid = f"-100{i.id}" + KeyM.add(int(cid)) + except Exception as Ex: + LOGS.exception(Ex) + await x.edit(get_string("bd_3").format(KeyM.count(), new)) + return + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + raw_text = previous_message.text + lines = raw_text.split("\n") + length = len(lines) + for line_number in range(1, length - 2): + channel_id = lines[line_number][4:-1] + if not KeyM.contains(channel_id): + KeyM.add(channel_id) + await x.edit(get_string("bd_4")) + await asyncio.sleep(3) + await event.delete() + return + chat_id = event.chat_id + if chat_id == udB.get_key("LOG_CHANNEL"): + return + if KeyM.contains(chat_id): + await x.edit(get_string("bd_6")) + elif xx := KeyM.add(chat_id): + await x.edit(get_string("bd_5")) + else: + await x.edit(get_string("sf_8")) + await asyncio.sleep(3) + await x.delete() + + +@ultroid_cmd( + pattern="remch( (.*)|$)", + allow_sudo=False, +) +async def broadcast_remover(event): + chat_id = event.pattern_match.group(1).strip() or event.chat_id + x = await event.eor(get_string("com_1")) + if chat_id == "all": + await x.edit(get_string("bd_8")) + udB.del_key("BROADCAST") + await x.edit("Database cleared.") + return + if KeyM.contains(chat_id): + KeyM.remove(chat_id) + await x.edit(get_string("bd_7")) + else: + await x.edit(get_string("bd_9")) + await asyncio.sleep(3) + await x.delete() + + +@ultroid_cmd( + pattern="listchannels$", +) +async def list_all(event): + x = await event.eor(get_string("com_1")) + channels = KeyM.get() + num = KeyM.count() + if not channels: + return await eor(x, "No chats were added.", time=5) + msg = "Channels in database:\n" + for channel in channels: + name = "" + try: + name = get_display_name(await event.client.get_entity(channel)) + except ValueError: + name = "" + msg += f"=> **{name}** [`{channel}`]\n" + msg += f"\nTotal {num} channels." + if len(msg) > 4096: + MSG = msg.replace("*", "").replace("`", "") + with io.BytesIO(str.encode(MSG)) as out_file: + out_file.name = "channels.txt" + await event.reply( + "Channels in Database", + file=out_file, + force_document=True, + allow_cache=False, + ) + await x.delete() + else: + await x.edit(msg) + + +@ultroid_cmd( + pattern="forward$", + allow_sudo=False, +) +async def forw(event): + if not event.is_reply: + return await event.eor(get_string("ex_1")) + ultroid_bot = event.client + channels = KeyM.get() + x = await event.eor("Sending...") + if not channels: + return await x.edit(f"Please add channels by using `{HNDLR}add` in them.") + error_count = 0 + sent_count = 0 + previous_message = await event.get_reply_message() + error_count = 0 + for channel in channels: + try: + await ultroid_bot.forward_messages(channel, previous_message) + sent_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + except Exception: + try: + await ultroid_bot.send_message( + udB.get_key("LOG_CHANNEL"), + f"Error in sending at {channel}.", + ) + except Exception as Em: + LOGS.info(Em) + error_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + await x.edit(f"{sent_count} messages sent with {error_count} errors.") + if error_count > 0: + await ultroid_bot.send_message( + udB.get_key("LOG_CHANNEL"), f"{error_count} Errors" + ) + + +@ultroid_cmd( + pattern="broadcast( (.*)|$)", + allow_sudo=False, +) +async def sending(event): + x = await event.eor(get_string("com_1")) + if not event.is_reply: + return await x.edit(get_string("ex_1")) + channels = KeyM.get() + if not channels: + return await x.edit(f"Please add channels by using `{HNDLR}add` in them.") + await x.edit("Sending....") + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + if previous_message.poll: + return await x.edit(f"Reply `{HNDLR}forward` for polls.") + if previous_message: + error_count = 0 + sent_count = 0 + for channel in channels: + try: + await ultroid_bot.send_message(channel, previous_message) + sent_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + except Exception as error: + await ultroid_bot.send_message( + udB.get_key("LOG_CHANNEL"), + f"Error in sending at {channel}.\n\n{error}", + ) + error_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + await x.edit(f"{sent_count} messages sent with {error_count} errors.") + if error_count > 0: + await ultroid_bot.send_message( + udB.get_key("LOG_CHANNEL"), + f"{error_count} Errors", + ) diff --git a/plugins/button.py b/plugins/button.py new file mode 100644 index 0000000000000000000000000000000000000000..b3d616d709be1a04ede2c6996d393bf12ac27f56 --- /dev/null +++ b/plugins/button.py @@ -0,0 +1,56 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_button") + +import os + +from telegraph import upload_file as uf +from telethon.utils import pack_bot_file_id + +from pyUltroid.fns.tools import create_tl_btn, get_msg_button + +from . import HNDLR, get_string, mediainfo, ultroid_cmd +from ._inline import something + + +@ultroid_cmd(pattern="button") +async def butt(event): + media, wut, text = None, None, None + if event.reply_to: + wt = await event.get_reply_message() + if wt.text: + text = wt.text + if wt.media: + wut = mediainfo(wt.media) + if wut and wut.startswith(("pic", "gif")): + dl = await wt.download_media() + variable = uf(dl) + media = f"https://graph.org{variable[0]}" + elif wut == "video": + if wt.media.document.size > 8 * 1000 * 1000: + return await event.eor(get_string("com_4"), time=5) + dl = await wt.download_media() + variable = uf(dl) + os.remove(dl) + media = f"https://graph.org{variable[0]}" + else: + media = pack_bot_file_id(wt.media) + try: + text = event.text.split(maxsplit=1)[1] + except IndexError: + if not text: + return await event.eor( + f"**Please give some text in correct format.**\n\n`{HNDLR}help button`", + ) + text, buttons = get_msg_button(text) + if buttons: + buttons = create_tl_btn(buttons) + await something(event, text, media, buttons) + await event.delete() diff --git a/plugins/calculator.py b/plugins/calculator.py new file mode 100644 index 0000000000000000000000000000000000000000..28f2bae144d25287460e4a08daa452c6acba2f9f --- /dev/null +++ b/plugins/calculator.py @@ -0,0 +1,153 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +from . import get_help + +__doc__ = get_help("help_calculator") + +import re + +from . import Button, asst, callback, get_string, in_pattern, udB, ultroid_cmd + +CALC = {} + +m = [ + "AC", + "C", + "⌫", + "%", + "7", + "8", + "9", + "+", + "4", + "5", + "6", + "-", + "1", + "2", + "3", + "x", + "00", + "0", + ".", + "÷", +] +tultd = [Button.inline(f"{x}", data=f"calc{x}") for x in m] +lst = list(zip(tultd[::4], tultd[1::4], tultd[2::4], tultd[3::4])) +lst.append([Button.inline("=", data="calc=")]) + + +@ultroid_cmd(pattern="calc") +async def icalc(e): + udB.del_key("calc") + if e.client._bot: + return await e.reply(get_string("calc_1"), buttons=lst) + results = await e.client.inline_query(asst.me.username, "calc") + await results[0].click(e.chat_id, silent=True, hide_via=True) + await e.delete() + + +@in_pattern("calc", owner=True) +async def _(e): + calc = e.builder.article("Calc", text=get_string("calc_1"), buttons=lst) + await e.answer([calc]) + + +@callback(re.compile("calc(.*)"), owner=True) +async def _(e): + x = (e.data_match.group(1)).decode() + user = e.query.user_id + get = None + if x == "AC": + if CALC.get(user): + CALC.pop(user) + await e.edit( + get_string("calc_1"), + buttons=[Button.inline(get_string("calc_2"), data="recalc")], + ) + elif x == "C": + if CALC.get(user): + CALC.pop(user) + await e.answer("cleared") + elif x == "⌫": + if CALC.get(user): + get = CALC[user] + if get: + CALC.update({user: get[:-1]}) + await e.answer(str(get[:-1])) + elif x == "%": + if CALC.get(user): + get = CALC[user] + if get: + CALC.update({user: f"{get}/100"}) + await e.answer(str(f"{get}/100")) + elif x == "÷": + if CALC.get(user): + get = CALC[user] + if get: + CALC.update({user: f"{get}/"}) + await e.answer(str(f"{get}/")) + elif x == "x": + if CALC.get(user): + get = CALC[user] + if get: + CALC.update({user: f"{get}*"}) + await e.answer(str(f"{get}*")) + elif x == "=": + if CALC.get(user): + get = CALC[user] + if get: + if get.endswith(("*", ".", "/", "-", "+")): + get = get[:-1] + out = eval(get) + try: + num = float(out) + await e.answer(f"Answer : {num}", cache_time=0, alert=True) + except BaseException: + CALC.pop(user) + await e.answer(get_string("sf_8"), cache_time=0, alert=True) + await e.answer("None") + else: + if CALC.get(user): + get = CALC[user] + if get: + CALC.update({user: get + x}) + return await e.answer(str(get + x)) + CALC.update({user: x}) + await e.answer(str(x)) + + +@callback("recalc", owner=True) +async def _(e): + m = [ + "AC", + "C", + "⌫", + "%", + "7", + "8", + "9", + "+", + "4", + "5", + "6", + "-", + "1", + "2", + "3", + "x", + "00", + "0", + ".", + "÷", + ] + tultd = [Button.inline(f"{x}", data=f"calc{x}") for x in m] + lst = list(zip(tultd[::4], tultd[1::4], tultd[2::4], tultd[3::4])) + lst.append([Button.inline("=", data="calc=")]) + await e.edit(get_string("calc_1"), buttons=lst) diff --git a/plugins/channelhacks.py b/plugins/channelhacks.py new file mode 100644 index 0000000000000000000000000000000000000000..d333249a0fc0a82ec5cd8f37ec3014b25c21bcb6 --- /dev/null +++ b/plugins/channelhacks.py @@ -0,0 +1,224 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +from . import get_help + +__doc__ = get_help("help_channelhacks") + + +import asyncio +import io + +from telethon.errors.rpcerrorlist import FloodWaitError +from telethon.utils import get_display_name, get_peer_id + +from pyUltroid.dB.base import KeyManager + +from . import LOGS, asst, eor, events, get_string, udB, ultroid_bot, ultroid_cmd + +ERROR = {} +SourceM = KeyManager("CH_SOURCE", cast=list) +DestiM = KeyManager("CH_DESTINATIONS", cast=list) + + +async def autopost_func(e): + if not udB.get_key("AUTOPOST"): + return + x = SourceM.get() + th = await e.get_chat() + if get_peer_id(th) not in x: + return + y = DestiM.get() + for ys in y: + try: + await e.client.send_message(int(ys), e.message) + except Exception as ex: + try: + ERROR[str(ex)] + except KeyError: + ERROR.update({str(ex): ex}) + Error = f"**Error on AUTOPOST**\n\n`{ex}`" + await asst.send_message(udB.get_key("LOG_CHANNEL"), Error) + + +@ultroid_cmd(pattern="shift (.*)") +async def _(e): + x = e.pattern_match.group(1).strip() + z = await e.eor(get_string("com_1")) + a, b = x.split("|") + try: + c = await e.client.parse_id(a) + except Exception: + await z.edit(get_string("cha_1")) + return + try: + d = await e.client.parse_id(b) + except Exception as er: + LOGS.exception(er) + await z.edit(get_string("cha_1")) + return + async for msg in e.client.iter_messages(int(c), reverse=True): + try: + await asyncio.sleep(2) + await e.client.send_message(int(d), msg) + except FloodWaitError as er: + await asyncio.sleep(er.seconds + 5) + await e.client.send_message(int(d), msg) + except BaseException as er: + LOGS.exception(er) + await z.edit("Done") + + +@ultroid_cmd(pattern="asource (.*)") +async def source(e): + if x := e.pattern_match.group(1).strip(): + try: + y = await e.client.parse_id(x) + except Exception as er: + LOGS.exception(er) + return + else: + y = e.chat_id + if not SourceM.contains(y): + SourceM.add(y) + await e.eor(get_string("cha_2")) + ultroid_bot.add_handler(autopost_func, events.NewMessage()) + else: + await e.eor(get_string("cha_3")) + + +@ultroid_cmd(pattern="dsource( (.*)|$)") +async def dd(event): + chat_id = event.pattern_match.group(1).strip() + x = await event.eor(get_string("com_1")) + if chat_id == "all": + await x.edit(get_string("bd_8")) + udB.del_key("CH_SOURCE") + await x.edit(get_string("cha_4")) + return + if chat_id: + try: + y = await event.client.parse_id(chat_id) + except Exception as er: + LOGS.exception(er) + return + else: + y = event.chat_id + if SourceM.contains(y): + SourceM.remove(y) + await eor(x, get_string("cha_5"), time=5) + else: + await eor(x, "Source channel is already removed from database. ", time=3) + + +@ultroid_cmd(pattern="listsource") +async def list_all(event): + x = await event.eor(get_string("com_1")) + num = SourceM.count() + if not num: + return await eor(x, "No chats were added.", time=5) + msg = get_string("cha_8") + channels = SourceM.get() + for channel in channels: + name = "" + try: + name = get_display_name(await event.client.get_entity(int(channel))) + except BaseException: + name = "" + msg += f"\n=> **{name}** [`{channel}`]" + msg += f"\nTotal {num} channels." + if len(msg) > 4096: + MSG = msg.replace("*", "").replace("`", "") + with io.BytesIO(str.encode(MSG)) as out_file: + out_file.name = "channels.txt" + await event.reply( + "Channels in database", + file=out_file, + force_document=True, + allow_cache=False, + ) + await x.delete() + else: + await x.edit(msg) + + +@ultroid_cmd(pattern="adest (.*)") +async def destination(e): + if x := e.pattern_match.group(1).strip(): + try: + y = await e.client.parse_id(x) + except Exception as er: + LOGS.exception(er) + return + else: + y = e.chat_id + if not DestiM.contains(y): + DestiM.add(y) + await e.eor("Destination added succesfully") + else: + await e.eor("Destination channel already added") + + +@ultroid_cmd(pattern="ddest( (.*)|$)") +async def dd(event): + chat_id = event.pattern_match.group(1).strip() + x = await event.eor(get_string("com_1")) + if chat_id == "all": + await x.edit(get_string("bd_8")) + udB.del_key("CH_DESTINATION") + await x.edit("Destinations database cleared.") + return + if chat_id: + try: + y = await event.client.parse_id(chat_id) + except Exception as er: + LOGS.exception(er) + return + else: + y = event.chat_id + if DestiM.contains(y): + DestiM.remove(y) + await eor(x, "Destination removed from database") + else: + await eor(x, "Destination channel is already removed from database. ", time=5) + + +@ultroid_cmd(pattern="listdest") +async def list_all(event): + ultroid_bot = event.client + x = await event.eor(get_string("com_1")) + channels = DestiM.get() + num = len(channels) + if not num: + return await eor(x, "No chats were added.", time=5) + msg = get_string("cha_7") + for channel in channels: + name = "" + try: + name = get_display_name(await ultroid_bot.get_entity(int(channel))) + except BaseException: + name = "" + msg += f"\n=> **{name}** [`{channel}`]" + msg += f"\nTotal {num} channels." + if len(msg) > 4096: + MSG = msg.replace("*", "").replace("`", "") + with io.BytesIO(str.encode(MSG)) as out_file: + out_file.name = "channels.txt" + await ultroid_bot.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + caption="Destination channels in database", + reply_to=event, + ) + await x.delete() + else: + await x.edit(msg) + + +if udB.get_key("AUTOPOST"): + ultroid_bot.add_handler(autopost_func, events.NewMessage()) diff --git a/plugins/chatbot.py b/plugins/chatbot.py new file mode 100644 index 0000000000000000000000000000000000000000..0dfcec7359f0976288e4ef885567bd21180e90ba --- /dev/null +++ b/plugins/chatbot.py @@ -0,0 +1,174 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2024 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_chatbot") + + +from pyUltroid.fns.tools import get_chatbot_reply, get_oracle_reply + +from . import LOGS, eod, get_string, inline_mention, udB, ultroid_bot, ultroid_cmd + +try: + mongouri = udB.get_key("MONGO_URI") +except AttributeError: + if udB.get_key("MONGO_URI"): + mongouri = udB.get_key("MONGO_URI") + else: + udB.set_key("MONGO_URI", "") + LOGS.error("PLeasde set a MONGO_URI") + + +@ultroid_cmd(pattern="repoai") +async def im_oracle(event): + if event.reply_to: + message = (await event.get_reply_message()).text.strip() + else: + try: + message = event.text.split(" ", 1)[1] + except IndexError: + return await eod(event, get_string("tban_1"), time=10) + reply_ = await get_oracle_reply( + query=message, user_id=ultroid_bot.me.id, mongo_url=mongouri + ) + await event.eor(reply_) + + +@ultroid_cmd(pattern="addoai") +async def add_oracle(event): + await oracle_bot_fn(event, type_="add") + + +@ultroid_cmd(pattern="remoai") +async def rem_oracle(event): + await oracle_bot_fn(event, type_="remov") + + +@ultroid_cmd(pattern="listoai") +async def listoracle(event): + key = udB.get_key("ORACLE_USERS") or {} + users = key.get(event.chat_id, []) + if not users: + return await event.eor(get_string("chab_2"), time=5) + msg = "**Total List Of Oracle Enabled Users In This Chat :**\n\n" + for i in users: + try: + user = await event.client.get_entity(int(i)) + user = inline_mention(user) + except BaseException: + user = f"`{i}`" + msg += f"• {user}\n" + await event.eor(msg, link_preview=False) + + +async def oracle_bot_fn(event, type_): + if event.reply_to: + user_ = (await event.get_reply_message()).sender + else: + temp = event.text.split(maxsplit=1) + try: + user_ = await event.client.get_entity(await event.client.parse_id(temp[1])) + except BaseException as er: + LOGS.exception(er) + user_ = event.chat if event.is_private else None + if not user_: + return await eod( + event, + get_string("chab_1"), + ) + key = udB.get_key("ORACLE_USERS") or {} + chat = event.chat_id + user = user_.id + if type_ == "add": + if key.get(chat): + if user not in key[chat]: + key[chat].append(user) + else: + key.update({chat: [user]}) + elif type_ == "remov": + if key.get(chat): + if user in key[chat]: + key[chat].remove(user) + if chat in key and not key[chat]: + del key[chat] + udB.set_key("ORACLE_USERS", key) + await event.eor(f"**Oracle:**\n{type_}ed {inline_mention(user_)}") + + +@ultroid_cmd(pattern="repai") +async def im_lonely_chat_with_me(event): + if event.reply_to: + message = (await event.get_reply_message()).message + else: + try: + message = event.text.split(" ", 1)[1] + except IndexError: + return await eod(event, get_string("tban_1"), time=10) + reply_ = await get_chatbot_reply(message=message) + await event.eor(reply_) + + +@ultroid_cmd(pattern="addai") +async def add_chatBot(event): + await chat_bot_fn(event, type_="add") + + +@ultroid_cmd(pattern="remai") +async def rem_chatBot(event): + await chat_bot_fn(event, type_="remov") + + +@ultroid_cmd(pattern="listai") +async def lister(event): + key = udB.get_key("CHATBOT_USERS") or {} + users = key.get(event.chat_id, []) + if not users: + return await event.eor(get_string("chab_2"), time=5) + msg = "**Total List Of AI Enabled Users In This Chat :**\n\n" + for i in users: + try: + user = await event.client.get_entity(int(i)) + user = inline_mention(user) + except BaseException: + user = f"`{i}`" + msg += f"• {user}\n" + await event.eor(msg, link_preview=False) + + +async def chat_bot_fn(event, type_): + if event.reply_to: + user_ = (await event.get_reply_message()).sender + else: + temp = event.text.split(maxsplit=1) + try: + user_ = await event.client.get_entity(await event.client.parse_id(temp[1])) + except BaseException as er: + LOGS.exception(er) + user_ = event.chat if event.is_private else None + if not user_: + return await eod( + event, + get_string("chab_1"), + ) + key = udB.get_key("CHATBOT_USERS") or {} + chat = event.chat_id + user = user_.id + if type_ == "add": + if key.get(chat): + if user not in key[chat]: + key[chat].append(user) + else: + key.update({chat: [user]}) + elif type_ == "remov": + if key.get(chat): + if user in key[chat]: + key[chat].remove(user) + if chat in key and not key[chat]: + del key[chat] + udB.set_key("CHATBOT_USERS", key) + await event.eor(f"**ChatBot:**\n{type_}ed {inline_mention(user_)}") diff --git a/plugins/chats.py b/plugins/chats.py new file mode 100644 index 0000000000000000000000000000000000000000..2ef171b1de3fd9f5ac67936cd116d1c9885189fe --- /dev/null +++ b/plugins/chats.py @@ -0,0 +1,368 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +from . import get_help + +__doc__ = get_help("help_chats") + + +from telethon.errors import ChatAdminRequiredError as no_admin +from telethon.tl.functions.channels import ( + CreateChannelRequest, + DeleteChannelRequest, + EditPhotoRequest, + GetFullChannelRequest, + UpdateUsernameRequest, +) +from telethon.tl.functions.messages import ( + CreateChatRequest, + ExportChatInviteRequest, + GetFullChatRequest, +) +from telethon.tl.types import ( + ChannelParticipantsKicked, + User, + UserStatusEmpty, + UserStatusLastMonth, + UserStatusLastWeek, + UserStatusOffline, + UserStatusOnline, + UserStatusRecently, +) + +from . import HNDLR, LOGS, asst, con, get_string, mediainfo, os, types, udB, ultroid_cmd + + +@ultroid_cmd( + pattern="delchat", + groups_only=True, +) +async def _(e): + xx = await e.eor(get_string("com_1")) + try: + match = e.text.split(" ", maxsplit=1)[1] + chat = await e.client.parse_id(match) + except IndexError: + chat = e.chat_id + try: + await e.client(DeleteChannelRequest(chat)) + except TypeError: + return await xx.eor(get_string("chats_1"), time=10) + except no_admin: + return await xx.eor(get_string("chats_2"), time=10) + await e.client.send_message( + int(udB.get_key("LOG_CHANNEL")), get_string("chats_6").format(e.chat_id) + ) + + +@ultroid_cmd( + pattern="getlink( (.*)|$)", + groups_only=True, + manager=True, +) +async def _(e): + reply = await e.get_reply_message() + match = e.pattern_match.group(1).strip() + if reply and not isinstance(reply.sender, User): + chat = await reply.get_sender() + else: + chat = await e.get_chat() + if hasattr(chat, "username") and chat.username: + return await e.eor(f"Username: @{chat.username}") + request, usage, title, link = None, None, None, None + if match: + split = match.split(maxsplit=1) + request = split[0] in ["r", "request"] + title = "Created by Ultroid" + if len(split) > 1: + match = split[1] + spli = match.split(maxsplit=1) + if spli[0].isdigit(): + usage = int(spli[0]) + if len(spli) > 1: + title = spli[1] + elif not request: + if match.isdigit(): + usage = int(match) + else: + title = match + if request and usage: + usage = 0 + if request or title: + try: + r = await e.client( + ExportChatInviteRequest( + e.chat_id, + request_needed=request, + usage_limit=usage, + title=title, + ), + ) + except no_admin: + return await e.eor(get_string("chats_2"), time=10) + link = r.link + else: + if isinstance(chat, types.Chat): + FC = await e.client(GetFullChatRequest(chat.id)) + elif isinstance(chat, types.Channel): + FC = await e.client(GetFullChannelRequest(chat.id)) + else: + return + Inv = FC.full_chat.exported_invite + if Inv and not Inv.revoked: + link = Inv.link + if link: + return await e.eor(f"Link:- {link}") + await e.eor("`Failed to getlink!\nSeems like link is inaccessible to you...`") + + +@ultroid_cmd( + pattern="create (b|g|c)(?: |$)(.*)", +) +async def _(e): + type_of_group = e.pattern_match.group(1).strip() + group_name = e.pattern_match.group(2) + username = None + if " ; " in group_name: + group_ = group_name.split(" ; ", maxsplit=1) + group_name = group_[0] + username = group_[1] + xx = await e.eor(get_string("com_1")) + if type_of_group == "b": + try: + r = await e.client( + CreateChatRequest( + users=[asst.me.username], + title=group_name, + ), + ) + created_chat_id = r.chats[0].id + result = await e.client( + ExportChatInviteRequest( + peer=created_chat_id, + ), + ) + await xx.edit( + get_string("chats_4").format(group_name, result.link), + link_preview=False, + ) + except Exception as ex: + await xx.edit(str(ex)) + elif type_of_group in ["g", "c"]: + try: + r = await e.client( + CreateChannelRequest( + title=group_name, + about=get_string("chats_5"), + megagroup=type_of_group != "c", + ) + ) + + created_chat_id = r.chats[0].id + if username: + await e.client(UpdateUsernameRequest(created_chat_id, username)) + result = f"https://t.me/{username}" + else: + result = ( + await e.client( + ExportChatInviteRequest( + peer=created_chat_id, + ), + ) + ).link + await xx.edit( + get_string("chats_6").format(f"[{group_name}]({result})"), + link_preview=False, + ) + except Exception as ex: + await xx.edit(str(ex)) + + +# ---------------------------------------------------------------- # + + +@ultroid_cmd( + pattern="setgpic( (.*)|$)", admins_only=True, manager=True, require="change_info" +) +async def _(ult): + if not ult.is_reply: + return await ult.eor("`Reply to a Media..`", time=5) + match = ult.pattern_match.group(1).strip() + if not ult.client._bot and match: + try: + chat = await ult.client.parse_id(match) + except Exception as ok: + return await ult.eor(str(ok)) + else: + chat = ult.chat_id + reply = await ult.get_reply_message() + if reply.photo or reply.sticker or reply.video: + replfile = await reply.download_media() + elif reply.document and reply.document.thumbs: + replfile = await reply.download_media(thumb=-1) + else: + return await ult.eor("Reply to a Photo or Video..") + mediain = mediainfo(reply.media) + if "animated" in mediain: + replfile = await con.convert(replfile, convert_to="mp4") + else: + replfile = await con.convert( + replfile, outname="chatphoto", allowed_formats=["jpg", "png", "mp4"] + ) + file = await ult.client.upload_file(replfile) + try: + if "pic" not in mediain: + file = types.InputChatUploadedPhoto(video=file) + await ult.client(EditPhotoRequest(chat, file)) + await ult.eor("`Group Photo has Successfully Changed !`", time=5) + except Exception as ex: + await ult.eor(f"Error occured.\n`{str(ex)}`", time=5) + os.remove(replfile) + + +@ultroid_cmd( + pattern="delgpic( (.*)|$)", admins_only=True, manager=True, require="change_info" +) +async def _(ult): + match = ult.pattern_match.group(1).strip() + chat = ult.chat_id + if not ult.client._bot and match: + chat = match + try: + await ult.client(EditPhotoRequest(chat, types.InputChatPhotoEmpty())) + text = "`Removed Chat Photo..`" + except Exception as E: + text = str(E) + return await ult.eor(text, time=5) + + +@ultroid_cmd(pattern="unbanall$", manager=True, admins_only=True, require="ban_users") +async def _(event): + xx = await event.eor("Searching Participant Lists.") + p = 0 + title = (await event.get_chat()).title + async for i in event.client.iter_participants( + event.chat_id, + filter=ChannelParticipantsKicked, + aggressive=True, + ): + try: + await event.client.edit_permissions(event.chat_id, i, view_messages=True) + p += 1 + except no_admin: + pass + except BaseException as er: + LOGS.exception(er) + await xx.eor(f"{title}: {p} unbanned", time=5) + + +@ultroid_cmd( + pattern="rmusers( (.*)|$)", + groups_only=True, + admins_only=True, + fullsudo=True, +) +async def _(event): + xx = await event.eor(get_string("com_1")) + input_str = event.pattern_match.group(1).strip() + p, a, b, c, d, m, n, y, w, o, q, r = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + async for i in event.client.iter_participants(event.chat_id): + p += 1 # Total Count + if isinstance(i.status, UserStatusEmpty): + if "empty" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + y += 1 + if isinstance(i.status, UserStatusLastMonth): + if "month" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + m += 1 + if isinstance(i.status, UserStatusLastWeek): + if "week" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + w += 1 + if isinstance(i.status, UserStatusOffline): + if "offline" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + o += 1 + if isinstance(i.status, UserStatusOnline): + if "online" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + q += 1 + if isinstance(i.status, UserStatusRecently): + if "recently" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + r += 1 + if i.bot: + if "bot" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + b += 1 + elif i.deleted: + if "deleted" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + d += 1 + elif i.status is None: + if "none" in input_str: + try: + await event.client.kick_participant(event.chat_id, i) + c += 1 + except BaseException: + pass + else: + n += 1 + if input_str: + required_string = f"**>> Kicked** `{c} / {p}` **users**\n\n" + else: + required_string = f"**>> Total** `{p}` **users**\n\n" + required_string += f" `{HNDLR}rmusers deleted` **••** `{d}`\n" + required_string += f" `{HNDLR}rmusers empty` **••** `{y}`\n" + required_string += f" `{HNDLR}rmusers month` **••** `{m}`\n" + required_string += f" `{HNDLR}rmusers week` **••** `{w}`\n" + required_string += f" `{HNDLR}rmusers offline` **••** `{o}`\n" + required_string += f" `{HNDLR}rmusers online` **••** `{q}`\n" + required_string += f" `{HNDLR}rmusers recently` **••** `{r}`\n" + required_string += f" `{HNDLR}rmusers bot` **••** `{b}`\n" + required_string += f" `{HNDLR}rmusers none` **••** `{n}`" + await xx.eor(required_string) diff --git a/plugins/cleanaction.py b/plugins/cleanaction.py new file mode 100644 index 0000000000000000000000000000000000000000..ebc65752f3267e175da561ea383edc31cb5bfa20 --- /dev/null +++ b/plugins/cleanaction.py @@ -0,0 +1,48 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_cleanaction") + + +from telethon.utils import get_display_name + +from . import get_string, udB, ultroid_cmd + + +@ultroid_cmd(pattern="addclean$", admins_only=True) +async def _(e): + key = udB.get_key("CLEANCHAT") or [] + if e.chat_id in key: + return await eod(e, get_string("clan_5")) + key.append(e.chat_id) + udB.set_key("CLEANCHAT", key) + await e.eor(get_string("clan_1"), time=5) + + +@ultroid_cmd(pattern="remclean$") +async def _(e): + key = udB.get_key("CLEANCHAT") or [] + if e.chat_id in key: + key.remove(e.chat_id) + udB.set_key("CLEANCHAT", key) + await e.eor(get_string("clan_2"), time=5) + + +@ultroid_cmd(pattern="listclean$") +async def _(e): + if k := udB.get_key("CLEANCHAT"): + o = "" + for x in k: + try: + title = get_display_name(await e.client.get_entity(x)) + except BaseException: + title = get_string("clan_3") + o += f"{x} {title}\n" + return await e.eor(o) + await e.eor(get_string("clan_4"), time=5) diff --git a/plugins/codefix.py b/plugins/codefix.py new file mode 100644 index 0000000000000000000000000000000000000000..1340eabeacb96651cdf196fc8ddd93274af246a1 --- /dev/null +++ b/plugins/codefix.py @@ -0,0 +1,241 @@ +import os +from collections import deque +from io import BytesIO + +from . import ( + ultroid_cmd, + async_searcher, + udB, + LOGS, + get_paste, +) + +CR_O_CHAT_HISTORY = deque(maxlen=30) + +TELEGRAM_CHAR_LIMIT = 4096 # Telegram's message character limit + +initprompt = """ +You are an expert coding assistant. Your primary goal is to analyze, repair, and enhance the code provided by the user. + +Follow this structured approach: + +1. **Clarify Code Intent:** + * If the purpose of the code is unclear, ask the user for clarification. + * Understand what the code is supposed to achieve. + +2. **Analyze and Diagnose:** + * Identify errors, bugs, security vulnerabilities, or logical flaws. + * Look for performance inefficiencies and suggest improvements. + * Ensure adherence to coding standards and best practices (e.g., PEP 8 for Python). + +3. **Repair and Optimize:** + * Correct bugs, errors, and vulnerabilities, providing explanations for each fix. + * Optimize the code for speed, memory usage, or overall efficiency. + * Recommend alternative libraries or methods where they might offer better solutions. + +4. **Enhance Readability and Maintainability:** + * Apply consistent formatting and clean coding practices. + * Add meaningful comments to clarify complex logic or structures. + +5. **Summarize Improvements:** + * Present the corrected, optimized code. + * Provide a brief summary of the changes made and explain the benefits of each. +""" + +initset = False + +async def pastee(data): + err, linky = await get_paste(data) + if err: + return f">> [Raw Code Pasted Here](https://spaceb.in/{linky})\n" + else: + LOGS.error(linky) + return "" + + +@ultroid_cmd( + pattern=r"codefix( ([\s\S]*))?$", +) +async def openai_chat_gpt(e): + global initset + api_key = "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" + if not api_key: + return await e.eor("`OPENAI_API` key missing..", time=10) + + query = e.pattern_match.group(2) + reply = await e.get_reply_message() + + file_content = None + + if query: + # Check if query contains 'from filename' + if ' from ' in query: + query_text, filename = query.split(' from ', 1) + query_text = query_text.strip() + filename = filename.strip() + # Attempt to find and read the file from media in chat + file_found = False + async for message in e.client.iter_messages(e.chat_id, reverse=True, limit=50): + if message.media and message.file.name == filename: + if (message.file.name.endswith(".txt") or message.file.name.endswith(".py")): + file = await e.client.download_media(message) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + file_found = True + break + if not file_found: + return await e.eor(f"`File {filename} not found in recent messages.`", time=5) + if file_content: + query = f"{query_text}\n\n{file_content}" if query_text else file_content + else: + return await e.eor("`Failed to read file content.`", time=5) + else: + if reply and reply.media and (reply.file.name.endswith(".txt") or reply.file.name.endswith(".py")): + # Use the query and the replied file content + file = await e.client.download_media(reply) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + query = f"{query}\n\n{file_content}" + elif reply and reply.message: + # Use the query and the replied text message content + query = f"{query}\n\n{reply.message}" + # Else, use query as is + else: + if reply and reply.media and (reply.file.name.endswith(".txt") or reply.file.name.endswith(".py")): + # Use the replied file content + file = await e.client.download_media(reply) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + query = file_content + elif reply and reply.message: + # Use the replied text message content + query = reply.message + else: + return await e.eor("`Please provide a question or reply to a message or .txt/.py file.`", time=5) + + if query.strip() == "-c": + initset = False + CR_O_CHAT_HISTORY.clear() + return await e.eor("__Cleared o1-mini Chat History!__", time=6) + + if initset == False: + CR_O_CHAT_HISTORY.append({"role": "user", "content": initprompt}) + try: + data = { + "model": "o1-mini", + "messages": list(CR_O_CHAT_HISTORY), + } + request = await async_searcher( + "https://api.openai.com/v1/chat/completions", + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + }, + json=data, + re_json=True, + post=True, + ) + response = request["choices"][0]["message"]["content"] + CR_O_CHAT_HISTORY.append({"role": "assistant", "content": response}) + initset = True + except Exception as exc: + LOGS.warning(exc, exc_info=True) + CR_O_CHAT_HISTORY.pop() + return await e.edit( + f"**Error while requesting data from OpenAI:** \n> `{exc}`" + ) + + eris = await e.eor(f"__Generating answer for:__\n`{query[:20]} ...`") + CR_O_CHAT_HISTORY.append({"role": "user", "content": query}) + + try: + data = { + "model": "o1-mini", + "messages": list(CR_O_CHAT_HISTORY), + } + request = await async_searcher( + "https://api.openai.com/v1/chat/completions", + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + }, + json=data, + re_json=True, + post=True, + ) + response = request["choices"][0]["message"]["content"] + CR_O_CHAT_HISTORY.append({"role": "assistant", "content": response}) + except Exception as exc: + LOGS.warning(exc, exc_info=True) + CR_O_CHAT_HISTORY.pop() + return await eris.edit( + f"**Error while requesting data from OpenAI:** \n> `{exc}`" + ) + + LOGS.debug(f'Tokens Used on query: {request["usage"]["completion_tokens"]}') + + # Truncate query to 50 characters for display + truncated_query = query[:100] + + # Prepare the full message + full_message = f"**Query:**\n~ __{truncated_query}__\n\n**o1-mini:**\n~ {response}" + + # Check if response contains code blocks + code_blocks = [] + in_code_block = False + code_block_lines = [] + for line in response.split('\n'): + if line.strip().startswith('```'): + if in_code_block: + # End of code block + in_code_block = False + code_blocks.append('\n'.join(code_block_lines)) + code_block_lines = [] + else: + # Start of code block + in_code_block = True + elif in_code_block: + code_block_lines.append(line) + + # If the response contains code blocks, select the largest one and paste it + if code_blocks: + # Select the largest code block based on length + largest_code_block = max(code_blocks, key=lambda block: len(block)) + # Upload the largest code block to spaceb.in and get the link + paste_link = await pastee(largest_code_block) + else: + paste_link = "" + + if len(full_message) <= TELEGRAM_CHAR_LIMIT: + # If it fits within the limit, send as a message + await eris.edit(full_message + f"\n\n{paste_link}") + else: + # If it exceeds the limit, send as a file and include paste link + file = BytesIO(full_message.encode('utf-8')) + file.name = "o1-mini-output.txt" + await eris.respond( + "__The query and response were too long, so they have been sent as a file.__\n\n" + paste_link, + file=file, + reply_to=e.reply_to_msg_id or e.id, + link_preview=False + ) + await eris.delete() + diff --git a/plugins/codegpt.py b/plugins/codegpt.py new file mode 100644 index 0000000000000000000000000000000000000000..ca3b6d545ac389119aaddd155722c1bc9852aa0d --- /dev/null +++ b/plugins/codegpt.py @@ -0,0 +1,302 @@ +import os +from collections import deque +from io import BytesIO + +from . import ( + ultroid_cmd, + async_searcher, + udB, + LOGS, + get_paste, +) + +CG_GPT_CHAT_HISTORY = deque(maxlen=30) + +TELEGRAM_CHAR_LIMIT = 4096 # Telegram's message character limit + +initprompt = """ +Your name is User Coding Helper. Your task is to create plugins for the Ultroid Telegram userbot. Follow these guidelines: +1. Imports: Include all necessary imports as demonstrated in the example code provided below. +2. Command Creation: Generate a random, suitable Ultroid command. Ensure that this command can either: + - Process a query, or + - Be used directly with the command. +3. Code Submission: Do not send any code without a corresponding post request or without the user providing a code snippet. + +Example Code: +``` +from os import system, remove +from io import BytesIO + +try: + import openai +except ImportError: + system("pip install -q openai") + import openai + +from . import ultroid_cmd, check_filename, udB, LOGS, fast_download, run_async + +@run_async +def get_gpt_answer(gen_image, question, api_key): + openai.api_key = api_key + if gen_image: + x = openai.Image.create( + prompt=question, + n=1, + size="1024x1024", + user="arc", + ) + return x["data"][0]["url"] + x = openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=[{"role": "user", "content": question}], + ) + LOGS.debug(f'Token Used on ({question}) > {x["usage"]["total_tokens"]}') + return x["choices"][0]["message"]["content"].lstrip("+AFw-n") + +@ultroid_cmd(pattern="(chat)?gpt( (.*)|$)") +async def openai_chat_gpt(e): + api_key = udB.get_key("OPENAI_API") + gen_image = False + if not api_key: + return await e.eor("OPENAI_API key missing..") + + args = e.pattern_match.group(3) + reply = await e.get_reply_message() + if not args: + if reply and reply.text: + args = reply.message + if not args: + return await e.eor("Gimme a Question to ask from ChatGPT") + + moi = await e.eor(f"+2D3cIw") + if args.startswith("-i"): + gen_image = True + args = args[2:].strip() + try: + response = await get_gpt_answer(gen_image, args, api_key) + except Exception as exc: + LOGS.warning(exc, exc_info=True) + return await moi.edit(f"Error: +AFw-n> {exc}") + else: + if gen_image: + path, _ = await fast_download( + response, filename=check_filename("dall-e.png") + ) + await e.client.send_file( + e.chat_id, + path, + caption=f"{args[:1020]}", + reply_to=e.reply_to_msg_id, + ) + await moi.delete() + return remove(path) + if len(response) < 4095: + answer = f"+AFw-n {response}" + return await moi.edit(answer, parse_mode="html") + with BytesIO(response.encode()) as file: + file.name = "gpt_response.txt" + await e.client.send_file( + e.chat_id, file, caption=f"{args[:1020]}", reply_to=e.reply_to_msg_id + ) + await moi.delete() +``` + +Based on this template, whenever a new prompt is given, create a suitable Ultroid plugin code snippet that includes a POST request, handles the query, and assigns a new command. +""" + +initset = False + +async def pastee(data): + err, linky = await get_paste(data) + if err: + return f">> [Raw Code Pasted Here](https://spaceb.in/{linky})\n" + else: + LOGS.error(linky) + return "" + + +@ultroid_cmd( + pattern=r"codegen( ([\s\S]*))?$", +) +async def openai_chat_gpt(e): + global initset + api_key = "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" + if not api_key: + return await e.eor("`OPENAI_API` key missing..", time=10) + + query = e.pattern_match.group(2) + reply = await e.get_reply_message() + + file_content = None + + if query: + # Check if query contains 'from filename' + if ' from ' in query: + query_text, filename = query.split(' from ', 1) + query_text = query_text.strip() + filename = filename.strip() + # Attempt to find and read the file from media in chat + file_found = False + async for message in e.client.iter_messages(e.chat_id, reverse=True, limit=50): + if message.media and message.file.name == filename: + if (message.file.name.endswith(".txt") or message.file.name.endswith(".py")): + file = await e.client.download_media(message) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + file_found = True + break + if not file_found: + return await e.eor(f"`File {filename} not found in recent messages.`", time=5) + if file_content: + query = f"{query_text}\n\n{file_content}" if query_text else file_content + else: + return await e.eor("`Failed to read file content.`", time=5) + else: + if reply and reply.media and (reply.file.name.endswith(".txt") or reply.file.name.endswith(".py")): + # Use the query and the replied file content + file = await e.client.download_media(reply) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + query = f"{query}\n\n{file_content}" + elif reply and reply.message: + # Use the query and the replied text message content + query = f"{query}\n\n{reply.message}" + # Else, use query as is + else: + if reply and reply.media and (reply.file.name.endswith(".txt") or reply.file.name.endswith(".py")): + # Use the replied file content + file = await e.client.download_media(reply) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + query = file_content + elif reply and reply.message: + # Use the replied text message content + query = reply.message + else: + return await e.eor("`Please provide a question or reply to a message or .txt/.py file.`", time=5) + + if query.strip() == "-c": + CG_GPT_CHAT_HISTORY.clear() + return await e.eor("__Cleared o1-mini Chat History!__", time=6) + + if initset == False: + CG_GPT_CHAT_HISTORY.append({"role": "user", "content": initprompt}) + try: + data = { + "model": "o1-mini", + "messages": list(CG_GPT_CHAT_HISTORY), + } + request = await async_searcher( + "https://api.openai.com/v1/chat/completions", + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + }, + json=data, + re_json=True, + post=True, + ) + response = request["choices"][0]["message"]["content"] + CG_GPT_CHAT_HISTORY.append({"role": "assistant", "content": response}) + initset = True + except Exception as exc: + LOGS.warning(exc, exc_info=True) + CG_GPT_CHAT_HISTORY.pop() + return await eris.edit( + f"**Error while requesting data from OpenAI:** \n> `{exc}`" + ) + + eris = await e.eor(f"__Generating answer for:__\n`{query[:20]} ...`") + CG_GPT_CHAT_HISTORY.append({"role": "user", "content": query}) + + try: + data = { + "model": "o1-mini", + "messages": list(CG_GPT_CHAT_HISTORY), + } + request = await async_searcher( + "https://api.openai.com/v1/chat/completions", + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + }, + json=data, + re_json=True, + post=True, + ) + response = request["choices"][0]["message"]["content"] + CG_GPT_CHAT_HISTORY.append({"role": "assistant", "content": response}) + except Exception as exc: + LOGS.warning(exc, exc_info=True) + CG_GPT_CHAT_HISTORY.pop() + return await eris.edit( + f"**Error while requesting data from OpenAI:** \n> `{exc}`" + ) + + LOGS.debug(f'Tokens Used on query: {request["usage"]["completion_tokens"]}') + + # Truncate query to 50 characters for display + truncated_query = query[:100] + + # Prepare the full message + full_message = f"**Query:**\n~ __{truncated_query}__\n\n**o1-mini:**\n~ {response}" + + # Check if response contains code blocks + code_blocks = [] + in_code_block = False + code_block_lines = [] + for line in response.split('\n'): + if line.strip().startswith('```'): + if in_code_block: + # End of code block + in_code_block = False + code_blocks.append('\n'.join(code_block_lines)) + code_block_lines = [] + else: + # Start of code block + in_code_block = True + elif in_code_block: + code_block_lines.append(line) + + # If the response contains code blocks, select the largest one and paste it + if code_blocks: + # Select the largest code block based on length + largest_code_block = max(code_blocks, key=lambda block: len(block)) + # Upload the largest code block to spaceb.in and get the link + paste_link = await pastee(largest_code_block) + else: + paste_link = "" + + if len(full_message) <= TELEGRAM_CHAR_LIMIT: + # If it fits within the limit, send as a message + await eris.edit(full_message + f"\n\n{paste_link}") + else: + # If it exceeds the limit, send as a file and include paste link + file = BytesIO(full_message.encode('utf-8')) + file.name = "o1-mini-output.txt" + await eris.respond( + "__The query and response were too long, so they have been sent as a file.__\n\n" + paste_link, + file=file, + reply_to=e.reply_to_msg_id or e.id, + link_preview=False + ) + await eris.delete() + diff --git a/plugins/compressor.py b/plugins/compressor.py new file mode 100644 index 0000000000000000000000000000000000000000..4161a9f4fa6d397ccd225ceda0ef031f80458a1b --- /dev/null +++ b/plugins/compressor.py @@ -0,0 +1,175 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_compressor") + + +import asyncio +import os +import re +import time +from datetime import datetime as dt + +from telethon.errors.rpcerrorlist import MessageNotModifiedError +from telethon.tl.types import DocumentAttributeVideo + +from pyUltroid.fns.tools import metadata + +from . import ( + ULTConfig, + bash, + downloader, + get_string, + humanbytes, + math, + mediainfo, + time_formatter, + ultroid_cmd, + uploader, +) + + +@ultroid_cmd(pattern="compress( (.*)|$)") +async def _(e): + cr = e.pattern_match.group(1).strip() + crf = 27 + to_stream = False + if cr: + k = e.text.split() + if len(k) == 2: + crf = int(k[1]) if k[1].isdigit() else 27 + elif len(k) > 2: + crf = int(k[1]) if k[1].isdigit() else 27 + to_stream = "stream" in k[2] + vido = await e.get_reply_message() + if vido and vido.media and "video" in mediainfo(vido.media): + if hasattr(vido.media, "document"): + vfile = vido.media.document + name = vido.file.name + else: + vfile = vido.media + name = "" + if not name: + name = "video_" + dt.now().isoformat("_", "seconds") + ".mp4" + xxx = await e.eor(get_string("audiotools_5")) + c_time = time.time() + file = await downloader( + f"resources/downloads/{name}", + vfile, + xxx, + c_time, + f"Downloading {name}...", + ) + + o_size = os.path.getsize(file.name) + d_time = time.time() + diff = time_formatter((d_time - c_time) * 1000) + file_name = (file.name).split("/")[-1] + out = file_name.replace(file_name.split(".")[-1], "compressed.mkv") + await xxx.edit( + f"`Downloaded {file.name} of {humanbytes(o_size)} in {diff}.\nNow Compressing...`" + ) + x, y = await bash( + f'mediainfo --fullscan """{file.name}""" | grep "Frame count"' + ) + if y and y.endswith("NOT_FOUND"): + return await xxx.edit(f"ERROR: `{y}`") + total_frames = x.split(":")[1].split("\n")[0] + progress = f"progress-{c_time}.txt" + with open(progress, "w"): + pass + proce = await asyncio.create_subprocess_shell( + f'ffmpeg -hide_banner -loglevel quiet -progress {progress} -i """{file.name}""" -preset ultrafast -vcodec libx265 -crf {crf} -c:a copy """{out}""" -y', + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + while proce.returncode != 0: + await asyncio.sleep(3) + with open(progress, "r+") as fil: + text = fil.read() + frames = re.findall("frame=(\\d+)", text) + size = re.findall("total_size=(\\d+)", text) + speed = 0 + if len(frames): + elapse = int(frames[-1]) + if len(size): + size = int(size[-1]) + per = elapse * 100 / int(total_frames) + time_diff = time.time() - int(d_time) + speed = round(elapse / time_diff, 2) + if int(speed) != 0: + some_eta = ((int(total_frames) - elapse) / speed) * 1000 + text = f"`Compressing {file_name} at {crf} CRF.\n`" + progress_str = "`[{0}{1}] {2}%\n\n`".format( + "".join("●" for _ in range(math.floor(per / 5))), + "".join("" for _ in range(20 - math.floor(per / 5))), + round(per, 2), + ) + + e_size = f"{humanbytes(size)} of ~{humanbytes((size / per) * 100)}" + eta = f"~{time_formatter(some_eta)}" + try: + await xxx.edit( + text + + progress_str + + "`" + + e_size + + "`" + + "\n\n`" + + eta + + "`" + ) + except MessageNotModifiedError: + pass + os.remove(file.name) + c_size = os.path.getsize(out) + f_time = time.time() + difff = time_formatter((f_time - d_time) * 1000) + await xxx.edit( + f"`Compressed {humanbytes(o_size)} to {humanbytes(c_size)} in {difff}\nTrying to Upload...`" + ) + differ = 100 - ((c_size / o_size) * 100) + caption = f"**Original Size: **`{humanbytes(o_size)}`\n" + caption += f"**Compressed Size: **`{humanbytes(c_size)}`\n" + caption += f"**Compression Ratio: **`{differ:.2f}%`\n" + caption += f"\n**Time Taken To Compress: **`{difff}`" + mmmm = await uploader(out, out, f_time, xxx, f"Uploading {out}...") + if to_stream: + data = await metadata(out) + width = data["width"] + height = data["height"] + duration = data["duration"] + attributes = [ + DocumentAttributeVideo( + duration=duration, w=width, h=height, supports_streaming=True + ) + ] + await e.client.send_file( + e.chat_id, + mmmm, + thumb=ULTConfig.thumb, + caption=caption, + attributes=attributes, + force_document=False, + reply_to=e.reply_to_msg_id, + ) + else: + await e.client.send_file( + e.chat_id, + mmmm, + thumb=ULTConfig.thumb, + caption=caption, + force_document=True, + reply_to=e.reply_to_msg_id, + ) + await xxx.delete() + os.remove(out) + os.remove(progress) + else: + await e.eor(get_string("audiotools_8"), time=5) diff --git a/plugins/converter.py b/plugins/converter.py new file mode 100644 index 0000000000000000000000000000000000000000..0ed3e36037be740b8b23b96ef8f9073644f8dd47 --- /dev/null +++ b/plugins/converter.py @@ -0,0 +1,191 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_converter") + +import os +import time + +from . import LOGS + +try: + import cv2 +except ImportError: + cv2 = None + +try: + from PIL import Image +except ImportError: + LOGS.info(f"{__file__}: PIL not Installed.") + Image = None + +from telegraph import upload_file as uf + +from . import ( + ULTConfig, + bash, + con, + downloader, + get_paste, + get_string, + udB, + ultroid_cmd, + uploader, +) + +opn = [] + + +@ultroid_cmd( + pattern="thumbnail$", +) +async def _(e): + r = await e.get_reply_message() + if r.photo: + dl = await r.download_media() + elif r.document and r.document.thumbs: + dl = await r.download_media(thumb=-1) + else: + return await e.eor("`Reply to Photo or media with thumb...`") + variable = uf(dl) + os.remove(dl) + nn = f"https://graph.org{variable[0]}" + udB.set_key("CUSTOM_THUMBNAIL", str(nn)) + await bash(f"wget {nn} -O resources/extras/ultroid.jpg") + await e.eor(get_string("cvt_6").format(nn), link_preview=False) + + +@ultroid_cmd( + pattern="rename( (.*)|$)", +) +async def imak(event): + reply = await event.get_reply_message() + t = time.time() + if not reply: + return await event.eor(get_string("cvt_1")) + inp = event.pattern_match.group(1).strip() + if not inp: + return await event.eor(get_string("cvt_2")) + xx = await event.eor(get_string("com_1")) + if reply.media: + if hasattr(reply.media, "document"): + file = reply.media.document + image = await downloader( + reply.file.name or str(time.time()), + reply.media.document, + xx, + t, + get_string("com_5"), + ) + + file = image.name + else: + file = await event.client.download_media(reply.media) + if os.path.exists(inp): + os.remove(inp) + await bash(f'mv """{file}""" """{inp}"""') + if not os.path.exists(inp) or os.path.exists(inp) and not os.path.getsize(inp): + os.rename(file, inp) + k = time.time() + xxx = await uploader(inp, inp, k, xx, get_string("com_6")) + await event.reply( + f"`{xxx.name}`", + file=xxx, + force_document=True, + thumb=ULTConfig.thumb, + ) + os.remove(inp) + await xx.delete() + + +conv_keys = { + "img": "png", + "sticker": "webp", + "webp": "webp", + "image": "png", + "webm": "webm", + "gif": "gif", + "json": "json", + "tgs": "tgs", +} + + +@ultroid_cmd( + pattern="convert( (.*)|$)", +) +async def uconverter(event): + xx = await event.eor(get_string("com_1")) + a = await event.get_reply_message() + if a is None: + return await event.eor("`Reply to Photo or media with thumb...`") + input_ = event.pattern_match.group(1).strip() + b = await a.download_media("resources/downloads/") + if not b and (a.document and a.document.thumbs): + b = await a.download_media(thumb=-1) + if not b: + return await xx.edit(get_string("cvt_3")) + try: + convert = conv_keys[input_] + except KeyError: + return await xx.edit(get_string("sts_3").format("gif/img/sticker/webm")) + file = await con.convert(b, outname="ultroid", convert_to=convert) + if file: + await event.client.send_file( + event.chat_id, file, reply_to=event.reply_to_msg_id or event.id + ) + os.remove(file) + await xx.delete() + + +@ultroid_cmd( + pattern="doc( (.*)|$)", +) +async def _(event): + input_str = event.pattern_match.group(1).strip() + if not (input_str and event.is_reply): + return await event.eor(get_string("cvt_1"), time=5) + xx = await event.eor(get_string("com_1")) + a = await event.get_reply_message() + if not a.message: + return await xx.edit(get_string("ex_1")) + with open(input_str, "w") as b: + b.write(str(a.message)) + await xx.edit(f"**Packing into** `{input_str}`") + await event.reply(file=input_str, thumb=ULTConfig.thumb) + await xx.delete() + os.remove(input_str) + + +@ultroid_cmd( + pattern="open( (.*)|$)", +) +async def _(event): + a = await event.get_reply_message() + b = event.pattern_match.group(1).strip() + if not ((a and a.media) or (b and os.path.exists(b))): + return await event.eor(get_string("cvt_7"), time=5) + xx = await event.eor(get_string("com_1")) + rem = None + if not b: + b = await a.download_media() + rem = True + try: + with open(b) as c: + d = c.read() + except UnicodeDecodeError: + return await xx.eor(get_string("cvt_8"), time=5) + try: + await xx.edit(f"```{d}```") + except BaseException: + what, key = await get_paste(d) + await xx.edit( + f"**MESSAGE EXCEEDS TELEGRAM LIMITS**\n\nSo Pasted It On [SPACEBIN](https://spaceb.in/{key})" + ) + if rem: + os.remove(b) diff --git a/plugins/core.py b/plugins/core.py new file mode 100644 index 0000000000000000000000000000000000000000..6664fa5800275464bee832f87e88a1b2238cc5e5 --- /dev/null +++ b/plugins/core.py @@ -0,0 +1,124 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +from . import get_help + +__doc__ = get_help("help_core") + + +import os + +from pyUltroid.startup.loader import load_addons + +from . import LOGS, async_searcher, eod, get_string, safeinstall, ultroid_cmd, un_plug + + +@ultroid_cmd(pattern="install", fullsudo=True) +async def install(event): + await safeinstall(event) + + +@ultroid_cmd( + pattern=r"unload( (.*)|$)", +) +async def unload(event): + shortname = event.pattern_match.group(1).strip() + if not shortname: + await event.eor(get_string("core_9")) + return + lsd = os.listdir("addons") + zym = f"{shortname}.py" + if zym in lsd: + try: + un_plug(shortname) + await event.eor(f"**Uɴʟᴏᴀᴅᴇᴅ** `{shortname}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**", time=3) + except Exception as ex: + LOGS.exception(ex) + return await event.eor(str(ex)) + elif zym in os.listdir("plugins"): + return await event.eor(get_string("core_11"), time=3) + else: + await event.eor(f"**Nᴏ Pʟᴜɢɪɴ Nᴀᴍᴇᴅ** `{shortname}`", time=3) + + +@ultroid_cmd( + pattern=r"uninstall( (.*)|$)", +) +async def uninstall(event): + shortname = event.pattern_match.group(1).strip() + if not shortname: + await event.eor(get_string("core_13")) + return + lsd = os.listdir("addons") + zym = f"{shortname}.py" + if zym in lsd: + try: + un_plug(shortname) + await event.eor(f"**Uɴɪɴsᴛᴀʟʟᴇᴅ** `{shortname}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**", time=3) + os.remove(f"addons/{shortname}.py") + except Exception as ex: + return await event.eor(str(ex)) + elif zym in os.listdir("plugins"): + return await event.eor(get_string("core_15"), time=3) + else: + return await event.eor(f"**Nᴏ Pʟᴜɢɪɴ Nᴀᴍᴇᴅ** `{shortname}`", time=3) + + +@ultroid_cmd( + pattern=r"load( (.*)|$)", + fullsudo=True, +) +async def load(event): + shortname = event.pattern_match.group(1).strip() + if not shortname: + await event.eor(get_string("core_16")) + return + try: + try: + un_plug(shortname) + except BaseException: + pass + load_addons(f"addons/{shortname}.py") + await event.eor(get_string("core_17").format(shortname), time=3) + except Exception as e: + LOGS.exception(e) + await eod( + event, + get_string("core_18").format(shortname, e), + time=3, + ) + + +@ultroid_cmd(pattern="getaddons( (.*)|$)", fullsudo=True) +async def get_the_addons_lol(event): + thelink = event.pattern_match.group(1).strip() + xx = await event.eor(get_string("com_1")) + fool = get_string("gas_1") + if thelink is None: + return await xx.eor(fool, time=10) + split_thelink = thelink.split("/") + if not ("raw" in thelink and thelink.endswith(".py")): + return await xx.eor(fool, time=10) + name_of_it = split_thelink[-1] + plug = await async_searcher(thelink) + fil = f"addons/{name_of_it}" + await xx.edit("Packing the codes...") + with open(fil, "w", encoding="utf-8") as uult: + uult.write(plug) + await xx.edit("Packed. Now loading the plugin..") + shortname = name_of_it.split(".")[0] + try: + load_addons(fil) + await xx.eor(get_string("core_17").format(shortname), time=15) + except Exception as e: + LOGS.exception(e) + await eod( + xx, + get_string("core_18").format(shortname, e), + time=3, + ) diff --git a/plugins/database.py b/plugins/database.py new file mode 100644 index 0000000000000000000000000000000000000000..8c50ea2a3a80b452217dfdfdeca18fa4ae380279 --- /dev/null +++ b/plugins/database.py @@ -0,0 +1,77 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +from . import get_help + +__doc__ = get_help("help_database") + + +import re + +from . import Redis, eor, get_string, udB, ultroid_cmd + + +@ultroid_cmd(pattern="setdb( (.*)|$)", fullsudo=True) +async def _(ult): + match = ult.pattern_match.group(1).strip() + if not match: + return await ult.eor("Provide key and value to set!") + try: + delim = " " if re.search("[|]", match) is None else " | " + data = match.split(delim, maxsplit=1) + if data[0] in ["--extend", "-e"]: + data = data[1].split(maxsplit=1) + data[1] = f"{str(udB.get_key(data[0]))} {data[1]}" + udB.set_key(data[0], data[1]) + await ult.eor( + f"**DB Key Value Pair Updated\nKey :** `{data[0]}`\n**Value :** `{data[1]}`" + ) + + except BaseException: + await ult.eor(get_string("com_7")) + + +@ultroid_cmd(pattern="deldb( (.*)|$)", fullsudo=True) +async def _(ult): + key = ult.pattern_match.group(1).strip() + if not key: + return await ult.eor("Give me a key name to delete!", time=5) + _ = key.split(maxsplit=1) + try: + if _[0] == "-m": + for key in _[1].split(): + k = udB.del_key(key) + key = _[1] + else: + k = udB.del_key(key) + if k == 0: + return await ult.eor("`No Such Key.`") + await ult.eor(f"`Successfully deleted key {key}`") + except BaseException: + await ult.eor(get_string("com_7")) + + +@ultroid_cmd(pattern="rendb( (.*)|$)", fullsudo=True) +async def _(ult): + match = ult.pattern_match.group(1).strip() + if not match: + return await ult.eor("`Provide Keys name to rename..`") + delim = " " if re.search("[|]", match) is None else " | " + data = match.split(delim) + if Redis(data[0]): + try: + udB.rename(data[0], data[1]) + await eor( + ult, + f"**DB Key Rename Successful\nOld Key :** `{data[0]}`\n**New Key :** `{data[1]}`", + ) + + except BaseException: + await ult.eor(get_string("com_7")) + else: + await ult.eor("Key not found") diff --git a/plugins/dbx.py b/plugins/dbx.py new file mode 100644 index 0000000000000000000000000000000000000000..970a5a0000b89ff68a54a4dc54dcd50a5d466b34 --- /dev/null +++ b/plugins/dbx.py @@ -0,0 +1,123 @@ +import dns.resolver +import re + +from motor.motor_asyncio import AsyncIOMotorClient +from telethon import errors + +from . import ultroid_cmd, LOGS, run_async + +dns.resolver.default_resolver = dns.resolver.Resolver(configure=False) +dns.resolver.default_resolver.nameservers = ['8.8.8.8'] + +MONGO_URI = "mongodb+srv://xannychef:GlZdS1tZ4CiKDrcN@vouchdb.elfcz.mongodb.net/?retryWrites=true&w=majority&appName=vouchdb" +mongo_client = AsyncIOMotorClient(MONGO_URI) +db = mongo_client['vouchdata'] +vouch_collection = db['vouches'] + +BATCH_SIZE = 1000 + +AUTHORIZED_USERS = [5575183435] + +@ultroid_cmd(pattern=r"dbx(?: |$)(.*)", allow_sudo=True) +async def db_command_handler(event): + try: + args = event.pattern_match.group(1).split() + user_id = event.sender_id + + if user_id not in AUTHORIZED_USERS: + await event.reply("❌ You are not authorized to use this command.") + return + + if len(args) < 2: + await event.reply("❌ Invalid command. Usage:\n.db -index \n.db -update ") + return + + command = args[0] + try: + channel_id = int(args[1]) + except ValueError: + await event.reply("❌ Channel ID must be an integer.") + return + + from_message_id = int(args[2]) if command == "-update" and len(args) > 2 else None + + if command not in ["-index", "-update"]: + await event.reply("❌ Invalid flag. Use -index or -update.") + return + + processing_msg = await event.reply("🔍 Starting to process messages from the channel...") + + total_message_count = 0 + batch_data = [] + progress_update_interval = 10000 + + try: + channel = await event.client.get_entity(channel_id) + except errors.ChannelPrivateError: + await processing_msg.edit("❌ Cannot access the specified channel. It might be private or you lack permissions.") + return + except Exception as e: + await processing_msg.edit(f"❌ Error accessing the channel: {str(e)}") + return + + try: + if command == "-index": + total_messages = (await event.client.get_messages(channel, limit=1)).total + await processing_msg.edit(f"🔍 Total messages to process: {total_messages}") + + async for message in event.client.iter_messages(channel_id): + await process_message(message, batch_data, processing_msg, total_message_count, progress_update_interval) + total_message_count += 1 + + elif command == "-update": + if not from_message_id: + await processing_msg.edit("❌ For -update, you must provide a from_message_id.") + return + + async for message in event.client.iter_messages(channel_id, min_id=from_message_id): + await process_message(message, batch_data, processing_msg, total_message_count, progress_update_interval) + total_message_count += 1 + + if batch_data: + await vouch_collection.insert_many(batch_data) + batch_data.clear() + + await processing_msg.edit(f"✅ Completed {command[1:]}ing {total_message_count} messages.") + except Exception as e: + LOGS.error(f"Error during {command[1:]}ing: {str(e)}") + await processing_msg.edit(f"❌ Error during {command[1:]}ing: {str(e)}") + except Exception as e: + LOGS.error(f"Unexpected error: {str(e)}") + await event.reply(f"❌ An unexpected error occurred: {str(e)}") + +async def process_message(message, batch_data, processing_msg, total_message_count, progress_update_interval): + if message.sender and message.sender.username and message.sender.username.lower().endswith('bot'): + return + + vouched_by = message.sender.username if message.sender else "Unknown" + description = message.message or "No description" + message_id = message.id + + vouched_user_match = re.search(r"@\w+", description) + vouched_user = vouched_user_match.group(0) if vouched_user_match else "Unknown" + + vouch_data = { + "vouched_by": vouched_by, + "description": description, + "vouched_user": vouched_user, + "message_id": message_id, + "channel_id": message.chat_id + } + + existing_document = await vouch_collection.find_one({"message_id": message_id, "channel_id": message.chat_id}) + if existing_document: + await vouch_collection.update_one({"_id": existing_document["_id"]}, {"$set": vouch_data}) + else: + batch_data.append(vouch_data) + + if len(batch_data) >= BATCH_SIZE: + await vouch_collection.insert_many(batch_data) + batch_data.clear() + + if total_message_count and total_message_count % progress_update_interval == 0: + await processing_msg.edit(f"🔄 Processed {total_message_count} messages...") \ No newline at end of file diff --git a/plugins/devtools.py b/plugins/devtools.py new file mode 100644 index 0000000000000000000000000000000000000000..bd773ba97c7245739d3db4fd169a54b6ff246856 --- /dev/null +++ b/plugins/devtools.py @@ -0,0 +1,404 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_devtools") + +import inspect +import sys +import traceback +from io import BytesIO, StringIO +from os import remove +from pprint import pprint + +from telethon.utils import get_display_name + +from pyUltroid import _ignore_eval + +from . import * + +# Used for Formatting Eval Code, if installed +try: + import black +except ImportError: + black = None +from random import choice + +try: + from yaml import safe_load +except ImportError: + from pyUltroid.fns.tools import safe_load +try: + from telegraph import upload_file as uf +except ImportError: + uf = None +from telethon.tl import functions + +fn = functions + + +@ultroid_cmd( + pattern="sysinfo$", +) +async def _(e): + try: + remove("Dockerfile") + except Exception: + pass + xx = await e.eor(get_string("com_1")) + x, y = await bash("neofetch|sed 's/\x1B\\[[0-9;\\?]*[a-zA-Z]//g' >> neo.txt") + if y and y.endswith("NOT_FOUND"): + return await xx.edit(f"Error: `{y}`") + with open("neo.txt", "r", encoding="utf-8") as neo: + p = (neo.read()).replace("\n\n", "") + haa = await Carbon(code=p, file_name="neofetch", backgroundColor=choice(ATRA_COL)) + if isinstance(haa, dict): + await xx.edit(f"`{haa}`") + else: + await e.reply(file=haa) + await xx.delete() + remove("neo.txt") + + +@ultroid_cmd(pattern="bash", fullsudo=True, only_devs=True) +async def _(event): + try: + remove("Dockerfile") + except Exception: + pass + carb, rayso, yamlf = None, None, False + try: + cmd = event.text.split(" ", maxsplit=1)[1] + if cmd.split()[0] in ["-c", "--carbon"]: + cmd = cmd.split(maxsplit=1)[1] + carb = True + if cmd.split()[0] in ["-r", "--rayso"]: + cmd = cmd.split(maxsplit=1)[1] + rayso = True + except IndexError: + return await event.eor(get_string("devs_1"), time=10) + xx = await event.eor(get_string("com_1")) + reply_to_id = event.reply_to_msg_id or event.id + stdout, stderr = await bash(cmd, run_code=1) + OUT = f"**[👩‍💻](emoji/5301083932211550593) Ⲃⲁⲋⲏ\n\n• COMMAND:**\n`{cmd}` \n\n" + err, out = "", "" + if stderr: + err = f"**[⚠️](emoji/5213205860498549992) Ⲉɴfⲟʀmⲁtⲓⲟɴ:** \n`{stderr}`\n\n" + if stdout: + if (carb or udB.get_key("CARBON_ON_BASH")) and ( + event.is_private + or event.chat.admin_rights + or event.chat.creator + or event.chat.default_banned_rights.embed_links + ): + li = await Carbon( + code=stdout, + file_name="bash", + download=True, + backgroundColor=choice(ATRA_COL), + ) + if isinstance(li, dict): + await xx.edit( + f"Unknown Response from Carbon: `{li}`\n\nstdout`:{stdout}`\nstderr: `{stderr}`" + ) + return + url = f"https://graph.org{uf(li)[-1]}" + OUT = f"[\xad]({url}){OUT}" + out = f"**[👨‍💻](emoji/5319161050128459957) Ⲟυⲧⲣυⲧ:**" + remove(li) + elif (rayso or udB.get_key("RAYSO_ON_BASH")) and ( + event.is_private + or event.chat.admin_rights + or event.chat.creator + or event.chat.default_banned_rights.embed_links + ): + li = await Carbon( + code=stdout, + file_name="bash", + download=True, + backgroundColor=choice(ATRA_COL), + rayso=True, + ) + if isinstance(li, dict): + await xx.edit( + f"Unknown Response from Carbon: `{li}`\n\nstdout`:{stdout}`\nstderr: `{stderr}`" + ) + return + url = f"https://graph.org{uf(li)[-1]}" + OUT = f"[\xad]({url}){OUT}" + out = f"**[👨‍💻](emoji/5319161050128459957) Ⲟυⲧⲣυⲧ:**" + remove(li) + else: + if "pip" in cmd and all(":" in line for line in stdout.split("\n")): + try: + load = safe_load(stdout) + stdout = "" + for data in list(load.keys()): + res = load[data] or "" + if res and "http" not in str(res): + res = f"`{res}`" + stdout += f"**{data}** : {res}\n" + yamlf = True + except Exception as er: + stdout = f"`{stdout}`" + LOGS.exception(er) + else: + stdout = f"`{stdout}`" + out = f"**[👨‍💻](emoji/5319161050128459957) Ⲟυⲧⲣυⲧ:**\n{stdout}" + if not stderr and not stdout: + out = f"**[👨‍💻](emoji/5319161050128459957) Ⲟυⲧⲣυⲧ:**\n`Ⲋυⲥⲥⲉⲋⲋ`" + OUT += err + out + if len(OUT) > 4096: + ultd = err + out + with BytesIO(str.encode(ultd)) as out_file: + out_file.name = "bash.txt" + await event.client.send_file( + event.chat_id, + out_file, + force_document=True, + thumb=ULTConfig.thumb, + allow_cache=False, + caption=f"`{cmd}`" if len(cmd) < 998 else None, + reply_to=reply_to_id, + ) + + await xx.delete() + else: + await xx.edit(OUT, link_preview=not yamlf) + + +pp = pprint # ignore: pylint +bot = ultroid = ultroid_bot + + +class u: + _ = "" + + +def _parse_eval(value=None): + if not value: + return value + if hasattr(value, "stringify"): + try: + return value.stringify() + except TypeError: + pass + elif isinstance(value, dict): + try: + return json_parser(value, indent=1) + except BaseException: + pass + elif isinstance(value, list): + newlist = "[" + for index, child in enumerate(value): + newlist += "\n " + str(_parse_eval(child)) + if index < len(value) - 1: + newlist += "," + newlist += "\n]" + return newlist + return str(value) + + +@ultroid_cmd(pattern="eval", fullsudo=True, only_devs=True) +async def _(event): + try: + remove("Dockerfile") + except Exception: + pass + try: + cmd = event.text.split(maxsplit=1)[1] + except IndexError: + return await event.eor(get_string("devs_2"), time=5) + xx = None + mode = "" + spli = cmd.split() + + async def get_(): + try: + cm = cmd.split(maxsplit=1)[1] + except IndexError: + await event.eor("->> Wrong Format <<-") + cm = None + return cm + + if spli[0] in ["-s", "--silent"]: + await event.delete() + mode = "silent" + elif spli[0] in ["-n", "-noedit"]: + mode = "no-edit" + xx = await event.reply(get_string("com_1")) + elif spli[0] in ["-gs", "--source"]: + mode = "gsource" + elif spli[0] in ["-ga", "--args"]: + mode = "g-args" + if mode: + cmd = await get_() + if not cmd: + return + if mode != "silent" and not xx: + xx = await event.eor(get_string("com_1")) + if black: + try: + cmd = black.format_str(cmd, mode=black.Mode()) + except BaseException: + # Consider it as Code Error, and move on to be shown ahead. + pass + reply_to_id = event.reply_to_msg_id or event + if ( + any(item in cmd for item in KEEP_SAFE().All) + and not event.out + and event.sender_id != ultroid_bot.uid + ): + warning = await event.forward_to(udB.get_key("LOG_CHANNEL")) + await warning.reply( + f"Malicious Activities suspected by {inline_mention(await event.get_sender())}" + ) + _ignore_eval.append(event.sender_id) + return await xx.edit( + f"`Malicious Activities suspected![⚠️](emoji/5213205860498549992)\nReported to owner. Aborted this request!`" + ) + old_stderr = sys.stderr + old_stdout = sys.stdout + redirected_output = sys.stdout = StringIO() + redirected_error = sys.stderr = StringIO() + stdout, stderr, exc, timeg = None, None, None, None + tima = time.time() + try: + value = await aexec(cmd, event) + except Exception: + value = None + exc = traceback.format_exc() + tima = time.time() - tima + stdout = redirected_output.getvalue() + stderr = redirected_error.getvalue() + sys.stdout = old_stdout + sys.stderr = old_stderr + if value: + try: + if mode == "gsource": + exc = inspect.getsource(value) + elif mode == "g-args": + args = inspect.signature(value).parameters.values() + name = "" + if hasattr(value, "__name__"): + name = value.__name__ + exc = f"**{name}**\n\n" + "\n ".join([str(arg) for arg in args]) + except Exception: + exc = traceback.format_exc() + evaluation = exc or stderr or stdout or _parse_eval(value) or get_string("instu_4") + if mode == "silent": + if exc: + msg = f"[⚠️](emoji/5213205860498549992) EVAL Ⲉʀʀⲟʀ\n\n• CHAT: {get_display_name(event.chat)} [{event.chat_id}]" + msg += f"\n\n∆ CODE:\n{cmd}\n\n∆ Ⲉʀʀⲟʀ:\n{exc}" + log_chat = udB.get_key("LOG_CHANNEL") + if len(msg) > 4000: + with BytesIO(msg.encode()) as out_file: + out_file.name = "Eval-Error.txt" + return await event.client.send_message( + log_chat, f"`{cmd}`", file=out_file + ) + await event.client.send_message(log_chat, msg, parse_mode="html") + return + tmt = tima * 1000 + timef = time_formatter(tmt) + timeform = timef if timef != "0s" else f"{tmt:.3f}ms" + final_output = ( + "{} **Ⲉⳳⲁⳑ** (__in {}__)\n```{}``` \n\n{} **Ⲟυⲧⲣυⲧ**: \n```{}``` \n".format( + f"[👩‍💻](emoji/5300928913956938544)", + timeform, + cmd, + f"[👨‍💻](emoji/5319161050128459957)", + evaluation, + ) + ) + if len(final_output) > 4096: + final_output = evaluation + with BytesIO(str.encode(final_output)) as out_file: + out_file.name = "eval.txt" + await event.client.send_file( + event.chat_id, + out_file, + force_document=True, + thumb=ULTConfig.thumb, + allow_cache=False, + caption=f"```{cmd}```" if len(cmd) < 998 else None, + reply_to=reply_to_id, + ) + return await xx.delete() + await xx.edit(final_output) + + +def _stringify(text=None, *args, **kwargs): + if text: + u._ = text + text = _parse_eval(text) + return print(text, *args, **kwargs) + + +async def aexec(code, event): + exec( + ( + "async def __aexec(e, client): " + + "\n print = p = _stringify" + + "\n message = event = e" + + "\n u.r = reply = await event.get_reply_message()" + + "\n chat = event.chat_id" + + "\n u.lr = locals()" + ) + + "".join(f"\n {l}" for l in code.split("\n")) + ) + + return await locals()["__aexec"](event, event.client) + + +DUMMY_CPP = """#include +using namespace std; + +int main(){ +!code +} +""" + + +@ultroid_cmd(pattern="cpp", only_devs=True) +async def doie(e): + match = e.text.split(" ", maxsplit=1) + try: + match = match[1] + except IndexError: + return await e.eor(get_string("devs_3")) + msg = await e.eor(get_string("com_1")) + if "main(" not in match: + new_m = "".join(" " * 4 + i + "\n" for i in match.split("\n")) + match = DUMMY_CPP.replace("!code", new_m) + open("cpp-ultroid.cpp", "w").write(match) + m = await bash("g++ -o CppUltroid cpp-ultroid.cpp") + o_cpp = f"• **Eval-Cpp**\n`{match}`" + if m[1]: + o_cpp += f"\n\n**• Error :**\n`{m[1]}`" + if len(o_cpp) > 3000: + os.remove("cpp-ultroid.cpp") + if os.path.exists("CppUltroid"): + os.remove("CppUltroid") + with BytesIO(str.encode(o_cpp)) as out_file: + out_file.name = "error.txt" + return await msg.reply(f"`{match}`", file=out_file) + return await eor(msg, o_cpp) + m = await bash("./CppUltroid") + if m[0] != "": + o_cpp += f"\n\n**• Output :**\n`{m[0]}`" + if m[1]: + o_cpp += f"\n\n**• Error :**\n`{m[1]}`" + if len(o_cpp) > 3000: + with BytesIO(str.encode(o_cpp)) as out_file: + out_file.name = "eval.txt" + await msg.reply(f"`{match}`", file=out_file) + else: + await eor(msg, o_cpp) + os.remove("CppUltroid") + os.remove("cpp-ultroid.cpp") diff --git a/plugins/downloadupload.py b/plugins/downloadupload.py new file mode 100644 index 0000000000000000000000000000000000000000..003da9fad7ae8c7bd92c83f4c71a44b1b18a83d0 --- /dev/null +++ b/plugins/downloadupload.py @@ -0,0 +1,222 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_downloadupload") + +import asyncio +import glob +import os +import time +from datetime import datetime as dt + +from aiohttp.client_exceptions import InvalidURL +from telethon.errors.rpcerrorlist import MessageNotModifiedError + +from pyUltroid.fns.helper import time_formatter +from pyUltroid.fns.tools import get_chat_and_msgid, set_attributes + +from . import ( + LOGS, + ULTConfig, + downloader, + eor, + fast_download, + get_all_files, + get_string, + progress, + time_formatter, + ultroid_cmd, +) + + +@ultroid_cmd( + pattern="download( (.*)|$)", +) +async def down(event): + matched = event.pattern_match.group(1).strip() + msg = await event.eor(get_string("udl_4")) + if not matched: + return await eor(msg, get_string("udl_5"), time=5) + try: + splited = matched.split(" | ") + link = splited[0] + filename = splited[1] + except IndexError: + filename = None + s_time = time.time() + try: + filename, d = await fast_download( + link, + filename, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress( + d, + t, + msg, + s_time, + f"Downloading from {link}", + ) + ), + ) + except InvalidURL: + return await msg.eor("`Invalid URL provided :(`", time=5) + await msg.eor(f"`{filename}` `downloaded in {time_formatter(d*1000)}.`") + + +@ultroid_cmd( + pattern="dl( (.*)|$)", +) +async def download(event): + match = event.pattern_match.group(1).strip() + if match and "t.me/" in match: + chat, msg = get_chat_and_msgid(match) + if not (chat and msg): + return await event.eor(get_string("gms_1")) + match = "" + ok = await event.client.get_messages(chat, ids=msg) + elif event.reply_to_msg_id: + ok = await event.get_reply_message() + else: + return await event.eor(get_string("cvt_3"), time=8) + xx = await event.eor(get_string("com_1")) + if not (ok and ok.media): + return await xx.eor(get_string("udl_1"), time=5) + s = dt.now() + k = time.time() + if hasattr(ok.media, "document"): + file = ok.media.document + mime_type = file.mime_type + filename = match or ok.file.name + if not filename: + if "audio" in mime_type: + filename = "audio_" + dt.now().isoformat("_", "seconds") + ".ogg" + elif "video" in mime_type: + filename = "video_" + dt.now().isoformat("_", "seconds") + ".mp4" + try: + result = await downloader( + f"resources/downloads/{filename}", + file, + xx, + k, + f"Downloading {filename}...", + ) + + except MessageNotModifiedError as err: + return await xx.edit(str(err)) + file_name = result.name + else: + d = "resources/downloads/" + file_name = await event.client.download_media( + ok, + d, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress( + d, + t, + xx, + k, + get_string("com_5"), + ), + ), + ) + e = dt.now() + t = time_formatter(((e - s).seconds) * 1000) + await xx.eor(get_string("udl_2").format(file_name, t)) + + +@ultroid_cmd( + pattern="ul( (.*)|$)", +) +async def _(event): + msg = await event.eor(get_string("com_1")) + match = event.pattern_match.group(1) + if match: + match = match.strip() + if not event.out and match == ".env": + return await event.reply("`You can't do this...`") + stream, force_doc, delete, thumb = ( + False, + True, + False, + ULTConfig.thumb, + ) + if "--stream" in match: + stream = True + force_doc = False + if "--delete" in match: + delete = True + if "--no-thumb" in match: + thumb = None + arguments = ["--stream", "--delete", "--no-thumb"] + if any(item in match for item in arguments): + match = ( + match.replace("--stream", "") + .replace("--delete", "") + .replace("--no-thumb", "") + .strip() + ) + if match.endswith("/"): + match += "*" + results = glob.glob(match) + if not results and os.path.exists(match): + results = [match] + if not results: + try: + await event.reply(file=match) + return await event.try_delete() + except Exception as er: + LOGS.exception(er) + return await msg.eor(get_string("ls1")) + for result in results: + if os.path.isdir(result): + c, s = 0, 0 + for files in get_all_files(result): + attributes = None + if stream: + try: + attributes = await set_attributes(files) + except KeyError as er: + LOGS.exception(er) + try: + file, _ = await event.client.fast_uploader( + files, show_progress=True, event=msg, to_delete=delete + ) + await event.client.send_file( + event.chat_id, + file, + supports_streaming=stream, + force_document=force_doc, + thumb=thumb, + attributes=attributes, + caption=f"`Uploaded` `{files}` `in {time_formatter(_*1000)}`", + reply_to=event.reply_to_msg_id or event, + ) + s += 1 + except (ValueError, IsADirectoryError): + c += 1 + break + attributes = None + if stream: + try: + attributes = await set_attributes(result) + except KeyError as er: + LOGS.exception(er) + file, _ = await event.client.fast_uploader( + result, show_progress=True, event=msg, to_delete=delete + ) + await event.client.send_file( + event.chat_id, + file, + supports_streaming=stream, + force_document=force_doc, + thumb=thumb, + attributes=attributes, + caption=f"`Uploaded` `{result}` `in {time_formatter(_*1000)}`", + ) + await msg.try_delete() diff --git a/plugins/echo.py b/plugins/echo.py new file mode 100644 index 0000000000000000000000000000000000000000..03c4d0e860a4988ec57111db09abb2216c0102b8 --- /dev/null +++ b/plugins/echo.py @@ -0,0 +1,76 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_echo") + + +from telethon.utils import get_display_name + +from pyUltroid.dB.echo_db import add_echo, check_echo, list_echo, rem_echo + +from . import inline_mention, ultroid_cmd + + +@ultroid_cmd(pattern="addecho( (.*)|$)") +async def echo(e): + r = await e.get_reply_message() + if r: + user = r.sender_id + else: + try: + user = e.text.split()[1] + if user.startswith("@"): + ok = await e.client.get_entity(user) + user = ok.id + else: + user = int(user) + except BaseException: + return await e.eor("Reply To A user.", time=5) + if check_echo(e.chat_id, user): + return await e.eor("Echo already activated for this user.", time=5) + add_echo(e.chat_id, user) + ok = await e.client.get_entity(user) + user = inline_mention(ok) + await e.eor(f"Activated Echo For {user}.") + + +@ultroid_cmd(pattern="remecho( (.*)|$)") +async def rm(e): + r = await e.get_reply_message() + if r: + user = r.sender_id + else: + try: + user = e.text.split()[1] + if user.startswith("@"): + ok = await e.client.get_entity(user) + user = ok.id + else: + user = int(user) + except BaseException: + return await e.eor("Reply To A User.", time=5) + if check_echo(e.chat_id, user): + rem_echo(e.chat_id, user) + ok = await e.client.get_entity(user) + user = f"[{get_display_name(ok)}](tg://user?id={ok.id})" + return await e.eor(f"Deactivated Echo For {user}.") + await e.eor("Echo not activated for this user") + + +@ultroid_cmd(pattern="listecho$") +async def lstecho(e): + if k := list_echo(e.chat_id): + user = "**Activated Echo For Users:**\n\n" + for x in k: + ok = await e.client.get_entity(int(x)) + kk = f"[{get_display_name(ok)}](tg://user?id={ok.id})" + user += f"•{kk}" + "\n" + await e.eor(user) + else: + await e.eor("`List is Empty, For echo`", time=5) diff --git a/plugins/extra.py b/plugins/extra.py new file mode 100644 index 0000000000000000000000000000000000000000..f9abda572addb4a676be73d4faf38abe6cb60bbc --- /dev/null +++ b/plugins/extra.py @@ -0,0 +1,85 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("extra") + +import asyncio + +from . import get_string, ultroid_cmd + + +@ultroid_cmd( + pattern="del$", + manager=True, +) +async def delete_it(delme): + msg_src = await delme.get_reply_message() + if not msg_src: + return + await msg_src.try_delete() + await delme.try_delete() + + +@ultroid_cmd( + pattern="copy$", +) +async def copy(e): + reply = await e.get_reply_message() + if reply: + await reply.reply(reply) + return await e.try_delete() + await e.eor(get_string("ex_1"), time=5) + + +@ultroid_cmd( + pattern="edit", +) +async def editer(edit): + message = edit.text + chat = await edit.get_input_chat() + string = str(message[6:]) + reply = await edit.get_reply_message() + if reply and reply.text: + try: + await reply.edit(string) + await edit.delete() + except BaseException: + pass + else: + i = 1 + async for message in edit.client.iter_messages(chat, from_user="me", limit=2): + if i == 2: + await message.edit(string) + await edit.delete() + break + i += 1 + + +@ultroid_cmd( + pattern="reply$", +) +async def _(e): + if e.reply_to_msg_id: + chat = e.chat_id + try: + msg = (await e.client.get_messages(e.chat_id, limit=1, max_id=e.id))[0] + except IndexError: + return await e.eor( + "`You have previously sent no message to reply again...`", time=5 + ) + except BaseException as er: + return await e.eor(f"**ERROR:** `{er}`") + await asyncio.wait( + [ + e.client.delete_messages(chat, [e.id, msg.id]), + e.client.send_message(chat, msg, reply_to=e.reply_to_msg_id), + ] + ) + else: + await e.try_delete() diff --git a/plugins/fakeaction.py b/plugins/fakeaction.py new file mode 100644 index 0000000000000000000000000000000000000000..0f4b25492e2c4b9afbae3f6972dd400f2acf504a --- /dev/null +++ b/plugins/fakeaction.py @@ -0,0 +1,36 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_fakeaction") + +import math +import time + +from pyUltroid.fns.admins import ban_time + +from . import asyncio, get_string, ultroid_cmd + + +@ultroid_cmd( + pattern="f(typing|audio|contact|document|game|location|sticker|photo|round|video)( (.*)|$)" +) +async def _(e): + act = e.pattern_match.group(1).strip() + t = e.pattern_match.group(2) + if act in ["audio", "round", "video"]: + act = f"record-{act}" + if t.isdigit(): + t = int(t) + elif t.endswith(("s", "h", "d", "m")): + t = math.ceil((ban_time(t)) - time.time()) + else: + t = 60 + await e.eor(get_string("fka_1").format(str(t)), time=5) + async with e.client.action(e.chat_id, act): + await asyncio.sleep(t) diff --git a/plugins/fileshare.py b/plugins/fileshare.py new file mode 100644 index 0000000000000000000000000000000000000000..430e8cd5beddec9e679000014085639e3926bf29 --- /dev/null +++ b/plugins/fileshare.py @@ -0,0 +1,95 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_fileshare") + +import os + +from pyUltroid.dB.filestore_db import del_stored, get_stored_msg, list_all_stored_msgs +from pyUltroid.fns.tools import get_file_link + +from . import HNDLR, asst, get_string, in_pattern, udB, ultroid_bot, ultroid_cmd + + +@ultroid_cmd(pattern="store$") +async def filestoreplg(event): + msg = await event.get_reply_message() + if not msg: + return await event.eor(get_string("fsh_3"), time=10) + # allow storing both messages and media. + filehash = await get_file_link(msg) + link_to_file = f"https://t.me/{asst.me.username}?start={filehash}" + await event.eor( + get_string("fsh_2").format(link_to_file), + link_preview=False, + ) + + +@ultroid_cmd("delstored ?(.*)") +async def _(event): + match = event.pattern_match.group(1) + if not match: + return await event.eor("`Give stored film's link to delete.`", time=5) + match = match.split("?start=") + botusername = match[0].split("/")[-1] + if botusername != asst.me.username: + return await event.eor( + "`Message/Media of provided link was not stored by this bot.`", time=5 + ) + msg_id = get_stored_msg(match[1]) + if not msg_id: + return await event.eor( + "`Message/Media of provided link was already deleted.`", time=5 + ) + del_stored(match[1]) + await ultroid_bot.delete_messages(udB.get_key("LOG_CHANNEL"), int(msg_id)) + await event.eor("__Deleted__") + + +@ultroid_cmd("liststored$") +async def liststored(event): + files = list_all_stored_msgs() + if not files: + return await event.eor(get_string("fsh_4"), time=5) + msg = "**Stored files:**\n" + for c, i in enumerate(files, start=1): + msg += f"`{c}`. https://t.me/{asst.me.username}?start={i}\n" + if len(msg) > 4095: + with open("liststored.txt", "w") as f: + f.write(msg.replace("**", "").replace("`", "")) + await event.reply(get_string("fsh_1"), file="liststored.txt") + os.remove("liststored.txt") + return + await event.eor(msg, link_preview=False) + + +@in_pattern("filestore", owner=True) +async def file_short(event): + all_ = list_all_stored_msgs() + res = [] + if all_: + LOG_CHA = udB.get_key("LOG_CHANNEL") + for msg in all_[:50]: + m_id = get_stored_msg(msg) + if not m_id: + continue + message = await asst.get_messages(LOG_CHA, ids=m_id) + if not message: + continue + if message.media: + res.append(await event.builder.document(title=msg, file=message.media)) + elif message.text: + res.append( + await event.builder.article(title=message.text, text=message.text) + ) + if not res: + title = "You have no stored file :(" + text = f"{title}\n\nRead `{HNDLR}help fileshare` to know how to store." + return await event.answer([await event.builder.article(title=title, text=text)]) + await event.answer(res, switch_pm="• File Store •", switch_pm_param="start") diff --git a/plugins/filter.py b/plugins/filter.py new file mode 100644 index 0000000000000000000000000000000000000000..84ab5931efb3e1d9c9ee359f52483ae45f6a5731 --- /dev/null +++ b/plugins/filter.py @@ -0,0 +1,102 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_filter") + +import os +import re + +from telegraph import upload_file as uf +from telethon.tl.types import User +from telethon.utils import pack_bot_file_id + +from pyUltroid.dB.filter_db import add_filter, get_filter, list_filter, rem_filter +from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button + +from . import events, get_string, mediainfo, udB, ultroid_bot, ultroid_cmd +from ._inline import something + + +@ultroid_cmd(pattern="addfilter( (.*)|$)") +async def af(e): + wrd = (e.pattern_match.group(1).strip()).lower() + wt = await e.get_reply_message() + chat = e.chat_id + if not (wt and wrd): + return await e.eor(get_string("flr_1")) + btn = format_btn(wt.buttons) if wt.buttons else None + if wt and wt.media: + wut = mediainfo(wt.media) + if wut.startswith(("pic", "gif")): + dl = await wt.download_media() + variable = uf(dl) + m = f"https://graph.org{variable[0]}" + elif wut == "video": + if wt.media.document.size > 8 * 1000 * 1000: + return await e.eor(get_string("com_4"), time=5) + dl = await wt.download_media() + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + else: + m = pack_bot_file_id(wt.media) + if wt.text: + txt = wt.text + if not btn: + txt, btn = get_msg_button(wt.text) + add_filter(chat, wrd, txt, m, btn) + else: + add_filter(chat, wrd, None, m, btn) + else: + txt = wt.text + if not btn: + txt, btn = get_msg_button(wt.text) + add_filter(chat, wrd, txt, None, btn) + await e.eor(get_string("flr_4").format(wrd)) + ultroid_bot.add_handler(filter_func, events.NewMessage()) + + +@ultroid_cmd(pattern="remfilter( (.*)|$)") +async def rf(e): + wrd = (e.pattern_match.group(1).strip()).lower() + chat = e.chat_id + if not wrd: + return await e.eor(get_string("flr_3")) + rem_filter(int(chat), wrd) + await e.eor(get_string("flr_5").format(wrd)) + + +@ultroid_cmd(pattern="listfilter$") +async def lsnote(e): + if x := list_filter(e.chat_id): + sd = "Filters Found In This Chats Are\n\n" + return await e.eor(sd + x) + await e.eor(get_string("flr_6")) + + +async def filter_func(e): + if isinstance(e.sender, User) and e.sender.bot: + return + xx = (e.text).lower() + chat = e.chat_id + if x := get_filter(chat): + for c in x: + pat = r"( |^|[^\w])" + re.escape(c) + r"( |$|[^\w])" + if re.search(pat, xx): + if k := x.get(c): + msg = k["msg"] + media = k["media"] + if k.get("button"): + btn = create_tl_btn(k["button"]) + return await something(e, msg, media, btn) + await e.reply(msg, file=media) + + +if udB.get_key("FILTERS"): + ultroid_bot.add_handler(filter_func, events.NewMessage()) diff --git a/plugins/flux2.py b/plugins/flux2.py new file mode 100644 index 0000000000000000000000000000000000000000..8aded2e5955ecf309c1a03e8dc132c2ac98664d3 --- /dev/null +++ b/plugins/flux2.py @@ -0,0 +1,95 @@ +import requests +import os +import json +from . import ultroid_cmd, LOGS, fast_download + +@ultroid_cmd(pattern="flux2(?:\s+(-p1|-p2|-l1|-l2|-s1|-s2|-hd)\s+(.*))?$") +async def codegen(e): + # Default to "portrait_16_9" if no specific command is provided + args = e.pattern_match.group(2) + size_option = e.pattern_match.group(1) or "portrait_16_9" + + # Map the size_option to the corresponding image size + size_mapping = { + "-p1": "portrait_4_3", + "-p2": "portrait_16_9", + "-l1": "landscape_4_3", + "-l2": "landscape_16_9", + "-s1": "square", + "-s2": "square_hd", + "-hd": "square_hd" + } + image_size = size_mapping.get(size_option, "portrait_16_9") + + # Handle when no prompt is provided + if not args: + reply = await e.get_reply_message() + if reply and reply.text: + args = reply.text + if not args: + return await e.eor("Please provide a prompt to generate images.") + + # Prepare the request + API_URL = "http://fal.run/fal-ai/flux/schnell" + headers = { + "user-agent": "Python/3.x", + "content-type": "application/json; charset=utf-8", + "accept-encoding": "gzip", + "authorization": "Key f2438e21-b687-46c3-998f-0ed0deed8778:6a073a3d9bb73a9ed1c7aa8e8d905ced" + } + data = { + "prompt": args, + "image_size": image_size, + "num_inference_steps": 4, + "num_images": 4, + "embeddings": [], + "format": "jpeg", + "sync_mode": False, + "seed": "0", + "enable_safety_checker": False + } + + # Notify the user that image generation is in progress + moi = await e.eor("🔄 Generating images, please wait...") + + try: + response = requests.post(API_URL, headers=headers, json=data) + + if response.status_code != 200: + LOGS.error(f"Request failed with status code {response.status_code}") + return await moi.edit("Failed to generate images. Please try again later.") + + images = response.json().get("images", []) + if not images: + return await moi.edit("No images were generated.") + + # Download images + image_paths = await download_images([img["url"] for img in images]) + + # Send images as a group + await send_images_as_group(e, args, image_paths) + + # Clean up the files after sending + for path in image_paths: + os.remove(path) + + await moi.delete() + + except Exception as exc: + LOGS.error(f"Error: {exc}") + await moi.edit(f"An error occurred: {exc}") + +async def download_images(image_urls): + downloaded_paths = [] + for i, url in enumerate(image_urls, start=1): + filename = f"image_{i}.png" + path, _ = await fast_download(url, filename=filename) + downloaded_paths.append(path) + return downloaded_paths + +async def send_images_as_group(e, query, image_paths): + caption = f"^^{query}^^" + media = [await e.client.upload_file(path) for path in image_paths] + await e.client.send_message( + e.chat_id, caption, file=media, parse_mode="markdown", reply_to=e.reply_to_msg_id + ) \ No newline at end of file diff --git a/plugins/fontgen.py b/plugins/fontgen.py new file mode 100644 index 0000000000000000000000000000000000000000..1cce172bef98b71597fbf085ce14ae1df696ac28 --- /dev/null +++ b/plugins/fontgen.py @@ -0,0 +1,60 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import get_help + +__doc__ = get_help("help_fontgen") + +import string + +from . import eod, ultroid_cmd + +_default = string.ascii_letters +Fonts = { + "small caps": "ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘϙʀsᴛᴜᴠᴡxʏᴢABCDEFGHIJKLMNOPQRSTUVWXYZ", + "monospace": "𝚊𝚋𝚌𝚍𝚎𝚏𝚐𝚑𝚒𝚓𝚔𝚕𝚖𝚗𝚘𝚙𝚚𝚛𝚜𝚝𝚞𝚟𝚠𝚡𝚢𝚣𝙰𝙱𝙲𝙳𝙴𝙵𝙶𝙷𝙸𝙹𝙺𝙻𝙼𝙽𝙾𝙿𝚀𝚁𝚂𝚃𝚄𝚅𝚆𝚇𝚈𝚉", + "double stroke": "𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ", + "script royal": "𝒶𝒷𝒸𝒹𝑒𝒻𝑔𝒽𝒾𝒿𝓀𝓁𝓂𝓃𝑜𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏𝒜ℬ𝒞𝒟ℰℱ𝒢ℋℐ𝒥𝒦ℒℳ𝒩𝒪𝒫𝒬ℛ𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵", +} + + +@ultroid_cmd( + pattern="font( (.*)|$)", +) +async def _(e): + input = e.pattern_match.group(1).strip() + reply = await e.get_reply_message() + if not input: + m = "**Available Fonts**\n\n" + for x in Fonts.keys(): + m += f"• `{x}`\n" + return await e.eor(m, time=5) + if not reply: + try: + _ = input.split(":", maxsplit=1) + font = _[0][:-1] + text = _[1] + except IndexError: + return await eod(e, help) + elif not input: + return await eod(e, "`Give font dude :/`") + else: + font = input + text = reply.message + if font not in Fonts.keys(): + return await e.eor(f"`{font} not in font list`.", time=5) + msg = gen_font(text, Fonts[font]) + await e.eor(msg) + + +def gen_font(text, new_font): + new_font = " ".join(new_font).split() + for q in text: + if q in _default: + new = new_font[_default.index(q)] + text = text.replace(q, new) + return text diff --git a/plugins/forcesubscribe.py b/plugins/forcesubscribe.py new file mode 100644 index 0000000000000000000000000000000000000000..9804b28687bd4f6082783323a8aab989300e9ff4 --- /dev/null +++ b/plugins/forcesubscribe.py @@ -0,0 +1,179 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}fsub ` + Enable ForceSub in Used Chat ! + +• `{i}checkfsub` + Check/Get Active ForceSub Setting of Used Chat. + +• `{i}remfsub` + Remove ForceSub from Used Chat ! + + Note - You Need to be Admin in Both Channel/Chats + in order to Use ForceSubscribe. +""" + +import re + +from telethon.errors.rpcerrorlist import ChatAdminRequiredError, UserNotParticipantError +from telethon.tl.custom import Button +from telethon.tl.functions.channels import GetParticipantRequest +from telethon.tl.functions.messages import ExportChatInviteRequest +from telethon.tl.types import ( + Channel, + ChannelParticipantBanned, + ChannelParticipantLeft, + User, +) + +from pyUltroid.dB.forcesub_db import add_forcesub, get_forcesetting, rem_forcesub + +from . import ( + LOGS, + asst, + callback, + events, + get_string, + in_pattern, + inline_mention, + udB, + ultroid_bot, + ultroid_cmd, +) + +CACHE = {} + + +@ultroid_cmd(pattern="fsub( (.*)|$)", admins_only=True, groups_only=True) +async def addfor(e): + match = e.pattern_match.group(1).strip() + if not match: + return await e.eor(get_string("fsub_1"), time=5) + try: + match = await e.client.parse_id(match) + except BaseException: + return await e.eor(get_string("fsub_2"), time=5) + add_forcesub(e.chat_id, match) + await e.eor("Added ForceSub in This Chat !") + ultroid_bot.add_handler(force_sub, events.NewMessage(incoming=True)) + + +@ultroid_cmd(pattern="remfsub$") +async def remor(e): + res = rem_forcesub(e.chat_id) + if not res: + return await e.eor(get_string("fsub_3"), time=5) + await e.eor("Removed ForceSub...") + + +@ultroid_cmd(pattern="checkfsub$") +async def getfsr(e): + res = get_forcesetting(e.chat_id) + if not res: + return await e.eor("ForceSub is Not Active In This Chat !", time=5) + cha = await e.client.get_entity(int(res)) + await e.eor(f"**ForceSub Status** : `Active`\n- **{cha.title}** `({res})`") + + +@in_pattern("fsub( (.*)|$)", owner=True) +async def fcall(e): + match = e.pattern_match.group(1).strip() + spli = match.split("_") + user = await ultroid_bot.get_entity(int(spli[0])) + cl = await ultroid_bot.get_entity(int(spli[1])) + text = f"Hi {inline_mention(user)}, You Need to Join" + text += f" {cl.title} in order to Chat in this Group." + el = ( + f"https://t.me/{cl.username}" + if cl.username + else (await ultroid_bot(ExportChatInviteRequest(cl))).link + ) + + res = [ + await e.builder.article( + title="forcesub", + text=text, + buttons=[ + [Button.url(text=get_string("fsub_4"), url=el)], + [Button.inline(get_string("fsub_5"), data=f"unm_{match}")], + ], + ) + ] + await e.answer(res) + + +@callback(re.compile("unm_(.*)")) +async def diesoon(e): + match = (e.data_match.group(1)).decode("UTF-8") + spli = match.split("_") + if e.sender_id != int(spli[0]): + return await e.answer(get_string("fsub_7"), alert=True) + try: + values = await ultroid_bot(GetParticipantRequest(int(spli[1]), int(spli[0]))) + if isinstance(values.participant, ChannelParticipantLeft) or ( + isinstance(values.participant, ChannelParticipantBanned) and values.left + ): + raise UserNotParticipantError("") + except UserNotParticipantError: + return await e.answer( + "Please Join That Channel !\nThen Click This Button !", alert=True + ) + await ultroid_bot.edit_permissions( + e.chat_id, int(spli[0]), send_messages=True, until_date=None + ) + await e.edit(get_string("fsub_8")) + + +async def force_sub(ult): + if not udB.get_key("FORCESUB"): + return + user = await ult.get_sender() + joinchat = get_forcesetting(ult.chat_id) + if (not joinchat) or (isinstance(user, User) and user.bot): + return + if CACHE.get(ult.chat_id): + if CACHE[ult.chat_id].get(user.id): + CACHE[ult.chat_id].update({user.id: CACHE[ult.chat_id][user.id] + 1}) + else: + CACHE[ult.chat_id].update({user.id: 1}) + else: + CACHE.update({ult.chat_id: {user.id: 1}}) + count = CACHE[ult.chat_id][user.id] + if count == 11: + CACHE[ult.chat_id][user.id] = 1 + return + if count in range(2, 11): + return + try: + await ultroid_bot.get_permissions(int(joinchat), user.id) + return + except UserNotParticipantError: + pass + if isinstance(user, Channel): + try: + await ultroid_bot.edit_permissions( + ult.chat_id, user.id, view_messages=False + ) + return + except BaseException as er: + LOGS.exception(er) + try: + await ultroid_bot.edit_permissions(ult.chat_id, user.id, send_messages=False) + except ChatAdminRequiredError: + return + except Exception as e: + await ult.delete() + LOGS.info(e) + res = await ultroid_bot.inline_query(asst.me.username, f"fsub {user.id}_{joinchat}") + await res[0].click(ult.chat_id, reply_to=ult.id) + + +if udB.get_key("FORCESUB"): + ultroid_bot.add_handler(force_sub, events.NewMessage(incoming=True)) diff --git a/plugins/gdrive.py b/plugins/gdrive.py new file mode 100644 index 0000000000000000000000000000000000000000..fbadce676830ef2d2b582eed78f7646c572dd606 --- /dev/null +++ b/plugins/gdrive.py @@ -0,0 +1,232 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available + +• `{i}gdul ` + Reply to file to upload on Google Drive. + Add file name to upload on Google Drive. + +• `{i}gdown | ` + Download from Gdrive link or file id. + +• `{i}gdsearch ` + Search file name on Google Drive and get link. + +• `{i}gdlist` + List all GDrive files. + +• `{i}gdfolder` + Link to your Google Drive Folder. + If added then all files will be uploaded in this folder. +""" + +import os +import time + +from telethon.tl.types import Message + +from pyUltroid.fns.gDrive import GDriveManager +from pyUltroid.fns.helper import time_formatter + +from . import ULTConfig, asst, eod, eor, get_string, ultroid_cmd + + +@ultroid_cmd( + pattern="gdown( (.*)|$)", + fullsudo=True, +) +async def gdown(event): + GDrive = GDriveManager() + match = event.pattern_match.group(1).strip() + if not match: + return await eod(event, "`Give file id or Gdrive link to download from!`") + filename = match.split(" | ")[1].strip() if " | " in match else None + eve = await event.eor(get_string("com_1")) + _start = time.time() + status, response = await GDrive._download_file(eve, match, filename) + if not status: + return await eve.edit(response) + await eve.edit( + f"`Downloaded ``{response}`` in {time_formatter((time.time() - _start)*1000)}`" + ) + + +@ultroid_cmd( + pattern="gdlist$", + fullsudo=True, +) +async def files(event): + GDrive = GDriveManager() + if not os.path.exists(GDrive.token_file): + return await event.eor(get_string("gdrive_6").format(asst.me.username)) + eve = await event.eor(get_string("com_1")) + msg = "" + if files := GDrive._list_files: + msg += f"{len(files.keys())} files found in gdrive.\n\n" + for _ in files: + msg += f"> [{files[_]}]({_})\n" + else: + msg += "Nothing in Gdrive" + if len(msg) < 4096: + await eve.edit(msg, link_preview=False) + else: + with open("drive-files.txt", "w") as f: + f.write( + msg.replace("[", "File Name: ") + .replace("](", "\n» Link: ") + .replace(")\n", "\n\n") + ) + try: + await eve.delete() + except BaseException: + pass + await event.client.send_file( + event.chat_id, + "drive-files.txt", + thumb=ULTConfig.thumb, + reply_to=event, + ) + os.remove("drive-files.txt") + + +@ultroid_cmd( + pattern="gdul( (.*)|$)", + fullsudo=True, +) +async def _(event): + GDrive = GDriveManager() + if not os.path.exists(GDrive.token_file): + return await eod(event, get_string("gdrive_6").format(asst.me.username)) + input_file = event.pattern_match.group(1).strip() or await event.get_reply_message() + if not input_file: + return await eod(event, "`Reply to file or give its location.`") + mone = await event.eor(get_string("com_1")) + if isinstance(input_file, Message): + location = "resources/downloads" + if input_file.photo: + filename = await input_file.download_media(location) + else: + filename = input_file.file.name + if not filename: + filename = str(round(time.time())) + filename = f"{location}/{filename}" + try: + filename, downloaded_in = await event.client.fast_downloader( + file=input_file.media.document, + filename=filename, + show_progress=True, + event=mone, + message=get_string("com_5"), + ) + filename = filename.name + except Exception as e: + return await eor(mone, str(e), time=10) + await mone.edit( + f"`Downloaded to ``{filename}`.`", + ) + else: + filename = input_file.strip() + if not os.path.exists(filename): + return await eod( + mone, + "File Not found in local server. Give me a file path :((", + time=5, + ) + folder_id = None + if os.path.isdir(filename): + files = os.listdir(filename) + if not files: + return await eod( + mone, "`Requested directory is empty. Can't create empty directory.`" + ) + folder_id = GDrive.create_directory(filename) + c = 0 + for files in sorted(files): + file = f"{filename}/{files}" + if not os.path.isdir(file): + try: + await GDrive._upload_file(mone, path=file, folder_id=folder_id) + c += 1 + except Exception as e: + return await mone.edit( + f"Exception occurred while uploading to gDrive {e}" + ) + return await mone.edit( + f"`Uploaded `[{filename}](https://drive.google.com/folderview?id={folder_id})` with {c} files.`" + ) + try: + g_drive_link = await GDrive._upload_file( + mone, + filename, + ) + await mone.edit( + get_string("gdrive_7").format(filename.split("/")[-1], g_drive_link) + ) + except Exception as e: + await mone.edit(f"Exception occurred while uploading to gDrive {e}") + + +@ultroid_cmd( + pattern="gdsearch( (.*)|$)", + fullsudo=True, +) +async def _(event): + GDrive = GDriveManager() + if not os.path.exists(GDrive.token_file): + return await event.eor(get_string("gdrive_6").format(asst.me.username)) + input_str = event.pattern_match.group(1).strip() + if not input_str: + return await event.eor("`Give filename to search on GDrive...`") + eve = await event.eor(f"`Searching for {input_str} in G-Drive...`") + files = GDrive.search(input_str) + msg = "" + if files: + msg += ( + f"{len(files.keys())} files with {input_str} in title found in GDrive.\n\n" + ) + for _ in files: + msg += f"> [{files[_]}]({_})\n" + else: + msg += f"`No files with title {input_str}`" + if len(msg) < 4096: + await eve.eor(msg, link_preview=False) + else: + with open("drive-files.txt", "w") as f: + f.write( + msg.replace("[", "File Name: ") + .replace("](", "\n» Link: ") + .replace(")\n", "\n\n") + ) + try: + await eve.delete() + except BaseException: + pass + await event.client.send_file( + event.chat_id, + f"{input_str}.txt", + thumb=ULTConfig.thumb, + reply_to=event, + ) + os.remove(f"{input_str}.txt") + + +@ultroid_cmd( + pattern="gdfolder$", + fullsudo=True, +) +async def _(event): + GDrive = GDriveManager() + if not os.path.exists(GDrive.token_file): + return await event.eor(get_string("gdrive_6").format(asst.me.username)) + if GDrive.folder_id: + await event.eor( + "`Your G-Drive Folder link : `\n" + + GDrive._create_folder_link(GDrive.folder_id) + ) + else: + await eod(event, "Set FOLDERID from your Assistant bot's Settings ") diff --git a/plugins/gemi.py b/plugins/gemi.py new file mode 100644 index 0000000000000000000000000000000000000000..876302a6b7af85edfe0a647d956354184ace472a --- /dev/null +++ b/plugins/gemi.py @@ -0,0 +1,413 @@ +# Nimbus ~ UserBot +# Copyright (C) 2023 NimbusTheCloud +# +# This file is a part of < https://github.com/ufoptg/Nimbus/ > +# PLease read the GNU Affero General Public License in +# . +# by @SoulOfSukuna +""" +Gemini Command Handler + +This script provides the `.gemini` command to interact with Google's Gemini AI for generating content, selecting models, and managing chat history. + +Available Gemini Models: +- `gemini-2.0-flash-exp` ➔ Trait: `g2f-exp` (Default model) +- `gemini-1.5-flash` ➔ Trait: `g1f` +- `gemini-1.5-flash-8b` ➔ Trait: `g1f8b` +- `gemini-1.5-pro` ➔ Trait: `g1p` + +Features: +1. Query Gemini AI: + - `.gemini ` ➔ Generates a response using the currently selected model. + - Example: `.gemini Write a poem about the stars.` + +2. Select a Model: + - `.gemini -m ` ➔ Selects a specific model based on its trait. + - Example: `.gemini -m g1f` ➔ Switches to the `gemini-1.5-flash` model. + - If an invalid trait is provided, an error message will be returned. + +3. Clear Chat History: + - `.gemini -c` ➔ Clears the chat history stored in memory. + - Example: `.gemini -c` ➔ Removes all previous queries and responses. + +4. Handle Long Responses: + - If the response exceeds Telegram's character limit (4096 characters), it will be sent as a `.txt` file. + +5. Reply-Based Query: + - Reply to a message with `.gemini write a cool caption for this image` ➔ Uses the replied message's content as the query and processes the image. + +Examples: +- `.gemini Tell me a joke about programmers.` +- `.gemini -m g2f-exp` +- `.gemini -c` +- Reply to an image with `.gemini write a cool caption for this image` +""" + +import asyncio +import mimetypes +from collections import deque, defaultdict +from io import BytesIO +from os import system, path, remove +from googleapiclient.discovery import build +import time +import logging +from bs4 import BeautifulSoup + +try: + import google.generativeai as genai +except ImportError: + system("pip install -q google-generativeai") + import google.generativeai as genai + +try: + from PIL import Image +except ImportError: + system("pip install -q Pillow") + from PIL import Image + +from typing import Optional + +from . import ( + ultroid_cmd, + async_searcher, + check_filename, + udB, + LOGS, + download_file, + run_async, +) + +MODELS = [ + {"id": "gemini-2.0-flash-exp", "traits": ["g2f-exp"]}, + {"id": "gemini-1.5-flash", "traits": ["g1f"]}, + {"id": "gemini-1.5-flash-8b", "traits": ["g1f8b"]}, + {"id": "gemini-1.5-pro", "traits": ["g1p"]}, +] + + +def select_model(trait: str) -> Optional[str]: + """Selects the Gemini model ID based on the provided trait.""" + for model in MODELS: + if trait in model["traits"]: + return model["id"] + return None + +logging.getLogger("googleapiclient.discovery_cache").setLevel(logging.WARNING) + +CONFIG = {"model": select_model("g2f-exp")} + +GEMINI_CHAT_HISTORY = defaultdict(lambda: deque(maxlen=80)) + +async def generate_content_with_search(prompt, model): + try: + search_results = await google_search(prompt) + + search_summary = "\n".join( + [f"{idx + 1}. {res['title']} - {res['snippet']}" for idx, res in enumerate(search_results)] + ) + + + enhanced_prompt = ( + f"Use the following search results to create a comprehensive response:\n\n" + f"{search_summary}\n\n" + f"Original Query: {prompt}" + ) + + response = await model.generate_content_async(enhanced_prompt) + return response.text.strip() + + except Exception as e: + return f"An error occurred while including search results: {e}. Generating content...\n\n{model.generate_content(prompt).text.strip()}" + +async def fetch_full_content(url): + try: + api_url = f"https://scraper.api.airforce/scrape?url={url}" + response = await async_searcher(api_url) + + soup = BeautifulSoup(response, "html.parser") + main_content = soup.select_one("article") or soup.select_one("main") or soup + paragraphs = [ + para.get_text(separator=" ").strip() + for para in main_content.find_all("p") + if len(para.get_text(strip=True)) > 30 + and not any( + keyword in para.get_text().lower() + for keyword in [ + "privacy", + "cookie", + "subscribe", + "sign up", + "terms", + "all rights reserved", + "see all", + "see more", + ] + ) + ] + full_text = ( + " ".join(paragraphs[:5]) if paragraphs else "No main content available." + ) + return full_text + + except Exception as e: + return f"Error fetching content: {e}" + +async def google_search(query): + api_key = "AIzaSyAOhKEVXRX-DJbxjyUz5Ol54qCygeRQRTA" + cse_id = "a44275f02ca2946da" + service = build("customsearch", "v1", developerKey=api_key) + + results = service.cse().list(q=query, cx=cse_id, gl="AU").execute() + search_items = results.get("items", []) + + search_results = await asyncio.gather( + *(fetch_search_result(item) for item in search_items) + ) + + return search_results + +async def fetch_search_result(item): + title = item.get("title") + link = item.get("link") + snippet = item.get("snippet") + full_content = await fetch_full_content(link) + return { + "title": title, + "link": link, + "snippet": snippet, + "full_content": full_content or "No additional content available." + } + +async def process_file(file_path: str) -> str: + """ + Uploads a file to Gemini and returns the file URL. + """ + try: + mime_type, _ = mimetypes.guess_type(file_path) + if not mime_type: + mime_type = 'application/octet-stream' + file_url = await asyncio.to_thread(genai.upload_file, file_path, mime_type=mime_type) + return file_url + except Exception as exc: + LOGS.error(f"File upload failed: {exc}") + raise + +async def process_video_file(file_path: str) -> str: + """ + Uploads a video to Gemini and returns the file URL. + """ + try: + video_file = await asyncio.to_thread(genai.upload_file, path=file_path) + while video_file.state.name == "PROCESSING": + await asyncio.sleep(10) + video_file = genai.get_file(video_file.name) + + if video_file.state.name == "FAILED": + raise ValueError(video_file.state.name) + return video_file + except Exception as exc: + LOGS.error(f"File upload failed: {exc}") + raise + +async def process_image_with_pillow(file_path: str) -> Optional[str]: + """ + Processes an image file using PIL.Image, saves it temporarily, + uploads it to Gemini, and returns the file URL. + """ + try: + with Image.open(file_path) as img: + img = img.convert("RGB") + buffer = BytesIO() + buffer.name = "processed_image.jpeg" + img.save(buffer, format="JPEG", quality=90) + buffer.seek(0) + + temp_image_path = "temp_processed_image.jpeg" + with open(temp_image_path, "wb") as temp_file: + temp_file.write(buffer.read()) + + file_url = await process_file(temp_image_path) + + remove(temp_image_path) + + return file_url + except Exception as exc: + LOGS.error(f"Image processing failed: {exc}") + return None + + +async def handle_multimodal_input(event, e) -> Optional[str]: + """ + Checks and processes images, audio, or video in a replied message. + Ensures cleanup of downloaded files. + Returns the file URL or None if processing fails. + """ + temp_file = None + try: + if event.photo: + temp_file = await event.download_media() + await e.eor("Processing image with Pillow...") + return await process_image_with_pillow(temp_file) + elif event.voice or event.audio: + temp_file = await event.download_media() + await e.eor("Uploading audio...") + return await process_file(temp_file) + elif event.video: + temp_file = await event.download_media() + await e.eor("Uploading video...") + return await process_video_file(temp_file) + except Exception as exc: + LOGS.error(f"Error processing media: {exc}") + finally: + if temp_file and path.exists(temp_file): + try: + remove(temp_file) + LOGS.info(f"Cleaned up temporary file: {temp_file}") + except Exception as cleanup_exc: + LOGS.warning(f"Failed to clean up temporary file: {cleanup_exc}") + return None + + +async def get_gemini_response(user_id: int, query: str, api_key: str, file_url: Optional[str] = None) -> str: + """ + Generates a response from the selected Gemini model based on the user query. + Includes the user's chat history in the request. + If a file URL is provided, it is included in the content generation. + """ + try: + genai.configure(api_key=api_key) + model = genai.GenerativeModel(CONFIG["model"]) + + chat_history = GEMINI_CHAT_HISTORY[user_id] + + if chat_history: + formatted_history = "\n".join( + [f"{msg['role']}: {msg['content']}" for msg in chat_history] + ) + if file_url: + content = [file_url, "\n\n", f"{formatted_history}\nuser: {query}"] + else: + content = f"{formatted_history}\nuser: {query}" + else: + if file_url: + content = [file_url, "\n\n", query] + else: + content = query + + # Key Addition: Handle queries without file_url using Google Search + if not file_url: + response = await generate_content_with_search(query, model) + return response + + response = await asyncio.to_thread(model.generate_content, content) + return response.text.strip() + except Exception as exc: + LOGS.error(f"Error generating response: {exc}") + raise + + +@ultroid_cmd(pattern=r"gemi(?:\s+([\s\S]*))?$") +async def gemini_handler(e): + """ + Handles the .gemini command with optional model selection. + """ + args = e.pattern_match.group(1) + + trait = None + user_query = None + file_url = None + + try: + user_id = e.sender.id + except AttributeError: + user_id = e.from_id.user_id + + if args: + if args.startswith("-m"): + trait = args[3:].lower().strip() + selected_model = select_model(trait) + if not selected_model: + return await e.eor("❌ **Error:** Invalid model trait specified.", time=10) + CONFIG["model"] = selected_model + return await e.eor(f"✅ **Success:** Selected Model: `{CONFIG['model']}`", time=10) + elif args.strip().lower() == "-c": + GEMINI_CHAT_HISTORY[user_id].clear() + return await e.eor("🧹 **Success:** Cleared your Gemini Chat History!", time=6) + else: + user_query = args.strip() + + api_key = udB.get_key("GEMINI_API") + if not api_key: + return await e.eor( + "⚠️ **Error:** `GEMINI_API` key missing. Please set it using `.setvar GEMINI_API your_api_key_here`.", + time=10, + ) + + query = user_query + file_url = None + + reply = await e.get_reply_message() + if reply: + # New logic to handle file content + if ( + reply.file + and reply.file.mime_type in ["text/x-python", "text/plain"] + ): + # Download the file and read its content + file = await reply.download_media(BytesIO()) + file.seek(0) + query = file.read().decode("utf-8") + + multimodal_content = await handle_multimodal_input(reply, e) + if multimodal_content: + file_url = multimodal_content + if not query: + if reply.photo: + query = "Analyse this image" + elif reply.voice or reply.audio: + query = "Analyse this audio." + elif reply.video: + query = "Analyse this video" + elif reply.text and not query: + query = reply.text.strip() + + if not query and not file_url: + return await e.eor( + "💬 **Usage:** `.gemini `\n*Provide a query or reply with media to generate content using Gemini AI.*", + time=5, + ) + + processing_message = await e.eor(f"🔄 **Processing your request using `{CONFIG['model']}`...**") + + GEMINI_CHAT_HISTORY[user_id].append({"role": "user", "content": query}) + + try: + response = await get_gemini_response(user_id, query, api_key, file_url=file_url) + GEMINI_CHAT_HISTORY[user_id].append({"role": "assistant", "content": response}) + except Exception as exc: + LOGS.warning(f"Gemini response generation failed: {exc}", exc_info=True) + if query: + GEMINI_CHAT_HISTORY[user_id].pop() + return await processing_message.edit(f"❌ **Error:** {exc}") + + if len(response) < 4096: + reply_text = f"📄 **Gemini Response:**\n\n{response}" + await processing_message.edit(reply_text, parse_mode="markdown") + else: + buffer = BytesIO() + try: + buffer.write(response.encode('utf-8')) + buffer.seek(0) + buffer.name = "gemini_response.txt" + await e.client.send_file( + e.chat_id, + buffer, + caption="📄 **Gemini Response:**", + reply_to=e.reply_to_msg_id, + ) + except Exception as exc: + LOGS.error(f"Error sending file: {exc}") + await processing_message.edit("❌ **Error:** Failed to send the response as a file.") + finally: + buffer.close() + await processing_message.delete() diff --git a/plugins/giftools.py b/plugins/giftools.py new file mode 100644 index 0000000000000000000000000000000000000000..38fdb1f79e4869ac71b7e170d692abf13697f3d1 --- /dev/null +++ b/plugins/giftools.py @@ -0,0 +1,128 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available + +•`{i}invertgif` + Make Gif Inverted(negative). + +•`{i}bwgif` + Make Gif black and white + +•`{i}rvgif` + Reverse a gif + +•`{i}vtog` + Reply To Video , It will Create Gif + Video to Gif + +•`{i}gif ` + Send video regarding to query. +""" +import os +import random +import time +from datetime import datetime as dt + +from . import HNDLR, LOGS, bash, downloader, get_string, mediainfo, ultroid_cmd + + +@ultroid_cmd(pattern="(bw|invert)gif$") +async def igif(e): + match = e.pattern_match.group(1).strip() + a = await e.get_reply_message() + if not (a and a.media): + return await e.eor("`Reply To gif only`", time=5) + wut = mediainfo(a.media) + if "gif" not in wut: + return await e.eor("`Reply To Gif Only`", time=5) + xx = await e.eor(get_string("com_1")) + z = await a.download_media() + if match == "bw": + cmd = f'ffmpeg -i "{z}" -vf format=gray ult.gif -y' + else: + cmd = f'ffmpeg -i "{z}" -vf lutyuv="y=negval:u=negval:v=negval" ult.gif -y' + try: + await bash(cmd) + await e.client.send_file(e.chat_id, "ult.gif", supports_streaming=True) + os.remove(z) + os.remove("ult.gif") + await xx.delete() + except Exception as er: + LOGS.info(er) + + +@ultroid_cmd(pattern="rvgif$") +async def reverse_gif(event): + a = await event.get_reply_message() + if not (a and a.media) and "video" not in mediainfo(a.media): + return await event.eor("`Reply To Video only`", time=5) + msg = await event.eor(get_string("com_1")) + file = await a.download_media() + await bash(f'ffmpeg -i "{file}" -vf reverse -af areverse reversed.mp4 -y') + await event.respond("- **Reversed Video/GIF**", file="reversed.mp4") + await msg.delete() + os.remove(file) + os.remove("reversed.mp4") + + +@ultroid_cmd(pattern="gif( (.*)|$)") +async def gifs(ult): + get = ult.pattern_match.group(1).strip() + xx = random.randint(0, 5) + n = 0 + if ";" in get: + try: + n = int(get.split(";")[-1]) + except IndexError: + pass + if not get: + return await ult.eor(f"`{HNDLR}gif `") + m = await ult.eor(get_string("com_2")) + gifs = await ult.client.inline_query("gif", get) + if not n: + await gifs[xx].click( + ult.chat_id, reply_to=ult.reply_to_msg_id, silent=True, hide_via=True + ) + else: + for x in range(n): + await gifs[x].click( + ult.chat_id, reply_to=ult.reply_to_msg_id, silent=True, hide_via=True + ) + await m.delete() + + +@ultroid_cmd(pattern="vtog$") +async def vtogif(e): + a = await e.get_reply_message() + if not (a and a.media): + return await e.eor("`Reply To video only`", time=5) + wut = mediainfo(a.media) + if "video" not in wut: + return await e.eor("`Reply To Video Only`", time=5) + xx = await e.eor(get_string("com_1")) + dur = a.media.document.attributes[0].duration + tt = time.time() + if int(dur) < 120: + z = await a.download_media() + await bash( + f'ffmpeg -i {z} -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 ult.gif -y' + ) + else: + filename = a.file.name + if not filename: + filename = "video_" + dt.now().isoformat("_", "seconds") + ".mp4" + vid = await downloader(filename, a.media.document, xx, tt, get_string("com_5")) + z = vid.name + await bash( + f'ffmpeg -ss 3 -t 100 -i {z} -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 ult.gif' + ) + + await e.client.send_file(e.chat_id, "ult.gif", support_stream=True) + os.remove(z) + os.remove("ult.gif") + await xx.delete() diff --git a/plugins/glitch.py b/plugins/glitch.py new file mode 100644 index 0000000000000000000000000000000000000000..a612e959e57fe8a9c75c9af5965d03b3d8368612 --- /dev/null +++ b/plugins/glitch.py @@ -0,0 +1,42 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +•`{i}glitch ` + gives a glitchy gif. +""" +import os + +from . import bash, get_string, mediainfo, ultroid_cmd + + +@ultroid_cmd(pattern="glitch$") +async def _(e): + try: + import glitch_me # ignore :pylint + except ModuleNotFoundError: + await bash( + "pip install -e git+https://github.com/1Danish-00/glitch_me.git#egg=glitch_me" + ) + reply = await e.get_reply_message() + if not reply or not reply.media: + return await e.eor(get_string("cvt_3")) + xx = await e.eor(get_string("glitch_1")) + wut = mediainfo(reply.media) + if wut.startswith(("pic", "sticker")): + ok = await reply.download_media() + elif reply.document and reply.document.thumbs: + ok = await reply.download_media(thumb=-1) + else: + return await xx.eor(get_string("com_4")) + cmd = f"glitch_me gif --line_count 200 -f 10 -d 50 '{ok}' ult.gif" + await bash(cmd) + await e.reply(file="ult.gif", force_document=False) + await xx.delete() + os.remove(ok) + os.remove("ult.gif") diff --git a/plugins/globaltools.py b/plugins/globaltools.py new file mode 100644 index 0000000000000000000000000000000000000000..087db364c488745a470477c022f0b978c7cbc6a7 --- /dev/null +++ b/plugins/globaltools.py @@ -0,0 +1,753 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}gban ` +• `{i}ungban` + Ban/Unban Globally. + +• `{i}gstat ` + Check if user is GBanned. + +• `{i}listgban` : List all GBanned users. + +• `{i}gmute` | `{i}ungmute` + Mute/UnMute Globally. + +• `{i}gkick ` `Globally Kick User` +• `{i}gcast ` `Globally Send msg in all grps` + +• `{i}gadmincast ` `Globally broadcast in your admin chats` +• `{i}gucast ` `Globally send msg in all pm users` + +• `{i}gblacklist ` + globally promote user where you are admin + - Set whether To promote only in groups/channels/all. + Eg- `gpromote group boss` ~ promotes user in all grps. + `gpromote @username all sar` ~ promote the user in all group & channel +• `{i}gdemote` - `demote user globally` +""" +import asyncio +import os + +from telethon.errors.rpcerrorlist import ChatAdminRequiredError, FloodWaitError +from telethon.tl.functions.channels import EditAdminRequest +from telethon.tl.functions.contacts import BlockRequest, UnblockRequest +from telethon.tl.types import ChatAdminRights, User + +from pyUltroid.dB import DEVLIST +from pyUltroid.dB.base import KeyManager +from pyUltroid.dB.gban_mute_db import ( + gban, + gmute, + is_gbanned, + is_gmuted, + list_gbanned, + ungban, + ungmute, +) +from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button + +from . import ( + HNDLR, + LOGS, + NOSPAM_CHAT, + OWNER_NAME, + eod, + eor, + get_string, + inline_mention, + ultroid_bot, + ultroid_cmd, +) +from ._inline import something + +_gpromote_rights = ChatAdminRights( + add_admins=False, + invite_users=True, + change_info=False, + ban_users=True, + delete_messages=True, + pin_messages=True, +) + +_gdemote_rights = ChatAdminRights( + add_admins=False, + invite_users=False, + change_info=False, + ban_users=False, + delete_messages=False, + pin_messages=False, +) + +keym = KeyManager("GBLACKLISTS", cast=list) + + +@ultroid_cmd(pattern="gpromote( (.*)|$)", fullsudo=True) +async def _(e): + x = e.pattern_match.group(1).strip() + ultroid_bot = e.client + if not x: + return await e.eor(get_string("schdl_2"), time=5) + user = await e.get_reply_message() + if user: + ev = await e.eor("`Promoting Replied User Globally`") + ok = e.text.split() + key = "all" + if len(ok) > 1 and (("group" in ok[1]) or ("channel" in ok[1])): + key = ok[1] + rank = ok[2] if len(ok) > 2 else "AdMin" + c = 0 + user.id = user.peer_id.user_id if e.is_private else user.from_id.user_id + async for x in e.client.iter_dialogs(): + if ( + "group" in key.lower() + and x.is_group + or "group" not in key.lower() + and "channel" in key.lower() + and x.is_channel + ): + try: + await e.client( + EditAdminRequest( + x.id, + user.id, + _gpromote_rights, + rank, + ), + ) + c += 1 + except BaseException: + pass + elif ( + ("group" not in key.lower() or x.is_group) + and ( + "group" in key.lower() + or "channel" not in key.lower() + or x.is_channel + ) + and ( + "group" in key.lower() + or "channel" in key.lower() + or x.is_group + or x.is_channel + ) + ): + try: + await e.client( + EditAdminRequest( + x.id, + user.id, + _gpromote_rights, + rank, + ), + ) + c += 1 + except Exception as er: + LOGS.info(er) + await eor(ev, f"Promoted The Replied Users in Total : {c} {key} chats") + else: + k = e.text.split() + if not k[1]: + return await eor( + e, "`Give someone's username/id or replied to user.", time=5 + ) + user = k[1] + if user.isdigit(): + user = int(user) + try: + name = await e.client.get_entity(user) + except BaseException: + return await e.eor(f"`No User Found Regarding {user}`", time=5) + ev = await e.eor(f"`Promoting {name.first_name} globally.`") + key = "all" + if len(k) > 2 and (("group" in k[2]) or ("channel" in k[2])): + key = k[2] + rank = k[3] if len(k) > 3 else "AdMin" + c = 0 + async for x in e.client.iter_dialogs(): + if ( + "group" in key.lower() + and x.is_group + or "group" not in key.lower() + and "channel" in key.lower() + and x.is_channel + or "group" not in key.lower() + and "channel" not in key.lower() + and (x.is_group or x.is_channel) + ): + try: + await ultroid_bot( + EditAdminRequest( + x.id, + user, + _gpromote_rights, + rank, + ), + ) + c += 1 + except BaseException: + pass + await eor(ev, f"Promoted {name.first_name} in Total : {c} {key} chats.") + + +@ultroid_cmd(pattern="gdemote( (.*)|$)", fullsudo=True) +async def _(e): + x = e.pattern_match.group(1).strip() + ultroid_bot = e.client + if not x: + return await e.eor(get_string("schdl_2"), time=5) + user = await e.get_reply_message() + if user: + user.id = user.peer_id.user_id if e.is_private else user.from_id.user_id + ev = await e.eor("`Demoting Replied User Globally`") + ok = e.text.split() + key = "all" + if len(ok) > 1 and (("group" in ok[1]) or ("channel" in ok[1])): + key = ok[1] + rank = "Not AdMin" + c = 0 + async for x in e.client.iter_dialogs(): + if ( + "group" in key.lower() + and x.is_group + or "group" not in key.lower() + and "channel" in key.lower() + and x.is_channel + or "group" not in key.lower() + and "channel" not in key.lower() + and (x.is_group or x.is_channel) + ): + try: + await ultroid_bot( + EditAdminRequest( + x.id, + user.id, + _gdemote_rights, + rank, + ), + ) + c += 1 + except BaseException: + pass + await eor(ev, f"Demoted The Replied Users in Total : {c} {key} chats") + else: + k = e.text.split() + if not k[1]: + return await eor( + e, "`Give someone's username/id or replied to user.", time=5 + ) + user = k[1] + if user.isdigit(): + user = int(user) + try: + name = await ultroid_bot.get_entity(user) + except BaseException: + return await e.eor(f"`No User Found Regarding {user}`", time=5) + ev = await e.eor(f"`Demoting {name.first_name} globally.`") + key = "all" + if len(k) > 2 and (("group" in k[2]) or ("channel" in k[2])): + key = k[2] + rank = "Not AdMin" + c = 0 + async for x in ultroid_bot.iter_dialogs(): + if ( + "group" in key.lower() + and x.is_group + or "group" not in key.lower() + and "channel" in key.lower() + and x.is_channel + or "group" not in key.lower() + and "channel" not in key.lower() + and (x.is_group or x.is_channel) + ): + try: + await ultroid_bot( + EditAdminRequest( + x.id, + user, + _gdemote_rights, + rank, + ), + ) + c += 1 + except BaseException: + pass + await eor(ev, f"Demoted {name.first_name} in Total : {c} {key} chats.") + + +@ultroid_cmd(pattern="ungban( (.*)|$)", fullsudo=True) +async def _(e): + xx = await e.eor("`UnGbanning...`") + match = e.pattern_match.group(1).strip() + peer = None + if e.reply_to_msg_id: + userid = (await e.get_reply_message()).sender_id + elif match: + try: + userid = int(match) + except ValueError: + userid = match + try: + userid = (await e.client.get_entity(userid)).id + except Exception as er: + return await xx.edit(f"Failed to get User...\nError: {er}") + elif e.is_private: + userid = e.chat_id + else: + return await xx.eor("`Reply to some msg or add their id.`", time=5) + if not is_gbanned(userid): + return await xx.edit("`User/Channel is not Gbanned...`") + try: + if not peer: + peer = await e.client.get_entity(userid) + name = inline_mention(peer) + except BaseException: + userid = int(userid) + name = str(userid) + chats = 0 + if e.client._dialogs: + dialog = e.client._dialogs + else: + dialog = await e.client.get_dialogs() + e.client._dialogs.extend(dialog) + for ggban in dialog: + if ggban.is_group or ggban.is_channel: + try: + await e.client.edit_permissions(ggban.id, userid, view_messages=True) + chats += 1 + except FloodWaitError as fw: + LOGS.info( + f"[FLOOD_WAIT_ERROR] : on Ungban\nSleeping for {fw.seconds+10}" + ) + await asyncio.sleep(fw.seconds + 10) + try: + await e.client.edit_permissions( + ggban.id, userid, view_messages=True + ) + chats += 1 + except BaseException as er: + LOGS.exception(er) + except (ChatAdminRequiredError, ValueError): + pass + except BaseException as er: + LOGS.exception(er) + ungban(userid) + if isinstance(peer, User): + await e.client(UnblockRequest(userid)) + await xx.edit( + f"`Ungbaned` {name} in {chats} `chats.\nRemoved from gbanwatch.`", + ) + + +@ultroid_cmd(pattern="gban( (.*)|$)", fullsudo=True) +async def _(e): + xx = await e.eor("`Gbanning...`") + reason = "" + if e.reply_to_msg_id: + userid = (await e.get_reply_message()).sender_id + try: + reason = e.text.split(" ", maxsplit=1)[1] + except IndexError: + pass + elif e.pattern_match.group(1).strip(): + usr = e.text.split(maxsplit=2)[1] + try: + userid = await e.client.parse_id(usr) + except ValueError: + userid = usr + try: + reason = e.text.split(maxsplit=2)[2] + except IndexError: + pass + elif e.is_private: + userid = e.chat_id + try: + reason = e.text.split(" ", maxsplit=1)[1] + except IndexError: + pass + else: + return await xx.eor("`Reply to some msg or add their id.`", time=5) + user = None + try: + user = await e.client.get_entity(userid) + name = inline_mention(user) + except BaseException: + userid = int(userid) + name = str(userid) + chats = 0 + if userid == ultroid_bot.uid: + return await xx.eor("`I can't gban myself.`", time=3) + elif userid in DEVLIST: + return await xx.eor("`I can't gban my Developers.`", time=3) + elif is_gbanned(userid): + return await eod( + xx, + "`User is already gbanned and added to gbanwatch.`", + time=4, + ) + if e.client._dialogs: + dialog = e.client._dialogs + else: + dialog = await e.client.get_dialogs() + e.client._dialogs.extend(dialog) + for ggban in dialog: + if ggban.is_group or ggban.is_channel: + try: + await e.client.edit_permissions(ggban.id, userid, view_messages=False) + chats += 1 + except FloodWaitError as fw: + LOGS.info( + f"[FLOOD_WAIT_ERROR] : on GBAN Command\nSleeping for {fw.seconds+10}" + ) + await asyncio.sleep(fw.seconds + 10) + try: + await e.client.edit_permissions( + ggban.id, userid, view_messages=False + ) + chats += 1 + except BaseException as er: + LOGS.exception(er) + except (ChatAdminRequiredError, ValueError): + pass + except BaseException as er: + LOGS.exception(er) + gban(userid, reason) + if isinstance(user, User): + await e.client(BlockRequest(userid)) + gb_msg = f"**#Gbanned** {name} `in {chats} chats and added to gbanwatch!`" + if reason: + gb_msg += f"\n**Reason** : {reason}" + await xx.edit(gb_msg) + + +@ultroid_cmd(pattern="g(admin|)cast( (.*)|$)", fullsudo=True) +async def gcast(event): + text, btn, reply = "", None, None + if xx := event.pattern_match.group(2): + msg, btn = get_msg_button(event.text.split(maxsplit=1)[1]) + elif event.is_reply: + reply = await event.get_reply_message() + msg = reply.text + if reply.buttons: + btn = format_btn(reply.buttons) + else: + msg, btn = get_msg_button(msg) + else: + return await eor( + event, "`Give some text to Globally Broadcast or reply a message..`" + ) + + kk = await event.eor("`Globally Broadcasting Msg...`") + er = 0 + done = 0 + err = "" + if event.client._dialogs: + dialog = event.client._dialogs + else: + dialog = await event.client.get_dialogs() + event.client._dialogs.extend(dialog) + for x in dialog: + if x.is_group: + chat = x.entity.id + if ( + not keym.contains(chat) + and int(f"-100{str(chat)}") not in NOSPAM_CHAT + and ( + ( + event.text[2:7] != "admin" + or (x.entity.admin_rights or x.entity.creator) + ) + ) + ): + try: + if btn: + bt = create_tl_btn(btn) + await something( + event, + msg, + reply.media if reply else None, + bt, + chat=chat, + reply=False, + ) + else: + await event.client.send_message( + chat, msg, file=reply.media if reply else None + ) + done += 1 + except FloodWaitError as fw: + await asyncio.sleep(fw.seconds + 10) + try: + if btn: + bt = create_tl_btn(btn) + await something( + event, + msg, + reply.media if reply else None, + bt, + chat=chat, + reply=False, + ) + else: + await event.client.send_message( + chat, msg, file=reply.media if reply else None + ) + done += 1 + except Exception as rr: + err += f"• {rr}\n" + er += 1 + except BaseException as h: + err += f"• {str(h)}" + "\n" + er += 1 + text += f"Done in {done} chats, error in {er} chat(s)" + if err != "": + open("gcast-error.log", "w+").write(err) + text += f"\nYou can do `{HNDLR}ul gcast-error.log` to know error report." + await kk.edit(text) + + +@ultroid_cmd(pattern="gucast( (.*)|$)", fullsudo=True) +async def gucast(event): + msg, btn, reply = "", None, None + if xx := event.pattern_match.group(1).strip(): + msg, btn = get_msg_button(event.text.split(maxsplit=1)[1]) + elif event.is_reply: + reply = await event.get_reply_message() + msg = reply.text + if reply.buttons: + btn = format_btn(reply.buttons) + else: + msg, btn = get_msg_button(msg) + else: + return await eor( + event, "`Give some text to Globally Broadcast or reply a message..`" + ) + kk = await event.eor("`Globally Broadcasting Msg...`") + er = 0 + done = 0 + if event.client._dialogs: + dialog = event.client._dialogs + else: + dialog = await event.client.get_dialogs() + event.client._dialogs.extend(dialog) + for x in dialog: + if x.is_user and not x.entity.bot: + chat = x.id + if not keym.contains(chat): + try: + if btn: + bt = create_tl_btn(btn) + await something( + event, + msg, + reply.media if reply else None, + bt, + chat=chat, + reply=False, + ) + else: + await event.client.send_message( + chat, msg, file=reply.media if reply else None + ) + done += 1 + except BaseException: + er += 1 + await kk.edit(f"Done in {done} chats, error in {er} chat(s)") + + +@ultroid_cmd(pattern="gkick( (.*)|$)", fullsudo=True) +async def gkick(e): + xx = await e.eor("`Gkicking...`") + if e.reply_to_msg_id: + userid = (await e.get_reply_message()).sender_id + elif e.pattern_match.group(1).strip(): + userid = await e.client.parse_id(e.pattern_match.group(1).strip()) + elif e.is_private: + userid = e.chat_id + else: + return await xx.edit("`Reply to some msg or add their id.`", time=5) + name = (await e.client.get_entity(userid)).first_name + chats = 0 + if userid == ultroid_bot.uid: + return await xx.eor("`I can't gkick myself.`", time=3) + if userid in DEVLIST: + return await xx.eor("`I can't gkick my Developers.`", time=3) + if e.client._dialogs: + dialog = e.client._dialogs + else: + dialog = await e.client.get_dialogs() + e.client._dialogs.extend(dialog) + for gkick in dialog: + if gkick.is_group or gkick.is_channel: + try: + await e.client.kick_participant(gkick.id, userid) + chats += 1 + except BaseException: + pass + await xx.edit(f"`Gkicked` [{name}](tg://user?id={userid}) `in {chats} chats.`") + + +@ultroid_cmd(pattern="gmute( (.*)|$)", fullsudo=True) +async def _(e): + xx = await e.eor("`Gmuting...`") + if e.reply_to_msg_id: + userid = (await e.get_reply_message()).sender_id + elif e.pattern_match.group(1).strip(): + userid = await e.client.parse_id(e.pattern_match.group(1).strip()) + elif e.is_private: + userid = e.chat_id + else: + return await xx.eor("`Reply to some msg or add their id.`", tome=5, time=5) + name = await e.client.get_entity(userid) + chats = 0 + if userid == ultroid_bot.uid: + return await xx.eor("`I can't gmute myself.`", time=3) + if userid in DEVLIST: + return await xx.eor("`I can't gmute my Developers.`", time=3) + if is_gmuted(userid): + return await xx.eor("`User is already gmuted.`", time=4) + if e.client._dialogs: + dialog = e.client._dialogs + else: + dialog = await e.client.get_dialogs() + e.client._dialogs.extend(dialog) + for onmute in dialog: + if onmute.is_group: + try: + await e.client.edit_permissions(onmute.id, userid, send_messages=False) + chats += 1 + except BaseException: + pass + gmute(userid) + await xx.edit(f"`Gmuted` {inline_mention(name)} `in {chats} chats.`") + + +@ultroid_cmd(pattern="ungmute( (.*)|$)", fullsudo=True) +async def _(e): + xx = await e.eor("`UnGmuting...`") + if e.reply_to_msg_id: + userid = (await e.get_reply_message()).sender_id + elif e.pattern_match.group(1).strip(): + userid = await e.client.parse_id(e.pattern_match.group(1).strip()) + elif e.is_private: + userid = e.chat_id + else: + return await xx.eor("`Reply to some msg or add their id.`", time=5) + name = (await e.client.get_entity(userid)).first_name + chats = 0 + if not is_gmuted(userid): + return await xx.eor("`User is not gmuted.`", time=3) + if e.client._dialogs: + dialog = e.client._dialogs + else: + dialog = await e.client.get_dialogs() + e.client._dialogs.extend(dialog) + for hurr in dialog: + if hurr.is_group: + try: + await e.client.edit_permissions(hurr.id, userid, send_messages=True) + chats += 1 + except BaseException: + pass + ungmute(userid) + await xx.edit(f"`Ungmuted` {inline_mention(name)} `in {chats} chats.`") + + +@ultroid_cmd( + pattern="listgban$", +) +async def list_gengbanned(event): + users = list_gbanned() + x = await event.eor(get_string("com_1")) + msg = "" + if not users: + return await x.edit("`You haven't GBanned anyone!`") + for i in users: + try: + name = await event.client.get_entity(int(i)) + except BaseException: + name = i + msg += f"User: {inline_mention(name, html=True)}\n" + reason = users[i] + msg += f"Reason: {reason}\n\n" if reason is not None else "\n" + gbanned_users = f"List of users GBanned by {OWNER_NAME}:\n\n{msg}" + if len(gbanned_users) > 4096: + with open("gbanned.txt", "w") as f: + f.write( + gbanned_users.replace("", "") + .replace("", "") + .replace("", "") + ) + await x.reply( + file="gbanned.txt", + message=f"List of users GBanned by {inline_mention(ultroid_bot.me)}", + ) + os.remove("gbanned.txt") + await x.delete() + else: + await x.edit(gbanned_users, parse_mode="html") + + +@ultroid_cmd( + pattern="gstat( (.*)|$)", +) +async def gstat_(e): + xx = await e.eor(get_string("com_1")) + if e.is_private: + userid = (await e.get_chat()).id + elif e.reply_to_msg_id: + userid = (await e.get_reply_message()).sender_id + elif e.pattern_match.group(1).strip(): + try: + userid = await e.client.parse_id(e.pattern_match.group(1).strip()) + except Exception as err: + return await xx.eor(f"{err}", time=10) + else: + return await xx.eor("`Reply to some msg or add their id.`", time=5) + name = (await e.client.get_entity(userid)).first_name + msg = f"**{name} is " + is_banned = is_gbanned(userid) + reason = list_gbanned().get(userid) + if is_banned: + msg += "Globally Banned" + msg += f" with reason** `{reason}`" if reason else ".**" + else: + msg += "not Globally Banned.**" + await xx.edit(msg) + + +@ultroid_cmd(pattern="gblacklist$") +async def blacklist_(event): + await gblacker(event, "add") + + +@ultroid_cmd(pattern="ungblacklist$") +async def ungblacker(event): + await gblacker(event, "remove") + + +async def gblacker(event, type_): + try: + chat_id = int(event.text.split(maxsplit=1)[1]) + try: + chat_id = (await event.client.get_entity(chat_id)).id + except Exception as e: + return await event.eor(f"**ERROR**\n`{str(e)}`") + except IndexError: + chat_id = event.chat_id + if type_ == "add": + keym.add(chat_id) + elif type_ == "remove": + keym.remove(chat_id) + await event.eor(f"Global Broadcasts: \n{type_}ed {chat_id}") diff --git a/plugins/gpt.py b/plugins/gpt.py new file mode 100644 index 0000000000000000000000000000000000000000..11f9f577fc77394f34169eec2cfeca3974b5611f --- /dev/null +++ b/plugins/gpt.py @@ -0,0 +1,183 @@ +import os +from collections import deque +from io import BytesIO + +from . import ( + ultroid_cmd, + async_searcher, + udB, + LOGS, + get_paste, +) + +GPT_CHAT_HISTORY = deque(maxlen=30) + +TELEGRAM_CHAR_LIMIT = 4096 # Telegram's message character limit + + +async def pastee(data): + err, linky = await get_paste(data) + if err: + return f">> [Raw Code Pasted Here](https://spaceb.in/{linky})\n" + else: + LOGS.error(linky) + return "" + + +@ultroid_cmd( + pattern=r"gpt( ([\s\S]*))?$", +) +async def openai_chat_gpt(e): + api_key = "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" + if not api_key: + return await e.eor("`OPENAI_API` key missing..", time=10) + + query = e.pattern_match.group(2) + reply = await e.get_reply_message() + + file_content = None + + if query: + # Check if query contains 'from filename' + if ' from ' in query: + query_text, filename = query.split(' from ', 1) + query_text = query_text.strip() + filename = filename.strip() + # Attempt to find and read the file from media in chat + file_found = False + async for message in e.client.iter_messages(e.chat_id, reverse=True, limit=50): + if message.media and message.file.name == filename: + if (message.file.name.endswith(".txt") or message.file.name.endswith(".py")): + file = await e.client.download_media(message) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + file_found = True + break + if not file_found: + return await e.eor(f"`File {filename} not found in recent messages.`", time=5) + if file_content: + query = f"{query_text}\n\n{file_content}" if query_text else file_content + else: + return await e.eor("`Failed to read file content.`", time=5) + else: + if reply and reply.media and (reply.file.name.endswith(".txt") or reply.file.name.endswith(".py")): + # Use the query and the replied file content + file = await e.client.download_media(reply) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + query = f"{query}\n\n{file_content}" + elif reply and reply.message: + # Use the query and the replied text message content + query = f"{query}\n\n{reply.message}" + # Else, use query as is + else: + if reply and reply.media and (reply.file.name.endswith(".txt") or reply.file.name.endswith(".py")): + # Use the replied file content + file = await e.client.download_media(reply) + try: + with open(file, "r", encoding='utf-8') as f: + file_content = f.read() + except Exception as exc: + LOGS.error(f"Error reading file: {exc}") + return await e.eor("`Failed to read file content.`", time=5) + finally: + os.remove(file) + query = file_content + elif reply and reply.message: + # Use the replied text message content + query = reply.message + else: + return await e.eor("`Please provide a question or reply to a message or .txt/.py file.`", time=5) + + if query.strip() == "-c": + GPT_CHAT_HISTORY.clear() + return await e.eor("__Cleared o1-mini Chat History!__", time=6) + + eris = await e.eor(f"__Generating answer for:__\n`{query[:20]} ...`") + GPT_CHAT_HISTORY.append({"role": "user", "content": query}) + + try: + data = { + "model": "o1-mini", + "messages": list(GPT_CHAT_HISTORY), + } + request = await async_searcher( + "https://api.openai.com/v1/chat/completions", + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + }, + json=data, + re_json=True, + post=True, + ) + response = request["choices"][0]["message"]["content"] + GPT_CHAT_HISTORY.append({"role": "assistant", "content": response}) + except Exception as exc: + LOGS.warning(exc, exc_info=True) + GPT_CHAT_HISTORY.pop() + return await eris.edit( + f"**Error while requesting data from OpenAI:** \n> `{exc}`" + ) + + LOGS.debug(f'Tokens Used on query: {request["usage"]["completion_tokens"]}') + + # Truncate query to 50 characters for display + truncated_query = query[:100] + + # Prepare the full message + full_message = f"**Query:**\n~ __{truncated_query}__\n\n**o1-mini:**\n~ {response}" + + # Check if response contains code blocks + code_blocks = [] + in_code_block = False + code_block_lines = [] + for line in response.split('\n'): + if line.strip().startswith('```'): + if in_code_block: + # End of code block + in_code_block = False + code_blocks.append('\n'.join(code_block_lines)) + code_block_lines = [] + else: + # Start of code block + in_code_block = True + elif in_code_block: + code_block_lines.append(line) + + # If the response contains code blocks, select the largest one and paste it + if code_blocks: + # Select the largest code block based on length + largest_code_block = max(code_blocks, key=lambda block: len(block)) + # Upload the largest code block to spaceb.in and get the link + paste_link = await pastee(largest_code_block) + else: + paste_link = "" + + if len(full_message) <= TELEGRAM_CHAR_LIMIT: + # If it fits within the limit, send as a message + await eris.edit(full_message + f"\n\n{paste_link}") + else: + # If it exceeds the limit, send as a file and include paste link + file = BytesIO(full_message.encode('utf-8')) + file.name = "o1-mini-output.txt" + await eris.respond( + "__The query and response were too long, so they have been sent as a file.__\n\n" + paste_link, + file=file, + reply_to=e.reply_to_msg_id or e.id, + link_preview=False + ) + await eris.delete() + diff --git a/plugins/greetings.py b/plugins/greetings.py new file mode 100644 index 0000000000000000000000000000000000000000..6254a6be539c94ee6529ae141d12cb9ab7807bf1 --- /dev/null +++ b/plugins/greetings.py @@ -0,0 +1,205 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +---- Welcomes ---- +• `{i}setwelcome ` + Set welcome message in the current chat. + +• `{i}clearwelcome` + Delete the welcome in the current chat. + +• `{i}getwelcome` + Get the welcome message in the current chat. + +---- GoodByes ---- +• `{i}setgoodbye ` + Set goodbye message in the current chat. + +• `{i}cleargoodbye` + Delete the goodbye in the current chat. + +• `{i}getgoodbye` + Get the goodbye message in the current chat. + +• `{i}thankmembers on/off` + Send a thank you sticker on hitting a members count of 100*x in your groups. +""" +import os + +from telegraph import upload_file as uf +from telethon.utils import pack_bot_file_id + +from pyUltroid.dB.greetings_db import ( + add_goodbye, + add_thanks, + add_welcome, + delete_goodbye, + delete_welcome, + get_goodbye, + get_welcome, + must_thank, + remove_thanks, +) +from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button + +from . import HNDLR, eor, get_string, mediainfo, ultroid_cmd +from ._inline import something + +Note = "\n\nNote: `{mention}`, `{group}`, `{count}`, `{name}`, `{fullname}`, `{username}`, `{userid}` can be used as formatting parameters.\n\n" + + +@ultroid_cmd(pattern="setwelcome", groups_only=True) +async def setwel(event): + x = await event.eor(get_string("com_1")) + r = await event.get_reply_message() + btn = format_btn(r.buttons) if (r and r.buttons) else None + try: + text = event.text.split(maxsplit=1)[1] + except IndexError: + text = r.text if r else None + if r and r.media: + wut = mediainfo(r.media) + if wut.startswith(("pic", "gif")): + dl = await r.download_media() + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + elif wut == "video": + if r.media.document.size > 8 * 1000 * 1000: + return await eor(x, get_string("com_4"), time=5) + dl = await r.download_media() + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + elif wut == "web": + m = None + else: + m = pack_bot_file_id(r.media) + if r.text: + txt = r.text + if not btn: + txt, btn = get_msg_button(r.text) + add_welcome(event.chat_id, txt, m, btn) + else: + add_welcome(event.chat_id, None, m, btn) + await eor(x, get_string("grt_1")) + elif text: + if not btn: + txt, btn = get_msg_button(text) + add_welcome(event.chat_id, txt, None, btn) + await eor(x, get_string("grt_1")) + else: + await eor(x, get_string("grt_3"), time=5) + + +@ultroid_cmd(pattern="clearwelcome$", groups_only=True) +async def clearwel(event): + if not get_welcome(event.chat_id): + return await event.eor(get_string("grt_4"), time=5) + delete_welcome(event.chat_id) + await event.eor(get_string("grt_5"), time=5) + + +@ultroid_cmd(pattern="getwelcome$", groups_only=True) +async def listwel(event): + wel = get_welcome(event.chat_id) + if not wel: + return await event.eor(get_string("grt_4"), time=5) + msgg, med = wel["welcome"], wel["media"] + if wel.get("button"): + btn = create_tl_btn(wel["button"]) + return await something(event, msgg, med, btn) + await event.reply(f"**Welcome Note in this chat**\n\n`{msgg}`", file=med) + await event.delete() + + +@ultroid_cmd(pattern="setgoodbye", groups_only=True) +async def setgb(event): + x = await event.eor(get_string("com_1")) + r = await event.get_reply_message() + btn = format_btn(r.buttons) if (r and r.buttons) else None + try: + text = event.text.split(maxsplit=1)[1] + except IndexError: + text = r.text if r else None + if r and r.media: + wut = mediainfo(r.media) + if wut.startswith(("pic", "gif")): + dl = await r.download_media() + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + elif wut == "video": + if r.media.document.size > 8 * 1000 * 1000: + return await eor(x, get_string("com_4"), time=5) + dl = await r.download_media() + variable = uf(dl) + os.remove(dl) + m = f"https://graph.org{variable[0]}" + elif wut == "web": + m = None + else: + m = pack_bot_file_id(r.media) + if r.text: + txt = r.text + if not btn: + txt, btn = get_msg_button(r.text) + add_goodbye(event.chat_id, txt, m, btn) + else: + add_goodbye(event.chat_id, None, m, btn) + await eor(x, "`Goodbye note saved`") + elif text: + if not btn: + txt, btn = get_msg_button(text) + add_goodbye(event.chat_id, txt, None, btn) + await eor(x, "`Goodbye note saved`") + else: + await eor(x, get_string("grt_7"), time=5) + + +@ultroid_cmd(pattern="cleargoodbye$", groups_only=True) +async def clearwgb(event): + if not get_goodbye(event.chat_id): + return await event.eor(get_string("grt_6"), time=5) + delete_goodbye(event.chat_id) + await event.eor("`Goodbye Note Deleted`", time=5) + + +@ultroid_cmd(pattern="getgoodbye$", groups_only=True) +async def listgd(event): + wel = get_goodbye(event.chat_id) + if not wel: + return await event.eor(get_string("grt_6"), time=5) + msgg = wel["goodbye"] + med = wel["media"] + if wel.get("button"): + btn = create_tl_btn(wel["button"]) + return await something(event, msgg, med, btn) + await event.reply(f"**Goodbye Note in this chat**\n\n`{msgg}`", file=med) + await event.delete() + + +@ultroid_cmd(pattern="thankmembers (on|off)", groups_only=True) +async def thank_set(event): + type_ = event.pattern_match.group(1).strip() + if not type_ or type_ == "": + await eor( + event, + f"**Current Chat Settings:**\n**Thanking Members:** `{must_thank(event.chat_id)}`\n\nUse `{HNDLR}thankmembers on` or `{HNDLR}thankmembers off` to toggle current settings!", + ) + return + chat = event.chat_id + if type_.lower() == "on": + add_thanks(chat) + elif type_.lower() == "off": + remove_thanks(chat) + await eor( + event, + f"**Done! Thank you members has been turned** `{type_.lower()}` **for this chat**!", + ) diff --git a/plugins/imagetools.py b/plugins/imagetools.py new file mode 100644 index 0000000000000000000000000000000000000000..ef633427e4df89fb6d964a4fbce7f83001561f69 --- /dev/null +++ b/plugins/imagetools.py @@ -0,0 +1,292 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}border ` + To create border around that media.. + Ex - `{i}border 12,22,23` + - `{i}border 12,22,23 ; width (in number)` + +• `{i}grey ` + To make it black nd white. + +• `{i}color ` + To make it Colorfull. + +• `{i}toon ` + To make it toon. + +• `{i}danger ` + To make it look Danger. + +• `{i}negative ` + To make negative image. + +• `{i}blur ` + To make it blurry. + +• `{i}quad ` + create a Vortex. + +• `{i}mirror ` + To create mirror pic. + +• `{i}flip ` + To make it flip. + +• `{i}sketch ` + To draw its sketch. + +• `{i}blue ` + just cool. + +• `{i}csample ` + example : `{i}csample red` + `{i}csample #ffffff` + +• `{i}pixelator ` + Create a Pixelated Image.. +""" +import os + +from . import LOGS, con + +try: + import cv2 +except ImportError: + LOGS.error(f"{__file__}: OpenCv not Installed.") + +import numpy as np + +try: + from PIL import Image +except ImportError: + Image = None + LOGS.info(f"{__file__}: PIL not Installed.") +from telegraph import upload_file as upf +from telethon.errors.rpcerrorlist import ( + ChatSendMediaForbiddenError, + MessageDeleteForbiddenError, +) + +from . import ( + Redis, + async_searcher, + download_file, + get_string, + requests, + udB, + ultroid_cmd, +) + + +@ultroid_cmd(pattern="color$") +async def _(event): + reply = await event.get_reply_message() + if not (reply and reply.media): + return await event.eor("`Reply To a Black and White Image`") + xx = await event.eor("`Coloring image 🎨🖌️...`") + image = await reply.download_media() + img = cv2.VideoCapture(image) + ret, frame = img.read() + cv2.imwrite("ult.jpg", frame) + if udB.get_key("DEEP_API"): + key = Redis("DEEP_API") + else: + key = "quickstart-QUdJIGlzIGNvbWluZy4uLi4K" + r = requests.post( + "https://api.deepai.org/api/colorizer", + files={"image": open("ult.jpg", "rb")}, + headers={"api-key": key}, + ) + os.remove("ult.jpg") + os.remove(image) + if "status" in r.json(): + return await event.edit( + r.json()["status"] + "\nGet api nd set `{i}setdb DEEP_API key`" + ) + r_json = r.json()["output_url"] + await event.client.send_file(event.chat_id, r_json, reply_to=reply) + await xx.delete() + + +@ultroid_cmd(pattern="(grey|blur|negative|danger|mirror|quad|sketch|flip|toon)$") +async def ult_tools(event): + match = event.pattern_match.group(1) + ureply = await event.get_reply_message() + if not (ureply and (ureply.media)): + await event.eor(get_string("cvt_3")) + return + ultt = await ureply.download_media() + xx = await event.eor(get_string("com_1")) + if ultt.endswith(".tgs"): + xx = await xx.edit(get_string("sts_9")) + file = await con.convert(ultt, convert_to="png", outname="ult") + ult = cv2.imread(file) + if match == "grey": + ultroid = cv2.cvtColor(ult, cv2.COLOR_BGR2GRAY) + elif match == "blur": + ultroid = cv2.GaussianBlur(ult, (35, 35), 0) + elif match == "negative": + ultroid = cv2.bitwise_not(ult) + elif match == "danger": + dan = cv2.cvtColor(ult, cv2.COLOR_BGR2RGB) + ultroid = cv2.cvtColor(dan, cv2.COLOR_HSV2BGR) + elif match == "mirror": + ish = cv2.flip(ult, 1) + ultroid = cv2.hconcat([ult, ish]) + elif match == "flip": + trn = cv2.flip(ult, 1) + ish = cv2.rotate(trn, cv2.ROTATE_180) + ultroid = cv2.vconcat([ult, ish]) + elif match == "quad": + ult = cv2.imread(file) + roid = cv2.flip(ult, 1) + mici = cv2.hconcat([ult, roid]) + fr = cv2.flip(mici, 1) + trn = cv2.rotate(fr, cv2.ROTATE_180) + ultroid = cv2.vconcat([mici, trn]) + elif match == "sketch": + gray_image = cv2.cvtColor(ult, cv2.COLOR_BGR2GRAY) + inverted_gray_image = 255 - gray_image + blurred_img = cv2.GaussianBlur(inverted_gray_image, (21, 21), 0) + inverted_blurred_img = 255 - blurred_img + ultroid = cv2.divide(gray_image, inverted_blurred_img, scale=256.0) + elif match == "toon": + height, width, _ = ult.shape + samples = np.zeros([height * width, 3], dtype=np.float32) + count = 0 + for x in range(height): + for y in range(width): + samples[count] = ult[x][y] + count += 1 + _, labels, centers = cv2.kmeans( + samples, + 12, + None, + (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001), + 5, + cv2.KMEANS_PP_CENTERS, + ) + centers = np.uint8(centers) + ish = centers[labels.flatten()] + ultroid = ish.reshape(ult.shape) + cv2.imwrite("ult.jpg", ultroid) + await ureply.reply( + file="ult.jpg", + force_document=False, + ) + await xx.delete() + os.remove("ult.jpg") + os.remove(file) + + +@ultroid_cmd(pattern="csample (.*)") +async def sampl(ult): + if color := ult.pattern_match.group(1).strip(): + img = Image.new("RGB", (200, 100), f"{color}") + img.save("csample.png") + try: + try: + await ult.delete() + await ult.respond(f"Colour Sample for `{color}` !", file="csample.png") + except MessageDeleteForbiddenError: + await ult.reply(f"Colour Sample for `{color}` !", file="csample.png") + except ChatSendMediaForbiddenError: + await ult.eor("Umm! Sending Media is disabled here!") + + else: + await ult.eor("Wrong Color Name/Hex Code specified!") + + +@ultroid_cmd( + pattern="blue$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await event.eor("`...`") + if not (ureply and (ureply.media)): + await xx.edit(get_string("cvt_3")) + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit(get_string("sts_9")) + file = await con.convert(ultt, convert_to="png", outname="ult") + got = upf(file) + lnk = f"https://graph.org{got[0]}" + r = await async_searcher( + f"https://nekobot.xyz/api/imagegen?type=blurpify&image={lnk}", re_json=True + ) + ms = r.get("message") + if not r["success"]: + return await xx.edit(ms) + await download_file(ms, "ult.png") + img = Image.open("ult.png").convert("RGB") + img.save("ult.webp", "webp") + await event.client.send_file( + event.chat_id, + "ult.webp", + force_document=False, + reply_to=event.reply_to_msg_id, + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.webp") + os.remove(ultt) + + +@ultroid_cmd(pattern="border( (.*)|$)") +async def ok(event): + hm = await event.get_reply_message() + if not (hm and (hm.photo or hm.sticker)): + return await event.eor("`Reply to Sticker or Photo..`") + col = event.pattern_match.group(1).strip() + wh = 20 + if not col: + col = [255, 255, 255] + else: + try: + if ";" in col: + col_ = col.split(";", maxsplit=1) + wh = int(col_[1]) + col = col_[0] + col = [int(col) for col in col.split(",")[:2]] + except ValueError: + return await event.eor("`Not a Valid Input...`") + okla = await hm.download_media() + img1 = cv2.imread(okla) + constant = cv2.copyMakeBorder(img1, wh, wh, wh, wh, cv2.BORDER_CONSTANT, value=col) + cv2.imwrite("output.png", constant) + await event.client.send_file(event.chat.id, "output.png") + os.remove("output.png") + os.remove(okla) + await event.delete() + + +@ultroid_cmd(pattern="pixelator( (.*)|$)") +async def pixelator(event): + reply_message = await event.get_reply_message() + if not (reply_message and (reply_message.photo or reply_message.sticker)): + return await event.eor("`Reply to a photo`") + hw = 50 + try: + hw = int(event.pattern_match.group(1).strip()) + except (ValueError, TypeError): + pass + msg = await event.eor(get_string("com_1")) + image = await reply_message.download_media() + input_ = cv2.imread(image) + height, width = input_.shape[:2] + w, h = (hw, hw) + temp = cv2.resize(input_, (w, h), interpolation=cv2.INTER_LINEAR) + output = cv2.resize(temp, (width, height), interpolation=cv2.INTER_NEAREST) + cv2.imwrite("output.jpg", output) + await msg.respond("• Pixelated by Ultroid", file="output.jpg") + await msg.delete() + os.remove("output.jpg") + os.remove(image) diff --git a/plugins/imagine.py b/plugins/imagine.py new file mode 100644 index 0000000000000000000000000000000000000000..7bbffcb7af7b0debd8257fb48f1e3fbe74b56797 --- /dev/null +++ b/plugins/imagine.py @@ -0,0 +1,80 @@ +from os import system, remove +import json +import requests +import urllib.request +import os +from . import ultroid_cmd, udB, LOGS, run_async + +# Ensure the necessary library is installed +try: + import requests +except ImportError: + system("pip install requests") + import requests + +@run_async +def generate_dalle_image(prompt, api_key): + url = "https://aiassistquizapp899573677638.openai.azure.com/openai/deployments/Dalle3/images/generations?api-version=2024-02-15-preview" + headers = { + "api-key": api_key, + "content-type": "application/json; charset=UTF-8", + "accept-encoding": "gzip", + "user-agent": "okhttp/4.10.0" + } + data = { + "response_format": "url", + "model": "dall-e-3", + "n": 1, + "prompt": prompt, + "size": "1024x1792" + } + + response = requests.post(url, headers=headers, data=json.dumps(data)) + if response.status_code == 200: + result = response.json() + return result["data"][0] + else: + return {"error": f"Error: {response.status_code} - {response.text}"} + +@ultroid_cmd(pattern="imagine(?: |$)(.*)") +async def dalle_generator(event): + api_key = udB.get_key("DALL_E_API") + if not api_key: + return await event.eor("DALL_E_API key missing..") + + query = event.pattern_match.group(1) + if not query: + reply = await event.get_reply_message() + if reply and reply.text: + query = reply.text + if not query: + return await event.eor("`need a prompt to generate image! `", time=6) + + eris = await event.eor(f"__Generating image for:__\n`{query[:128]} ...`") + + response = await generate_dalle_image(query, api_key) + if "error" in response: + await eris.edit(response["error"]) + else: + image_url = response["url"] + revised_prompt = response.get("revised_prompt", "No revised prompt available.") + image_path = "generated_image.png" + + try: + # Download the image + urllib.request.urlretrieve(image_url, image_path) + + # Send the image + await event.client.send_file( + event.chat_id, + image_path, + caption=f"Model: • ([source]({image_url}))\n• $${revised_prompt}$$", + reply_to=event.id + ) + await eris.delete() + except Exception as e: + await eris.edit(f"Failed to download or send image: {str(e)}") + finally: + # Remove the downloaded image after sending + if os.path.exists(image_path): + remove(image_path) \ No newline at end of file diff --git a/plugins/lastonult.py b/plugins/lastonult.py new file mode 100644 index 0000000000000000000000000000000000000000..725113b93dd7b3a6073b215406a9f85703bcbecb --- /dev/null +++ b/plugins/lastonult.py @@ -0,0 +1,387 @@ +""" +❍ Commands Available - + +• `{i}lastonline` + +• `{i}seen ` + + 🌀 __@TrueSaiyan__ 🌀 +""" + +import html + +import motor.motor_asyncio +import pytz +from telethon import events, types +from telethon.tl.functions.channels import GetParticipantsRequest +from telethon.tl.types import ( + ChannelParticipantsSearch, + User, + UserStatusOffline, + UserStatusOnline, + UserStatusRecently, +) + +from . import * + +if udB.get_key("MONg"): + lastSeendB = udB.get_key("MONg") +else: + lastSeendB = "mongodb+srv://LastSeenUlt:YKzBfhfjtObPfQLD@cluster0.iil65vg.mongodb.net/" + +# MongoDB client setup +mongo_client = motor.motor_asyncio.AsyncIOMotorClient(lastSeendB) +db = mongo_client["User_Status"] +collection = db["user_data"] + +# Define the UTC timezone and Local timezone +if udB.get_key("TIMEZONE"): + localTZ = udB.get_key("TIMEZONE") +else: + localTZ = "Asia/Kolkata" + +utc_tz = pytz.utc +perth_tz = pytz.timezone(localTZ) + + +async def mention_user(user_id): + entity = await ultroid_bot.get_entity(user_id) + mention = get_display_name(entity) + escaped_mention = html.escape(mention) + permalink = f"{escaped_mention}" + return permalink + + +async def get_group_members_last_online(event): + group = await event.client.get_entity(event.chat_id) + participants = await event.client( + GetParticipantsRequest(group, ChannelParticipantsSearch(""), 0, 25, hash=0) + ) + + users_currently_online = [] + users_last_online = [] + users_unknown_status = [] + + for user in participants.users: + if isinstance(user, User) and not user.bot: + user_status = user.status + user_id = user.id + + if isinstance(user_status, UserStatusOffline): + was_online_utc = user_status.was_online.replace(tzinfo=utc_tz) + users_last_online.append((was_online_utc, user)) + elif isinstance(user_status, UserStatusOnline): + users_currently_online.append(user) + else: + # Check the database for last seen data + db_user = await collection.find_one({"user_id": user_id}) + if db_user: + last_online_db = db_user.get("last_online_time") + if last_online_db: + last_online_db = last_online_db.replace(tzinfo=utc_tz) + users_last_online.append((last_online_db, user)) + else: + users_unknown_status.append(user) + else: + users_unknown_status.append(user) + + users_last_online.sort(key=lambda x: x[0], reverse=True) + + result = "Last Online Times for Group Members:\n\n" + + for user in users_currently_online: + mention_text = await mention_user(user.id) + result += f"╭ User: {mention_text} ({user.id})\n" + result += f"⌬ Status: Currently online\n" + result += "╰──────────────\n\n" + + for last_online_time, user in users_last_online: + mention_text = await mention_user(user.id) + last_online_perth = last_online_time.astimezone(perth_tz) + readable_time = last_online_perth.strftime("%d/%m/%Y %I:%M:%S %p %Z%z") + result += f"╭ User: {mention_text} ({user.id})\n" + result += f"⌬ Last Online: {readable_time}\n" + result += "╰──────────────\n\n" + + for user in users_unknown_status: + mention_text = await mention_user(user.id) + result += f"╭ User: {mention_text} ({user.id})\n" + result += f"⌬ Status: Unknown or unsupported\n" + result += "╰──────────────\n\n" + + return result + + +@ultroid_cmd(pattern="lastonline$", manager=True) +async def _(event): + xx = await event.eor( + "Fetching last online times for group members...", parse_mode="html" + ) + try: + result = await get_group_members_last_online(event) + await xx.edit(result, parse_mode="html") + except Exception as er: + await xx.edit(f"ERROR : {er}") + + +async def get_user_last_online(event, user_id): + user = await event.client.get_entity(user_id) + mention_text = await mention_user(user.id) + + if not user.bot: + user_status = user.status + + # Check the database for last seen data + db_user = await collection.find_one({"user_id": user.id}) + if db_user: + first_seen = db_user.get("first_seen") + current_username = db_user.get("username") + last_online_db = db_user.get("last_online_time") + previous_usernames = db_user.get("previous_usernames", []) + + if isinstance(user_status, UserStatusOffline) or isinstance( + user_status, UserStatusRecently + ): + if last_online_db: + last_online_db = last_online_db.replace(tzinfo=utc_tz).astimezone( + perth_tz + ) + readable_last_online = last_online_db.strftime( + "%d/%m/%Y %I:%M:%S %p %Z%z" + ) + if first_seen: + if user.id == 5575183435: + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ First Seen: {first_seen}\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Current Username: @{current_username}" + ) + first_seen = first_seen.replace(tzinfo=utc_tz).astimezone( + perth_tz + ) + readable_first_seen = first_seen.strftime( + "%d/%m/%Y %I:%M:%S %p %Z%z" + ) + if previous_usernames: + prev_usernames_text = ", @".join(previous_usernames) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ First Seen: {readable_first_seen}\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Previous Usernames: @{prev_usernames_text}" + ) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ First Seen: {readable_first_seen}\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Current Username: @{current_username}" + ) + + if previous_usernames: + prev_usernames_text = ", @".join(previous_usernames) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Previous Usernames: @{prev_usernames_text}" + ) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Current Username: @{current_username}" + ) + + elif isinstance(user_status, UserStatusOnline): + if previous_usernames: + prev_usernames_text = ", @".join(previous_usernames) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Status: Currently online\n" + f"⌬ Previous Usernames: @{prev_usernames_text}" + ) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Status: Currently online\n" + f"⌬ Current Username: @{current_username}" + ) + + else: + try: + was_online_utc = user_status.was_online.replace(tzinfo=utc_tz) + was_online_perth = was_online_utc.astimezone(perth_tz) + readable_time = was_online_perth.strftime( + "%d/%m/%Y %I:%M:%S %p %Z%z" + ) + if previous_usernames: + prev_usernames_text = ", @".join(previous_usernames) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Last Online: {readable_time}\n" + f"⌬ Previous Usernames: @{prev_usernames_text}" + ) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Last Online: {readable_time}\n" + f"⌬ Current Username: @{current_username}" + ) + except Exception: + if last_online_db: + last_online_db = last_online_db.replace( + tzinfo=utc_tz + ).astimezone(perth_tz) + readable_last_online = last_online_db.strftime( + "%d/%m/%Y %I:%M:%S %p %Z%z" + ) + if first_seen: + first_seen = first_seen.replace(tzinfo=utc_tz).astimezone( + perth_tz + ) + readable_first_seen = first_seen.strftime( + "%d/%m/%Y %I:%M:%S %p %Z%z" + ) + if previous_usernames: + prev_usernames_text = ", @".join(previous_usernames) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ First Seen: {readable_first_seen}\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Previous Usernames: @{prev_usernames_text}" + ) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ First Seen: {readable_first_seen}\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Current Username: @{current_username}" + ) + if previous_usernames: + prev_usernames_text = ", @".join(previous_usernames) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Previous Usernames: @{prev_usernames_text}" + ) + return ( + f"User: {mention_text} ({user.id})\n" + f"⌬ Last Online: {readable_last_online}\n" + f"⌬ Current Username: @{current_username}" + ) + + return f"User: {mention_text} ({user.id})\n⌬ Status: Unknown or unsupported" + + else: + return f"User: {mention_text} ({user.id}) is a bot and their status is not tracked." + + +async def last_online_info(event, user_id): + user = await event.client.get_entity(user_id) + mention_text = inline_mention(user) + + if not user.bot: + user.status + + try: + db_user = await collection.find_one({"user_id": user.id}) + if db_user: + db_user.get("first_seen") + last_online_db = db_user.get("last_online_time") + if last_online_db: + last_online_db = last_online_db.replace(tzinfo=utc_tz).astimezone( + perth_tz + ) + readable_last_online = last_online_db.strftime( + "%d/%m/%Y %I:%M:%S %p %Z%z" + ) + return f"{readable_last_online}" + return f"\n⌬ Status: Unknown or unsupported" + except Exception as e: + LOGS.error(f"Error: {e}") + else: + return f"User: {mention_text} ({user.id}) is a bot and their status is not tracked." + + +@ultroid_cmd(pattern="seen(?: |$)(.*)", manager=True) +async def _(event): + input_str = event.pattern_match.group(1) + xx = await event.eor("Fetching last online time...", parse_mode="html") + + try: + if input_str: + if input_str.isdigit(): + user_id = int(input_str) + result = await get_user_last_online(event, user_id) + await xx.edit(result, parse_mode="html") + else: + user = await event.client.get_entity(input_str) + result = await get_user_last_online(event, user.id) + await xx.edit(result, parse_mode="html") + else: + reply = await event.get_reply_message() + if reply and reply.sender_id: + result = await get_user_last_online(event, reply.sender_id) + await xx.edit(result, parse_mode="html") + else: + await xx.edit( + "Please specify a username or user ID or reply to a user's message to get their last online time." + ) + except Exception as e: + await xx.edit(f"Error: {e}") + + +@ultroid_bot.on(events.NewMessage(incoming=True)) +@ultroid_bot.on(events.ChatAction) +async def all_messages_catcher(event): + if isinstance(event, events.NewMessage.Event): + sender = await event.get_sender() + utc_time = event.date.replace(tzinfo=utc_tz) + elif isinstance(event, events.ChatAction.Event): + utc_time = event.action_message.date.replace(tzinfo=utc_tz) + sender = await event.action_message.get_sender() + else: + return + + if sender is None: + return + + if isinstance(sender, types.User) and (sender.bot or sender.verified): + return + + + perth_time = utc_time.astimezone(perth_tz) + + user_id = sender.id + username = sender.username or None + + existing_user = await collection.find_one({"user_id": user_id}) + + if existing_user: + last_username = existing_user.get("username") + + if last_username != username: + previous_usernames = existing_user.get("previous_usernames", []) + if last_username: + previous_usernames.append(last_username) + + await collection.update_one( + {"user_id": user_id}, + { + "$set": { + "last_online_time": perth_time, + "username": username, + "previous_usernames": previous_usernames, + } + }, + ) + else: + await collection.update_one( + {"user_id": user_id}, {"$set": {"last_online_time": perth_time}} + ) + else: + await collection.insert_one( + { + "user_id": user_id, + "username": username, + "first_seen": perth_time, + "last_online_time": perth_time, + "previous_usernames": [], + } + ) \ No newline at end of file diff --git a/plugins/lipsync.py b/plugins/lipsync.py new file mode 100644 index 0000000000000000000000000000000000000000..14311573db19762c84ed8db25ee7972c683b10f1 --- /dev/null +++ b/plugins/lipsync.py @@ -0,0 +1,73 @@ +from os import remove +from io import BytesIO +import random + +try: + import requests +except ImportError: + system("pip install -q requests") + import requests + +from . import ultroid_cmd, check_filename, fast_download, run_async, LOGS, async_searcher + + +async def synthesize_lipsync(face_video_path, text): + url = "https://3v305hiwo6tem3-8888.proxy.runpod.net/synthesize" + headers = { + "User-Agent": "Dart/3.5 (dart:io)", + "Content-Type": "application/json", + "Accept-Encoding": "gzip", + } + data = { + "face": face_video_path, + "text": text, + "wav2lip_settings": { + "nosmooth": True, + "resize_factor": 2 + }, + "tts_settings": { + "voice_id": "LtPsVjX1k0Kl4StEMZPK" + } + } + response = await async_searcher(url, headers=headers, json=data, post=True, re_json=True) + return response + +@ultroid_cmd(pattern="lipsync( (.*)|$)") +async def lipsync(event): + text = event.pattern_match.group(2) + reply = await event.get_reply_message() + + if not text and reply and reply.text: + text = reply.text + + if not text: + return await event.eor("Please provide the text to lip-sync.") + + status_message = await event.eor("🔄 Processing lip-sync...") + face_video_path = None + + if reply and reply.media: + await status_message.edit("📥 Downloading face video...") + face_video_path = await event.client.download_media(reply.media) + else: + # Generate a random number between 1 and 10 for the face video path + random_number = random.randint(1, 10) + face_video_path = f"characters/2aigo/lipsync/{random_number}.mp4" + + try: + result = await synthesize_lipsync(face_video_path, text) + outfile_url = result.get('outfile') + if outfile_url: + await status_message.edit("📤 Uploading the result...") + result_file, _ = await fast_download(outfile_url, filename=check_filename("lipsynced_video.mp4")) + await event.client.send_file(event.chat_id, result_file, reply_to=event.reply_to_msg_id) + remove(result_file) + await status_message.delete() + else: + await status_message.edit("❌ Failed to generate the lip-synced video.") + except Exception as e: + LOGS.error(e, exc_info=True) + await status_message.edit(f"❌ An error occurred: {e}") + finally: + if face_video_path and not face_video_path.startswith("characters/2aigo/lipsync"): + remove(face_video_path) \ No newline at end of file diff --git a/plugins/locks.py b/plugins/locks.py new file mode 100644 index 0000000000000000000000000000000000000000..849c242164be9a5b588b513a6d868742eeb51311 --- /dev/null +++ b/plugins/locks.py @@ -0,0 +1,39 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}lock ` + Lock the Used Setting in Used Group. + +• `{i}unlock ` + UNLOCK the Used Setting in Used Group. +""" +from telethon.tl.functions.messages import EditChatDefaultBannedRightsRequest + +from pyUltroid.fns.admins import lock_unlock + +from . import ultroid_cmd + + +@ultroid_cmd( + pattern="(un|)lock( (.*)|$)", admins_only=True, manager=True, require="change_info" +) +async def un_lock(e): + mat = e.pattern_match.group(2).strip() + if not mat: + return await e.eor("`Give some Proper Input..`", time=5) + lock = e.pattern_match.group(1) == "" + ml = lock_unlock(mat, lock) + if not ml: + return await e.eor("`Incorrect Input`", time=5) + msg = "Locked" if lock else "Unlocked" + try: + await e.client(EditChatDefaultBannedRightsRequest(e.chat_id, ml)) + except Exception as er: + return await e.eor(str(er)) + await e.eor(f"**{msg}** - `{mat}` ! ") diff --git a/plugins/logo.py b/plugins/logo.py new file mode 100644 index 0000000000000000000000000000000000000000..92531bb1bf342597c0f3a9e1e4a12a1ce7cba95d --- /dev/null +++ b/plugins/logo.py @@ -0,0 +1,101 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}logo ` + Generate a logo of the given Text + Or Reply To image , to write ur text on it. + Or Reply To Font File, To write with that font. + +""" +import glob +import os +import random + +from telethon.tl.types import InputMessagesFilterPhotos + +try: + from PIL import Image +except ImportError: + Image = None +from pyUltroid.fns.misc import unsplashsearch +from pyUltroid.fns.tools import LogoHelper + +from . import OWNER_ID, OWNER_NAME, download_file, get_string, mediainfo, ultroid_cmd + + +@ultroid_cmd(pattern="logo( (.*)|$)") +async def logo_gen(event): + xx = await event.eor(get_string("com_1")) + name = event.pattern_match.group(1).strip() + if not name: + return await xx.eor("`Give a name too!`", time=5) + bg_, font_ = None, None + if event.reply_to_msg_id: + temp = await event.get_reply_message() + if temp.media: + if hasattr(temp.media, "document") and ( + ("font" in temp.file.mime_type) + or (".ttf" in temp.file.name) + or (".otf" in temp.file.name) + ): + font_ = await temp.download_media("resources/fonts/") + elif "pic" in mediainfo(temp.media): + bg_ = await temp.download_media() + if not bg_: + SRCH = [ + "background", + "neon", + "anime", + "art", + "bridges", + "streets", + "computer", + "cyberpunk", + "nature", + "abstract", + "exoplanet", + "magic", + "3d render", + ] + res = await unsplashsearch(random.choice(SRCH), limit=1) + bg_, _ = await download_file(res[0], "resources/downloads/logo.png") + newimg = "resources/downloads/unsplash-temp.jpg" + img_ = Image.open(bg_) + img_.save(newimg) + os.remove(bg_) + bg_ = newimg + + if not font_: + fpath_ = glob.glob("resources/fonts/*") + font_ = random.choice(fpath_) + if len(name) <= 8: + strke = 10 + elif len(name) >= 9: + strke = 5 + else: + strke = 20 + name = LogoHelper.make_logo( + bg_, + name, + font_, + fill="white", + stroke_width=strke, + stroke_fill="black", + ) + await xx.edit("`Done!`") + await event.client.send_file( + event.chat_id, + file=name, + caption=f"Logo by [{OWNER_NAME}](tg://user?id={OWNER_ID})", + force_document=True, + ) + os.remove(name) + await xx.delete() + if os.path.exists(bg_): + os.remove(bg_) diff --git a/plugins/mediatools.py b/plugins/mediatools.py new file mode 100644 index 0000000000000000000000000000000000000000..91773026da9ccf5e1d586cabd29d9c360d09b199 --- /dev/null +++ b/plugins/mediatools.py @@ -0,0 +1,146 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}mediainfo //` + To get info about it. + +• `{i}rotate ` + Rotate any video/photo/media.. + Note : for video it should be angle of 90's +""" +import os +import time +from datetime import datetime as dt + +from pyUltroid.fns.misc import rotate_image +from pyUltroid.fns.tools import make_html_telegraph + +from . import ( + LOGS, + Telegraph, + bash, + downloader, + get_string, + is_url_ok, + mediainfo, + ultroid_cmd, +) + +try: + import cv2 +except ImportError: + LOGS.info("WARNING: 'cv2' not found!") + cv2 = None + + +@ultroid_cmd(pattern="mediainfo( (.*)|$)") +async def mi(e): + r = await e.get_reply_message() + match = e.pattern_match.group(1).strip() + taime = time.time() + extra = "" + if r and r.media: + xx = mediainfo(r.media) + murl = r.media.stringify() + url = await make_html_telegraph("Mediainfo", f"
{murl}
") + extra = f"**[{xx}]({url})**\n\n" + e = await e.eor(f"{extra}`Loading More...`", link_preview=False) + + if hasattr(r.media, "document"): + file = r.media.document + mime_type = file.mime_type + filename = r.file.name + if not filename: + if "audio" in mime_type: + filename = "audio_" + dt.now().isoformat("_", "seconds") + ".ogg" + elif "video" in mime_type: + filename = "video_" + dt.now().isoformat("_", "seconds") + ".mp4" + dl = await downloader( + f"resources/downloads/{filename}", + file, + e, + taime, + f"{extra}`Loading More...`", + ) + + naam = dl.name + else: + naam = await r.download_media() + elif match and ( + os.path.isfile(match) + or (match.startswith("https://") and (await is_url_ok(match))) + ): + naam, xx = match, "file" + else: + return await e.eor(get_string("cvt_3"), time=5) + out, er = await bash(f"mediainfo '{naam}'") + if er: + LOGS.info(er) + out = extra or str(er) + return await e.edit(out, link_preview=False) + makehtml = "" + if naam.endswith((".jpg", ".png")): + if os.path.exists(naam): + med = "https://graph.org" + Telegraph.upload_file(naam)[0]["src"] + else: + med = match + makehtml += f"
" + for line in out.split("\n"): + line = line.strip() + if not line: + makehtml += "
" + elif ":" not in line: + makehtml += f"

{line}

" + else: + makehtml += f"

{line}

" + try: + urll = await make_html_telegraph("Mediainfo", makehtml) + except Exception as er: + LOGS.exception(er) + return + await e.eor(f"{extra}[{get_string('mdi_1')}]({urll})", link_preview=False) + if not match: + os.remove(naam) + + +@ultroid_cmd(pattern="rotate( (.*)|$)") +async def rotate_(ult): + match = ult.pattern_match.group(1).strip() + if not ult.is_reply: + return await ult.eor("`Reply to a media...`") + if match: + try: + match = int(match) + except ValueError: + match = None + if not match: + return await ult.eor("`Please provide a valid angle to rotate media..`") + reply = await ult.get_reply_message() + msg = await ult.eor(get_string("com_1")) + photo = reply.game.photo if reply.game else None + if reply.video: + media = await reply.download_media() + file = f"{media}.mp4" + await bash( + f'ffmpeg -i "{media}" -c copy -metadata:s:v:0 rotate={match} "{file}" -y' + ) + elif photo or reply.photo or reply.sticker: + media = await ult.client.download_media(photo or reply) + img = cv2.imread(media) + new_ = rotate_image(img, match) + file = "ult.png" + cv2.imwrite(file, new_) + else: + return await msg.edit("`Unsupported Media..\nReply to Photo/Video`") + if os.path.exists(file): + await ult.client.send_file( + ult.chat_id, file=file, video_note=bool(reply.video_note), reply_to=reply.id + ) + os.remove(media) + await msg.try_delete() diff --git a/plugins/misc.py b/plugins/misc.py new file mode 100644 index 0000000000000000000000000000000000000000..7a34a4ea6e1d2ebe64c530702053bc9b9189c3a3 --- /dev/null +++ b/plugins/misc.py @@ -0,0 +1,222 @@ +# Ultroid - UserBot +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}eod` + `Get Event of the Today` + +• `{i}pntrst ` + Download and send pinterest pins + +• `{i}gadget ` + Gadget Search from Telegram. + +• `{i}randomuser` + Generate details about a random user. + +• `{i}ascii ` + Convert replied image into html. + +• `{i}igdl ` + Download Instagram media +""" + +import os +from datetime import datetime as dt + +from bs4 import BeautifulSoup as bs + +from telethon import events +from telethon.errors.rpcerrorlist import YouBlockedUserError +from telethon.tl.types import DocumentAttributeVideo + +try: + from htmlwebshot import WebShot +except ImportError: + WebShot = None +try: + from img2html.converter import Img2HTMLConverter +except ImportError: + Img2HTMLConverter = None + +from . import async_searcher, get_random_user_data, get_string, re, ultroid_cmd, eod + + +async def get_gallery(msg_id): + msgs = await nimbus_bot.get_messages( + 5210630997, ids=[*range(msg_id - 9, msg_id + 10)] + ) + return [msg for msg in msgs if msg and msg.grouped_id == msgs[9].grouped_id] + +@ultroid_cmd(pattern="igdl ?(.*)$") +async def instagram(e): + listx = [] + durations = [] + resolutions = [] + inp = e.pattern_match.group(1) + chat = "@TopSaverBot" + load = await e.eor(get_pstring("com_1")) + async with e.client.conversation(chat) as conv: + try: + response = conv.wait_event( + events.NewMessage( + incoming=True, from_users=5210630997, func=lambda e: e.media + ) + ) + await e.client.send_message(chat, f"{inp}") + response = await response + await e.client.send_read_acknowledge(conv.chat_id) + if inp.split("/")[3] == "p": + url = f"[Pᴏsᴛ]({inp})" + captions = get_pstring("instagram_1").format(url) + if inp.split("/")[3] == "reel": + url = f"[Rᴇᴇʟ]({inp})" + captions = get_pstring("instagram_1").format(url) + if inp.split("/")[3] == "stories": + url = f"[Sᴛᴏʀʏ]({inp})" + captions = get_pstring("instagram_1").format(url) + except YouBlockedUserError: + await load.eor("Please Unblock the bot...", time=4) + except Exception: + await load.eor("No media found...", time=4) + + if response.grouped_id: + gallery_msgs = await get_gallery(response.id) + for msg in gallery_msgs: + media = msg.media + listx.append(media) + if media and hasattr(media.document, "attributes"): + for attribute in media.document.attributes: + if isinstance(attribute, DocumentAttributeVideo): + durations.append(int(attribute.duration)) + resolutions.append(f"{attribute.w}x{attribute.h}") + else: + listx.append(response.media) + if response.media and hasattr(response.media.document, "attributes"): + for attribute in response.media.document.attributes: + if isinstance(attribute, DocumentAttributeVideo): + durations.append(int(attribute.duration)) + resolutions.append(f"{attribute.w}x{attribute.h}") + + if durations: + durations_str = ", ".join([f"{d}s" for d in durations]) + captions += f"\n**Dᴜʀᴀᴛɪᴏɴs**: {durations_str}" + if resolutions: + resolutions_str = ", ".join(resolutions) + captions += f"\n**Rᴇsᴏʟᴜᴛɪᴏɴs**: {resolutions_str}" + + try: + await e.client.send_file( + e.chat_id, + file=listx, + caption=captions, + ) + await load.delete() + except Exception as er: + await e.eor(f"Unable to send media: {er}") + + + +@ultroid_cmd(pattern="eod$") +async def diela(e): + m = await e.eor(get_string("com_1")) + li = "https://daysoftheyear.com" + te = "🎊 **Events of the Day**\n\n" + da = dt.now() + month = da.strftime("%b") + li += f"/days/{month}/" + da.strftime("%F").split("-")[2] + ct = await async_searcher(li, re_content=True) + bt = bs(ct, "html.parser", from_encoding="utf-8") + ml = bt.find_all("a", "js-link-target", href=re.compile("daysoftheyear.com/days")) + for eve in ml[:5]: + te += f'• [{eve.text}]({eve["href"]})\n' + await m.edit(te, link_preview=False) + + +@ultroid_cmd( + pattern="pntrst( (.*)|$)", +) +async def pinterest(e): + m = e.pattern_match.group(1).strip() + if not m: + return await e.eor("`Give pinterest link.`", time=3) + soup = await async_searcher( + "https://www.expertstool.com/download-pinterest-video/", + data={"url": m}, + post=True, + ) + try: + _soup = bs(soup, "html.parser").find("table").tbody.find_all("tr") + except BaseException: + return await e.eor("`Wrong link or private pin.`", time=5) + file = _soup[1] if len(_soup) > 1 else _soup[0] + file = file.td.a["href"] + await e.client.send_file(e.chat_id, file, caption=f"Pin:- {m}") + + +@ultroid_cmd(pattern="gadget( (.*)|$)") +async def mobs(e): + mat = e.pattern_match.group(1).strip() + if not mat: + await e.eor("Please Give a Mobile Name to look for.") + query = mat.replace(" ", "%20") + jwala = f"https://gadgets.ndtv.com/search?searchtext={query}" + c = await async_searcher(jwala) + b = bs(c, "html.parser", from_encoding="utf-8") + co = b.find_all("div", "rvw-imgbox") + if not co: + return await e.eor("No Results Found!") + bt = await e.eor(get_string("com_1")) + out = "**📱 Mobile / Gadgets Search**\n\n" + li = co[0].find("a") + imu, title = None, li.find("img")["title"] + cont = await async_searcher(li["href"]) + nu = bs(cont, "html.parser", from_encoding="utf-8") + req = nu.find_all("div", "_pdsd") + imu = nu.find_all( + "img", src=re.compile("https://i.gadgets360cdn.com/products/large/") + ) + if imu: + imu = imu[0]["src"].split("?")[0] + "?downsize=*:420&output-quality=80" + out += f"☑️ **[{title}]({li['href']})**\n\n" + for fp in req: + ty = fp.findNext() + out += f"- **{ty.text}** - `{ty.findNext().text}`\n" + out += "_" + if imu == []: + imu = None + await e.reply(out, file=imu, link_preview=False) + await bt.delete() + + +@ultroid_cmd(pattern="randomuser") +async def _gen_data(event): + x = await event.eor(get_string("com_1")) + msg, pic = await get_random_user_data() + await event.reply(file=pic, message=msg) + await x.delete() + + +@ultroid_cmd( + pattern="ascii( (.*)|$)", +) +async def _(e): + if not Img2HTMLConverter: + return await e.eor("'img2html-converter' not installed!") + if not e.reply_to_msg_id: + return await e.eor(get_string("ascii_1")) + m = await e.eor(get_string("ascii_2")) + img = await (await e.get_reply_message()).download_media() + char = e.pattern_match.group(1).strip() or "■" + converter = Img2HTMLConverter(char=char) + html = converter.convert(img) + shot = WebShot(quality=85) + pic = await shot.create_pic_async(html=html) + await m.delete() + await e.reply(file=pic) + os.remove(pic) + os.remove(img) diff --git a/plugins/mute.py b/plugins/mute.py new file mode 100644 index 0000000000000000000000000000000000000000..2939908fa0fb5959ef01ae54d345c1054a38ee4c --- /dev/null +++ b/plugins/mute.py @@ -0,0 +1,210 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . +""" +✘ Commands Available - + +• `{i}mute ` + Mute user in current chat. + +• `{i}unmute ` + Unmute user in current chat. + +• `{i}dmute ` + Mute user in current chat by deleting msgs. + +• `{i}undmute ` + Unmute dmuted user in current chat. + +• `{i}tmute