diff --git a/Dockerfile b/Dockerfile index 2650a49c..2951a245 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,13 +34,14 @@ RUN apk add --no-cache --update \ postgresql \ postgresql-client \ postgresql-dev \ - py-lxml \ - py-pillow \ - py-pip \ - py-psycopg2 \ - py-requests \ - py-sqlalchemy \ - py-tz \ + py3-lxml \ + py3-pillow \ + py3-pip \ + py3-setuptools \ + py3-psycopg2 \ + py3-requests \ + py3-sqlalchemy \ + py3-tz \ py3-aiohttp \ python-dev \ openssl \ @@ -55,8 +56,6 @@ RUN apk add --no-cache --update \ sudo \ zlib-dev -RUN pip3 install --upgrade pip setuptools - # Copy Python Requirements to /app RUN sed -e 's;^# \(%wheel.*NOPASSWD.*\);\1;g' -i /etc/sudoers @@ -86,6 +85,7 @@ ENV PATH="/home/userbot/bin:$PATH" # RUN sudo pip3 install -r requirements.txt ADD . /home/userbot/userbot +RUN sudo chown -R $(whoami) /usr/lib/python3.7/site-packages RUN sudo chown -R userbot /home/userbot/userbot RUN sudo chmod -R 777 /home/userbot/userbot CMD ["python3","-m","userbot"] diff --git a/LICENSE b/LICENSE index 830429d2..3a326af8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,16 +1,52 @@ RAPHIELSCAPE PUBLIC LICENSE - Version 1.b, January 2019 + Version 1.c, June 2019 - Copyright (C) 2019 Raphielscape Open Source Holding LLC. + Copyright (C) 2019 Raphielscape LLC. + Copyright (C) 2019 Devscapes Open Source Holding GmbH. + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. RAPHIELSCAPE PUBLIC LICENSE - A. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + A-1. DEFINITIONS + +0. “This License” refers to version 1.c of the Raphielscape Public License. + +1. “Copyright” also means copyright-like laws that apply to other kinds of works. + +2. “The Work" refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. + “Licensees” and “recipients” may be individuals or organizations. + +3. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, + other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work + or a work “based on” the earlier work. + +4. Source Form. The “source form” for a work means the preferred form of the work for making modifications to it. + “Object code” means any non-source form of a work. + + The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and + (for an executable work) run the object code and to modify the work, including scripts to control those activities. + + The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + The Corresponding Source for a work in source code form is that same work. + +5. "The author" refers to "author" of the code, which is the one that made the particular code which exists inside of + the Corresponding Source. + +6. "Owner" refers to any parties which is made the early form of the Corresponding Source. + + A-2. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You must give any other recipients of the Work or Derivative Works a copy of this License; and + 1. You must cause any modified files to carry prominent notices stating that You changed the files; and + 2. You must retain, in the Source form of any Derivative Works that You distribute, - all copyright, patent, trademark, and attribution notices from the Source form of the Work; and -3. Respecting the owner of works that being distributed in any ways + this license, all copyright, patent, trademark, authorships and attribution notices + from the Source form of the Work; and + +3. Respecting the author and owner of works that are distributed in any way. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, @@ -32,15 +68,15 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. C. REVISED VERSION OF THIS LICENSE - The Raphielscape Open Source Holding LLC. may publish revised and/or new versions of the + The Devscapes Open Source Holding GmbH. may publish revised and/or new versions of the Raphielscape Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - Each version is given a distinguishing version number and version letter. If the Program specifies -that a certain numbered version of the Raphielscape Public License "or any later version" applies -to it, you have the option of following the terms and conditions either of that numbered version or of -any later version published by the Raphielscape Open Source Holding LLC. If the Program does not specify a + Each version is given a distinguishing version number. If the Program specifies that a +certain numbered version of the Raphielscape Public License "or any later version" applies to it, +you have the option of following the terms and conditions either of that numbered version or of +any later version published by the Devscapes Open Source Holding GmbH. If the Program does not specify a version number of the Raphielscape Public License, you may choose any version ever published -by the Raphielscape Open Source Holding LLC. +by the Devscapes Open Source Holding GmbH. - END OF LICENSE \ No newline at end of file + END OF LICENSE diff --git a/app.json b/app.json index 3cbbe5c1..476c0371 100644 --- a/app.json +++ b/app.json @@ -16,23 +16,34 @@ "env": { "API_KEY": { "description": "Get this value from my.telegram.org.", - "value": "" + "required": true }, "API_HASH": { "description": "Get this value from my.telegram.org.", - "value": "" + "required": true }, "STRING_SESSION": { "description": "Get this value by running [python3 string_session.py] in Termux or local system.", - "value": "" + "required": true + }, + "COUNTRY": { + "description": "Set your Country to be used in the .time and .date commands.", + "required": false + }, + "TZ_NUMBER": { + "description": "Change this value in case your country has multiple Time Zones.", + "value": "1", + "required": false }, "CHROME_DRIVER": { - "description": "ChromeDriver location.", - "value": "/usr/bin/chromedriver" + "description": "ChromeDriver location for selenium based modules.", + "value": "/usr/bin/chromedriver", + "required": false }, "GOOGLE_CHROME_BIN": { - "description": "Google Chrome (or) Chromium binary location.", - "value": "/usr/bin/chromium-browser" + "description": "Google Chrome (or) Chromium binary location for selenium based modules.", + "value": "/usr/bin/chromium-browser", + "required": false }, "OPEN_WEATHER_MAP_APPID": { "description": "Get your own APPID (API key)from https://api.openweathermap.org/data/2.5/weather", @@ -43,15 +54,15 @@ "value": "False" }, "BOTLOG_CHATID": { - "description": "ChatID for the Log group", + "description": "ChatID of the Log group. Set it to '0' if BOTLOG = False", "value": "0" }, "CONSOLE_LOGGER_VERBOSE": { - "description": "If you need Verbosity on the Logging", + "description": "If you need verbosity on the console logging", "value": "False" }, "PM_AUTO_BAN": { - "description": "PM Auto-Ban Feature Switch", + "description": "PM Auto-Ban Feature Switch. Also known as the 'bleep blop, this is a bot...' module.", "value": "False" }, "YOUTUBE_API_KEY": { @@ -79,7 +90,7 @@ "value": "./downloads/" }, "CLEAN_WELCOME": { - "description": "Deletes old welcome messages; when a new person joins, the old message is deleted.", + "description": "When a new person joins, the old welcome message is deleted.", "value": "True" }, "G_DRIVE_CLIENT_ID": { @@ -110,6 +121,10 @@ "description": "Default profile bio.", "required": false }, + "ALIVE_NAME": { + "description": "Name to show in .alive message", + "required": false + }, "G_DRIVE_CLIENT_SECRET": { "description": "Enter Your Client Secret for Google Drive.", "required": false diff --git a/requirements.txt b/requirements.txt index 8c039a9d..547990c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,11 +23,13 @@ psycopg2-binary pybase64>=0.4.0 pylast pySmartDL +python-barcode python-dotenv pytube>=9.5.1 pytz qrcode requests>=2.18.4 +search-engine-parser speedtest-cli>=2.0.2 sqlalchemy>=1.2 telethon>=1.9 diff --git a/sample_config.env b/sample_config.env index 5e6a5bf0..0e89b4d1 100644 --- a/sample_config.env +++ b/sample_config.env @@ -15,9 +15,9 @@ OPEN_WEATHER_MAP_APPID = "" # # Location of ChromeDriver for .carbon module -# Default for Heroku : "/app/.chromedriver/bin/chromedriver" +# Default for Heroku Slugs : "/app/.chromedriver/bin/chromedriver" # -CHROME_DRIVER= "" +CHROME_DRIVER = "" # # Get this value by running python3 string_session.py locally @@ -26,28 +26,28 @@ STRING_SESSION = "" # # Headless GoogleChrome location for .carbon module -# Default for Heroku : "/app/.apt/usr/bin/google-chrome" +# Default for Heroku Slugs : "/app/.apt/usr/bin/google-chrome" # -GOOGLE_CHROME_BIN= "" +GOOGLE_CHROME_BIN = "" # # OCR Space API Key for .ocr command # Get from https://ocr.space/ocrapi # -OCR_SPACE_API_KEY= "" +OCR_SPACE_API_KEY = "" # # remove.bg API Key for .rbg command # Get from https://www.remove.bg/api # -REM_BG_API_KEY= "" +REM_BG_API_KEY = "" # # ChatID for the Log group # Add a Hypen or a Negative Sign before ID # This is a integer, Please don't use Strings # -BOTLOG_CHATID = #- +BOTLOG_CHATID = # Chat ID should be integer. # # Incase you want to turn off logging, put this to false @@ -62,19 +62,31 @@ CONSOLE_LOGGER_VERBOSE = False # # PM Auto-Ban Feature Switch # -PM_AUTO_BAN=False +PM_AUTO_BAN = False + +# +# Custom Default name for .alive +# +ALIVE_NAME = None # # Your Database URL # Example: 'postgres://userbot:userbot@localhost:5432/userbot' # -DATABASE_URL= "" +DATABASE_URL = "" # # YouTube Data API Key for .yt command # Get from https://console.cloud.google.com # -YOUTUBE_API_KEY= "" +YOUTUBE_API_KEY = "" + +# +# Country and Time Zone setup for +# .time and .date modules +# +COUNTRY = "" +TZ_NUMBER = # this is an integer. # # Google Drive Credentials @@ -96,9 +108,9 @@ LASTFM_PASSWORD = "Your last.fm password" # Bot will add before song name. For last.fm module. # Example: GitHub: MacTavishAO : Skillet - Feel Invincible -BIO_PREFIX="" +BIO_PREFIX = "" # default bio message -DEFAULT_BIO="" +DEFAULT_BIO = "" # # Report or kick some known spammer bots after diff --git a/userbot/__init__.py b/userbot/__init__.py index 476f1a77..99012bc2 100644 --- a/userbot/__init__.py +++ b/userbot/__init__.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot initialization. """ @@ -44,10 +44,12 @@ # Check if the config was edited by using the already used variable. # Basically, its the 'virginity check' for the config file ;) -CONFIG_CHECK = os.environ.get("___________PLOX_______REMOVE_____THIS_____LINE__________", None) +CONFIG_CHECK = os.environ.get( + "___________PLOX_______REMOVE_____THIS_____LINE__________", None) if CONFIG_CHECK: - LOGS.error("Please remove the line mentioned in the first hashtag from the config.env file") + LOGS.error( + "Please remove the line mentioned in the first hashtag from the config.env file") quit(1) # Telegram App KEY and HASH @@ -70,7 +72,7 @@ # Console verbose logging CONSOLE_LOGGER_VERBOSE = sb( os.environ.get("CONSOLE_LOGGER_VERBOSE", "False") - ) +) # SQL Database URI DB_URI = os.environ.get("DATABASE_URL", None) @@ -100,7 +102,22 @@ # Youtube API key YOUTUBE_API_KEY = os.environ.get( "YOUTUBE_API_KEY", None - ) +) + +# Default .alive name +ALIVE_NAME = os.environ.get( + "ALIVE_NAME", None +) + +# Time & Date - Country and Time Zone +COUNTRY = str(os.environ.get( + "COUNTRY", "" +)) + +TZ_NUMBER = int(os.environ.get( + "TZ_NUMBER", 1 +)) + # Clean Welcome CLEAN_WELCOME = sb(os.environ.get( @@ -131,7 +148,8 @@ G_DRIVE_CLIENT_SECRET = os.environ.get("G_DRIVE_CLIENT_SECRET", None) G_DRIVE_AUTH_TOKEN_DATA = os.environ.get("G_DRIVE_AUTH_TOKEN_DATA", None) GDRIVE_FOLDER_ID = os.environ.get("GDRIVE_FOLDER_ID", None) -TEMP_DOWNLOAD_DIRECTORY = os.environ.get("TMP_DOWNLOAD_DIRECTORY", "./downloads") +TEMP_DOWNLOAD_DIRECTORY = os.environ.get( + "TMP_DOWNLOAD_DIRECTORY", "./downloads") # 'bot' variable if STRING_SESSION: @@ -149,3 +167,5 @@ LASTMSG = {} ENABLE_KILLME = True CMD_HELP = {} +ISAFK = False +AFKREASON = None diff --git a/userbot/__main__.py b/userbot/__main__.py index 33465adf..f34ace08 100644 --- a/userbot/__main__.py +++ b/userbot/__main__.py @@ -1,24 +1,21 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot start point """ from importlib import import_module -from sqlite3 import connect from sys import argv from telethon.errors.rpcerrorlist import PhoneNumberInvalidError from userbot import LOGS, bot from userbot.modules import ALL_MODULES -DB = connect("learning-data-root.check") -CURSOR = DB.cursor() -ALL_ROWS = CURSOR.fetchall() + INVALID_PH = '\nERROR: The Phone No. entered is INVALID' \ '\n Tip: Use Country Code along with number.' \ - '\n Recheck your Phone Number' + '\n or check your phone number and try again !' try: bot.start() @@ -29,10 +26,11 @@ for module_name in ALL_MODULES: imported_module = import_module("userbot.modules." + module_name) -LOGS.info("Your userbot version is 3.0 sql-extended") +LOGS.info("Your userbot version is 4.0 - Extended") -LOGS.info("Congratulations, your userbot is now running !! Test it by typing .alive in any chat." - "If you need assistance, head to https://t.me/PaperplaneExtendedChat") +LOGS.info( + "Congratulations, your userbot is now running !! Test it by typing .alive in any chat." + "If you need assistance, head to https://t.me/PaperplaneExtendedChat") if len(argv) not in (1, 3, 4): diff --git a/userbot/events.py b/userbot/events.py index de45f20d..a6559a65 100644 --- a/userbot/events.py +++ b/userbot/events.py @@ -1,14 +1,14 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # -""" Userbot module for managing events. One of the main components of the userbot. """ +""" Userbot module for managing events. + One of the main components of the userbot. """ from telethon import events -from telethon.events import StopPropagation import asyncio -from userbot import bot +from userbot import bot, BOTLOG, BOTLOG_CHATID from traceback import format_exc from time import gmtime, strftime import math @@ -36,4 +36,71 @@ def decorator(func): return func - return decorator \ No newline at end of file + return decorator + + +def errors_handler(func): + async def wrapper(errors): + try: + await func(errors) + except BaseException: + + date = strftime("%Y-%m-%d %H:%M:%S", gmtime()) + new = { + 'error': str(sys.exc_info()[1]), + 'date': datetime.datetime.now() + } + + text = "**USERBOT CRASH REPORT**\n\n" + + link = "[here](https://t.me/PaperplaneExtendedSupport)" + text += "If you wanna you can report it" + text += f"- just forward this message {link}.\n" + text += "Nothing is logged except the fact of error and date\n" + + ftext = "\nDisclaimer:\nThis file uploaded ONLY here," + ftext += "\nwe logged only fact of error and date," + ftext += "\nwe respect your privacy," + ftext += "\nyou may not report this error if you've" + ftext += "\nany confidential data here, no one will see your data\n\n" + + ftext += "--------BEGIN USERBOT TRACEBACK LOG--------" + ftext += "\nDate: " + date + ftext += "\nGroup ID: " + str(errors.chat_id) + ftext += "\nSender ID: " + str(errors.sender_id) + ftext += "\n\nEvent Trigger:\n" + ftext += str(errors.text) + ftext += "\n\nTraceback info:\n" + ftext += str(traceback.format_exc()) + ftext += "\n\nError text:\n" + ftext += str(sys.exc_info()[1]) + ftext += "\n\n--------END USERBOT TRACEBACK LOG--------" + + command = "git log --pretty=format:\"%an: %s\" -5" + + ftext += "\n\n\nLast 5 commits:\n" + + process = await asyncio.create_subprocess_shell( + command, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + result = str(stdout.decode().strip()) \ + + str(stderr.decode().strip()) + + ftext += result + + file = open("error.log", "w+") + file.write(ftext) + file.close() + + if BOTLOG: + await errors.client.send_file( + BOTLOG_CHATID, + "error.log", + caption=text, + ) + return + + return wrapper diff --git a/userbot/modules/__init__.py b/userbot/modules/__init__.py index caf75487..1b02ff88 100644 --- a/userbot/modules/__init__.py +++ b/userbot/modules/__init__.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Init file which loads all of the modules """ diff --git a/userbot/modules/admin.py b/userbot/modules/admin.py index f1247b1d..9db99260 100644 --- a/userbot/modules/admin.py +++ b/userbot/modules/admin.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. """ Userbot module to help you manage a group @@ -23,7 +23,7 @@ MessageMediaPhoto) from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, bot -from userbot.events import register +from userbot.events import register, errors_handler # =================== CONSTANT =================== PP_TOO_SMOL = "`The image is too small`" @@ -77,7 +77,9 @@ ) # ================================================ + @register(outgoing=True, pattern="^.setgrouppic$") +@errors_handler async def set_group_photo(gpic): """ For .setgrouppic command, changes the picture of a group """ if not gpic.text[0].isalpha() and gpic.text[0] not in ("/", "#", "@", "!"): @@ -102,8 +104,8 @@ async def set_group_photo(gpic): if photo: try: await gpic.client(EditPhotoRequest( - gpic.chat_id, - await gpic.client.upload_file(photo) + gpic.chat_id, + await gpic.client.upload_file(photo) )) await gpic.edit(CHAT_PP_CHANGED) @@ -114,6 +116,7 @@ async def set_group_photo(gpic): @register(outgoing=True, pattern="^.promote(?: |$)(.*)") +@errors_handler async def promote(promt): """ For .promote command, promotes the replied/tagged person """ if not promt.text[0].isalpha() \ @@ -174,6 +177,7 @@ async def promote(promt): @register(outgoing=True, pattern="^.demote(?: |$)(.*)") +@errors_handler async def demote(dmod): """ For .demote command, demotes the replied/tagged person """ if not dmod.text[0].isalpha() and dmod.text[0] not in ("/", "#", "@", "!"): @@ -232,6 +236,7 @@ async def demote(dmod): @register(outgoing=True, pattern="^.ban(?: |$)(.*)") +@errors_handler async def ban(bon): """ For .ban command, bans the replied/tagged person """ if not bon.text[0].isalpha() and bon.text[0] not in ("/", "#", "@", "!"): @@ -251,7 +256,6 @@ async def ban(bon): else: return - # Announce that we're going to whack the pest await bon.edit("`Whacking the pest!`") @@ -280,7 +284,8 @@ async def ban(bon): await bon.edit("`{}` was banned!".format(str(user.id))) - # Announce to the logging group if we have banned the person successfully! + # Announce to the logging group if we have banned the person + # successfully! if BOTLOG: await bon.client.send_message( BOTLOG_CHATID, @@ -291,6 +296,7 @@ async def ban(bon): @register(outgoing=True, pattern="^.unban(?: |$)(.*)") +@errors_handler async def nothanos(unbon): """ For .unban command, unbans the replied/tagged person """ if not unbon.text[0].isalpha() and unbon.text[0] \ @@ -335,6 +341,7 @@ async def nothanos(unbon): @register(outgoing=True, pattern="^.mute(?: |$)(.*)") +@errors_handler async def spider(spdr): """ This function is basically muting peeps @@ -366,9 +373,8 @@ async def spider(spdr): self_user = await spdr.client.get_me() if user.id == self_user.id: - await spdr.edit("`Hands too short, can't duct tape myself...\n(ヘ・_・)ヘ┳━┳`") - return - + await spdr.edit("`Hands too short, can't duct tape myself...\n(ヘ・_・)ヘ┳━┳`") + return # If everything goes well, do announcing and mute await spdr.edit("`Gets a tape!`") @@ -400,6 +406,7 @@ async def spider(spdr): @register(outgoing=True, pattern="^.unmute(?: |$)(.*)") +@errors_handler async def unmoot(unmot): """ For .unmute command, unmute the replied/tagged person """ if not unmot.text[0].isalpha() and unmot.text[0] \ @@ -457,6 +464,7 @@ async def unmoot(unmot): @register(incoming=True) +@errors_handler async def muter(moot): """ Used for deleting the messages of muted people """ try: @@ -491,6 +499,7 @@ async def muter(moot): @register(outgoing=True, pattern="^.ungmute(?: |$)(.*)") +@errors_handler async def ungmoot(un_gmute): """ For .ungmute command, ungmutes the target in the userbot """ if not un_gmute.text[0].isalpha() and un_gmute.text[0] \ @@ -537,9 +546,11 @@ async def ungmoot(un_gmute): @register(outgoing=True, pattern="^.gmute(?: |$)(.*)") +@errors_handler async def gspider(gspdr): """ For .gmute command, globally mutes the replied/tagged person """ - if not gspdr.text[0].isalpha() and gspdr.text[0] not in ("/", "#", "@", "!"): + if not gspdr.text[0].isalpha() and gspdr.text[0] not in ( + "/", "#", "@", "!"): # Admin or creator check chat = await gspdr.get_chat() admin = chat.admin_rights @@ -563,7 +574,6 @@ async def gspider(gspdr): else: return - # If pass, inform and start gmuting await gspdr.edit("`Grabs a huge, sticky duct tape!`") if gmute(user.id) is False: @@ -581,6 +591,7 @@ async def gspider(gspdr): @register(outgoing=True, pattern="^.delusers(?: |$)(.*)") +@errors_handler async def rm_deletedacc(show): """ For .delusers command, list all the ghost/deleted accounts in a chat. """ if not show.text[0].isalpha() and show.text[0] not in ("/", "#", "@", "!"): @@ -656,8 +667,16 @@ async def rm_deletedacc(show): await show.edit(del_status) + if BOTLOG: + await show.client.send_message( + BOTLOG_CHATID, + "#CLEANUP\n" + f"Cleaned **{del_u}** deleted account(s) !!" + ) + @register(outgoing=True, pattern="^.adminlist$") +@errors_handler async def get_admin(show): """ For .adminlist command, list all of the admins of the chat. """ if not show.text[0].isalpha() and show.text[0] not in ("/", "#", "@", "!"): @@ -683,6 +702,7 @@ async def get_admin(show): @register(outgoing=True, pattern="^.pin(?: |$)(.*)") +@errors_handler async def pin(msg): """ For .pin command, pins the replied/tagged message on the top the chat. """ if not msg.text[0].isalpha() and msg.text[0] not in ("/", "#", "@", "!"): @@ -730,6 +750,7 @@ async def pin(msg): @register(outgoing=True, pattern="^.kick(?: |$)(.*)") +@errors_handler async def kick(usr): """ For .kick command, kicks the replied/tagged person from the group. """ if not usr.text[0].isalpha() and usr.text[0] not in ("/", "#", "@", "!"): @@ -748,7 +769,6 @@ async def kick(usr): await usr.edit("`Couldn't fetch user.`") return - await usr.edit("`Kicking...`") try: @@ -783,6 +803,7 @@ async def kick(usr): @register(outgoing=True, pattern="^.userslist ?(.*)") +@errors_handler async def get_users(show): """ For .userslist command, list all of the users in a chat. """ if not show.text[0].isalpha() and show.text[0] not in ("/", "#", "@", "!"): @@ -842,7 +863,9 @@ async def get_user_from_event(event): if event.message.entities is not None: probable_user_mention_entity = event.message.entities[0] - if isinstance(probable_user_mention_entity, MessageEntityMentionName): + if isinstance( + probable_user_mention_entity, + MessageEntityMentionName): user_id = probable_user_mention_entity.user_id user_obj = await event.client.get_entity(user_id) return user_obj @@ -854,6 +877,7 @@ async def get_user_from_event(event): return user_obj + async def get_user_from_id(user, event): if isinstance(user, str): user = int(user) diff --git a/userbot/modules/afk.py b/userbot/modules/afk.py index 441649f6..0b2691fd 100644 --- a/userbot/modules/afk.py +++ b/userbot/modules/afk.py @@ -1,58 +1,64 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot module which contains afk-related commands """ import random + from asyncio import sleep from telethon.events import StopPropagation -from userbot import (COUNT_MSG, CMD_HELP, BOTLOG, BOTLOG_CHATID, - USERS, PM_AUTO_BAN) - -from userbot.events import register +from userbot import ( + AFKREASON, + COUNT_MSG, + CMD_HELP, + ISAFK, + BOTLOG, + BOTLOG_CHATID, + USERS, + PM_AUTO_BAN) -from userbot.modules.sql_helper.globals import gvarstatus, addgvar, delgvar -from sqlalchemy.exc import IntegrityError +from userbot.events import register, errors_handler # ========================= CONSTANTS ============================ AFKSTR = [ - "I'm busy right now. Please talk in a bag and when I come back you can just give me the bag!", - "I'm away right now. If you need anything, leave a message after the beep:\n\n`beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep`!", - "You missed me, next time aim better.", - "I'll be back in a few minutes and if I'm not...,\nwait longer.", - "I'm not here right now, so I'm probably somewhere else.", - "Roses are red,\nViolets are blue,\nLeave me a message,\nAnd I'll get back to you.", - "Sometimes the best things in life are worth waiting for…\nI`ll be right back.", - "I'll be right back,\nbut if I'm not right back,\nI'll be back later.", - "If you haven't figured it out already,\nI'm not here.", - "Hello, welcome to my away message, how may I ignore you today?", - "I'm away over 7 seas and 7 countries,\n7 waters and 7 continents,\n7 mountains and 7 hills,\n7 plains and 7 mounds,\n7 pools and 7 lakes,\n7 springs and 7 meadows,\n7 cities and 7 neighborhoods,\n7 blocks and 7 houses...\n\nWhere not even your messages can reach me!", - "I'm away from the keyboard at the moment, but if you'll scream loud enough at your screen, I might just hear you.", - "I went that way\n---->", - "I went this way\n<----", - "Please leave a message and make me feel even more important than I already am.", - "I am not here so stop writing to me,\nor else you will find yourself with a screen full of your own messages.", - "If I were here, I'd tell you where I am. But I'm not, so ask me when I return...", - "I am away! I don't know when I'll be back! Hopefully a few minutes from now!", - "I'm not available right now so please leave your name, number, and address and I will stalk you later.", - "Sorry, I'm not here right now. Feel free to talk to my userbot as long as you like. I'll get back to you later.", - "I bet you were expecting an away message!", - "Life is so short, there are so many things to do...\nI'm away doing one of them..", - "I am not here right now...\nbut if I was...\n\nwouldn't that be awesome?", + "I'm busy right now. Please talk in a bag and when I come back you can just give me the bag!", + "I'm away right now. If you need anything, leave a message after the beep:\n`beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep`!", + "You missed me, next time aim better.", + "I'll be back in a few minutes and if I'm not...,\nwait longer.", + "I'm not here right now, so I'm probably somewhere else.", + "Roses are red,\nViolets are blue,\nLeave me a message,\nAnd I'll get back to you.", + "Sometimes the best things in life are worth waiting for…\nI`ll be right back.", + "I'll be right back,\nbut if I'm not right back,\nI'll be back later.", + "If you haven't figured it out already,\nI'm not here.", + "Hello, welcome to my away message, how may I ignore you today?", + "I'm away over 7 seas and 7 countries,\n7 waters and 7 continents,\n7 mountains and 7 hills,\n7 plains and 7 mounds,\n7 pools and 7 lakes,\n7 springs and 7 meadows,\n7 cities and 7 neighborhoods,\n7 blocks and 7 houses...\n\nWhere not even your messages can reach me!", + "I'm away from the keyboard at the moment, but if you'll scream loud enough at your screen, I might just hear you.", + "I went that way\n---->", + "I went this way\n<----", + "Please leave a message and make me feel even more important than I already am.", + "I am not here so stop writing to me,\nor else you will find yourself with a screen full of your own messages.", + "If I were here,\nI'd tell you where I am.\n\nBut I'm not,\nso ask me when I return...", + "I am away!\nI don't know when I'll be back!\nHopefully a few minutes from now!", + "I'm not available right now so please leave your name, number, and address and I will stalk you later.", + "Sorry, I'm not here right now.\nFeel free to talk to my userbot as long as you like.\nI'll get back to you later.", + "I bet you were expecting an away message!", + "Life is so short, there are so many things to do...\nI'm away doing one of them..", + "I am not here right now...\nbut if I was...\n\nwouldn't that be awesome?", ] # ================================================================= + @register(incoming=True, disable_edited=True) +@errors_handler async def mention_afk(mention): """ This function takes care of notifying the people who mention you that you are AFK.""" global COUNT_MSG global USERS - ISAFK = gvarstatus("AFK_STATUS") - AFKREASON = gvarstatus("AFK_REASON") + global ISAFK if mention.message.mentioned and not (await mention.get_sender()).bot: if ISAFK: if mention.sender_id not in USERS: @@ -83,20 +89,23 @@ async def mention_afk(mention): COUNT_MSG = COUNT_MSG + 1 -@register(incoming=True, disable_edited=True) +@register(incoming=True) +@errors_handler async def afk_on_pm(sender): """ Function which informs people that you are AFK in PM """ - ISAFK = gvarstatus("AFK_STATUS") + global ISAFK global USERS global COUNT_MSG - AFKREASON = gvarstatus("AFK_REASON") if sender.is_private and sender.sender_id != 777000 and not (await sender.get_sender()).bot: - try: - from userbot.modules.sql_helper.pm_permit_sql import is_approved - except AttributeError: - return - apprv = is_approved(sender.sender_id) - if (PM_AUTO_BAN and apprv) and ISAFK: + if PM_AUTO_BAN: + try: + from userbot.modules.sql_helper.pm_permit_sql import is_approved + apprv = is_approved(sender.sender_id) + except AttributeError: + apprv = True + else: + apprv = True + if apprv and ISAFK: if sender.sender_id not in USERS: if AFKREASON: await sender.reply( @@ -125,43 +134,36 @@ async def afk_on_pm(sender): COUNT_MSG = COUNT_MSG + 1 -@register(outgoing=True, pattern="^.afk(?: |$)(.*)") +@register(outgoing=True, pattern="^.afk") async def set_afk(afk_e): """ For .afk command, allows you to inform people that you are afk when they message you """ - if not afk_e.text[0].isalpha() and afk_e.text[0] not in ("/", "#", "@", "!"): + if not afk_e.text[0].isalpha() and afk_e.text[0] not in ( + "/", "#", "@", "!"): message = afk_e.text - ISAFK = gvarstatus("AFK_STATUS") - AFKREASON = gvarstatus("AFK_REASON") - REASON = afk_e.pattern_match.group(1) - if REASON: - addgvar("AFK_REASON", REASON) - await afk_e.edit(f"Going AFK !!\nReason: {REASON}") - else: - await afk_e.edit("Going AFK !!") + string = str(message[5:]) + global ISAFK + global AFKREASON + await afk_e.edit("Going AFK !!") + if string != "": + AFKREASON = string if BOTLOG: await afk_e.client.send_message(BOTLOG_CHATID, "You went AFK!") - addgvar("AFK_STATUS", True) + ISAFK = True raise StopPropagation @register(outgoing=True) +@errors_handler async def type_afk_is_not_true(notafk): """ This sets your status as not afk automatically when you write something while being afk """ - ISAFK = gvarstatus("AFK_STATUS") + global ISAFK global COUNT_MSG global USERS - AFKREASON = gvarstatus("AFK_REASON") + global AFKREASON if ISAFK: - delgvar("AFK_STATUS") + ISAFK = False await notafk.respond("I'm no longer AFK.") - delgvar("AFK_REASON") - afk_info = await notafk.respond( - "`You recieved " + - str(COUNT_MSG) + - " messages while you were away. Check log for more details.`" - ) - await sleep(4) - await afk_info.delete() + sleep(2) if BOTLOG: await notafk.client.send_message( BOTLOG_CHATID, @@ -188,7 +190,7 @@ async def type_afk_is_not_true(notafk): ) COUNT_MSG = 0 USERS = {} - delgvar("AFKREASON") + AFKREASON = None CMD_HELP.update({ "afk": ".afk [Optional Reason]\ diff --git a/userbot/modules/android.py b/userbot/modules/android.py index 57b72780..8ff413f2 100644 --- a/userbot/modules/android.py +++ b/userbot/modules/android.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot module containing commands related to android""" @@ -10,42 +10,33 @@ from bs4 import BeautifulSoup from userbot import CMD_HELP -from userbot.events import register +from userbot.events import register, errors_handler GITHUB = 'https://github.com' -MAGISK_REPO = f'{GITHUB}/topjohnwu/Magisk/releases' DEVICES_DATA = 'https://raw.githubusercontent.com/androidtrackers/' \ 'certified-android-devices/master/devices.json' @register(outgoing=True, pattern="^.magisk$") +@errors_handler async def magisk(request): """ magisk latest releases """ if not request.text[0].isalpha( ) and request.text[0] not in ("/", "#", "@", "!"): - page = BeautifulSoup(get(MAGISK_REPO).content, 'lxml') - links = '\n'.join([i['href'] for i in page.findAll('a')]) + url = 'https://raw.githubusercontent.com/topjohnwu/magisk_files/master/' releases = 'Latest Magisk Releases:\n' - try: - latest_apk = re.findall(r'/.*MagiskManager-v.*apk', links)[0] - releases += f'[{latest_apk.split("/")[-1]}]({GITHUB}{latest_apk})\n' - except IndexError: - releases += "`Can't find latest APK !!`" - try: - latest_zip = re.findall(r'/.*Magisk-v.*zip', links)[0] - releases += f'[{latest_zip.split("/")[-1]}]({GITHUB}{latest_zip})\n' - except IndexError: - releases += "`Can't find latest ZIP !!`" - try: - latest_uninstaller = re.findall(r'/.*Magisk-uninstaller-.*zip', links)[0] - releases += f'[{latest_uninstaller.split("/")[-1]}]({GITHUB}{latest_uninstaller})\n' - except IndexError: - releases += "`Can't find latest uninstaller !!`" + for variant in ['stable', 'beta', 'canary_builds/canary']: + data = get(url + variant + '.json').json() + name = variant.split('_')[0].capitalize() + releases += f'{name}: [ZIP v{data["magisk"]["version"]}]({data["magisk"]["link"]}) | ' \ + f'[APK v{data["app"]["version"]}]({data["app"]["link"]}) | ' \ + f'[Uninstaller]({data["uninstaller"]["link"]})\n' await request.edit(releases) @register(outgoing=True, pattern=r"^.device(?: |$)(\S*)") +@errors_handler async def device_info(request): """ get android device basic info from its codename """ if not request.text[0].isalpha()\ @@ -62,7 +53,7 @@ async def device_info(request): found = [i for i in get(DEVICES_DATA).json() if i["device"] == device or i["model"] == device] if found: - reply = f'Search results for {device}:\n' + reply = f'Search results for {device}:\n\n' for item in found: brand = item['brand'] name = item['name'] @@ -77,6 +68,7 @@ async def device_info(request): @register(outgoing=True, pattern=r"^.codename(?: |)([\S]*)(?: |)([\s\S]*)") +@errors_handler async def codename_info(request): """ search for android codename """ if not request.text[0].isalpha()\ @@ -92,10 +84,12 @@ async def codename_info(request): else: await request.edit("`Usage: .codename `") return - found = [i for i in get(DEVICES_DATA).json() - if i["brand"].lower() == brand and device in i["name"].lower()] + found = [i for i in get(DEVICES_DATA).json( + ) if i["brand"].lower() == brand and device in i["name"].lower()] + if len(found) > 8: + found = found[:8] if found: - reply = f'Search results for {brand.capitalize()} {device.capitalize()}:\n' + reply = f'Search results for {brand.capitalize()} {device.capitalize()}:\n\n' for item in found: brand = item['brand'] name = item['name'] @@ -110,6 +104,7 @@ async def codename_info(request): @register(outgoing=True, pattern=r"^.specs(?: |)([\S]*)(?: |)([\s\S]*)") +@errors_handler async def devices_specifications(request): """ Mobile devices specifications """ if not request.text[0].isalpha( @@ -126,19 +121,23 @@ async def devices_specifications(request): await request.edit("`Usage: .specs `") return all_brands = BeautifulSoup( - get('https://www.devicespecifications.com/en/brand-more').content, 'lxml') \ - .find('div', {'class': 'brand-listing-container-news'}).findAll('a') + get('https://www.devicespecifications.com/en/brand-more').content, + 'lxml').find('div', + {'class': 'brand-listing-container-news'}).findAll('a') brand_page_url = None try: - brand_page_url = [i['href'] for i in all_brands if brand == i.text.strip().lower()][0] + brand_page_url = [i['href'] + for i in all_brands if brand == i.text.strip().lower()][0] except IndexError: await request.edit(f'`{brand} is unknown brand!`') devices = BeautifulSoup(get(brand_page_url).content, 'lxml') \ .findAll('div', {'class': 'model-listing-container-80'}) device_page_url = None try: - device_page_url = [i.a['href'] for i in BeautifulSoup(str(devices), 'lxml') - .findAll('h3') if device in i.text.strip().lower()] + device_page_url = [ + i.a['href'] for i in BeautifulSoup( + str(devices), + 'lxml') .findAll('h3') if device in i.text.strip().lower()] except IndexError: await request.edit(f"`can't find {device}!`") if len(device_page_url) > 2: @@ -146,7 +145,7 @@ async def devices_specifications(request): reply = '' for url in device_page_url: info = BeautifulSoup(get(url).content, 'lxml') - reply = '\n' + info.title.text.split('-')[0].strip() + '\n' + reply = '\n**' + info.title.text.split('-')[0].strip() + '**\n\n' info = info.find('div', {'id': 'model-brief-specifications'}) specifications = re.findall(r'.*?
', str(info)) for item in specifications: @@ -158,6 +157,7 @@ async def devices_specifications(request): @register(outgoing=True, pattern=r"^.twrp(?: |$)(\S*)") +@errors_handler async def twrp(request): """ get android device twrp """ if not request.text[0].isalpha()\ @@ -188,17 +188,14 @@ async def twrp(request): await request.edit(reply) CMD_HELP.update({ - "magisk": "Get latest Magisk releases" + "android": ".magisk\ +\nGet latest Magisk releases\ +\n\n.device \ +\nUsage: Get info about android device codename or model.\ +\n\n.codename \ +\nUsage: Search for android device codename.\ +\n\n.specs \ +\nUsage: Get device specifications info.\ +\n\n.twrp \ +\nUsage: Get latest twrp download for android device." }) -CMD_HELP.update({ - "device": ".device \nUsage: Get info about android device codename or model." -}) -CMD_HELP.update({ - "codename": ".codename \nUsage: Search for android device codename." -}) -CMD_HELP.update({ - "specs": ".specs \nUsage: Get device specifications info." -}) -CMD_HELP.update({ - "twrp": ".twrp \nUsage: Get latest twrp download for android device." -}) \ No newline at end of file diff --git a/userbot/modules/anti_spambot.py b/userbot/modules/anti_spambot.py index 99d6ded1..9f34e5d2 100644 --- a/userbot/modules/anti_spambot.py +++ b/userbot/modules/anti_spambot.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # @@ -16,9 +16,12 @@ from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, ANTI_SPAMBOT, ANTI_SPAMBOT_SHOUT, bot from userbot.modules.admin import KICK_RIGHTS +from userbot.events import errors_handler + @bot.on(ChatAction) -async def welcome_mute(welcm): +@errors_handler +async def ANTI_SPAMBOT(welcm): try: ''' Ban a recently joined user if it matches the spammer checking algorithm. ''' @@ -27,6 +30,7 @@ async def welcome_mute(welcm): if welcm.user_joined or welcm.user_added: adder = None ignore = False + users = None if welcm.user_added: ignore = False @@ -39,17 +43,17 @@ async def welcome_mute(welcm): if ignore: return - + elif welcm.user_joined: users_list = hasattr(welcm.action_message.action, "users") if users_list: users = welcm.action_message.action.users else: users = [welcm.action_message.from_id] - + await sleep(5) spambot = False - + if not users: return @@ -69,26 +73,29 @@ async def welcome_mute(welcm): if message_date < join_time: continue # The message was sent before the user joined, thus ignore it - user = await welcm.client.get_entity(user_id) + check_user = await welcm.client.get_entity(user_id) # DEBUGGING. LEAVING IT HERE FOR SOME TIME ### - print(f"User Joined: {user.first_name} [ID: {user.id}]") + print( + f"User Joined: {check_user.first_name} [ID: {check_user.id}]") print(f"Chat: {welcm.chat.title}") print(f"Time: {join_time}") - print(f"Message Sent: {message.text}\n\n[Time: {message_date}]") - # + print( + f"Message Sent: {message.text}\n\n[Time: {message_date}]") + ############################################## try: - cas_url = f"https://combot.org/api/cas/check?user_id={user.id}" - r = get(cas_url, timeout = 3) + cas_url = f"https://combot.org/api/cas/check?user_id={check_user.id}" + r = get(cas_url, timeout=3) data = r.json() - except: - print("CAS check failed, falling back to legacy anti_spambot behaviour.") + except BaseException: + print( + "CAS check failed, falling back to legacy anti_spambot behaviour.") data = None pass if data and data['ok']: - reason = f"[Banned by Combot Anti Spam](https://combot.org/cas/query?u={user.id})" + reason = f"[Banned by Combot Anti Spam](https://combot.org/cas/query?u={check_user.id})" spambot = True elif "t.cn/" in message.text: reason = "Match on `t.cn` URLs" @@ -106,7 +113,7 @@ async def welcome_mute(welcm): reason = "Match on `bit.ly` URLs" spambot = True else: - if user.first_name in ( + if check_user.first_name in ( "Bitmex", "Promotion", "Information", @@ -126,6 +133,7 @@ async def welcome_mute(welcm): continue # Check the next messsage if spambot: + chat = await welcm.get_chat() admin = chat.admin_rights creator = chat.creator @@ -134,41 +142,54 @@ async def welcome_mute(welcm): await welcm.reply( "@admins\n" "`ANTI SPAMBOT DETECTOR!\n" - "THIS USER MATCHES MY ALGORITHMS AS A SPAMBOT!`\n" - f"REASON: {reason}") + "THIS USER MATCHES MY ALGORITHMS AS A SPAMBOT!`" + f"REASON: {reason}" + ) + kicked = False + reported = True else: - await welcm.reply( - "`Potential Spambot Detected! Kicking away! " - "Will log the ID for further purposes!\n" - f"USER:` [{user.first_name}](tg://user?id={user.id})") try: + + await welcm.reply( + "`Potential Spambot Detected !!`\n" + f"`REASON:` {reason}\n" + "Kicking away for now, will log the ID for further purposes.\n" + f"USER:` [{check_user.first_name}](tg://user?id={check_user.id})" + ) + await welcm.client( EditBannedRequest( welcm.chat_id, - user.id, + check_user.id, KICK_RIGHTS ) ) - await sleep(1) + kicked = True + reported = False + except BaseException: if ANTI_SPAMBOT_SHOUT: await welcm.reply( "@admins\n" "`ANTI SPAMBOT DETECTOR!\n" - "THIS USER MATCHES MY ALGORITHMS AS A SPAMBOT!`\n" - f"REASON: {reason}") + "THIS USER MATCHES MY ALGORITHMS AS A SPAMBOT!`" + f"REASON: {reason}" + ) + kicked = False + reported = True if BOTLOG: - await welcm.client.send_message( - BOTLOG_CHATID, - "#ANTI_SPAMBOT REPORT\n" - f"USER: [{user.first_name}](tg://user?id={user.id})\n" - f"USER ID: `{user.id}`\n" - f"CHAT: {welcm.chat.title}\n" - f"CHAT ID: `{welcm.chat_id}`\n" - f"REASON: {reason}\n" - f"MESSAGE:\n\n{message.text}" - ) + if kicked or reported: + await welcm.client.send_message( + BOTLOG_CHATID, + "#ANTI_SPAMBOT REPORT\n" + f"USER: [{user.first_name}](tg://user?id={check_user.id})\n" + f"USER ID: `{check_user.id}`\n" + f"CHAT: {welcm.chat.title}\n" + f"CHAT ID: `{welcm.chat_id}`\n" + f"REASON: {reason}\n" + f"MESSAGE:\n\n{message.text}" + ) except ValueError: pass diff --git a/userbot/modules/chat.py b/userbot/modules/chat.py index 5242a0a5..0b877a5f 100644 --- a/userbot/modules/chat.py +++ b/userbot/modules/chat.py @@ -1,23 +1,22 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. """ Userbot module containing userid, chatid and log commands""" from time import sleep from telethon.tl.functions.channels import LeaveChannelRequest -from telethon.tl.functions.users import GetFullUserRequest -from telethon.tl.types import MessageEntityMentionName - from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID, bot -from userbot.events import register +from userbot.events import register, errors_handler @register(outgoing=True, pattern="^.userid$") +@errors_handler async def useridgetter(target): """ For .userid command, returns the ID of the target user. """ - if not target.text[0].isalpha() and target.text[0] not in ("/", "#", "@", "!"): + if not target.text[0].isalpha() and target.text[0] not in ( + "/", "#", "@", "!"): message = await target.get_reply_message() if message: if not message.forward: @@ -40,37 +39,19 @@ async def useridgetter(target): @register(outgoing=True, pattern="^.chatid$") +@errors_handler async def chatidgetter(chat): """ For .chatid, returns the ID of the chat you are in at that moment. """ if not chat.text[0].isalpha() and chat.text[0] not in ("/", "#", "@", "!"): await chat.edit("Chat ID: `" + str(chat.chat_id) + "`") -@register(outgoing=True, pattern="^.mention (.*)") -async def mention(event): - """ For .chatid, returns the ID of the chat you are in at that moment. """ - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): - if event.fwd_from: - return - input_str = event.pattern_match.group(1) - if event.reply_to_msg_id: - previous_message = await event.get_reply_message() - if previous_message.forward: - replied_user = previous_message.forward.from_id - else: - replied_user = previous_message.from_id - else: - return - user_id = replied_user - caption = """{}""".format( - user_id, input_str) - await event.edit(caption, parse_mode="HTML") - - @register(outgoing=True, pattern=r"^.log(?: |$)([\s\S]*)") +@errors_handler async def log(log_text): """ For .log command, forwards a message or the command argument to the bot logs group """ - if not log_text.text[0].isalpha() and log_text.text[0] not in ("/", "#", "@", "!"): + if not log_text.text[0].isalpha( + ) and log_text.text[0] not in ("/", "#", "@", "!"): if BOTLOG: if log_text.reply_to_msg_id: reply_msg = await log_text.get_reply_message() @@ -90,18 +71,23 @@ async def log(log_text): @register(outgoing=True, pattern="^.kickme$") +@errors_handler async def kickme(leave): """ Basically it's .kickme command """ - if not leave.text[0].isalpha() and leave.text[0] not in ("/", "#", "@", "!"): + if not leave.text[0].isalpha() and leave.text[0] not in ( + "/", "#", "@", "!"): await leave.edit("`Nope, no, no, I go away`") + sleep(2) + await leave.delete() await bot(LeaveChannelRequest(leave.chat_id)) @register(outgoing=True, pattern="^.unmutechat$") - +@errors_handler async def unmute_chat(unm_e): """ For .unmutechat command, unmute a muted chat. """ - if not unm_e.text[0].isalpha() and unm_e.text[0] not in ("/", "#", "@", "!"): + if not unm_e.text[0].isalpha() and unm_e.text[0] not in ( + "/", "#", "@", "!"): try: from userbot.modules.sql_helper.keep_read_sql import unkread except AttributeError: @@ -109,12 +95,16 @@ async def unmute_chat(unm_e): return unkread(str(unm_e.chat_id)) await unm_e.edit("```Unmuted this chat Successfully```") + sleep(2) + await unm_e.delete() @register(outgoing=True, pattern="^.mutechat$") +@errors_handler async def mute_chat(mute_e): """ For .mutechat command, mute any chat. """ - if not mute_e.text[0].isalpha() and mute_e.text[0] not in ("/", "#", "@", "!"): + if not mute_e.text[0].isalpha() and mute_e.text[0] not in ( + "/", "#", "@", "!"): try: from userbot.modules.sql_helper.keep_read_sql import kread except AttributeError: @@ -123,6 +113,8 @@ async def mute_chat(mute_e): await mute_e.edit(str(mute_e.chat_id)) kread(str(mute_e.chat_id)) await mute_e.edit("`Shush! This chat will be silenced!`") + sleep(2) + await mute_e.delete() if BOTLOG: await mute_e.client.send_message( BOTLOG_CHATID, @@ -130,6 +122,7 @@ async def mute_chat(mute_e): @register(incoming=True) +@errors_handler async def keep_read(message): """ The mute logic. """ try: @@ -154,7 +147,5 @@ async def keep_read(message): \n\n.unmutechat\ \nUsage: Unmutes a muted chat.\ \n\n.mutechat\ -\nUsage: Allows you to mute any chat.\ -\n\n.mention \ -\nUsage: Reply to generate the user's permanent link with custom text." -}) \ No newline at end of file +\nUsage: Allows you to mute any chat." +}) diff --git a/userbot/modules/direct_links.py b/userbot/modules/direct_links.py index a8d2c414..af1a9436 100644 --- a/userbot/modules/direct_links.py +++ b/userbot/modules/direct_links.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot module containing various sites direct links generators""" @@ -15,10 +15,11 @@ from humanize import naturalsize from userbot import CMD_HELP -from userbot.events import register +from userbot.events import register, errors_handler @register(outgoing=True, pattern=r"^.direct(?: |$)([\s\S]*)") +@errors_handler async def direct_link_generator(request): """ direct links generator """ if not request.text[0].isalpha( @@ -365,4 +366,4 @@ def useragent(): "List of supported URLs:\n" "`Google Drive - MEGA.nz - Cloud Mail - Yandex.Disk - AFH - " "ZippyShare - MediaFire - SourceForge - OSDN - GitHub`" -}) \ No newline at end of file +}) diff --git a/userbot/modules/dogbin.py b/userbot/modules/dogbin.py index c4804b38..2b30f34b 100644 --- a/userbot/modules/dogbin.py +++ b/userbot/modules/dogbin.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot module containing commands for interacting with dogbin(https://del.dog)""" @@ -9,11 +9,13 @@ import asyncio import os from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, LOGS, TEMP_DOWNLOAD_DIRECTORY -from userbot.events import register +from userbot.events import register, errors_handler DOGBIN_URL = "https://del.dog/" + @register(outgoing=True, pattern=r"^.paste(?: |$)([\s\S]*)") +@errors_handler async def paste(pstl): """ For .paste command, pastes the text directly to dogbin. """ if not pstl.text[0].isalpha() and pstl.text[0] not in ("/", "#", "@", "!"): @@ -76,9 +78,11 @@ async def paste(pstl): @register(outgoing=True, pattern="^.getpaste(?: |$)(.*)") +@errors_handler async def get_dogbin_content(dog_url): """ For .getpaste command, fetches the content of a dogbin URL. """ - if not dog_url.text[0].isalpha() and dog_url.text[0] not in ("/", "#", "@", "!"): + if not dog_url.text[0].isalpha() and dog_url.text[0] not in ( + "/", "#", "@", "!"): textx = await dog_url.get_reply_message() message = dog_url.pattern_match.group(1) await dog_url.edit("`Getting dogbin content . . .`") @@ -107,7 +111,7 @@ async def get_dogbin_content(dog_url): await dog_url.edit("Request returned an unsuccessful status code.\n\n" + str(HTTPErr)) return except exceptions.Timeout as TimeoutErr: - await dog_url.edit("Request timed out."+ str(TimeoutErr)) + await dog_url.edit("Request timed out." + str(TimeoutErr)) return except exceptions.TooManyRedirects as RedirectsErr: await dog_url.edit("Request exceeded the configured number of maximum redirections." + str(RedirectsErr)) diff --git a/userbot/modules/evaluators.py b/userbot/modules/evaluators.py index 10f8bfc7..0a8871cd 100644 --- a/userbot/modules/evaluators.py +++ b/userbot/modules/evaluators.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # @@ -12,13 +12,15 @@ from sys import executable from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID -from userbot.events import register +from userbot.events import register, errors_handler @register(outgoing=True, pattern="^.eval(?: |$)(.*)") +@errors_handler async def evaluate(query): """ For .eval command, evaluates the given Python expression. """ - if not query.text[0].isalpha() and query.text[0] not in ("/", "#", "@", "!"): + if not query.text[0].isalpha() and query.text[0] not in ( + "/", "#", "@", "!"): if query.is_channel and not query.is_group: await query.edit("`Eval isn't permitted on channels`") return @@ -77,9 +79,11 @@ async def evaluate(query): @register(outgoing=True, pattern=r"^.exec(?: |$)([\s\S]*)") +@errors_handler async def run(run_q): """ For .exec command, which executes the dynamically created program """ - if not run_q.text[0].isalpha() and run_q.text[0] not in ("/", "#", "@", "!"): + if not run_q.text[0].isalpha() and run_q.text[0] not in ( + "/", "#", "@", "!"): code = run_q.pattern_match.group(1) if run_q.is_channel and not run_q.is_group: @@ -147,6 +151,7 @@ async def run(run_q): @register(outgoing=True, pattern="^.term(?: |$)(.*)") +@errors_handler async def terminal_runner(term): """ For .term command, runs bash commands and scripts on your server. """ if not term.text[0].isalpha() and term.text[0] not in ("/", "#", "@", "!"): @@ -222,4 +227,4 @@ async def terminal_runner(term): }) CMD_HELP.update({ "term": ".term ls\nUsage: Run bash commands and scripts on your server." -}) \ No newline at end of file +}) diff --git a/userbot/modules/filter.py b/userbot/modules/filter.py index 750537c3..1b438573 100644 --- a/userbot/modules/filter.py +++ b/userbot/modules/filter.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot module for filter commands """ @@ -10,13 +10,15 @@ from telethon.tl import types from telethon import utils from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP -from userbot.events import register +from userbot.events import register, errors_handler TYPE_TEXT = 0 TYPE_PHOTO = 1 TYPE_DOCUMENT = 2 + @register(incoming=True, disable_edited=True) +@errors_handler async def filter_incoming_handler(handler): """ Checks if the incoming message contains handler of a filter """ try: @@ -30,9 +32,10 @@ async def filter_incoming_handler(handler): name = handler.raw_text filters = get_filters(handler.chat_id) if not filters: - return + return for trigger in filters: - pattern = r"( |^|[^\w])" + escape(trigger.keyword) + r"( |$|[^\w])" + pattern = r"( |^|[^\w])" + \ + escape(trigger.keyword) + r"( |$|[^\w])" pro = fullmatch(pattern, name, flags=IGNORECASE) if pro: if trigger.snip_type == TYPE_PHOTO: @@ -58,9 +61,11 @@ async def filter_incoming_handler(handler): @register(outgoing=True, pattern="^.filter (.*)") +@errors_handler async def add_new_filter(new_handler): """ For .filter command, allows adding new filters in a chat """ - if not new_handler.text[0].isalpha() and new_handler.text[0] not in ("/", "#", "@", "!"): + if not new_handler.text[0].isalpha( + ) and new_handler.text[0] not in ("/", "#", "@", "!"): try: from userbot.modules.sql_helper.filter_sql import add_filter except AttributeError: @@ -88,16 +93,24 @@ async def add_new_filter(new_handler): success = "`Filter` **{}** `{} successfully`" - if add_filter(str(new_handler.chat_id), keyword, snip['text'], snip['type'], snip.get('id'), snip.get('hash'), snip.get('fr')) is True: + if add_filter(str(new_handler.chat_id), + keyword, + snip['text'], + snip['type'], + snip.get('id'), + snip.get('hash'), + snip.get('fr')) is True: await new_handler.edit(success.format(keyword, 'added')) else: await new_handler.edit(success.format(keyword, 'updated')) @register(outgoing=True, pattern="^.stop\\s.*") +@errors_handler async def remove_a_filter(r_handler): """ For .stop command, allows you to remove a filter from a chat. """ - if not r_handler.text[0].isalpha() and r_handler.text[0] not in ("/", "#", "@", "!"): + if not r_handler.text[0].isalpha( + ) and r_handler.text[0] not in ("/", "#", "@", "!"): try: from userbot.modules.sql_helper.filter_sql import remove_filter except AttributeError: @@ -108,13 +121,14 @@ async def remove_a_filter(r_handler): if not remove_filter(r_handler.chat_id, filt): await r_handler.edit("`Filter` **{}** `doesn't exist.`" - .format(filt)) + .format(filt)) else: await r_handler.edit("`Filter` **{}** `was deleted successfully`" - .format(filt)) + .format(filt)) @register(outgoing=True, pattern="^.rmfilters (.*)") +@errors_handler async def kick_marie_filter(event): """ For .rmfilters command, allows you to kick all \ Marie(or her clones) filters from a chat. """ @@ -146,9 +160,11 @@ async def kick_marie_filter(event): @register(outgoing=True, pattern="^.filters$") +@errors_handler async def filters_active(event): """ For .filters command, lists all of the active filters in a chat. """ - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): try: from userbot.modules.sql_helper.filter_sql import get_filters except AttributeError: @@ -167,7 +183,6 @@ async def filters_active(event): await event.edit(transact) - CMD_HELP.update({ "filter": ".filters\ \nUsage: Lists all active userbot filters in a chat.\ diff --git a/userbot/modules/gdrive.py b/userbot/modules/gdrive.py index dd4b4f36..965e992e 100644 --- a/userbot/modules/gdrive.py +++ b/userbot/modules/gdrive.py @@ -10,15 +10,22 @@ import time from pySmartDL import SmartDL from telethon import events -from datetime import datetime from apiclient.discovery import build from apiclient.http import MediaFileUpload from apiclient.errors import ResumableUploadError from oauth2client.client import OAuth2WebServerFlow from oauth2client.file import Storage from oauth2client import file, client, tools -from userbot import (G_DRIVE_CLIENT_ID, G_DRIVE_CLIENT_SECRET, G_DRIVE_AUTH_TOKEN_DATA, GDRIVE_FOLDER_ID, BOTLOG_CHATID, TEMP_DOWNLOAD_DIRECTORY, CMD_HELP, LOGS) -from userbot.events import register +from userbot import ( + G_DRIVE_CLIENT_ID, + G_DRIVE_CLIENT_SECRET, + G_DRIVE_AUTH_TOKEN_DATA, + GDRIVE_FOLDER_ID, + BOTLOG_CHATID, + TEMP_DOWNLOAD_DIRECTORY, + CMD_HELP, + LOGS) +from userbot.events import register, errors_handler from mimetypes import guess_type import httplib2 import subprocess @@ -38,6 +45,7 @@ @register(pattern=r"^.gdrive(?: |$)(.*)", outgoing=True) +@errors_handler async def download(dryb): """ For .gdrive command, upload files to google drive. """ if not dryb.text[0].isalpha() and dryb.text[0] not in ("/", "#", "@", "!"): @@ -51,14 +59,16 @@ async def download(dryb): os.makedirs(TEMP_DOWNLOAD_DIRECTORY) required_file_name = None if "|" in input_str: - start = datetime.now() url, file_name = input_str.split("|") url = url.strip() # https://stackoverflow.com/a/761825/4723940 file_name = file_name.strip() head, tail = os.path.split(file_name) if head: - if not os.path.isdir(os.path.join(TEMP_DOWNLOAD_DIRECTORY, head)): + if not os.path.isdir( + os.path.join( + TEMP_DOWNLOAD_DIRECTORY, + head)): os.makedirs(os.path.join(TEMP_DOWNLOAD_DIRECTORY, head)) file_name = os.path.join(head, tail) downloaded_file_name = TEMP_DOWNLOAD_DIRECTORY + "" + file_name @@ -72,7 +82,7 @@ async def download(dryb): downloaded = downloader.get_dl_size() now = time.time() diff = now - c_time - percentage = downloader.get_progress()*100 + percentage = downloader.get_progress() * 100 speed = downloader.get_speed() elapsed_time = round(diff) * 1000 progress_str = "[{0}{1}]\nProgress: {2}%".format( @@ -89,12 +99,10 @@ async def download(dryb): except Exception as e: LOGS.info(str(e)) pass - end = datetime.now() - duration = (end - start).seconds if downloader.isSuccessful(): await dryb.edit( - "Downloaded to `{}` in {} seconds.\nNow uploading to GDrive...".format( - downloaded_file_name, duration) + "Downloaded to `{}` successfully !!\nInitiating upload to Google Drive..".format( + downloaded_file_name) ) required_file_name = downloaded_file_name else: @@ -104,16 +112,12 @@ async def download(dryb): elif input_str: input_str = input_str.strip() if os.path.exists(input_str): - start = datetime.now() - end = datetime.now() - duration = (end - start).seconds required_file_name = input_str - await dryb.edit("Found `{}` in {} seconds, uploading to Google Drive !!".format(input_str, duration)) + await dryb.edit("Found `{}` in local server, initiating upload to Google Drive..".format(input_str, duration)) else: - await dryb.edit("File not found in local server. Give me a valid file path !!") + await dryb.edit("File not found in local server. Give me a valid file path !") return False elif dryb.reply_to_msg_id: - start = datetime.now() try: c_time = time.time() downloaded_file_name = await dryb.client.download_media( @@ -123,26 +127,26 @@ async def download(dryb): progress(d, t, dryb, c_time, "Downloading...") ) ) - except Exception as e: # pylint:disable=C0103,W0703 + except Exception as e: # pylint:disable=C0103,W0703 await dryb.edit(str(e)) else: - end = datetime.now() required_file_name = downloaded_file_name - duration = (end - start).seconds await dryb.edit( - "Downloaded to `{}` in {} seconds.\nNow uploading to GDrive...".format( - downloaded_file_name, duration) + "Downloaded to `{}` successfully !!\nInitiating upload to Google Drive..".format( + downloaded_file_name) ) if required_file_name: # if G_DRIVE_AUTH_TOKEN_DATA is not None: with open(G_DRIVE_TOKEN_FILE, "w") as t_file: t_file.write(G_DRIVE_AUTH_TOKEN_DATA) - # Check if token file exists, if not create it by requesting authorization code + # Check if token file exists, if not create it by requesting + # authorization code if not os.path.isfile(G_DRIVE_TOKEN_FILE): storage = await create_token_file(G_DRIVE_TOKEN_FILE, dryb) http = authorize(G_DRIVE_TOKEN_FILE, storage) - # Authorize, get file parameters, upload file and print out result URL for download + # Authorize, get file parameters, upload file and print out result URL + # for download http = authorize(G_DRIVE_TOKEN_FILE, None) file_name, mime_type = file_ops(required_file_name) # required_file_name will have the full path @@ -154,7 +158,10 @@ async def download(dryb): await dryb.edit(f"Error while uploading to Google Drive\nError Code:\n`{e}`") -@register(pattern=r"^.gsetf https?://drive\.google\.com/drive/u/\d/folders/([-\w]{25,})", outgoing=True) +@register( + pattern=r"^.gsetf https?://drive\.google\.com/drive/u/\d/folders/([-\w]{25,})", + outgoing=True) +@errors_handler async def download(set): """For .gsetf command, allows you to set path""" if not set.text[0].isalpha() and set.text[0] not in ("/", "#", "@", "!"): @@ -171,6 +178,7 @@ async def download(set): @register(pattern="^.gsetclear$", outgoing=True) +@errors_handler async def download(gclr): """For .gsetclear command, allows you clear ur curnt custom path""" if not gclr.text[0].isalpha() and gclr.text[0] not in ("/", "#", "@", "!"): @@ -239,7 +247,8 @@ async def upload_file(http, file_path, file_name, mime_type, event): if parent_id: body["parents"] = [{"id": parent_id}] # Permissions body description: anyone who has link can upload - # Other permissions can be found at https://developers.google.com/drive/v2/reference/permissions + # Other permissions can be found at + # https://developers.google.com/drive/v2/reference/permissions permissions = { "role": "reader", "type": "anyone", @@ -262,17 +271,21 @@ async def upload_file(http, file_path, file_name, mime_type, event): if file: await event.edit(file_name + " uploaded successfully") # Insert new permissions - drive_service.permissions().insert(fileId=response.get('id'), body=permissions).execute() + drive_service.permissions().insert( + fileId=response.get('id'), + body=permissions).execute() # Define file instance and get url for download file = drive_service.files().get(fileId=response.get('id')).execute() download_url = response.get("webContentLink") return download_url + @register(pattern="^.gfolder$", outgoing=True) +@errors_handler async def _(event): if event.fwd_from: return - folder_link =f"https://drive.google.com/drive/u/2/folders/"+parent_id + folder_link = f"https://drive.google.com/drive/u/2/folders/" + parent_id await event.edit(f"Userbot is currently uploading files to [this Gdrive folder]({folder_link})") diff --git a/userbot/modules/github.py b/userbot/modules/github.py index fec82b4c..fd9fe7ee 100644 --- a/userbot/modules/github.py +++ b/userbot/modules/github.py @@ -1,10 +1,13 @@ import aiohttp -from userbot.events import register +from userbot.events import register, errors_handler from userbot import CMD_HELP + @register(pattern=r".git (.*)", outgoing=True) +@errors_handler async def github(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): URL = f"https://api.github.com/users/{event.pattern_match.group(1)}" chat = await event.get_chat() async with aiohttp.ClientSession() as session: @@ -50,4 +53,4 @@ async def github(event): CMD_HELP.update({ "git": "Like .whois but for GitHub usernames." -}) \ No newline at end of file +}) diff --git a/userbot/modules/hash.py b/userbot/modules/hash.py index 79cb1f34..7a5ecad0 100644 --- a/userbot/modules/hash.py +++ b/userbot/modules/hash.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # @@ -10,13 +10,15 @@ from subprocess import run as runapp import pybase64 from userbot import CMD_HELP -from userbot.events import register +from userbot.events import register, errors_handler @register(outgoing=True, pattern="^.hash (.*)") +@errors_handler async def gethash(hash_q): """ For .hash command, find the md5, sha1, sha256, sha512 of the string. """ - if not hash_q.text[0].isalpha() and hash_q.text[0] not in ("/", "#", "@", "!"): + if not hash_q.text[0].isalpha() and hash_q.text[0] not in ( + "/", "#", "@", "!"): hashtxt_ = hash_q.pattern_match.group(1) hashtxt = open("hashdis.txt", "w+") hashtxt.write(hashtxt_) @@ -59,13 +61,14 @@ async def gethash(hash_q): @register(outgoing=True, pattern="^.base64 (en|de) (.*)") +@errors_handler async def endecrypt(query): """ For .base64 command, find the base64 encoding of the given string. """ - if not query.text[0].isalpha() and query.text[0] not in ("/", "#", "@", "!"): + if not query.text[0].isalpha() and query.text[0] not in ( + "/", "#", "@", "!"): if query.pattern_match.group(1) == "en": - lething = str(pybase64.b64encode(bytes(query.pattern_match.group(2), "utf-8")))[ - 2: - ] + lething = str(pybase64.b64encode( + bytes(query.pattern_match.group(2), "utf-8")))[2:] await query.reply("Encoded: `" + lething[:-1] + "`") else: lething = str( @@ -82,4 +85,4 @@ async def endecrypt(query): CMD_HELP.update({ "hash": "Find the md5, sha1, sha256, sha512 of the string when written into a txt file." -}) \ No newline at end of file +}) diff --git a/userbot/modules/help.py b/userbot/modules/help.py index 4396bbc2..41ad4f53 100644 --- a/userbot/modules/help.py +++ b/userbot/modules/help.py @@ -1,19 +1,21 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # """ Userbot help command """ from userbot import CMD_HELP -from userbot.events import register +from userbot.events import register, errors_handler @register(outgoing=True, pattern="^.help(?: |$)(.*)") +@errors_handler async def help(event): """ For .help command,""" - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): args = event.pattern_match.group(1) if args: if args in CMD_HELP: @@ -21,7 +23,7 @@ async def help(event): else: await event.edit("Please specify a valid module name.") else: - await event.edit("Please specify which module do you want help for!") + await event.edit("Please specify which module do you want help for !!\nSyntax: .help ") string = "" for i in CMD_HELP: string += "ℹ️ `" + str(i) diff --git a/userbot/modules/lastfm.py b/userbot/modules/lastfm.py index b9dceb83..19b39ea6 100644 --- a/userbot/modules/lastfm.py +++ b/userbot/modules/lastfm.py @@ -1,3 +1,9 @@ +# Copyright (C) 2019 The Raphielscape Company LLC. +# +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); +# you may not use this file except in compliance with the License. +# + from asyncio import sleep from pylast import User, WSError from re import sub @@ -12,7 +18,7 @@ from telethon.errors.rpcerrorlist import FloodWaitError from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID, DEFAULT_BIO, BIO_PREFIX, lastfm, LASTFM_USERNAME, bot -from userbot.events import register +from userbot.events import register, errors_handler # =================== CONSTANT =================== LFM_BIO_ENABLED = "```last.fm current music to bio is now enabled.```" @@ -40,22 +46,28 @@ @register(outgoing=True, pattern="^.lastfm$") +@errors_handler async def last_fm(lastFM): """ For .lastfm command, fetch scrobble data from last.fm. """ - if not lastFM.text[0].isalpha() and lastFM.text[0] not in ("/", "#", "@", "!"): + if not lastFM.text[0].isalpha() and lastFM.text[0] not in ( + "/", "#", "@", "!"): await lastFM.edit("Processing...") preview = None playing = User(LASTFM_USERNAME, lastfm).get_now_playing() username = f"https://www.last.fm/user/{LASTFM_USERNAME}" if playing is not None: try: - image = User(LASTFM_USERNAME, lastfm).get_now_playing().get_cover_image() + image = User(LASTFM_USERNAME, + lastfm).get_now_playing().get_cover_image() except IndexError: image = None pass tags = gettags(isNowPlaying=True, playing=playing) rectrack = parse.quote_plus(f"{playing}") - rectrack = sub("^", "https://www.youtube.com/results?search_query=", rectrack) + rectrack = sub( + "^", + "https://www.youtube.com/results?search_query=", + rectrack) if image: output = f"[‎]({image})[{LASTFM_USERNAME}]({username}) __is now listening to:__\n\n• [{playing}]({rectrack})\n`{tags}`" preview = True @@ -66,11 +78,14 @@ async def last_fm(lastFM): playing = User(LASTFM_USERNAME, lastfm).get_now_playing() output = f"[{LASTFM_USERNAME}]({username}) __was last listening to:__\n\n" for i, track in enumerate(recent): - print(i) # vscode hates the i being there so lets make it chill + print(i) # vscode hates the i being there so lets make it chill printable = artist_and_song(track) tags = gettags(track) rectrack = parse.quote_plus(str(printable)) - rectrack = sub("^", "https://www.youtube.com/results?search_query=", rectrack) + rectrack = sub( + "^", + "https://www.youtube.com/results?search_query=", + rectrack) output += f"• [{printable}]({rectrack})\n" if tags: output += f"`{tags}`\n\n" @@ -162,8 +177,10 @@ async def get_curr_track(lfmbio): @register(outgoing=True, pattern=r"^.lastbio (\S*)") +@errors_handler async def lastbio(lfmbio): - if not lfmbio.text[0].isalpha() and lfmbio.text[0] not in ("/", "#", "@", "!"): + if not lfmbio.text[0].isalpha() and lfmbio.text[0] not in ( + "/", "#", "@", "!"): arg = lfmbio.pattern_match.group(1) global LASTFMCHECK global RUNNING @@ -187,8 +204,10 @@ async def lastbio(lfmbio): @register(outgoing=True, pattern=r"^.lastlog (\S*)") +@errors_handler async def lastlog(lstlog): - if not lstlog.text[0].isalpha() and lstlog.text[0] not in ("/", "#", "@", "!"): + if not lstlog.text[0].isalpha() and lstlog.text[0] not in ( + "/", "#", "@", "!"): arg = lstlog.pattern_match.group(1) global LastLog LastLog = False diff --git a/userbot/modules/locks.py b/userbot/modules/locks.py index c5fe6d3b..7a87ad14 100644 --- a/userbot/modules/locks.py +++ b/userbot/modules/locks.py @@ -1,14 +1,17 @@ -from telethon import events, functions, types -import asyncio -from userbot import bot -# import datetime +from telethon.tl.functions.channels import EditBannedRequest +from telethon.tl.functions.messages import EditChatDefaultBannedRightsRequest +from telethon.tl.types import ChatBannedRights +from asyncio import sleep +from userbot import CMD_HELP +from userbot.events import register, errors_handler -@bot.on(events.NewMessage(pattern=r"\.lock ?(.*)", outgoing=True)) -async def _(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): - if event.fwd_from: - return + +@register(outgoing=True, pattern=r"^.lock ?(.*)") +@errors_handler +async def locks(event): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): input_str = event.pattern_match.group(1) peer_id = event.chat_id msg = None @@ -21,29 +24,137 @@ async def _(event): adduser = None cpin = None changeinfo = None - if "msg" in input_str: + if input_str is "msg": + msg = True + what = "messages" + if input_str is "media": + media = True + what = "media" + if input_str is "sticker": + sticker = True + what = "stickers" + if input_str is "gif": + gif = True + what = "GIFs" + if input_str is "game": + gamee = True + what = "games" + if input_str is "inline": + ainline = True + what = "inline bots" + if input_str is "poll": + gpoll = True + what = "polls" + if input_str is "invite": + adduser = True + what = "invites" + if input_str is "pin": + cpin = True + what = "pins" + if input_str is "info": + changeinfo = True + what = "chat info" + if input_str is "all": msg = True - if "media" in input_str: media = True - if "sticker" in input_str: sticker = True - if "gif" in input_str: gif = True - if "gamee" in input_str: gamee = True - if "ainline" in input_str: ainline = True - if "gpoll" in input_str: gpoll = True - if "adduser" in input_str: adduser = True - if "cpin" in input_str: cpin = True - if "changeinfo" in input_str: changeinfo = True - banned_rights=types.ChatBannedRights( + what = "everything" + + banned_rights = ChatBannedRights( + until_date=None, + send_messages=msg, + send_media=media, + send_stickers=sticker, + send_gifs=gif, + send_games=gamee, + send_inline=ainline, + send_polls=gpoll, + invite_users=adduser, + pin_messages=cpin, + change_info=changeinfo, + ) + try: + result = await event.client(EditChatDefaultBannedRightsRequest( + peer=peer_id, + banned_rights=banned_rights + )) + except BaseException: + await event.edit("`Do I have proper rights fot that ??`") + else: + await event.edit(f"`Locked {what} for this chat !!`") + await sleep(3) + await event.delete() + + +@register(outgoing=True, pattern=r"^.unlock ?(.*)") +@errors_handler +async def rem_locks(event): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): + input_str = event.pattern_match.group(1) + peer_id = event.chat_id + msg = None + media = None + sticker = None + gif = None + gamee = None + ainline = None + gpoll = None + adduser = None + cpin = None + changeinfo = None + if input_str is "msg": + msg = False + what = "messages" + if input_str is "media": + media = False + what = "media" + if input_str is "sticker": + sticker = False + what = "stickers" + if input_str is "gif": + gif = False + what = "GIFs" + if input_str is "game": + gamee = False + what = "games" + if input_str is "inline": + ainline = False + what = "inline bots" + if input_str is "poll": + gpoll = False + what = "polls" + if input_str is "invite": + adduser = False + what = "invites" + if input_str is "pin": + cpin = False + what = "pins" + if input_str is "info": + changeinfo = False + what = "chat info" + if input_str is "all": + msg = False + media = False + sticker = False + gif = False + gamee = False + ainline = False + gpoll = False + adduser = False + cpin = False + changeinfo = False + what = "everything" + + banned_rights = ChatBannedRights( until_date=None, - # view_messages=None, send_messages=msg, send_media=media, send_stickers=sticker, @@ -56,13 +167,21 @@ async def _(event): change_info=changeinfo, ) try: - result = await bot(functions.messages.EditChatDefaultBannedRightsRequest( + result = await event.client(EditChatDefaultBannedRightsRequest( peer=peer_id, banned_rights=banned_rights )) - # logger.info(result.stringify()) - except Exception as e: - await event.edit(str(e)) + except BaseException: + await event.edit("`Do I have proper rights fot that ??`") else: - await asyncio.sleep(5) + await event.edit(f"`Unlocked {what} for this chat !!`") + await sleep(3) await event.delete() + +CMD_HELP.update({ + "locks": ".lock or .unlock \ +\nUsage: Allows you to lock/unlock some common message types in the chat.\ +[NOTE: Requires proper admin rights in the chat !!]\ +\n\nAvailable message types to lock/unlock are: \ +\n`all, msg, media, sticker, gif, game, inline, poll, invite, pin, info`\ +"}) diff --git a/userbot/modules/memes.py b/userbot/modules/memes.py index 6a93e072..bd755fdc 100644 --- a/userbot/modules/memes.py +++ b/userbot/modules/memes.py @@ -1,6 +1,6 @@ # Copyright (C) 2019 The Raphielscape Company LLC. # -# Licensed under the Raphielscape Public License, Version 1.b (the "License"); +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. # # @@ -22,7 +22,7 @@ from cowpy import cow from userbot import CMD_HELP -from userbot.events import register +from userbot.events import register, errors_handler # ================= CONSTANT ================= METOOSTR = [ @@ -364,22 +364,21 @@ ] RUNSREACTS = [ - "Runs to Thanos", - "Runs far, far away from earth", - "Running faster than usian bolt coz I'mma Bot", - "Runs to Marie", + "Runs to Thanos..", + "Runs far, far away from earth..", + "Running faster than Bolt coz i'mma userbot !!", + "Runs to Marie..", "This Group is too cancerous to deal with.", "Cya bois", "Kys", - "I am a mad person. Plox Ban me.", "I go away", "I am just walking off, coz me is too fat.", "I Fugged off!", "Will run for chocolate.", "I run because I really like food.", - "Running...because dieting is not an option.", + "Running...\nbecause dieting is not an option.", "Wicked fast runnah", - "If you wanna catch me, you got to be fast...if you wanna stay with me, you got to be good...if you wanna pass me...You've got to be kidding.", + "If you wanna catch me, you got to be fast...\nIf you wanna stay with me, you got to be good...\nBut if you wanna pass me...\nYou've got to be kidding.", "Anyone can run a hundred meters, it's the next forty-two thousand and two hundred that count.", "Why are all these people following me?", "Are the kids still chasing me?", @@ -418,26 +417,19 @@ "┐(´д`)┌", "┐(´∀`)┌", "ʅ(́◡◝)ʃ", - "ლ(゚д゚ლ)", "┐(゚~゚)┌", "┐('д')┌", - "ლ|^Д^ლ|", - "ლ(╹ε╹ლ)", - "ლ(ಠ益ಠ)ლ", "┐(‘~`;)┌", "ヘ(´-`;)ヘ", "┐( -“-)┌", - "乁༼☯‿☯✿༽ㄏ", "ʅ(´◔౪◔)ʃ", - "ლ(•ω •ლ)", "ヽ(゜~゜o)ノ", "ヽ(~~~ )ノ", "┐(~ー~;)┌", "┐(-。ー;)┌", - "¯\_(ツ)_/¯", - "¯\_(⊙_ʖ⊙)_/¯", - "乁ʕ •̀ ۝ •́ ʔㄏ", - "¯\_༼ ಥ ‿ ಥ ༽_/¯", + r"¯\_(ツ)_/¯", + r"¯\_(⊙_ʖ⊙)_/¯", + r"¯\_༼ ಥ ‿ ಥ ༽_/¯", "乁( ⁰͡ Ĺ̯ ⁰͡ ) ㄏ", ] @@ -553,9 +545,11 @@ @register(outgoing=True, pattern=r"^.(\w+)say (.*)") +@errors_handler async def univsaye(cowmsg): """ For .cowsay module, userbot wrapper for cow which says things. """ - if not cowmsg.text[0].isalpha() and cowmsg.text[0] not in ("/", "#", "@", "!"): + if not cowmsg.text[0].isalpha() and cowmsg.text[0] not in ( + "/", "#", "@", "!"): arg = cowmsg.pattern_match.group(1).lower() text = cowmsg.pattern_match.group(2) @@ -570,18 +564,20 @@ async def univsaye(cowmsg): @register(outgoing=True, pattern="^:/$") +@errors_handler async def kek(keks): - if not keks.text[0].isalpha() and keks.text[0] not in ("/", "#", "@", "!"): - """ Check yourself ;)""" - uio = ["/", "\\"] - for i in range(1, 15): - time.sleep(0.3) - await keks.edit(":" + uio[i % 2]) + """ Check yourself ;)""" + uio = ["/", "\\"] + for i in range(1, 15): + time.sleep(0.3) + await keks.edit(":" + uio[i % 2]) @register(outgoing=True, pattern=r"^.coinflip (.*)") -async def _(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): +@errors_handler +async def coin(event): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): if event.fwd_from: return r = random.randint(1, 100) @@ -607,8 +603,10 @@ async def _(event): @register(pattern="^.slap(?: |$)(.*)", outgoing=True) +@errors_handler async def who(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): """ slaps a user, or get slapped if not a reply. """ if event.fwd_from: return @@ -623,7 +621,7 @@ async def who(event): try: await event.edit(caption) - except: + except BaseException: await event.edit("`Can't slap this person, need to fetch some sticks and stones !!`") @@ -645,7 +643,9 @@ async def get_user(event): if event.message.entities is not None: probable_user_mention_entity = event.message.entities[0] - if isinstance(probable_user_mention_entity, MessageEntityMentionName): + if isinstance( + probable_user_mention_entity, + MessageEntityMentionName): user_id = probable_user_mention_entity.user_id replied_user = await event.client(GetFullUserRequest(user_id)) return replied_user @@ -683,18 +683,20 @@ async def slap(replied_user, event): @register(outgoing=True, pattern="^-_-$") +@errors_handler async def lol(lel): - if not lel.text[0].isalpha() and lel.text[0] not in ("/", "#", "@", "!"): - """ Ok... """ - okay = "-_-" - for _ in range(10): - okay = okay[:-1] + "_-" - await lel.edit(okay) + """ Ok... """ + okay = "-_-" + for i in range(10): + okay = okay[:-1] + "_-" + await lel.edit(okay) @register(outgoing=True, pattern="^.decide(?: |$)(.*)") +@errors_handler async def decide(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): if event.fwd_from: return message = event.pattern_match.group(1) @@ -705,8 +707,9 @@ async def decide(event): r = requests.get("https://yesno.wtf/api").json() else: try: - r = requests.get(f"https://yesno.wtf/api?force={message.lower()}").json() - except: + r = requests.get( + f"https://yesno.wtf/api?force={message.lower()}").json() + except BaseException: await event.edit("`Available decisions:` *yes*, *no*, *maybe*") return await event.client.send_message( @@ -719,15 +722,23 @@ async def decide(event): @register(outgoing=True, pattern="^;_;$") +@errors_handler async def fun(e): + t = ";__;" + for j in range(10): + t = t[:-1] + "_;" + await e.edit(t) + + +@register(outgoing=True, pattern="^.fp$") +@errors_handler +async def facepalm(e): if not e.text[0].isalpha() and e.text[0] not in ("/", "#", "@", "!"): - t = ";__;" - for j in range(10): - t = t[:-1] + "_;" - await e.edit(t) + await e.edit("🤦‍♂") @register(outgoing=True, pattern="^.cry$") +@errors_handler async def cry(e): """ y u du dis, i cry everytime !! """ if not e.text[0].isalpha() and e.text[0] not in ("/", "#", "@", "!"): @@ -735,6 +746,7 @@ async def cry(e): @register(outgoing=True, pattern="^.insult$") +@errors_handler async def insult(e): """ I make you cry !! """ if not e.text[0].isalpha() and e.text[0] not in ("/", "#", "@", "!"): @@ -742,6 +754,7 @@ async def insult(e): @register(outgoing=True, pattern="^.cp(?: |$)(.*)") +@errors_handler async def copypasta(cp_e): """ Copypasta the famous meme """ if not cp_e.text[0].isalpha() and cp_e.text[0] not in ("/", "#", "@", "!"): @@ -757,9 +770,8 @@ async def copypasta(cp_e): return reply_text = random.choice(EMOJIS) - b_char = random.choice( - message - ).lower() # choose a random character in the message to be substituted with 🅱️ + # choose a random character in the message to be substituted with 🅱️ + b_char = random.choice(message).lower() for owo in message: if owo == " ": reply_text += random.choice(EMOJIS) @@ -778,6 +790,7 @@ async def copypasta(cp_e): @register(outgoing=True, pattern="^.vapor(?: |$)(.*)") +@errors_handler async def vapor(vpr): """ Vaporize everything! """ if not vpr.text[0].isalpha() and vpr.text[0] not in ("/", "#", "@", "!"): @@ -804,9 +817,11 @@ async def vapor(vpr): @register(outgoing=True, pattern="^.str(?: |$)(.*)") +@errors_handler async def stretch(stret): """ Stretch it.""" - if not stret.text[0].isalpha() and stret.text[0] not in ("/", "#", "@", "!"): + if not stret.text[0].isalpha() and stret.text[0] not in ( + "/", "#", "@", "!"): textx = await stret.get_reply_message() message = stret.text message = stret.pattern_match.group(1) @@ -821,13 +836,14 @@ async def stretch(stret): count = random.randint(3, 10) reply_text = re.sub( r"([aeiouAEIOUaeiouAEIOUаеиоуюяыэё])", - (r"\1"*count), + (r"\1" * count), message ) await stret.edit(reply_text) @register(outgoing=True, pattern="^.zal(?: |$)(.*)") +@errors_handler async def zal(zgfy): """ Invoke the feeling of chaos. """ if not zgfy.text[0].isalpha() and zgfy.text[0] not in ("/", "#", "@", "!"): @@ -868,13 +884,16 @@ async def zal(zgfy): @register(outgoing=True, pattern="^.hi$") +@errors_handler async def hoi(hello): """ Greet everyone! """ - if not hello.text[0].isalpha() and hello.text[0] not in ("/", "#", "@", "!"): + if not hello.text[0].isalpha() and hello.text[0] not in ( + "/", "#", "@", "!"): await hello.edit(random.choice(HELLOSTR)) @register(outgoing=True, pattern="^.owo(?: |$)(.*)") +@errors_handler async def faces(owo): """ UwU """ if not owo.text[0].isalpha() and owo.text[0] not in ("/", "#", "@", "!"): @@ -899,13 +918,16 @@ async def faces(owo): @register(outgoing=True, pattern="^.react$") +@errors_handler async def react_meme(react): """ Make your userbot react to everything. """ - if not react.text[0].isalpha() and react.text[0] not in ("/", "#", "@", "!"): + if not react.text[0].isalpha() and react.text[0] not in ( + "/", "#", "@", "!"): await react.edit(random.choice(FACEREACTS)) @register(outgoing=True, pattern="^.shg$") +@errors_handler async def shrugger(shg): r""" ¯\_(ツ)_/¯ """ if not shg.text[0].isalpha() and shg.text[0] not in ("/", "#", "@", "!"): @@ -913,6 +935,7 @@ async def shrugger(shg): @register(outgoing=True, pattern="^.runs$") +@errors_handler async def runner_lol(run): """ Run, run, RUNNN! """ if not run.text[0].isalpha() and run.text[0] not in ("/", "#", "@", "!"): @@ -920,52 +943,66 @@ async def runner_lol(run): @register(outgoing=True, pattern="^.metoo$") +@errors_handler async def metoo(hahayes): """ Haha yes """ - if not hahayes.text[0].isalpha() and hahayes.text[0] not in ("/", "#", "@", "!"): + if not hahayes.text[0].isalpha() and hahayes.text[0] not in ( + "/", "#", "@", "!"): await hahayes.edit(random.choice(METOOSTR)) -@register(outgoing=True, pattern="^.oof$") +@register(outgoing=True, pattern="^Oof$") +@errors_handler async def Oof(e): - if not e.text[0].isalpha() and e.text[0] not in ("/", "#", "@", "!"): - t = "Oof" - for j in range(15): - t = t[:-1] + "of" - await e.edit(t) + t = "Oof" + for j in range(15): + t = t[:-1] + "of" + await e.edit(t) @register(outgoing=True, pattern="^.10iq$") +@errors_handler async def iqless(e): if not e.text[0].isalpha() and e.text[0] not in ("/", "#", "@", "!"): await e.edit("♿") @register(outgoing=True, pattern="^.moon$") +@errors_handler async def _(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): if event.fwd_from: return deq = deque(list("🌗🌘🌑🌒🌓🌔🌕🌖")) - for _ in range(32): - await asyncio.sleep(0.1) - await event.edit("".join(deq)) - deq.rotate(1) + try: + for _ in range(32): + await asyncio.sleep(0.1) + await event.edit("".join(deq)) + deq.rotate(1) + except BaseException: + return @register(outgoing=True, pattern="^.clock$") +@errors_handler async def _(event): - if not event.text[0].isalpha() and event.text[0] not in ("/", "#", "@", "!"): + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): if event.fwd_from: return deq = deque(list("🕙🕘🕗🕖🕕🕔🕓🕒🕑🕐🕛")) - for _ in range(32): - await asyncio.sleep(0.1) - await event.edit("".join(deq)) - deq.rotate(1) + try: + for _ in range(32): + await asyncio.sleep(0.1) + await event.edit("".join(deq)) + deq.rotate(1) + except BaseException: + return @register(outgoing=True, pattern="^.mock(?: |$)(.*)") +@errors_handler async def spongemocktext(mock): """ Do it and find the real fun. """ if not mock.text[0].isalpha() and mock.text[0] not in ("/", "#", "@", "!"): @@ -991,9 +1028,11 @@ async def spongemocktext(mock): @register(outgoing=True, pattern="^.clap(?: |$)(.*)") +@errors_handler async def claptext(memereview): """ Praise people! """ - if not memereview.text[0].isalpha() and memereview.text[0] not in ("/", "#", "@", "!"): + if not memereview.text[0].isalpha( + ) and memereview.text[0] not in ("/", "#", "@", "!"): textx = await memereview.get_reply_message() message = memereview.pattern_match.group(1) if message: @@ -1010,51 +1049,47 @@ async def claptext(memereview): @register(outgoing=True, pattern="^.bt$") +@errors_handler async def bluetext(bt_e): """ Believe me, you will find this useful. """ if not bt_e.text[0].isalpha() and bt_e.text[0] not in ("/", "#", "@", "!"): if await bt_e.get_reply_message(): await bt_e.edit( "/BLUETEXT /MUST /CLICK.\n" - "/ARE /YOU /A /STUPID /ANIMAL /WHICH /IS /ATTRACTED /TO /COLOURS ??" + "/ARE /YOU /A /STUPID /ANIMAL /WHICH /IS /ATTRACTED /TO /COLOURS ?" ) -@register(outgoing=True, pattern="^.smk (.*)") -async def smrk(smk): - if not smk.text[0].isalpha() and smk.text[0] not in ("/", "#", "@", "!"): - textx = await smk.get_reply_message() - message = smk.text - if message[5:]: - message = str(message[5:]) - elif textx: - message = textx - message = str(message.message) - if message == 'dele': - await smk.edit(message + 'te the hell' + "ツ") - await smk.edit("ツ") - else: - smirk = " ツ" - reply_text = message + smirk - await smk.edit(reply_text) - - -@register(outgoing=True, pattern=r"\.f (.*)") +@register(outgoing=True, pattern=r"^.f (.*)") +@errors_handler async def payf(e): if not e.text[0].isalpha() and e.text[0] not in ("/", "#", "@", "!"): paytext = e.pattern_match.group(1) pay = "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}".format( - paytext*8, paytext*8, paytext*2, paytext*2, paytext*2, paytext*6, paytext*6, paytext*2, paytext*2, paytext*2, paytext*2, paytext*2) + paytext * 8, + paytext * 8, + paytext * 2, + paytext * 2, + paytext * 2, + paytext * 6, + paytext * 6, + paytext * 2, + paytext * 2, + paytext * 2, + paytext * 2, + paytext * 2) await e.edit(pay) @register(outgoing=True, pattern="^.lfy (.*)") +@errors_handler async def let_me_google_that_for_you(lmgtfy_q): - if not lmgtfy_q.text[0].isalpha() and lmgtfy_q.text[0] not in ("/", "#", "@", "!"): + if not lmgtfy_q.text[0].isalpha( + ) and lmgtfy_q.text[0] not in ("/", "#", "@", "!"): textx = await lmgtfy_q.get_reply_message() - query = lmgtfy_q.text - if query[5:]: - query = str(query[5:]) + qry = lmgtfy_q.pattern_match.group(1) + if qry: + query = str(qry) elif textx: query = textx query = query.message @@ -1065,21 +1100,33 @@ async def let_me_google_that_for_you(lmgtfy_q): await lmgtfy_q.edit(f"[{query}]({r.json()['shorturl']})") -@register(pattern=r".scam(?: |$)(.*)", outgoing=True) +@register(pattern=r".scam (.*) (.*)", outgoing=True) +@errors_handler async def scam(event): - await event.delete() - input_str = event.pattern_match.group(1) - action = "typing" - if input_str: - action = input_str - async with event.client.action(event.chat_id, action): - await asyncio.sleep(60) + """ Just a small command to fake chat actions for fun !! """ + if not event.text[0].isalpha() and event.text[0] not in ( + "/", "#", "@", "!"): + input_str = event.pattern_match.group(1) + input_time = event.pattern_match.group(2) + action = "typing" + try: + input_time = int(input_time) + if (input_time > 0): + action_time = input_time + await event.delete() + async with event.client.action(event.chat_id, action): + await asyncio.sleep(int(time)) + except BaseException: + await event.edit("`Wrong Syntax !!`") + return -@register(pattern='.type(?: |$)(.*)') +@register(pattern=r".type(?: |$)(.*)", outgoing=True) +@errors_handler async def typewriter(typew): """ Just a small command to make your keyboard become a typewriter! """ - if not typew.text[0].isalpha() and typew.text[0] not in ("/", "#", "@", "!"): + if not typew.text[0].isalpha() and typew.text[0] not in ( + "/", "#", "@", "!"): textx = await typew.get_reply_message() message = typew.pattern_match.group(1) if message: @@ -1090,8 +1137,8 @@ async def typewriter(typew): await typew.edit("`Give a text to type!`") return sleep_time = 0.03 - typing_symbol = "|" - old_text = '' + typing_symbol = "█" + old_text = "" await typew.edit(typing_symbol) await asyncio.sleep(sleep_time) for character in message: @@ -1122,8 +1169,10 @@ async def typewriter(typew): \nUsage: You retard !!\ \n\n.zal\ \nUsage: Invoke the feeling of chaos.\ -\n\n.oof\ +\n\nOof\ \nUsage: Ooooof\ +\n\n.fp\ +\nUsage: Facepalm :P\ \n\n.moon\ \nUsage: kensar moon animation.\ \n\n.clock\ @@ -1154,15 +1203,14 @@ async def typewriter(typew): \nUsage: Pay Respects.\ \n\n.bt\ \nUsage: Believe me, you will find this useful.\ -\n\n.smk \ -\nUsage: A shit module for ツ , who cares.\ \n\n.type\ \nUsage: Just a small command to make your keyboard become a typewriter!\ \n\n.lfy \ \nUsage: Let me Google that for you real quick !!\ \n\n.decide [Optional: (yes, no, maybe)]\ \nUsage: Make a quick decision.\ -\n\n.scam [Optional: (typing, contact, game, location, voice, round, video, photo, document)]\ +\n\n.scam