From b0f6d58d77e0c4a4a211d92438060380f77f4c63 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 4 Mar 2021 23:00:10 +0530 Subject: [PATCH] Ultroid - v0.0.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ultroid - v0.0.3 Full Changelog - https://t.me/TheUltroid/21 Co-authored-by: Amit Sharma <48654350+buddhhu@users.noreply.github.com> Co-authored-by: Danish <72792730+1Danish-00@users.noreply.github.com> Co-authored-by: Aditya Co-authored-by: buddhhu Co-authored-by: New-dev0 Co-authored-by: 1Danish-00 <1Danish-00@users.noreply.github.com> Co-authored-by: Sρι∂у <68327188+sppidy@users.noreply.github.com> Co-authored-by: sppidy Co-authored-by: Arnab Paryali Co-authored-by: Programming Error Co-authored-by: ArnabXD Co-authored-by: xditya Co-authored-by: ProgrammingError --- .gitignore | 5 +- README.md | 2 +- assistant/api_setter.py | 5 +- assistant/customvars.py | 96 +++++++- assistant/inlinestuff.py | 2 + assistant/othervars.py | 133 +++++++++-- assistant/start.py | 38 ++- plugins/__init__.py | 40 +--- plugins/_help.py | 4 +- plugins/_inline.py | 83 +++++-- plugins/_wspr.py | 2 +- plugins/admintools.py | 15 +- plugins/afk.py | 2 +- plugins/autopic.py | 13 +- plugins/bot.py | 6 +- plugins/broadcast.py | 319 +++++++++++++++++++++++++ plugins/carbon.py | 2 +- plugins/chats.py | 2 +- plugins/converter.py | 91 +++++++ plugins/core.py | 10 +- plugins/fedutils.py | 4 +- plugins/gdrive.py | 211 ++++++++++++++++ plugins/github.py | 2 +- plugins/globaltools.py | 299 +++++++++++++++++++++++ plugins/google.py | 2 +- plugins/imagetools.py | 2 +- plugins/mute.py | 2 +- plugins/pdftools.py | 2 +- plugins/pmpermit.py | 61 ++++- plugins/profile.py | 5 +- plugins/redis.py | 23 +- plugins/specialtools.py | 2 +- plugins/stickertools.py | 35 ++- plugins/sudo.py | 26 +- plugins/tag.py | 96 ++++++++ plugins/tools.py | 10 +- plugins/uploads_files.py | 2 +- plugins/utilities.py | 109 ++++++--- plugins/words.py | 2 +- requirements.txt | 5 +- resources/extras/ultroid_assistant.jpg | Bin 0 -> 26622 bytes resources/startup/deploy.sh | 5 +- 42 files changed, 1551 insertions(+), 224 deletions(-) create mode 100644 plugins/broadcast.py create mode 100644 plugins/converter.py create mode 100644 plugins/gdrive.py create mode 100644 plugins/globaltools.py create mode 100644 plugins/tag.py create mode 100644 resources/extras/ultroid_assistant.jpg diff --git a/.gitignore b/.gitignore index 5f03c41..959f179 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ BOT_TOKEN.session *.tgs logs-ultroid.txt .vscode/* -ultroid-log.txt \ No newline at end of file +ultroid-log.txt +/*.jpg +/*.png +/*.mp4 \ No newline at end of file diff --git a/README.md b/README.md index 0a58b17..c34b7db 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ A stable pluggable Telegram userbot, based on Telethon.
More Info
- Documentation - ultroid.netlify.app
+ Documentation - ultroid.tech
# Deploy diff --git a/assistant/api_setter.py b/assistant/api_setter.py index a51ad68..cb11866 100644 --- a/assistant/api_setter.py +++ b/assistant/api_setter.py @@ -17,8 +17,9 @@ async def apiset(event): "Choose which API you want to set.", buttons=[ [Button.inline("Remove.bg", data="rmbg")], - [custom.Button.inline("« Back", data="setter")] - ]) + [custom.Button.inline("« Back", data="setter")], + ], + ) # remove.bg api diff --git a/assistant/customvars.py b/assistant/customvars.py index 7318a23..aa42fda 100644 --- a/assistant/customvars.py +++ b/assistant/customvars.py @@ -22,12 +22,12 @@ auth_url = r["auth_url"] @owner async def alvcs(event): await event.edit( - "Customise your {}alive. Choose from the below options -".format(Var.HNDLR), + "Customise your {}alive. Choose from the below options -".format(HNDLR), buttons=[ - [Button.inline("Alive Text", data="alvtx")], - [Button.inline("Alive Media", data="alvmed")], - [Button.inline("Delete Alive Media", data="delmed")], - [Button.inline("« Back", data="allcstms")] + [Button.inline("Aʟɪᴠᴇ Tᴇxᴛ", data="alvtx")], + [Button.inline("Aʟɪᴠᴇ ᴍᴇᴅɪᴀ", data="alvmed")], + [Button.inline("Dᴇʟᴇᴛᴇ Aʟɪᴠᴇ Mᴇᴅɪᴀ", data="delmed")], + [Button.inline("« Bᴀᴄᴋ", data="setter")], ], ) @@ -50,7 +50,11 @@ async def name(event): return await conv.send_message("Cancelled!!") else: await setit(event, var, themssg) - await conv.send_message("{} changed to {}\n\nDo {}restart".format(name, themssg, Var.HNDLR)) + await conv.send_message( + "{} changed to {}\n\nAfter Setting All Things Do restart".format( + name, themssg + ) + ) @callback("alvmed") @@ -101,10 +105,11 @@ async def alvcs(event): await event.edit( "Customise your PMPERMIT Settings -", buttons=[ - [Button.inline("PM Text", data="pmtxt")], - [Button.inline("Pm Media", data="pmmed")], - [Button.inline("Delete PM Media", data="delpmmed")], - [Button.inline("« Back", data="allcstms")] + [Button.inline("Pᴍ Tᴇxᴛ", data="pmtxt")], + [Button.inline("Pᴍ Mᴇᴅɪᴀ", data="pmmed")], + [Button.inline("PMLOGGER", data="pml")], + [Button.inline("Dᴇʟᴇᴛᴇ Pᴍ Mᴇᴅɪᴀ", data="delpmmed")], + [Button.inline("« Bᴀᴄᴋ", data="pmset")], ], ) @@ -118,7 +123,7 @@ async def name(event): name = "PM Text" async with event.client.conversation(pru) as conv: await conv.send_message( - "**PM Text**\nEnter the new Pmpermit text.\n\nUse /cancel to terminate the operation." + "**PM Text**\nEnter the new Pmpermit text.\n\nu can use `{name}` `{fullname}` `{count}` `{mention}` `{username}` Too\n\nUse /cancel to terminate the operation." ) response = conv.wait_event(events.NewMessage(chats=pru)) response = await response @@ -127,7 +132,11 @@ async def name(event): return await conv.send_message("Cancelled!!") else: await setit(event, var, themssg) - await conv.send_message("{} changed to {}\n\nDo {}restart".format(name, themssg, Var.HNDLR)) + await conv.send_message( + "{} changed to {}\n\nAfter Setting All Things Do restart".format( + name, themssg + ) + ) @callback("pmmed") @@ -139,7 +148,7 @@ async def media(event): name = "PM Media" async with event.client.conversation(pru) as conv: await conv.send_message( - "**PM Media**\nSend me a pic/gif/bot api id of sticker to set as Pmpermit media.\n\nUse /cancel to terminate the operation." + "**PM Media**\nSend me a pic/gif/bot api id of sticker to set as pmpermit media.\n\nUse /cancel to terminate the operation." ) response = await conv.get_response() try: @@ -170,3 +179,64 @@ async def dell(event): return await event.edit("Done!") except BaseException: return await event.edit("Something went wrong...") + + +@callback("pml") +@owner +async def alvcs(event): + await event.edit( + "PMLOGGER This Will Forward Ur Pm to Ur Private Group -", + buttons=[ + [Button.inline("PMLOGGER ON", data="pmlog")], + [Button.inline("PMLOGGER OFF", data="pmlogof")], + [Button.inline("« Bᴀᴄᴋ", data="pmcstm")], + ], + ) + + +@callback("pmlog") +@owner +async def pmlog(event): + var = "PMLOG" + await setit(event, var, "True") + await event.edit(f"Done!! PMLOGGER Started!!") + + +@callback("pmlogof") +@owner +async def pmlogof(event): + try: + udB.delete("PMLOG") + return await event.edit("Done! PMLOGGER Stopped!!") + except BaseException: + return await event.edit("Something went wrong...") + + +@callback("pmset") +@owner +async def pmset(event): + await event.edit( + "PMPermit Settings:", + buttons=[ + [Button.inline("Tᴜʀɴ PMPᴇʀᴍɪᴛ Oɴ", data="pmon")], + [Button.inline("Tᴜʀɴ PMPᴇʀᴍɪᴛ Oғғ", data="pmoff")], + [Button.inline("Cᴜsᴛᴏᴍɪᴢᴇ PMPᴇʀᴍɪᴛ", data="pmcstm")], + [Button.inline("« Bᴀᴄᴋ", data="setter")], + ], + ) + + +@callback("pmon") +@owner +async def pmonn(event): + var = "PMSETTING" + await setit(event, var, "True") + await event.edit(f"Done! PMPermit has been turned on!!") + + +@callback("pmoff") +@owner +async def pmofff(event): + var = "PMSETTING" + await setit(event, var, "False") + await event.edit(f"Done! PMPermit has been turned off!!") diff --git a/assistant/inlinestuff.py b/assistant/inlinestuff.py index 0597af3..9bad9bc 100644 --- a/assistant/inlinestuff.py +++ b/assistant/inlinestuff.py @@ -16,6 +16,8 @@ from search_engine_parser import GoogleSearch, YahooSearch from telethon import Button from telethon.tl.types import InputWebDocument as wb +from . import * + gugirl = "https://telegra.ph/file/0df54ae4541abca96aa11.jpg" yeah = "https://telegra.ph/file/e3c67885e16a194937516.jpg" ps = "https://telegra.ph/file/de0b8d9c858c62fae3b6e.jpg" diff --git a/assistant/othervars.py b/assistant/othervars.py index d72b374..ae00e7a 100644 --- a/assistant/othervars.py +++ b/assistant/othervars.py @@ -16,11 +16,65 @@ async def otvaar(event): await event.edit( "Other Variables to set for @TheUltroid:", buttons=[ - [Button.inline("Tag Logger", data="taglog")], - [Button.inline("PM Permit", data="pmset")], - [Button.inline("SuperFban", data="sfban")], - [Button.inline("« Back", data="setter")] - ]) + [Button.inline("Tᴀɢ Lᴏɢɢᴇʀ", data="taglog")], + [Button.inline("SᴜᴘᴇʀFʙᴀɴ", data="sfban")], + [ + Button.inline("Sᴜᴅᴏ Mᴏᴅᴇ", data="sudo"), + Button.inline("Hᴀɴᴅʟᴇʀ", data="hhndlr"), + ], + [ + Button.inline("Exᴛʀᴀ Pʟᴜɢɪɴs", data="plg"), + Button.inline("Aᴅᴅᴏɴs", data="eaddon"), + ], + [Button.inline("« Bᴀᴄᴋ", data="setter")], + ], + ) + + +@callback("plg") +@owner +async def pluginch(event): + await event.delete() + pru = event.sender_id + var = "PLUGIN_CHANNEL" + name = "Plugin Channel" + async with event.client.conversation(pru) as conv: + await conv.send_message( + "Send id or username of a channel from where u want to install all plugins\n\nOur Channel~ @ultroidplugins\n\nUse /cancel to cancel." + ) + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message( + "{} changed to {}\n After Setting All Things Do Restart".format( + name, themssg + ) + ) + + +@callback("hhndlr") +@owner +async def hndlrr(event): + await event.delete() + pru = event.sender_id + var = "HNDLR" + name = "Handler/ Trigger" + async with event.client.conversation(pru) as conv: + await conv.send_message( + f"Send The Symbol Which u want as Handler/Trigger to use bot\nUr Current Handler is [ `{HNDLR}` ]\n\n use /cancel to cancel." + ) + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message("{} changed to {}".format(name, themssg)) @callback("taglog") @@ -44,33 +98,70 @@ async def tagloggerr(event): await conv.send_message("{} changed to {}".format(name, themssg)) -@callback("pmset") +@callback("eaddon") @owner async def pmset(event): await event.edit( - "PMPermit Settings:", + "ADDONS~ Extra Plugins:", buttons=[ - [Button.inline("Turn PMPermit On", data="pmon")], - [Button.inline("Turn PMPermit Off", data="pmoff")], - [Button.inline("« Back", data="otvars")] + [Button.inline("Aᴅᴅᴏɴs Oɴ", data="edon")], + [Button.inline("Aᴅᴅᴏɴs Oғғ", data="edof")], + [Button.inline("« Bᴀᴄᴋ", data="otvars")], ], ) -@callback("pmon") +@callback("edon") @owner -async def pmonn(event): - var = "PMSETTING" +async def eddon(event): + var = "ADDONS" await setit(event, var, "True") - await event.edit(f"Done! PMPermit has been turned on!! Please `{hndlr}restart`") + await event.edit( + "Done! ADDONS has been turned on!!\n\n After Setting All Things Do Restart" + ) -@callback("pmoff") +@callback("edof") @owner -async def pmofff(event): - var = "PMSETTING" +async def eddof(event): + var = "ADDONS" await setit(event, var, "False") - await event.edit(f"Done! PMPermit has been turned off!! Please `{hndlr}restart`") + await event.edit( + "Done! ADDONS has been turned off!! After Setting All Things Do Restart" + ) + + +@callback("sudo") +@owner +async def pmset(event): + await event.edit( + f"SUDO MODE ~ Some peoples can use ur Bot which u selected. To know More use `{HNDLR}help sudo`", + buttons=[ + [Button.inline("Sᴜᴅᴏ Mᴏᴅᴇ Oɴ", data="onsudo")], + [Button.inline("Sᴜᴅᴏ Mᴏᴅᴇ Oғғ", data="ofsudo")], + [Button.inline("« Bᴀᴄᴋ", data="otvars")], + ], + ) + + +@callback("onsudo") +@owner +async def eddon(event): + var = "SUDO" + await setit(event, var, "True") + await event.edit( + "Done! SUDO MODE has been turned on!!\n\n After Setting All Things Do Restart" + ) + + +@callback("ofsudo") +@owner +async def eddof(event): + var = "SUDO" + await setit(event, var, "False") + await event.edit( + "Done! SUDO MODE has been turned off!! After Setting All Things Do Restart" + ) @callback("sfban") @@ -79,9 +170,9 @@ async def sfban(event): await event.edit( "SuperFban Settings:", buttons=[ - [Button.inline("FBan Group", data="sfgrp")], - [Button.inline("Exclude Feds", data="sfexf")], - [Button.inline("« Back", data="otvars")] + [Button.inline("FBᴀɴ Gʀᴏᴜᴘ", data="sfgrp")], + [Button.inline("Exᴄʟᴜᴅᴇ Fᴇᴅs", data="sfexf")], + [Button.inline("« Bᴀᴄᴋ", data="otvars")], ], ) diff --git a/assistant/start.py b/assistant/start.py index b7c03d7..76cce4b 100644 --- a/assistant/start.py +++ b/assistant/start.py @@ -27,7 +27,7 @@ async def assistant(event): f"Bot started by [{event.sender_id}](tg://user?id={event.sender_id})", ) ok = "" - if Var.MSG_FRWD is True: + if udB.get("MSG_FRWD") == True: ok = "You can contact me using this bot!!" if event.is_private and event.sender_id in sed: return @@ -46,12 +46,13 @@ async def ultroid(event): event.chat_id, f"Hi {OWNER_NAME}. Please browse through the options", buttons=[ - [Button.inline("Settings ⚙️", data="setter")], - [Button.inline("Stats", data="stat")], - [Button.inline("Broadcast", data="bcast")], + [Button.inline("Sᴇᴛᴛɪɴɢs ⚙️", data="setter")], + [Button.inline("Sᴛᴀᴛs", data="stat")], + [Button.inline("Bʀᴏᴀᴅᴄᴀsᴛ", data="bcast")], ], ) + # aah, repeat the codes.. @callback("mainmenu") @owner @@ -61,12 +62,13 @@ async def ultroid(event): await event.edit( f"Hi {OWNER_NAME}. Please browse through the options", buttons=[ - [Button.inline("Settings ⚙️", data="setter")], - [Button.inline("Stats", data="stat")], - [Button.inline("Broadcast", data="bcast")], + [Button.inline("Sᴇᴛᴛɪɴɢs ⚙️", data="setter")], + [Button.inline("Sᴛᴀᴛs", data="stat")], + [Button.inline("Bʀᴏᴀᴅᴄᴀsᴛ", data="bcast")], ], ) + @callback("stat") @owner async def botstat(event): @@ -120,20 +122,12 @@ async def setting(event): await event.edit( "Choose from the below options -", buttons=[ - [Button.inline("Customisations", data="allcstms")], - [Button.inline("API Keys", data="apiset")], - [Button.inline("Other Vars.", data="otvars")], - [Button.inline("« Back", data="mainmenu")] + [Button.inline("API Kᴇʏs", data="apiset")], + [ + Button.inline("Aʟɪᴠᴇ", data="alvcstm"), + Button.inline("PᴍPᴇʀᴍɪᴛ", data="pmset"), + ], + [Button.inline("Fᴇᴀᴛᴜʀᴇs", data="otvars")], + [Button.inline("« Bᴀᴄᴋ", data="mainmenu")], ], ) - -@callback("allcstms") -@owner -async def all(event): - await event.edit( - "All Customisable Stuff.", - buttons=[ - [Button.inline("Alive", data="alvcstm")], - [Button.inline("PM Permit", data="pmcstm")], - [Button.inline("« Back", data="setter")] - ]) \ No newline at end of file diff --git a/plugins/__init__.py b/plugins/__init__.py index f562b12..1daefe7 100644 --- a/plugins/__init__.py +++ b/plugins/__init__.py @@ -8,52 +8,20 @@ import time from pyUltroid import * +from pyUltroid.dB import * from pyUltroid.dB.core import * from pyUltroid.functions import * from pyUltroid.functions.all import * +from pyUltroid.functions.broadcast_db import * +from pyUltroid.functions.gban_mute_db import * from pyUltroid.functions.google_image import googleimagesdownload from pyUltroid.functions.sudos import * from pyUltroid.utils import * start_time = time.time() -ultroid_version = "v0.0.1" +ultroid_version = "v0.0.3" OWNER_NAME = ultroid_bot.me.first_name OWNER_ID = ultroid_bot.me.id -DEVLIST = [ - "1259468938", - "1452145387", - "719195224", - "1318486004", - "1289422521", - "1322549723", - "611816596", - "1003250439", - "1152902819", - "716243352", - "1444249738", - "559661211", - "881536550", - "630654925", -] - -# sudo -ok = udB.get("SUDOS") -if ok: - SUDO_USERS = set(int(x) for x in ok.split()) -else: - SUDO_USERS = "" - -if SUDO_USERS: - sudos = list(SUDO_USERS) -else: - sudos = "" - -on = Var.SUDO - -if Var.SUDO: - sed = [ultroid_bot.uid, *sudos] -else: - sed = [ultroid_bot.uid] def grt(seconds: int) -> str: diff --git a/plugins/_help.py b/plugins/_help.py index 9025b6f..fda2916 100644 --- a/plugins/_help.py +++ b/plugins/_help.py @@ -36,7 +36,7 @@ async def ult(ult): try: x = f"Plugin Name-{plug}\n\n✘ Commands Available-\n\n" for d in LIST[plug]: - x += Var.HNDLR + d + x += HNDLR + d x += "\n" await eor(ult, x) except BaseException: @@ -50,7 +50,7 @@ async def ult(ult): return await eor( ult, "`The bot did not respond to the inline query.\nConsider using {}restart`".format( - Var.HNDLR + HNDLR ), ) except dis: diff --git a/plugins/_inline.py b/plugins/_inline.py index 8607c0d..95d6e61 100644 --- a/plugins/_inline.py +++ b/plugins/_inline.py @@ -31,8 +31,8 @@ helps = """ Pʟᴜɢɪɴs ~ {}** """ - -if Var.ADDONS: +add_ons = udB.get("ADDONS") +if add_ons: zhelps = """ [Uʟᴛʀᴏɪᴅ Sᴜᴘᴘᴏʀᴛ](t.me/ultroidsupport) @@ -48,7 +48,7 @@ else: Aᴅᴅᴏɴs ~ {} -Gᴏ Aɴᴅ Aᴅᴅ ADDON Vᴀʀ Wɪᴛʜ Vᴀʟᴜᴇ Tʀᴜᴇ** +Gᴏ Aɴᴅ Aᴅᴅ ADDONS Vᴀʀ Wɪᴛʜ Vᴀʟᴜᴇ Tʀᴜᴇ** """ # ============================================# @@ -60,7 +60,7 @@ async def e(o): b = o.builder uptime = grt((time.time() - start_time)) ALIVEMSG = """ -**The Ultroid Userbot...**\n\n +**The Ultroid Userbot...**\n ✵ **Owner** - `{}` ✵ **Ultroid** - `{}` ✵ **UpTime** - `{}` @@ -82,6 +82,14 @@ async def e(o): description="Userbot | Telethon ", text=ALIVEMSG, thumb=InputWebDocument(ULTROID_PIC, 0, "image/jpeg", []), + buttons=[ + [Button.url(text="Support Group", url="t.me/UltroidSupport")], + [ + Button.url( + text="Repo", url="https://github.com/Teamultroid/Ultroid" + ) + ], + ], ) ] await o.answer(res, switch_pm=f"👥 ULTROID PORTAL", switch_pm_param="start") @@ -96,19 +104,37 @@ if Var.BOT_USERNAME is not None and asst is not None: result = None query = event.text if event.query.user_id in sed and query.startswith("ultd"): + z = [] + for x in LIST.values(): + for y in x: + z.append(y) + cmd = len(z) + 10 + bn = Var.BOT_USERNAME + if bn.startswith("@"): + bnn = bn.replace("@", "") + else: + bnn = bn result = builder.article( title="Help Menu", description="Help Menu - UserBot | Telethon ", url="https://t.me/TheUltroid", thumb=InputWebDocument(ULTROID_PIC, 0, "image/jpeg", []), - text=f"** Bᴏᴛ Oғ {OWNER_NAME}\n\nMᴀɪɴ Mᴇɴᴜ\n\nPʟᴜɢɪɴs ~ {len(PLUGINS) - 4}\nAᴅᴅᴏɴs ~ {len(ADDONS)}**", + text=f"** Bᴏᴛ Oғ {OWNER_NAME}\n\nMᴀɪɴ Mᴇɴᴜ\n\nPʟᴜɢɪɴs ~ {len(PLUGINS) - 4}\nAᴅᴅᴏɴs ~ {len(ADDONS)}\nTᴏᴛᴀʟ Cᴏᴍᴍᴀɴᴅs ~ {cmd}**", buttons=[ [ Button.inline("• Pʟᴜɢɪɴs", data="hrrrr"), Button.inline("• Aᴅᴅᴏɴs", data="frrr"), ], - [Button.inline("Oᴡɴᴇʀ•ᴛᴏᴏʟꜱ", data="ownr")], - [Button.inline("Iɴʟɪɴᴇ•Pʟᴜɢɪɴs", data="inlone")], + [ + Button.inline("Oᴡɴᴇʀ•ᴛᴏᴏʟꜱ", data="ownr"), + Button.inline("Iɴʟɪɴᴇ•Pʟᴜɢɪɴs", data="inlone"), + ], + [ + Button.url( + "⚙️Sᴇᴛᴛɪɴɢs⚙️", + url=f"https://t.me/{bnn}?start={ultroid_bot.me.id}", + ) + ], [Button.inline("••Cʟᴏꜱᴇ••", data="close")], ], ) @@ -166,7 +192,7 @@ if Var.BOT_USERNAME is not None and asst is not None: [ Button.switch_inline( "Sᴇɴᴅ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs", - query="send all", + query="send", same_peer=True, ) ], @@ -201,7 +227,7 @@ if Var.BOT_USERNAME is not None and asst is not None: [ Button.switch_inline( "YᴏᴜTᴜʙᴇ Dᴏᴡɴʟᴏᴀᴅᴇʀ", - query="yt How to Deploy Ultroid Userbot", + query="Ed Sheeran Perfect", same_peer=True, ) ], @@ -310,17 +336,34 @@ if Var.BOT_USERNAME is not None and asst is not None: @callback("open") @owner async def opner(event): + bn = Var.BOT_USERNAME + if bn.startswith("@"): + bnn = bn.replace("@", "") + else: + bnn = bn buttons = [ [ Button.inline("• Pʟᴜɢɪɴs ", data="hrrrr"), Button.inline("• Aᴅᴅᴏɴs", data="frrr"), ], - [Button.inline("Oᴡɴᴇʀ•Tᴏᴏʟꜱ", data="ownr")], - [Button.inline("Iɴʟɪɴᴇ•Pʟᴜɢɪɴs", data="inlone")], + [ + Button.inline("Oᴡɴᴇʀ•Tᴏᴏʟꜱ", data="ownr"), + Button.inline("Iɴʟɪɴᴇ•Pʟᴜɢɪɴs", data="inlone"), + ], + [ + Button.url( + "⚙️Sᴇᴛᴛɪɴɢs⚙️", url=f"https://t.me/{bnn}?start={ultroid_bot.me.id}" + ) + ], [Button.inline("••Cʟᴏꜱᴇ••", data="close")], ] + z = [] + for x in LIST.values(): + for y in x: + z.append(y) + cmd = len(z) + 10 await event.edit( - f"** Bᴏᴛ Oғ {OWNER_NAME}\n\nMᴀɪɴ Mᴇɴᴜ\n\nOꜰꜰɪᴄɪᴀʟ Pʟᴜɢɪɴs ~ {len(PLUGINS) - 4}\nUɴᴏꜰꜰɪᴄɪᴀʟ Pʟᴜɢɪɴs ~ {len(ADDONS)}**", + f"** Bᴏᴛ Oғ {OWNER_NAME}\n\nMᴀɪɴ Mᴇɴᴜ\n\nPʟᴜɢɪɴs ~ {len(PLUGINS) - 4}\nAᴅᴅᴏɴs ~ {len(ADDONS)}\nTᴏᴛᴀʟ Cᴏᴍᴍᴀɴᴅs ~ {cmd}**", buttons=buttons, link_preview=False, ) @@ -394,7 +437,7 @@ if Var.BOT_USERNAME is not None and asst is not None: f"Plugin Name-{plugin_name}\n\n✘ Commands Available-\n\n" ) for d in LIST[plugin_name]: - help_string += Var.HNDLR + d + help_string += HNDLR + d help_string += "\n" except BaseException: pass @@ -423,8 +466,11 @@ if Var.BOT_USERNAME is not None and asst is not None: def paginate_help(page_number, loaded_plugins, prefix): number_of_rows = 5 number_of_cols = 2 - multi = os.environ.get("EMOJI_TO_DESPLAY_IN_HELP", "✘") - mult2i = os.environ.get("EMOJI2_TO_DESPLAY_IN_HELP", "✘") + emoji = Redis("EMOJI_IN_HELP") + if emoji: + multi, mult2i = emoji, emoji + else: + multi, mult2i = "✘", "✘" helpable_plugins = [] global upage upage = page_number @@ -470,8 +516,11 @@ def paginate_help(page_number, loaded_plugins, prefix): def paginate_addon(page_number, loaded_plugins, prefix): number_of_rows = 5 number_of_cols = 2 - multi = os.environ.get("EMOJI_TO_DESPLAY_IN_HELP", "✘") - mult2i = os.environ.get("EMOJI2_TO_DESPLAY_IN_HELP", "✘") + emoji = Redis("EMOJI_IN_HELP") + if emoji: + multi, mult2i = emoji, emoji + else: + multi, mult2i = "✘", "✘" helpable_plugins = [] global addpage addpage = page_number diff --git a/plugins/_wspr.py b/plugins/_wspr.py index bc93db0..d799203 100644 --- a/plugins/_wspr.py +++ b/plugins/_wspr.py @@ -45,7 +45,7 @@ async def _(e): return await eor( e, "`The bot did not respond to the inline query.\nConsider using {}restart`".format( - Var.HNDLR + HNDLR ), ) except dis: diff --git a/plugins/admintools.py b/plugins/admintools.py index cddc252..27464e0 100644 --- a/plugins/admintools.py +++ b/plugins/admintools.py @@ -154,6 +154,8 @@ async def bban(ult): user, reason = await get_user_info(ult) if not user: return await xx.edit("`Reply to a user or give username to ban him!`") + if str(user.id) in DEVLIST: + return await xx.edit(" `LoL, I can't Ban my Developer 😂`") await xx.edit("`Getting user info...`") try: await ultroid_bot( @@ -233,6 +235,13 @@ async def uunban(ult): groups_only=True, ) async def kck(ult): + tt = ult.text + try: + tx = tt[5] + if tx: + return + except BaseException: + pass xx = await eor(ult, "`Processing...`") chat = await ult.get_chat() isAdmin = chat.admin_rights @@ -242,6 +251,8 @@ async def kck(ult): user, reason = await get_user_info(ult) if not user: return await xx.edit("`Kick? Whom? I couldn't get his info...`") + if str(user.id) in DEVLIST: + return await xx.edit(" `Lol, I can't Kick my Developer`😂") await xx.edit("`Kicking...`") try: await ultroid_bot.kick_participant(ult.chat_id, user.id) @@ -274,7 +285,7 @@ async def pin(msg): tt = msg.text try: kk = tt[4] - if kk == "g": + if kk: return except BaseException: pass @@ -451,4 +462,4 @@ async def editer(edit): i = i + 1 -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/afk.py b/plugins/afk.py index 45c412e..5da8f75 100644 --- a/plugins/afk.py +++ b/plugins/afk.py @@ -249,4 +249,4 @@ async def _(event): logger.warn(str(e)) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/autopic.py b/plugins/autopic.py index 9389532..3627135 100644 --- a/plugins/autopic.py +++ b/plugins/autopic.py @@ -8,18 +8,14 @@ """ ✘ Commands Available - -• `{i}autopic ` +• `{i}autopic ` Will change your profile pic at defined intervals with pics related to the given topic. """ import asyncio import os import random -import re -import urllib -from bs4 import BeautifulSoup as bs -from requests import get from telethon import functions from . import * @@ -33,7 +29,10 @@ async def autopic(e): clls = returnpage(search) if len(clls) == 0: return await eor(e, f"No Results found for `{search}`") - num = random.randrange(0, len(clls) - 1) + if not len(clls) == 1: + num = random.randrange(0, len(clls) - 1) + else: + num = 0 page = clls[num] title = page["title"] a = await eor( @@ -47,4 +46,4 @@ async def autopic(e): await asyncio.sleep(1100) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/bot.py b/plugins/bot.py index 7d3c121..66fa350 100644 --- a/plugins/bot.py +++ b/plugins/bot.py @@ -73,14 +73,14 @@ async def lol(ult): **{}** -┏━━━━━━━━━━━━━━━━━━━━━━ +┏━━━━━━━━━━━━━━━━━━━━━ ┣ **Owner** - `{}` ┣ **Version** - `{}` ┣ **UpTime** - `{}` ┣ **Python** - `{}` ┣ **Telethon** - `{}` ┣ **Branch** - `{}` -┗━━━━━━━━━━━━━━━━━━━━━━ +┗━━━━━━━━━━━━━━━━━━━━━ """.format( header, OWNER_NAME, @@ -231,4 +231,4 @@ async def shht(event): await ultroid_bot.disconnect() -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/broadcast.py b/plugins/broadcast.py new file mode 100644 index 0000000..f370b8e --- /dev/null +++ b/plugins/broadcast.py @@ -0,0 +1,319 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available + +• `{i}add ` + Add chat to database. Adds current chat if no id specified. + +• `{i}rem ` + Removes the specified chat (current chat if none specified), or all chats. + +• `{i}broadcast ` + Send the replied message to all chats in database. + +• `{i}forward ` + Forward the message to all chats in database. + +• `{i}listchannels` + To get list of all added chats. +""" +import asyncio +import io + +from . import * + + +@ultroid_cmd(pattern="add ?(.*)") +async def broadcast_adder(event): + if "addsudo" in event.text: # weird fix + return + msgg = event.pattern_match.group(1) + x = await eor(event, "`Adding to db...`") + aldone = new = crsh = 0 + if msgg == "all": + await x.edit("`Trying to add all admin channels to db...`") + chats = [ + e.entity + for e in await ultroid.get_dialogs() + if (e.is_group or e.is_channel) + ] + for i in chats: + try: + if i.broadcast: + if i.creator or i.admin_rights: + if is_channel_added(i.id): + aldone += 1 + else: + cid = f"-100{i.id}" + add_channel(int(cid)) + new += 1 + except BaseException: + pass + await x.edit( + f"**Done.**\nChats already in Database: {get_no_channels()}\nNewly Added: {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 is_channel_added(channel_id): + add_channel(channel_id) + await x.edit("Channels added!") + await asyncio.sleep(3) + await event.delete() + return + chat_id = event.chat_id + try: + if int(chat_id) == Var.LOG_CHANNEL: + return + except BaseException: + pass + if not is_channel_added(chat_id): + x = add_channel(chat_id) + if x: + await x.edit("`Added to database!`") + else: + await x.edit("Error") + await asyncio.sleep(3) + await event.delete() + elif is_channel_added(chat_id): + await x.edit("`Channel is already is database!`") + await asyncio.sleep(3) + await event.delete() + + +@ultroid_cmd(pattern="rem ?(.*)") +async def broadcast_remover(event): + chat_id = event.pattern_match.group(1) + x = await eor(event, "`Processing...`") + if chat_id == "all": + await x.edit("`Removing...`") + udB.delete("BROADCAST") + await x.edit("Database cleared.") + return + if is_channel_added(chat_id): + rem_channel(chat_id) + await x.edit("Removed from database") + await asyncio.sleep(3) + await x.delete() + elif is_channel_added(event.chat_id): + rem_channel(event.chat_id) + await x.edit("Removed from database") + await asyncio.sleep(3) + await x.delete() + elif not is_channel_added(event.chat_id): + await x.edit("Channel is already removed from database. ") + await asyncio.sleep(3) + await x.delete() + + +@ultroid_cmd(pattern="listchannels") +async def list_all(event): + x = await eor(event, "`Calculating...`") + channels = get_channels() + num = get_no_channels() + if num == 0: + return await eod(x, "No chats were added.", time=5) + msg = "Channels in database:\n" + for channel in channels: + name = "" + try: + name = (await ultroid.get_entity(int(channel))).title + except: + name = "" + msg += f"=> **{name}** [`{channel}`]\n" + msg += f"\nTotal {get_no_channels()} channels." + if len(msg) > 4096: + 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="Channels in database", + reply_to=event, + ) + await x.delete() + else: + await x.edit(msg) + + +@ultroid_cmd(pattern="forward ?(.*)") +async def forw(event): + if event.fwd_from: + return + if not event.is_reply: + await eor(event, "Reply to a message to broadcast.") + return + channels = get_channels() + x = await eor(event, "Sending...") + if get_no_channels() == 0: + return await x.edit(f"Please add channels by using `{hndlr}add` in them.") + error_count = 0 + sent_count = 0 + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + previous_message.message + previous_message.raw_text + error_count = 0 + for channel in channels: + try: + await ultroid_bot.forward_messages(int(channel), previous_message) + sent_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + except Exception as error: + try: + await ultroid_bot.send_message( + Var.LOG_CHANNEL, f"Error in sending at {channel}." + ) + await ultroid_bot.send_message(Var.LOG_CHANNEL, "Error! " + str(error)) + if error == "The message cannot be empty unless a file is provided": + return await x.edit( + "For sending files, upload in Saved Messages and reply .forward to it." + ) + except BaseException: + pass + 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: + try: + await ultroid_bot.send_message(Var.LOG_CHANNEL, f"{error_count} Errors") + except BaseException: + await x.edit("Set up log channel for checking errors.") + + +@ultroid_cmd(pattern="broadcast ?(.*)") +async def sending(event): + x = await eor(event, "`Processing...`") + if not event.is_reply: + return await x.edit("Reply to a message to broadcast.") + channels = get_channels() + error_count = 0 + sent_count = 0 + if len(channels) == 0: + return await x.edit( + f"You haven't added any channels. Use `{hndlr}add` in them fist!" + ) + await x.edit("Sending....") + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + if previous_message.sticker or previous_message.poll: + await x.edit(f"Reply `{hndlr}forward` for stickers and polls.") + return + if ( + previous_message.gif + or previous_message.audio + or previous_message.voice + or previous_message.video + or previous_message.video_note + or previous_message.contact + or previous_message.game + or previous_message.geo + or previous_message.invoice + ): + await x.edit(f"Not supported. Try `{hndlr}forward`") + return + if not previous_message.web_preview and previous_message.photo: + file = await ultroid_bot.download_file(previous_message.media) + uploaded_doc = await ultroid_bot.upload_file(file, file_name="img.png") + raw_text = previous_message.text + for channel in channels: + try: + if previous_message.photo: + await ultroid_bot.send_file( + int(channel), + InputMediaUploadedPhoto(file=uploaded_doc), + force_document=False, + caption=raw_text, + link_preview=False, + ) + + sent_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + except Exception as error: + try: + await ultroid_bot.send_message( + Var.LOG_CHANNEL, f"Error in sending at {channel}." + ) + await ultroid_bot.send_message( + Var.LOG_CHANNEL, "Error! " + str(error) + ) + if ( + error + == "The message cannot be empty unless a file is provided" + ): + return await x.edit( + f"For sending files, upload in Saved Messages and reply {hndlr}forward to in." + ) + except BaseException: + pass + 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: + try: + await ultroid_bot.send_message( + Var.LOG_CHANNEL, f"{error_count} Errors" + ) + except BaseException: + pass + else: + raw_text = previous_message.text + for channel in channels: + try: + await ultroid_bot.send_message( + int(channel), raw_text, link_preview=False + ) + sent_count += 1 + await x.edit( + f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", + ) + except Exception as error: + try: + await ultroid_bot.send_message( + Var.LOG_CHANNEL, f"Error in sending at {channel}." + ) + await ultroid_bot.send_message( + Var.LOG_CHANNEL, "Error! " + str(error) + ) + if ( + error + == "The message cannot be empty unless a file is provided" + ): + return await x.edit( + f"For sending files, upload in Saved Messages and reply {hndlr}forward to in." + ) + except BaseException: + pass + 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: + try: + await ultroid_bot.send_message( + Var.LOG_CHANNEL, f"{error_count} Errors" + ) + except BaseException: + await x.edit("Set up log channel for checking errors.") diff --git a/plugins/carbon.py b/plugins/carbon.py index e6c3369..31f0eab 100644 --- a/plugins/carbon.py +++ b/plugins/carbon.py @@ -232,4 +232,4 @@ async def crbn(event): os.remove(xx) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/chats.py b/plugins/chats.py index f0a57d0..a9805f0 100644 --- a/plugins/chats.py +++ b/plugins/chats.py @@ -114,4 +114,4 @@ async def _(e): await xx.edit(str(ex)) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/converter.py b/plugins/converter.py new file mode 100644 index 0000000..a358f9f --- /dev/null +++ b/plugins/converter.py @@ -0,0 +1,91 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}rename ` + rename the file + +• `{i}mtoi ` + media to image conversion + +• `{i}mtos ` + convert media to sticker. +""" + +import os + +import cv2 +from PIL import Image + +from . import * + + +@ultroid_cmd(pattern="rename ?(.*)") +async def imak(event): + reply = await event.get_reply_message() + if not reply: + await eor(event, "Reply to any media/Document.") + return + inp = event.pattern_match.group(1) + if not inp: + await eor(event, "Give The name nd extension of file") + return + xx = await eor(event, "`Processing...`") + image = await ultroid_bot.download_media(reply) + os.rename(image, inp) + await ultroid_bot.send_file(event.chat_id, inp, reply_to=reply) + os.remove(inp) + await xx.delete() + + +@ultroid_cmd(pattern="mtoi$") +async def imak(event): + reply = await event.get_reply_message() + if not (reply and (reply.media)): + await eor(event, "Reply to any media.") + return + xx = await eor(event, "`Processing...`") + image = await ultroid_bot.download_media(reply) + file = "ult.png" + if image.endswith((".webp", ".png")): + c = Image.open(image) + c.save(file) + else: + img = cv2.VideoCapture(image) + ult, roid = img.read() + cv2.imwrite(file, roid) + await ultroid_bot.send_file(event.chat_id, file, reply_to=reply) + await xx.delete() + os.remove(file) + os.remove(image) + + +@ultroid_cmd(pattern="mtos$") +async def smak(event): + reply = await event.get_reply_message() + if not (reply and (reply.media)): + await eor(event, "Reply to any media.") + return + xx = await eor(event, "`Processing...`") + image = await ultroid_bot.download_media(reply) + file = "ult.webp" + if image.endswith((".webp", ".png", ".jpg")): + c = Image.open(image) + c.save(file) + else: + img = cv2.VideoCapture(image) + ult, roid = img.read() + cv2.imwrite(file, roid) + await ultroid_bot.send_file(event.chat_id, file, reply_to=reply) + await xx.delete() + os.remove(file) + os.remove(image) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/core.py b/plugins/core.py index ab1821d..4e5e9ef 100644 --- a/plugins/core.py +++ b/plugins/core.py @@ -119,8 +119,8 @@ async def unload(event): try: un_plug(shortname) await eod(event, f"**Uɴʟᴏᴀᴅᴇᴅ** `{shortname}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**", time=3) - except BaseException: - pass + except Exception as ex: + return await eor(event, str(ex)) elif zym in lst: return await eod(event, "**Yᴏᴜ Cᴀɴ'ᴛ Uɴʟᴏᴀᴅ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs**", time=3) else: @@ -143,8 +143,8 @@ async def uninstall(event): un_plug(shortname) await eod(event, f"**Uɴɪɴsᴛᴀʟʟᴇᴅ** `{shortname}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**", time=3) os.remove(f"addons/{shortname}.py") - except BaseException: - pass + except Exception as ex: + return await eor(event, str(ex)) elif zym in lst: return await eod(event, "**Yᴏᴜ Cᴀɴ'ᴛ Uɴɪɴsᴛᴀʟʟ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs**", time=3) else: @@ -174,4 +174,4 @@ async def load(event): ) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/fedutils.py b/plugins/fedutils.py index da24359..8059026 100644 --- a/plugins/fedutils.py +++ b/plugins/fedutils.py @@ -25,7 +25,9 @@ Specify FBan Group and Feds to exclude in the assistant. import asyncio import os + from telethon.errors.rpcerrorlist import YouBlockedUserError + from . import * bot = "@MissRose_bot" @@ -391,4 +393,4 @@ async def _(event): await ok.edit("**Error**\n `Unblock` @MissRose_Bot `and try again!") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/gdrive.py b/plugins/gdrive.py new file mode 100644 index 0000000..da9cc15 --- /dev/null +++ b/plugins/gdrive.py @@ -0,0 +1,211 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +""" +✘ Commands Available + +• `{i}ulgdrive ` + Reply to file to upload on Google Drive. + Add file name to upload on Google Drive. + +• `{i}drivesearch ` + Search file name on Google Drive and get link. + +• `{i}uldir ` + Upload a directory on Google Drive. + +• `{i}gfolder` + Link to your Google Drive Folder. + If added then all uploaded files will be placed here. +""" + + +import asyncio +import os +import time +from datetime import datetime + +from telethon import events + +from . import * + +TOKEN_FILE = "resources/downloads/auth_token.txt" +TEMP_DOWNLOAD_DIRECTORY = "resources/downloads/" + + +@asst_cmd("auth") +async def aut(event): + if event.is_group: + return + if os.path.exists(TOKEN_FILE): + return await event.reply("`You have already authorised with Google Drive`") + if Redis("GDRIVE_CLIENT_ID") == None or Redis("GDRIVE_CLIENT_SECRET") == None: + await event.reply( + "Go [here](https://console.developers.google.com/flows/enableapi?apiid=drive) and get your GDRIVE_CLIENT_ID and GDRIVE_CLIENT_SECRET\n\n" + + "Send your GDRIVE_CLIENT_ID and GDRIVE_CLIENT_SECRET as this.\n`GDRIVE_CLIENT_ID GDRIVE_CLIENT_SECRET` separated by space.", + ) + async with asst.conversation(ultroid_bot.uid) as conv: + reply = conv.wait_event(events.NewMessage(from_users=ultroid_bot.uid)) + repl = await reply + try: + creds = repl.text.split(" ") + id = creds[0] + if not id.endswith("com"): + return await event.reply("`Wrong Client Id`") + try: + secret = creds[1] + except IndexError: + return await event.reply("`No Client Secret Found`") + udB.set("GDRIVE_CLIENT_ID", id) + udB.set("GDRIVE_CLIENT_SECRET", secret) + return await repl.reply("`Success!` Now send /auth again") + except Exception as exx: + return await repl.reply( + "`Something went wrong! Send `/auth` again.\nIf same happens contact `@TheUltroid" + ) + else: + storage = await create_token_file(TOKEN_FILE, event) + http = authorize(TOKEN_FILE, storage) + f = open(TOKEN_FILE, "r") + token_file_data = f.read() + udB.set("GDRIVE_TOKEN", token_file_data) + await event.reply( + "`Success!\nYou are all set to use Google Drive with Ultroid Userbot.`" + ) + + +@ultroid_cmd( + pattern="ulgdrive ?(.*)", +) +async def _(event): + mone = await eor(event, "Processing ...") + if not os.path.exists(TOKEN_FILE): + return await eod(mone, f"`Go to `{Var.BOT_USERNAME}` and send ``/auth.`") + input_str = event.pattern_match.group(1) + required_file_name = None + start = datetime.now() + dddd = time.time() + if event.reply_to_msg_id and not input_str: + reply_message = await event.get_reply_message() + try: + downloaded_file_name = await event.client.download_media( + reply_message, + TEMP_DOWNLOAD_DIRECTORY, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress( + d, + t, + mone, + dddd, + "Downloading...", + ), + ), + ) + except Exception as e: + return await eod(mone, str(e), time=10) + end = datetime.now() + ms = (end - start).seconds + required_file_name = downloaded_file_name + await mone.edit( + "Downloaded to `{}` in {} seconds.".format(downloaded_file_name, ms) + ) + elif input_str: + input_str = input_str.strip() + if os.path.exists(input_str): + end = datetime.now() + ms = (end - start).seconds + required_file_name = input_str + await mone.edit("Found `{}` in {} seconds.".format(input_str, ms)) + else: + return await eod( + mone, "File Not found in local server. Give me a file path :((", time=5 + ) + if required_file_name: + http = authorize(TOKEN_FILE, None) + file_name, mime_type = file_ops(required_file_name) + try: + g_drive_link = await upload_file( + http, + required_file_name, + file_name, + mime_type, + mone, + Redis("GDRIVE_FOLDER_ID"), + ) + await mone.edit( + "**Successfully Uploaded File on G-Drive :**\n\n[{}]({})".format( + file_name, g_drive_link + ) + ) + except Exception as e: + await mone.edit(f"Exception occurred while uploading to gDrive {e}") + else: + return await eod(mone, "`File Not found in local server.`", time=10) + + +@ultroid_cmd( + pattern="drivesearch ?(.*)", +) +async def sch(event): + if not os.path.exists(TOKEN_FILE): + return await eod(mone, f"`Go to `{Var.BOT_USERNAME}` and send ``/auth.`") + http = authorize(TOKEN_FILE, None) + input_str = event.pattern_match.group(1).strip() + a = await eor(event, "Searching for {} in G-Drive.".format(input_str)) + if Redis("GDRIVE_FOLDER_ID") is not None: + query = "'{}' in parents and (title contains '{}')".format( + Redis("GDRIVE_FOLDER_ID"), input_str + ) + else: + query = "title contains '{}'".format(input_str) + try: + msg = await gsearch(http, query, input_str) + return await a.edit(str(msg)) + except Exception as ex: + return await a.edit(str(ex)) + + +@ultroid_cmd( + pattern="uldir ?(.*)", +) +async def _(event): + if not os.path.exists(TOKEN_FILE): + return await eod(mone, f"`Go to `{Var.BOT_USERNAME}` and send ``/auth.`") + input_str = event.pattern_match.group(1) + if os.path.isdir(input_str): + http = authorize(TOKEN_FILE, None) + a = await eor(event, "Uploading `{}` to G-Drive...".format(input_str)) + dir_id = await create_directory( + http, + os.path.basename(os.path.abspath(input_str)), + Redis("GDRIVE_FOLDER_ID"), + ) + await DoTeskWithDir(http, input_str, event, dir_id) + dir_link = "https://drive.google.com/folderview?id={}".format(dir_id) + await eod( + a, + f"**Successfully Uploaded Folder To G-Drive...**\n[{input_str}]({dir_link})", + ) + else: + return await eod(event, f"Directory {input_str} does not seem to exist", time=5) + + +@ultroid_cmd( + pattern="gfolder$", +) +async def _(event): + if Redis("GDRIVE_FOLDER_ID"): + folder_link = "https://drive.google.com/folderview?id=" + Redis( + "GDRIVE_FOLDER_ID" + ) + await eod(event, "`Here is Your G-Drive Folder link : `\n" + folder_link) + else: + await eod(event, "Set GDRIVE_FOLDER_ID with value of your folder id") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/github.py b/plugins/github.py index 3ad0a82..02723b6 100644 --- a/plugins/github.py +++ b/plugins/github.py @@ -67,4 +67,4 @@ async def gitsearch(event): ) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/globaltools.py b/plugins/globaltools.py new file mode 100644 index 0000000..05272c3 --- /dev/null +++ b/plugins/globaltools.py @@ -0,0 +1,299 @@ +# Ultroid - UserBot +# Copyright (C) 2020 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 ` + Globally Ban User. + +• `{i}ungban ` + Unban Globally. + +• `{i}gmute ` + Globally Mute the User. + +• `{i}ungmute ` + UnMute Globally. + +• `{i}gkick ` + Globally Kick User. + +• `{i}gcast ` + Globally Send that msg in all grps. +""" + +from telethon import events +from telethon.tl.functions.channels import EditBannedRequest +from telethon.tl.types import ChatBannedRights + +from . import * + + +@ultroid_cmd( + pattern="ungban ?(.*)", +) +async def _(e): + xx = await eor(e, "`UnGbanning...`") + 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): + if (e.pattern_match.group(1)).isdigit(): + try: + userid = (await e.client.get_entity(int(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + try: + userid = (await e.client.get_entity(str(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + return await eod(xx, "`Reply to some msg or add their id.`", time=5) + name = (await e.client.get_entity(userid)).first_name + chats = 0 + if not is_gbanned(userid): + return await eod(xx, "`User is not gbanned.`", time=3) + async for ggban in e.client.iter_dialogs(): + if ggban.is_group or ggban.is_channel: + try: + await e.client.edit_permissions(ggban.id, userid, view_messages=True) + chats += 1 + except: + pass + ungban(userid) + await xx.edit( + f"`Ungbanned` [{name}](tg://user?id={userid}) `in {chats} chats.\nRemoved from gbanwatch.`" + ) + + +@ultroid_cmd( + pattern="gban ?(.*)", +) +async def _(e): + xx = await eor(e, "`Gbanning...`") + 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): + if (e.pattern_match.group(1)).isdigit(): + try: + userid = (await e.client.get_entity(int(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + try: + userid = (await e.client.get_entity(str(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + return await eod(xx, "`Reply to some msg or add their id.`", tome=5) + name = (await e.client.get_entity(userid)).first_name + chats = 0 + if userid == ultroid_bot.uid: + return await eod(xx, "`I can't gban myself.`", time=3) + if str(userid) in DEVLIST: + return await eod(xx, "`I can't gban my Developers.`", time=3) + if str(userid) in (Redis("SUDOS")).split(" "): + return await eod(xx, "`I can't gban a sudo user.`", time=3) + if is_gbanned(userid): + return await eod( + xx, "`User is already gbanned and added to gbanwatch.`", time=4 + ) + async for ggban in e.client.iter_dialogs(): + if ggban.is_group or ggban.is_channel: + try: + await e.client.edit_permissions(ggban.id, userid, view_messages=False) + chats += 1 + except: + pass + gban(userid) + await xx.edit( + f"`Gbanned` [{name}](tg://user?id={userid}) `in {chats} chats.\nAdded to gbanwatch.`" + ) + + +@ultroid_cmd( + pattern="gcast ?(.*)", +) +async def gcast(event): + xx = event.pattern_match.group(1) + if not xx: + return eor(event, "`Give some text to Globally Broadcast`") + tt = event.text + msg = tt[6:] + kk = await eor(event, "`Globally Broadcasting Msg...`") + er = 0 + done = 0 + async for x in ultroid_bot.iter_dialogs(): + if x.is_group: + chat = x.id + try: + done += 1 + await ultroid_bot.send_message(chat, msg) + except: + er += 1 + pass + await kk.edit(f"Done in {done} chats, error in {er} chat(s)") + + +@ultroid_cmd( + pattern="gkick ?(.*)", +) +async def gkick(e): + xx = await eor(e, "`Gkicking...`") + 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): + if (e.pattern_match.group(1)).isdigit(): + try: + userid = (await e.client.get_entity(int(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + try: + userid = (await e.client.get_entity(str(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + return await eod(xx, "`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 eod(xx, "`I can't gkick myself.`", time=3) + if str(userid) in DEVLIST: + return await eod(xx, "`I can't gkick my Developers.`", time=3) + if str(userid) in (Redis("SUDOS")).split(" "): + return await eod(xx, "`I can't gkick a sudo user.`", time=3) + async for gkick in e.client.iter_dialogs(): + if gkick.is_group or gkick.is_channel: + try: + await ultroid_bot.kick_participant(gkick.id, userid) + chats += 1 + except: + pass + await xx.edit(f"`Gkicked` [{name}](tg://user?id={userid}) `in {chats} chats.`") + + +@ultroid_cmd( + pattern="gmute ?(.*)", +) +async def _(e): + xx = await eor(e, "`Gmuting...`") + 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): + if (e.pattern_match.group(1)).isdigit(): + try: + userid = (await e.client.get_entity(int(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + try: + userid = (await e.client.get_entity(str(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + return await eod(xx, "`Reply to some msg or add their id.`", tome=5) + name = (await e.client.get_entity(userid)).first_name + chats = 0 + if userid == ultroid_bot.uid: + return await eod(xx, "`I can't gmute myself.`", time=3) + if str(userid) in DEVLIST: + return await eod(xx, "`I can't gmute my Developers.`", time=3) + if is_gmuted(userid): + return await eod(xx, "`User is already gmuted.`", time=4) + async for onmute in e.client.iter_dialogs(): + if onmute.is_group: + try: + await e.client( + EditBannedRequest( + onmute.id, + userid, + ChatBannedRights(until_date=None, send_messages=True), + ) + ) + chats += 1 + except: + pass + gmute(userid) + await xx.edit(f"`Gmuted` [{name}](tg://user?id={userid}) `in {chats} chats.`") + + +@ultroid_cmd( + pattern="ungmute ?(.*)", +) +async def _(e): + xx = await eor(e, "`UnGmuting...`") + 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): + if (e.pattern_match.group(1)).isdigit(): + try: + userid = (await e.client.get_entity(int(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + try: + userid = (await e.client.get_entity(str(e.pattern_match.group(1)))).id + except ValueError as err: + return await eod(xx, f"{str(err)}", time=5) + else: + return await eod(xx, "`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 eod(xx, "`User is not gmuted.`", time=3) + async for hurr in e.client.iter_dialogs(): + if hurr.is_group: + try: + await e.client( + EditBannedRequest( + hurr.id, + userid, + ChatBannedRights(until_date=None, send_messages=False), + ) + ) + chats += 1 + except: + pass + ungmute(userid) + await xx.edit(f"`Ungmuted` [{name}](tg://user?id={userid}) `in {chats} chats.`") + + +@ultroid_bot.on(events.ChatAction) +async def _(e): + if e.user_joined or e.added_by: + user = await e.get_user() + chat = await e.get_chat() + if is_gbanned(str(user.id)): + if chat.admin_rights: + try: + await e.client.edit_permissions( + chat.id, user.id, view_messages=False + ) + gban_watch = f"`Gbanned User` [{user.first_name}](tg://user?id={user.id}) `Spotted\n" + gban_watch += f"Banned Successfully`" + except: + pass + else: + gban_watch = ( + f"@admins `Gbanned user` [{user.first_name}]({user.id}) `Spotted.`" + ) + await e.reply(gban_watch) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/google.py b/plugins/google.py index a5cfa36..467a674 100644 --- a/plugins/google.py +++ b/plugins/google.py @@ -117,4 +117,4 @@ async def reverse(event): os.remove(dl) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/imagetools.py b/plugins/imagetools.py index 81150ad..3aa1827 100644 --- a/plugins/imagetools.py +++ b/plugins/imagetools.py @@ -465,4 +465,4 @@ async def ultd(event): os.remove(ultt) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/mute.py b/plugins/mute.py index 6f50732..4501aac 100644 --- a/plugins/mute.py +++ b/plugins/mute.py @@ -214,4 +214,4 @@ async def _(e): await eod(xx, f"`{str(m)}`") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/pdftools.py b/plugins/pdftools.py index 05a95ec..78b1ed2 100644 --- a/plugins/pdftools.py +++ b/plugins/pdftools.py @@ -292,4 +292,4 @@ async def sendpdf(event): os.makedirs("pdf/") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/pmpermit.py b/plugins/pmpermit.py index 55824dd..465a662 100644 --- a/plugins/pmpermit.py +++ b/plugins/pmpermit.py @@ -25,6 +25,7 @@ from pyUltroid.functions.pmpermit_db import * from telethon import events from telethon.tl.functions.contacts import BlockRequest, UnblockRequest from telethon.tl.functions.messages import ReportSpamRequest +from telethon.utils import get_display_name from . import * @@ -35,21 +36,20 @@ if Redis("PMPIC"): PMPIC = Redis("PMPIC") else: PMPIC = "https://telegra.ph/file/94f6a4aeb21ce2d58dd41.jpg" + if not Redis("PM_TEXT"): UNAPPROVED_MSG = """ **PMSecurity of {}!** + Please wait for me to respnd or you will be blocked and reported as spam!! You have {}/{} warnings!""" else: UNAPPROVED_MSG = ( """ -**PMSecurity of {}!** - -""" +**PMSecurity of {}!**""" f"""{Redis("PM_TEXT")}""" """ - Please wait for me to respnd or you will be blocked and reported as spam!! You have {}/{} warnings!""" @@ -57,6 +57,7 @@ You have {}/{} warnings!""" UND = "Please wait for me to respnd or you will be blocked and reported as spam!!" UNS = "You were spamming my Master's PM, which I didn't like." +# 1 WARNS = 3 NO_REPLY = "Reply to someone's msg or try this commmand in private." @@ -70,7 +71,18 @@ PMCMDS = [ ] # ================================================================= -sett = udB.get("PMSETTING") + +@ultroid_bot.on(events.NewMessage(incoming=True, func=lambda e: e.is_private)) +async def permitpm(event): + user = await event.get_chat() + if user.bot or user.is_self: + return + apprv = is_approved(user.id) + if apprv and (Redis("PMLOG") == "True"): + await event.forward_to(Var.LOG_CHANNEL) + + +sett = Redis("PMSETTING") if sett is None: sett = True if sett == "True" and sett != "False": @@ -80,6 +92,8 @@ if sett == "True" and sett != "False": miss = await e.get_chat() if miss.bot or miss.is_self or miss.verified: return + if str(miss.id) in DEVLIST: + return mssg = e.text if mssg in PMCMDS: # do not approve if outgoing is a command. return @@ -94,7 +108,7 @@ if sett == "True" and sett != "False": name0 = str(name.first_name) await e.client.send_message( Var.LOG_CHANNEL, - f"#AutoApproved\nUser - [{name0}](tg://user?id={e.chat_id})", + f"#AutoApproved\nßecoz of outgoing msg\nUser - [{name0}](tg://user?id={e.chat_id})", ) @ultroid_bot.on(events.NewMessage(incoming=True, func=lambda e: e.is_private)) @@ -102,8 +116,15 @@ if sett == "True" and sett != "False": user = await event.get_chat() if user.bot or user.is_self or user.verified: return + if str(user.id) in DEVLIST: + return apprv = is_approved(user.id) if not apprv and event.text != UND: + name = user.first_name + fullname = (user.first_name, user.last_name) + username = user.username + mention = f"[{get_display_name(user)}](tg://user?id={user.id})" + count = len(get_approved()) try: wrn = COUNT_PM[user.id] except KeyError: @@ -115,6 +136,7 @@ if sett == "True" and sett != "False": user.id, search=UND ): await message.delete() + async for message in event.client.iter_messages( user.id, search=UNS ): @@ -176,6 +198,10 @@ if sett == "True" and sett != "False": reply = await apprvpm.get_reply_message() replied_user = await apprvpm.client.get_entity(reply.sender_id) aname = replied_user.id + if str(aname) in DEVLIST: + return await eor( + apprvpm, "Lol, He is my Developer\nHe is auto Approved" + ) name0 = str(replied_user.first_name) uid = replied_user.id if not is_approved(uid): @@ -190,12 +216,17 @@ if sett == "True" and sett != "False": elif apprvpm.is_private: user = await apprvpm.get_chat() aname = await apprvpm.client.get_entity(user.id) + if str(user.id) in DEVLIST: + return await eor( + apprvpm, "Lol, He is my Developer\nHe is auto Approved" + ) name0 = str(aname.first_name) uid = user.id if not is_approved(uid): approve_user(uid) await apprvpm.edit(f"[{name0}](tg://user?id={uid}) `approved to PM!`") async for message in apprvpm.client.iter_messages(user.id, search=UND): + await message.delete() async for message in apprvpm.client.iter_messages(user.id, search=UNS): await message.delete() @@ -224,6 +255,10 @@ if sett == "True" and sett != "False": reply = await e.get_reply_message() replied_user = await e.client.get_entity(reply.sender_id) aname = replied_user.id + if str(aname) in DEVLIST: + return await eor( + e, "`Lol, He is my Developer\nHe Can't Be DisApproved.`" + ) name0 = str(replied_user.first_name) if is_approved(replied_user.id): disapprove_user(replied_user.id) @@ -241,6 +276,10 @@ if sett == "True" and sett != "False": elif e.is_private: bbb = await e.get_chat() aname = await e.client.get_entity(bbb.id) + if str(bbb.id) in DEVLIST: + return await eor( + e, "`Lol, He is my Developer\nHe Can't Be DisApproved.`" + ) name0 = str(aname.first_name) if is_approved(bbb.id): disapprove_user(bbb.id) @@ -265,12 +304,20 @@ if sett == "True" and sett != "False": reply = await block.get_reply_message() replied_user = await block.client.get_entity(reply.sender_id) aname = replied_user.id + if str(aname) in DEVLIST: + return await eor( + block, "`Lol, He is my Developer\nHe Can't Be Blocked`" + ) name0 = str(replied_user.first_name) await block.client(BlockRequest(replied_user.id)) await block.edit("`You've been blocked!`") uid = replied_user.id elif block.is_private: bbb = await block.get_chat() + if str(bbb.id) in DEVLIST: + return await eor( + block, "`Lol, He is my Developer\nHe Can't Be Blocked`" + ) await block.client(BlockRequest(bbb.id)) aname = await block.client.get_entity(bbb.id) await block.edit("`You've been blocked!`") @@ -304,4 +351,4 @@ if sett == "True" and sett != "False": ) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/profile.py b/plugins/profile.py index 7364ae3..adf0405 100644 --- a/plugins/profile.py +++ b/plugins/profile.py @@ -28,7 +28,8 @@ import asyncio import os from telethon.tl import functions -from telethon.tl.functions.photos import DeletePhotosRequest, GetUserPhotosRequest +from telethon.tl.functions.photos import (DeletePhotosRequest, + GetUserPhotosRequest) from telethon.tl.types import InputPhoto from . import * @@ -160,4 +161,4 @@ async def gpoto(e): await eor(e, f"ERROR - {str(e)}") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/redis.py b/plugins/redis.py index 29718a5..177f44a 100644 --- a/plugins/redis.py +++ b/plugins/redis.py @@ -8,6 +8,11 @@ """ ✘ Commands Available - +**DataBase Commands, do not use if you don't know what it is.** + +• `{i}redisusage` + Check Storaged Data Capacity. + • `{i}setredis key | value` Redis Set Value. e.g : @@ -39,7 +44,7 @@ async def _(ult): ok = await eor(ult, "`...`") try: delim = " " if re.search("[|]", ult.pattern_match.group(1)) is None else " | " - data = ult.pattern_match.group(1).split(delim) + data = ult.pattern_match.group(1).split(delim, maxsplit=1) udB.set(data[0], data[1]) redisdata = Redis(data[0]) await ok.edit( @@ -112,4 +117,18 @@ async def _(ult): await ok.edit("**List of Redis Keys :**\n{}".format(msg)) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +@ultroid_cmd( + pattern="redisusage$", +) +async def _(ult): + ok = await eor(ult, "`Calculating ...`") + x = 30 * 1024 * 1024 + z = 0 + for n in udB.keys(): + z += udB.memory_usage(n) + a = humanbytes(z) + "/" + humanbytes(x) + b = str(round(z / x * 100, 3)) + "%" + " Used" + await ok.edit(f"{a}\n{b}") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/specialtools.py b/plugins/specialtools.py index 3f15f42..734fae3 100644 --- a/plugins/specialtools.py +++ b/plugins/specialtools.py @@ -243,4 +243,4 @@ async def wall(event): await nn.delete() -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/stickertools.py b/plugins/stickertools.py index 8842cbf..7264718 100644 --- a/plugins/stickertools.py +++ b/plugins/stickertools.py @@ -14,8 +14,8 @@ • `{i}tiny ` To create Tiny stickers. -• `{i}convert ` - Reply to animated sticker. +• `{i}convert ` + Reply to sticker to convert into gif or image. • `{i}kang ` Kang the sticker (add to your pack). @@ -39,12 +39,10 @@ from os import remove import cv2 import numpy as np from PIL import Image, ImageDraw -from telethon.errors import ChatSendInlineForbiddenError, ChatSendStickersForbiddenError -from telethon.tl.types import ( - DocumentAttributeFilename, - DocumentAttributeSticker, - MessageMediaPhoto, -) +from telethon.errors import (ChatSendInlineForbiddenError, + ChatSendStickersForbiddenError) +from telethon.tl.types import (DocumentAttributeFilename, + DocumentAttributeSticker, MessageMediaPhoto) from . import * @@ -108,19 +106,19 @@ async def waifu(animu): async def uconverter(event): xx = await eor(event, "`Processing...`") a = await event.get_reply_message() + ok = ["image/webp", "application/x-tgsticker"] + if not (a.media and a.media.document and a.media.document.mime_type in ok): + return await eor(event, "`Reply to a Sticker...`") input = event.pattern_match.group(1) b = await event.client.download_media(a, "resources/downloads/") if "gif" in input: cmd = ["lottie_convert.py", b, "something.gif"] file = "something.gif" - elif "sticker" in input: - cmd = ["lottie_convert.py", b, "something.webp"] - file = "something.webp" elif "img" in input: cmd = ["lottie_convert.py", b, "something.png"] file = "something.png" else: - await xx.edit("**Please select from gif/sticker/img**") + return await xx.edit("**Please select from gif/img**") process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) @@ -398,9 +396,12 @@ async def ultdround(event): ) async def ultdestroy(event): ult = await event.get_reply_message() - if not (ult and ("tgsticker" in ult.media.document.mime_type)): - await eor(event, "`Reply to Animated Sticker Only...`") - return + if not event.is_reply: + return await eor(event, "`Reply to Animated Sticker Only...`") + if not ( + ult.media and ult.media.document and "tgsticker" in ult.media.document.mime_type + ): + return await eor(event, "`Reply to Animated Sticker only`") roid = await event.client.download_media(ult, "ultroid.tgs") xx = await eor(event, "`Processing...`") os.system("lottie_convert.py ultroid.tgs json.json") @@ -431,9 +432,7 @@ async def ultdestroy(event): reply_to=event.reply_to_msg_id, ) await xx.delete() - os.remove("ultroid.tgs") os.remove("json.json") - os.remove(roid) @ultroid_cmd( @@ -511,4 +510,4 @@ async def ultiny(event): os.remove(ik) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/sudo.py b/plugins/sudo.py index 2044beb..03bcedd 100644 --- a/plugins/sudo.py +++ b/plugins/sudo.py @@ -29,8 +29,18 @@ from . import * pattern="addsudo ?(.*)", ) async def _(ult): + if Var.BOT_MODE == True: + try: + if ult.sender_id != Var.OWNER_ID: + return await eor( + ult, "You are sudo user, You cant add other sudo user." + ) + except BaseException: + pass + else: + if ult.sender_id != ultroid_bot.uid: + return await eor(ult, "You are sudo user, You cant add other sudo user.") ok = await eor(ult, "`Updating SUDO Users List ...`") - if ult.reply_to_msg_id: replied_to = await ult.get_reply_message() id = replied_to.sender.id @@ -101,8 +111,18 @@ async def _(ult): pattern="delsudo ?(.*)", ) async def _(ult): + if Var.BOT_MODE == True: + try: + if ult.sender_id != Var.OWNER_ID: + return await eor( + ult, "You are sudo user, You cant add other sudo user." + ) + except BaseException: + pass + else: + if ult.sender_id != ultroid_bot.uid: + return await eor(ult, "You are sudo user, You cant add other sudo user.") ok = await eor(ult, "`Updating SUDO Users List ...`") - if ult.reply_to_msg_id: replied_to = await ult.get_reply_message() id = replied_to.sender.id @@ -191,4 +211,4 @@ async def _(ult): return await ok.edit(f"**List of SUDO Users :**\n{msg}") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/tag.py b/plugins/tag.py new file mode 100644 index 0000000..0177677 --- /dev/null +++ b/plugins/tag.py @@ -0,0 +1,96 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}tagall` + Tag Top 100 Members of chat. + +• `{i}tagadmins` + Tag Admins of that chat. + +• `{i}tagowner` + Tag Owner of that chat + +• `{i}tagbots` + Tag Bots of that chat. + +• `{i}tagrec` + Tag recently Active Members. + +• `{i}tagon` + Tag online Members(work only if privacy off). + +• `{i}tagoff` + Tag Offline Members(work only if privacy off). +""" + +from telethon.tl.types import ChannelParticipantAdmin as admin +from telethon.tl.types import ChannelParticipantCreator as owner +from telethon.tl.types import UserStatusOffline as off +from telethon.tl.types import UserStatusOnline as onn +from telethon.tl.types import UserStatusRecently as rec +from telethon.utils import get_display_name + +from . import * + + +@ultroid_cmd( + pattern="tag(on|off|all|bots|rec|admins|owner)?(.*)", + groups_only=True, +) +async def _(e): + okk = e.text + lll = e.pattern_match.group(2) + users = 0 + o = 0 + nn = 0 + rece = 0 + if lll: + xx = f"{lll}" + else: + xx = "" + async for bb in e.client.iter_participants(e.chat_id, 99): + users = users + 1 + x = bb.status + y = bb.participant + if isinstance(x, onn): + o = o + 1 + if "on" in okk: + xx += f"\n[{get_display_name(bb)}](tg://user?id={bb.id})" + if isinstance(x, off): + nn = nn + 1 + if "off" in okk: + if not (bb.bot or bb.deleted): + xx += f"\n[{get_display_name(bb)}](tg://user?id={bb.id})" + if isinstance(x, rec): + rece = rece + 1 + if "rec" in okk: + if not (bb.bot or bb.deleted): + xx += f"\n[{get_display_name(bb)}](tg://user?id={bb.id})" + if isinstance(y, owner): + if "admin" or "owner" in okk: + xx += f"\n꧁[{get_display_name(bb)}](tg://user?id={bb.id})꧂" + if isinstance(y, admin): + if "admin" in okk: + if not bb.deleted: + xx += f"\n[{get_display_name(bb)}](tg://user?id={bb.id})" + if "all" in okk: + if not (bb.bot or bb.deleted): + xx += f"\n[{get_display_name(bb)}](tg://user?id={bb.id})" + if "bot" in okk: + if bb.bot: + xx += f"\n[{get_display_name(bb)}](tg://user?id={bb.id})" + if len(xx) > 4096: + await eor(e, "`Telegram Word Limits Exceeds...`") + else: + await e.client.send_message(e.chat_id, xx) + await e.delete() + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/tools.py b/plugins/tools.py index 7c10b4d..6b4ab96 100644 --- a/plugins/tools.py +++ b/plugins/tools.py @@ -244,10 +244,10 @@ async def _(e): pattern="bash", ) async def _(event): - if (Var.I_DEV if Var.I_DEV else Redis("I_DEV")) != "True": + if Redis("I_DEV") != "True": await eor( event, - "Developer Restricted!\nIf you know what this does, and want to proceed\n\n set var `I_DEV` as `True`\n\nThis Might Be Dangerous.", + f"Developer Restricted!\nIf you know what this does, and want to proceed\n\n `{HNDLR}setredis I_DEV True`\n\nThis Might Be Dangerous.", ) return xx = await eor(event, "`Processing...`") @@ -295,10 +295,10 @@ async def _(event): pattern="eval", ) async def _(event): - if (Var.I_DEV if Var.I_DEV else Redis("I_DEV")) != "True": + if Redis("I_DEV") != "True": await eor( event, - "Developer Restricted!\nIf you know what this does, and want to proceed\n\n set var `I_DEV` as `True`\n\nThis Might Be Dangerous.", + f"Developer Restricted!\nIf you know what this does, and want to proceed\n\n `{HNDLR}setredis I_DEV True`\n\nThis Might Be Dangerous.", ) return xx = await eor(event, "`Processing ...`") @@ -412,4 +412,4 @@ async def lastname(steal): return await lol.edit("Error: @SangMataInfo_bot is not responding!.") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/uploads_files.py b/plugins/uploads_files.py index 0501e8f..d881f8c 100644 --- a/plugins/uploads_files.py +++ b/plugins/uploads_files.py @@ -172,4 +172,4 @@ async def _(event): return await eod(xx, "`Reply to a readable file`", time=10) -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/utilities.py b/plugins/utilities.py index 88be12a..e5241d1 100644 --- a/plugins/utilities.py +++ b/plugins/utilities.py @@ -46,6 +46,9 @@ • `{i}json ` Get the json encoding of the message. + +• `{i}suggest ` + Create a Yes/No poll for the replied suggestion. """ import asyncio import calendar @@ -62,12 +65,16 @@ import requests from telegraph import Telegraph from telegraph import upload_file as uf from telethon import functions -from telethon.errors.rpcerrorlist import BotInlineDisabledError, BotResponseTimeoutError +from telethon.errors.rpcerrorlist import BotInlineDisabledError +from telethon.errors.rpcerrorlist import BotMethodInvalidError as bmi +from telethon.errors.rpcerrorlist import (BotResponseTimeoutError, + ChatSendInlineForbiddenError) from telethon.events import NewMessage from telethon.tl.custom import Dialog from telethon.tl.functions.channels import LeaveChannelRequest from telethon.tl.functions.photos import GetUserPhotosRequest -from telethon.tl.types import Channel, Chat, User +from telethon.tl.types import (Channel, Chat, InputMediaPoll, Poll, PollAnswer, + User) from telethon.utils import get_input_location # =================================================================# @@ -305,12 +312,17 @@ async def _(event): .get("key") ) q = f"paste-{key}" + reply_text = f"• **Pasted to Nekobin :** [Neko](https://nekobin.com/{key})\n• **Raw Url :** : [Raw](https://nekobin.com/raw/{key})" try: ok = await ultroid_bot.inline_query(Var.BOT_USERNAME, q) await ok[0].click(event.chat_id, reply_to=event.reply_to_msg_id, hide_via=True) await xx.delete() - except BotInlineDisabledError or BotResponseTimeoutError: # incase the bot doesnt respond + except BotInlineDisabledError or BotResponseTimeoutError or ChatSendInlineForbiddenError: # handling possible exceptions await xx.edit(reply_text) + except bmi: + await xx.edit( + f"**Inline Not Available as You Are in Bot Mode\nPasted to Nekobin :**\n{reply_text}" + ) @ultroid_cmd( @@ -454,7 +466,7 @@ async def _(ult): @ultroid_cmd( - pattern=r"rmbg ?(.*)", + pattern=r"rmbg$", ) async def rmbg(event): RMBG_API = udB.get("RMBG_API") @@ -463,50 +475,42 @@ async def rmbg(event): return await xx.edit( "Get your API key from [here](https://www.remove.bg/) for this plugin to work.", ) - input_str = event.pattern_match.group(1) - message_id = event.message.id if event.reply_to_msg_id: - message_id = event.reply_to_msg_id - reply_message = await event.get_reply_message() - try: - dl_file = await ultroid_bot.download_media( - reply_message, TMP_DOWNLOAD_DIRECTORY - ) - except Exception as e: - return await xx.edit("**ERROR:**\n`{}`".format(str(e))) - else: - await xx.edit("`Sending to remove.bg`") - output_file_name = ReTrieveFile(dl_file) - os.remove(dl_file) - elif input_str: + reply = await event.get_reply_message() + dl = await ultroid_bot.download_media(reply) + if not dl.endswith(("webp", "jpg", "png", "jpeg")): + os.remove(dl) + return await xx.edit("`Unsupported Media`") await xx.edit("`Sending to remove.bg`") - output_file_name = ReTrieveURL(input_str) + out = ReTrieveFile("ult.png") + os.remove("ult.png") + os.remove(dl) else: - await xx.edit( - f"Use `{Var.HNDLR}rmbg` as reply to a pic to remove its background." - ) + await xx.edit(f"Use `{HNDLR}rmbg` as reply to a pic to remove its background.") await asyncio.sleep(5) await xx.delete() return - contentType = output_file_name.headers.get("content-type") + contentType = out.headers.get("content-type") + rmbgp = "ult.png" if "image" in contentType: - with io.BytesIO(output_file_name.content) as remove_bg_image: - remove_bg_image.name = "rmbg-ult.png" - await ultroid_bot.send_file( - event.chat_id, - remove_bg_image, - force_document=True, - supports_streaming=False, - allow_cache=False, - reply_to=message_id, - ) - await xx.edit("`Done.`") + with open(rmbgp, "wb") as rmbg: + rmbg.write(out.content) else: + error = out.json() await xx.edit( - "RemoveBG returned an error - \n`{}`".format( - output_file_name.content.decode("UTF-8") - ), + f"**Error ~** `{error['errors'][0]['title']}`,\n`{error['errors'][0]['detail']}`" ) + zz = Image.open(rmbgp) + if zz.mode != "RGB": + zz.convert("RGB") + zz.save("ult.webp", "webp") + await ultroid_bot.send_file( + event.chat_id, rmbgp, force_document=True, reply_to=reply + ) + await ultroid_bot.send_file(event.chat_id, "ult.webp", reply_to=reply) + os.remove(rmbgp) + os.remove("ult.webp") + await xx.delete() @ultroid_cmd( @@ -580,4 +584,31 @@ async def _(event): await eor(event, f"```{the_real_message}```") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +@ultroid_cmd(pattern="suggest") +async def sugg(event): + if await event.get_reply_message(): + msgid = (await event.get_reply_message()).id + try: + await ultroid.send_message( + event.chat_id, + file=InputMediaPoll( + poll=Poll( + id=12345, + question="Do you agree to the replied suggestion?", + answers=[PollAnswer("Yes", b"1"), PollAnswer("No", b"2")], + ) + ), + reply_to=msgid, + ) + except Exception as e: + return await eod( + event, f"`Oops, you can't send polls here!\n\n{str(e)}`", time=5 + ) + await event.delete() + else: + return await eod( + event, "`Please reply to a message to make a suggestion poll!`", time=5 + ) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/plugins/words.py b/plugins/words.py index f7556cb..ff33dd8 100644 --- a/plugins/words.py +++ b/plugins/words.py @@ -142,4 +142,4 @@ async def _(event): await xx.edit(f"**No result found for** `{word}`") -HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=HNDLR)}"}) diff --git a/requirements.txt b/requirements.txt index a03154b..eb82c86 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -py-Ultroid==2021.2.24 +py-Ultroid==2021.3.04 asyncurban carbonnow cairosvg emoji GitPython -googletrans==3.1.0a0 +googletrans==4.0.0rc1 heroku3 imutils lottie @@ -20,6 +20,7 @@ psutil pytz requests>=2.18.4 scikit-image +selenium speedtest-cli==2.1.2 telegraph validators diff --git a/resources/extras/ultroid_assistant.jpg b/resources/extras/ultroid_assistant.jpg new file mode 100644 index 0000000000000000000000000000000000000000..08a66c49f28a07794c8e6825c5af4cd02002ab19 GIT binary patch literal 26622 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 literal 0 HcmV?d00001 diff --git a/resources/startup/deploy.sh b/resources/startup/deploy.sh index cd668b8..73ac9ef 100644 --- a/resources/startup/deploy.sh +++ b/resources/startup/deploy.sh @@ -61,7 +61,9 @@ apt update && apt upgrade -y && apt install --no-install-recommends -y \ make \ libopus0 \ libopus-dev \ - gcc + gcc \ + mediainfo \ + megatools echo ' •• Cloning Repository @@ -69,6 +71,7 @@ echo ' git clone https://github.com/Teamultroid/Ultroid.git /root/TeamUltroid/ + echo ' •• Getting Libraries and Installing '