├── heroku.yml ├── Procfile.txt ├── resources └── MutantAcademyStyle.ttf ├── userbot ├── modules │ ├── sql_helper │ │ ├── .DS_Store │ │ ├── __init__.py │ │ ├── keep_read_sql.py │ │ ├── gmute_sql.py │ │ ├── pm_permit_sql.py │ │ ├── spam_mute_sql.py │ │ ├── globals.py │ │ ├── google_drive_sql.py │ │ ├── snips_sql.py │ │ ├── notes_sql.py │ │ ├── filter_sql.py │ │ ├── welcome_sql.py │ │ └── blacklist_sql.py │ ├── __init__.py │ ├── help.py │ ├── __help.py │ ├── pics.py │ ├── invite.py │ ├── figlet.py │ ├── adzan.py │ ├── nhentai.py │ ├── ocr.py │ ├── ssvideo.py │ ├── spotifynow.py │ ├── covid.py │ ├── lyrics.py │ ├── hash.py │ ├── www.py │ ├── sticklet.py │ ├── mention.py │ ├── create.py │ ├── screencapture.py │ ├── webupload.py │ ├── spam.py │ ├── wordcloud.py │ ├── sed.py │ ├── blacklist.py │ ├── remove_bg.py │ ├── telegraph.py │ ├── justwatch.py │ ├── snips.py │ ├── weather.py │ ├── filemanager.py │ ├── reverse.py │ ├── purge.py │ ├── github.py │ ├── ascii.py │ ├── qrcode.py │ ├── time.py │ ├── torrent_search.py │ ├── misc.py │ ├── transform.py │ ├── whois.py │ ├── notes.py │ ├── locks.py │ ├── filter.py │ └── dogbin.py ├── utils │ ├── exceptions.py │ ├── __init__.py │ ├── chrome.py │ ├── progress.py │ └── tools.py └── __main__.py ├── .gitignore ├── windows_startup_script.py ├── Dockerfile ├── generate_session_file.py ├── .github ├── FUNDING.yml └── workflows │ ├── pythonapp.yml │ └── pylint.yml ├── string_session.py ├── requirements.txt ├── CODE_OF_CONDUCT ├── README.md └── LICENSE /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile 4 | run: 5 | worker: python3 -m userbot 6 | -------------------------------------------------------------------------------- /Procfile.txt: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile 4 | run: 5 | worker: python3 -m userbot 6 | -------------------------------------------------------------------------------- /resources/MutantAcademyStyle.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfianandaa/ProjectAlf/HEAD/resources/MutantAcademyStyle.ttf -------------------------------------------------------------------------------- /userbot/modules/sql_helper/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfianandaa/ProjectAlf/HEAD/userbot/modules/sql_helper/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | config.env 2 | __pycache__/* 3 | userbot.db 4 | userbot.session 5 | userbot.session-journal 6 | userbot/__pycache__/* 7 | userbot/modules/__pycache__/* 8 | userbot/modules/sql_helper/__pycache__/* 9 | .progress 10 | .vscode/* 11 | bin/* 12 | TG_BOT_TOKEN.session -------------------------------------------------------------------------------- /windows_startup_script.py: -------------------------------------------------------------------------------- 1 | from telethon import TelegramClient 2 | API_KEY = "Type that here" 3 | API_HASH = "Type that here" 4 | # get it from my.telegram.org 5 | bot = TelegramClient('userbot', API_KEY, API_HASH) 6 | bot.start() 7 | 8 | # This script wont run your bot, it just generates a session. 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # We're using Ubuntu 20.10 2 | FROM alfianandaa/alf:groovy 3 | 4 | # 5 | # Clone repo and prepare working directory 6 | # 7 | RUN git clone -b master https://github.com/alfianandaa/ProjectAlf /home/projectalf/ 8 | RUN mkdir /home/projectalf/bin/ 9 | WORKDIR /home/projectalf/ 10 | 11 | CMD ["python3","-m","userbot"] 12 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker, scoped_session 4 | from userbot import DB_URI 5 | 6 | BASE = declarative_base() 7 | 8 | 9 | def start() -> scoped_session: 10 | engine = create_engine(DB_URI) 11 | BASE.metadata.bind = engine 12 | BASE.metadata.create_all(engine) 13 | return scoped_session(sessionmaker(bind=engine, autoflush=False)) 14 | 15 | 16 | SESSION = start() 17 | -------------------------------------------------------------------------------- /generate_session_file.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.b (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # This script wont run your bot, it just generates a session. 7 | 8 | from telethon import TelegramClient 9 | from dotenv import load_dotenv 10 | import os 11 | 12 | load_dotenv("config.env") 13 | 14 | API_KEY = os.environ.get("API_KEY", None) 15 | API_HASH = os.environ.get("API_HASH", None) 16 | 17 | bot = TelegramClient('userbot', API_KEY, API_HASH) 18 | bot.start() 19 | -------------------------------------------------------------------------------- /userbot/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | from userbot import LOGS 7 | 8 | 9 | def __list_all_modules(): 10 | import glob 11 | from os.path import basename, dirname, isfile 12 | 13 | mod_paths = glob.glob(dirname(__file__) + "/*.py") 14 | return [ 15 | basename(f)[:-3] 16 | for f in mod_paths 17 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") 18 | ] 19 | 20 | 21 | ALL_MODULES = sorted(__list_all_modules()) 22 | LOGS.info("Modules to load: %s", str(ALL_MODULES)) 23 | __all__ = ALL_MODULES + ["ALL_MODULES"] 24 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [alfianandaa] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /string_session.py: -------------------------------------------------------------------------------- 1 | from telethon.sync import TelegramClient 2 | from telethon.sessions import StringSession 3 | 4 | print("""Please go-to my.telegram.org 5 | Login using your Telegram account 6 | Click on API Development Tools 7 | Create a new application, by entering the required details""") 8 | 9 | API_KEY = input("API_KEY: ") 10 | API_HASH = input("API_HASH: ") 11 | 12 | with TelegramClient(StringSession(), API_KEY, API_HASH) as client: 13 | session_string = client.session.save() 14 | saved_messages_template = """STRING_SESSION: {} 15 | ️It is forbidden to pass this value to third parties""".format(session_string) 16 | client.send_message("me", saved_messages_template, parse_mode="html") 17 | print("Check Saved Messages on your telegram account !!") 18 | -------------------------------------------------------------------------------- /userbot/utils/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Adek Maulana 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | class CancelProcess(Exception): 18 | """Cancel Process""" 19 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/keep_read_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | 6 | from sqlalchemy import Column, String 7 | 8 | 9 | class KRead(BASE): 10 | __tablename__ = "kread" 11 | groupid = Column(String(14), primary_key=True) 12 | 13 | def __init__(self, sender): 14 | self.groupid = str(sender) 15 | 16 | 17 | KRead.__table__.create(checkfirst=True) 18 | 19 | 20 | def is_kread(): 21 | try: 22 | return SESSION.query(KRead).all() 23 | except BaseException: 24 | return None 25 | finally: 26 | SESSION.close() 27 | 28 | 29 | def kread(chat): 30 | adder = KRead(str(chat)) 31 | SESSION.add(adder) 32 | SESSION.commit() 33 | 34 | 35 | def unkread(chat): 36 | rem = SESSION.query(KRead).get((str(chat))) 37 | if rem: 38 | SESSION.delete(rem) 39 | SESSION.commit() 40 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/gmute_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | 6 | from sqlalchemy import Column, String 7 | 8 | 9 | class GMute(BASE): 10 | __tablename__ = "gmute" 11 | sender = Column(String(14), primary_key=True) 12 | 13 | def __init__(self, sender): 14 | self.sender = str(sender) 15 | 16 | 17 | GMute.__table__.create(checkfirst=True) 18 | 19 | 20 | def is_gmuted(sender_id): 21 | try: 22 | return SESSION.query(GMute).all() 23 | except BaseException: 24 | return None 25 | finally: 26 | SESSION.close() 27 | 28 | 29 | def gmute(sender): 30 | adder = GMute(str(sender)) 31 | SESSION.add(adder) 32 | SESSION.commit() 33 | 34 | 35 | def ungmute(sender): 36 | rem = SESSION.query(GMute).get((str(sender))) 37 | if rem: 38 | SESSION.delete(rem) 39 | SESSION.commit() 40 | -------------------------------------------------------------------------------- /userbot/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Adek Maulana 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | from .chrome import chrome, options 18 | from .google_images_download import googleimagesdownload 19 | from .progress import progress 20 | from .tools import humanbytes, time_formatter, human_to_bytes, md5 21 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/pm_permit_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | from sqlalchemy import Column, String 6 | 7 | 8 | class PMPermit(BASE): 9 | __tablename__ = "pmpermit" 10 | chat_id = Column(String(14), primary_key=True) 11 | 12 | def __init__(self, chat_id): 13 | self.chat_id = str(chat_id) # ensure string 14 | 15 | 16 | PMPermit.__table__.create(checkfirst=True) 17 | 18 | 19 | def is_approved(chat_id): 20 | try: 21 | return SESSION.query(PMPermit).filter( 22 | PMPermit.chat_id == str(chat_id)).one() 23 | except BaseException: 24 | return None 25 | finally: 26 | SESSION.close() 27 | 28 | 29 | def approve(chat_id): 30 | adder = PMPermit(str(chat_id)) 31 | SESSION.add(adder) 32 | SESSION.commit() 33 | 34 | 35 | def dissprove(chat_id): 36 | rem = SESSION.query(PMPermit).get(str(chat_id)) 37 | if rem: 38 | SESSION.delete(rem) 39 | SESSION.commit() 40 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp 2 | aria2p 3 | async_generator 4 | bs4 5 | cowpy 6 | cffi 7 | covid 8 | cryptg 9 | deezloader 10 | dnspython 11 | emoji 12 | gitpython 13 | google-api-python-client 14 | google-auth-httplib2 15 | google-auth-oauthlib 16 | googletrans==3.1.0a0 17 | google_images_download 18 | gTTS 19 | gTTS-token 20 | hachoir 21 | # heroku 22 | heroku3 23 | httplib2 24 | humanize 25 | lyricsgenius 26 | lxml 27 | oauth2client 28 | Pillow 29 | psycopg2 30 | psycopg2-binary 31 | pybase64 32 | pyfiglet 33 | pylast 34 | pySmartDL 35 | python-barcode 36 | python-dotenv 37 | youtube-dl 38 | pytz 39 | qrcode 40 | redis 41 | requests 42 | search-engine-parser 43 | speedtest-cli 44 | sqlalchemy 45 | TgCrypto 46 | telethon 47 | telethon-session-sqlalchemy 48 | telegraph 49 | urbandict 50 | wikipedia 51 | wget 52 | python-dateutil 53 | git+https://github.com/johnwmillr/LyricsGenius.git 54 | PyGithub 55 | justwatch 56 | jikanpy 57 | html_telegraph_poster 58 | pendulum 59 | psutil 60 | youtube_search 61 | validators 62 | glitch_this 63 | vcsi 64 | lottie 65 | cairosvg 66 | colour 67 | scipy 68 | wordcloud 69 | -------------------------------------------------------------------------------- /.github/workflows/pythonapp.yml: -------------------------------------------------------------------------------- 1 | name: FailCheck 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | max-parallel: 5 11 | matrix: 12 | python-version: [3.8] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | - name: Install dependencies 21 | run: | 22 | sudo apt-get install libpq-dev 23 | python -m pip install --upgrade pip 24 | pip install -r requirements.txt 25 | pip install flake8 flake8-print flake8-quotes 26 | - name: Check for showstoppers 27 | run: | 28 | # stop the build if there are Python syntax errors 29 | flake8 . --count --select=E999 --show-source --statistics 30 | shellcheck: 31 | 32 | runs-on: ubuntu-latest 33 | 34 | steps: 35 | - uses: actions/checkout@v1 36 | - name: Check for install script errors 37 | uses: ludeeus/action-shellcheck@0.1.0 38 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/spam_mute_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | 6 | from sqlalchemy import Column, String 7 | 8 | 9 | class Mute(BASE): 10 | __tablename__ = "muted" 11 | chat_id = Column(String(14), primary_key=True) 12 | sender = Column(String(14), primary_key=True) 13 | 14 | def __init__(self, chat_id, sender): 15 | self.chat_id = str(chat_id) # ensure string 16 | self.sender = str(sender) 17 | 18 | 19 | Mute.__table__.create(checkfirst=True) 20 | 21 | 22 | def is_muted(chat_id): 23 | try: 24 | return SESSION.query(Mute).filter(Mute.chat_id == str(chat_id)).all() 25 | except BaseException: 26 | return None 27 | finally: 28 | SESSION.close() 29 | 30 | 31 | def mute(chat_id, sender): 32 | adder = Mute(str(chat_id), str(sender)) 33 | SESSION.add(adder) 34 | SESSION.commit() 35 | 36 | 37 | def unmute(chat_id, sender): 38 | rem = SESSION.query(Mute).get(((str(chat_id)), (str(sender)))) 39 | if rem: 40 | SESSION.delete(rem) 41 | SESSION.commit() 42 | -------------------------------------------------------------------------------- /userbot/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import sys 8 | from importlib import import_module 9 | from sys import argv 10 | 11 | from telethon.errors.rpcerrorlist import PhoneNumberInvalidError 12 | 13 | from userbot import LOGS, bot 14 | from userbot.modules import ALL_MODULES 15 | 16 | INVALID_PH = ( 17 | "\nERROR: The Phone No. entered is INVALID" 18 | "\n Tip: Use Country Code along with number." 19 | "\n or check your phone number and try again !" 20 | ) 21 | 22 | try: 23 | bot.start() 24 | except PhoneNumberInvalidError: 25 | print(INVALID_PH) 26 | sys.exit(1) 27 | 28 | for module_name in ALL_MODULES: 29 | imported_module = import_module("userbot.modules." + module_name) 30 | 31 | 32 | LOGS.info("You are running ProjectAlf [v2]") 33 | 34 | LOGS.info("ProjectAlf is now running !!!" 35 | "Test it by typing .alive or .ping in any chat.") 36 | 37 | 38 | if len(argv) not in (1, 3, 4): 39 | bot.disconnect() 40 | else: 41 | bot.run_until_disconnected() 42 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/globals.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | 6 | from sqlalchemy import Column, String, UnicodeText 7 | 8 | 9 | class Globals(BASE): 10 | __tablename__ = "globals" 11 | variable = Column(String, primary_key=True, nullable=False) 12 | value = Column(UnicodeText, primary_key=True, nullable=False) 13 | 14 | def __init__(self, variable, value): 15 | self.variable = str(variable) 16 | self.value = value 17 | 18 | 19 | Globals.__table__.create(checkfirst=True) 20 | 21 | 22 | def gvarstatus(variable): 23 | try: 24 | return SESSION.query(Globals).filter( 25 | Globals.variable == str(variable)).first().value 26 | except BaseException: 27 | return None 28 | finally: 29 | SESSION.close() 30 | 31 | 32 | def addgvar(variable, value): 33 | if SESSION.query(Globals).filter( 34 | Globals.variable == str(variable)).one_or_none(): 35 | delgvar(variable) 36 | adder = Globals(str(variable), value) 37 | SESSION.add(adder) 38 | SESSION.commit() 39 | 40 | 41 | def delgvar(variable): 42 | rem = SESSION.query(Globals).filter(Globals.variable == str(variable))\ 43 | .delete(synchronize_session="fetch") 44 | if rem: 45 | SESSION.commit() 46 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/google_drive_sql.py: -------------------------------------------------------------------------------- 1 | from userbot.modules.sql_helper import SESSION, BASE 2 | from sqlalchemy import Column, String, Text 3 | 4 | 5 | class GoogleDriveCreds(BASE): 6 | __tablename__ = 'gdrive' 7 | user = Column(String, primary_key=True) 8 | credentials = Column(Text, nullable=False) 9 | 10 | def __init__(self, user): 11 | self.user = user 12 | 13 | 14 | GoogleDriveCreds.__table__.create(checkfirst=True) 15 | 16 | 17 | def save_credentials(user, credentials): 18 | saved_credentials = SESSION.query(GoogleDriveCreds).get(user) 19 | if not saved_credentials: 20 | saved_credentials = GoogleDriveCreds(user) 21 | 22 | saved_credentials.credentials = credentials 23 | 24 | SESSION.add(saved_credentials) 25 | SESSION.commit() 26 | return True 27 | 28 | 29 | def get_credentials(user): 30 | try: 31 | saved_credentials = SESSION.query(GoogleDriveCreds).get(user) 32 | creds = None 33 | 34 | if saved_credentials is not None: 35 | creds = saved_credentials.credentials 36 | return creds 37 | finally: 38 | SESSION.close() 39 | 40 | 41 | def clear_credentials(user): 42 | saved_credentials = SESSION.query(GoogleDriveCreds).get(user) 43 | if saved_credentials: 44 | SESSION.delete(saved_credentials) 45 | SESSION.commit() 46 | return True 47 | -------------------------------------------------------------------------------- /userbot/modules/help.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import asyncio 8 | 9 | from userbot import CMD_HELP 10 | from userbot.events import register 11 | 12 | 13 | @register(outgoing=True, pattern=r"^\.help(?: |$)(.*)") 14 | async def hep(event): 15 | args = event.pattern_match.group(1).lower() 16 | if args: 17 | if args in CMD_HELP: 18 | await event.edit(str(CMD_HELP[args])) 19 | await asyncio.sleep(15) 20 | await event.delete() 21 | else: 22 | await event.edit("Please specify a valid module name.") 23 | await asyncio.sleep(5) 24 | await event.delete() 25 | else: 26 | string1 = "Please specify which module do you want help for !!\nUsage: .help \n\n" 27 | string = "• " 28 | string3 = "List for all available commands below: " 29 | string2 = "-------------------------------------------------------------" 30 | for i in CMD_HELP: 31 | string += "`" + str(i) 32 | string += "` • " 33 | await event.edit( 34 | f"{string1}" f"{string3}" f"{string2}\n" f"{string}" f"{string2}" 35 | ) 36 | await asyncio.sleep(20) 37 | await event.delete() 38 | -------------------------------------------------------------------------------- /userbot/modules/__help.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 TeamDerUntergang. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.d (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | # @Qulec tarafından yazılmıştır. 8 | # Thanks @Spechide. 9 | 10 | import logging 11 | 12 | from telethon.errors.rpcerrorlist import BotInlineDisabledError 13 | 14 | from userbot import BOT_TOKEN, BOT_USERNAME 15 | from userbot.events import register 16 | 17 | logging.basicConfig( 18 | format="[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s", level=logging.WARNING 19 | ) 20 | 21 | 22 | @register(outgoing=True, pattern=r"^\.helpme") 23 | async def yardim(event): 24 | tgbotusername = BOT_USERNAME 25 | if tgbotusername and BOT_TOKEN: 26 | try: 27 | results = await event.client.inline_query(tgbotusername, "@ProjectAlf") 28 | except BotInlineDisabledError: 29 | return await event.edit( 30 | "`Bot can't be used in inline mode.\nMake sure to turn on inline mode!`" 31 | ) 32 | await results[0].click( 33 | event.chat_id, reply_to=event.reply_to_msg_id, hide_via=True 34 | ) 35 | await event.delete() 36 | else: 37 | return await event.edit( 38 | "`The bot doesn't work! Please set the Bot Token and Username correctly.`" 39 | "\n`The module has been stopped.`" 40 | ) 41 | -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: pylint 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | PEP8: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - name: Setup Python 12 | uses: actions/setup-python@v1 13 | with: 14 | python-version: 3.8 15 | 16 | - name: Install Python lint libraries 17 | run: | 18 | pip install autopep8 autoflake isort black 19 | - name: Check for showstoppers 20 | run: | 21 | autopep8 --verbose --in-place --recursive --aggressive --aggressive . *.py 22 | - name: Remove unused imports and variables 23 | run: | 24 | autoflake --in-place --recursive --remove-all-unused-imports --remove-unused-variables --ignore-init-module-imports . 25 | - name: lint with isort and black 26 | run: | 27 | isort userbot/modules/*.py 28 | black userbot/modules/*.py 29 | 30 | - name: Import GPG key 31 | id: import_gpg 32 | uses: crazy-max/ghaction-import-gpg@v2 33 | with: 34 | git_user_signingkey: true 35 | git_commit_gpgsign: true 36 | env: 37 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 38 | PASSPHRASE: ${{ secrets.PASSPHRASE }} 39 | 40 | # commit changes 41 | - uses: stefanzweifel/git-auto-commit-action@v4 42 | with: 43 | commit_message: 'pylint: auto fixes' 44 | commit_options: '--no-verify --signoff' 45 | repository: . 46 | commit_user_name: Alfiananda P.A 47 | commit_user_email: genengbendo12@gmail.com 48 | commit_author: Alfiananda P.A -------------------------------------------------------------------------------- /userbot/modules/pics.py: -------------------------------------------------------------------------------- 1 | from asyncio import sleep 2 | from io import BytesIO 3 | 4 | from telethon import types 5 | from telethon.errors import PhotoInvalidDimensionsError 6 | from telethon.tl.functions.messages import SendMediaRequest 7 | 8 | from userbot import CMD_HELP 9 | from userbot.events import register 10 | 11 | 12 | @register(outgoing=True, pattern=r"^\.pic(?: |$)(.*)") 13 | async def on_file_to_photo(pics): 14 | await pics.edit("`Please wait...`") 15 | await sleep(2.5) 16 | await pics.delete() 17 | target = await pics.get_reply_message() 18 | try: 19 | image = target.media.document 20 | except AttributeError: 21 | return 22 | if not image.mime_type.startswith("image/"): 23 | return # This isn't an image 24 | if image.mime_type == "image/webp": 25 | return # Telegram doesn't let you directly send stickers as photos 26 | if image.size > 10 * 2560 * 1440: 27 | return # We'd get PhotoSaveFileInvalidError otherwise 28 | 29 | file = await pics.client.download_media(target, file=BytesIO()) 30 | file.seek(0) 31 | img = await pics.client.upload_file(file) 32 | img.name = "image.png" 33 | 34 | try: 35 | await pics.client( 36 | SendMediaRequest( 37 | peer=await pics.get_input_chat(), 38 | media=types.InputMediaUploadedPhoto(img), 39 | message=target.message, 40 | entities=target.entities, 41 | reply_to_msg_id=target.id, 42 | ) 43 | ) 44 | except PhotoInvalidDimensionsError: 45 | return 46 | 47 | 48 | CMD_HELP.update( 49 | {"pics": "`>.pic`" "\nUsage : Convert any Document Image to Full Size Image."} 50 | ) 51 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/snips_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | 6 | from sqlalchemy import Column, Numeric, UnicodeText 7 | 8 | 9 | class Snips(BASE): 10 | __tablename__ = "snips" 11 | snip = Column(UnicodeText, primary_key=True) 12 | reply = Column(UnicodeText) 13 | f_mesg_id = Column(Numeric) 14 | 15 | def __init__(self, snip, reply, f_mesg_id): 16 | self.snip = snip 17 | self.reply = reply 18 | self.f_mesg_id = f_mesg_id 19 | 20 | 21 | Snips.__table__.create(checkfirst=True) 22 | 23 | 24 | def get_snip(keyword): 25 | try: 26 | return SESSION.query(Snips).get(keyword) 27 | finally: 28 | SESSION.close() 29 | 30 | 31 | def get_snips(): 32 | try: 33 | return SESSION.query(Snips).all() 34 | finally: 35 | SESSION.close() 36 | 37 | 38 | def add_snip(keyword, reply, f_mesg_id): 39 | to_check = get_snip(keyword) 40 | if not to_check: 41 | adder = Snips(keyword, reply, f_mesg_id) 42 | SESSION.add(adder) 43 | SESSION.commit() 44 | return True 45 | else: 46 | rem = SESSION.query(Snips).filter(Snips.snip == keyword) 47 | SESSION.delete(rem) 48 | SESSION.commit() 49 | adder = Snips(keyword, reply, f_mesg_id) 50 | SESSION.add(adder) 51 | SESSION.commit() 52 | return False 53 | 54 | 55 | def remove_snip(keyword): 56 | to_check = get_snip(keyword) 57 | if not to_check: 58 | return False 59 | else: 60 | rem = SESSION.query(Snips).filter(Snips.snip == keyword) 61 | rem.delete() 62 | SESSION.commit() 63 | return True 64 | -------------------------------------------------------------------------------- /userbot/modules/invite.py: -------------------------------------------------------------------------------- 1 | from telethon import functions 2 | 3 | from userbot import CMD_HELP 4 | from userbot.events import register 5 | 6 | 7 | @register(outgoing=True, pattern=r"^\.invite(?: |$)(.*)") 8 | async def _(event): 9 | if event.fwd_from: 10 | return 11 | to_add_users = event.pattern_match.group(1) 12 | if event.is_private: 13 | await event.edit("`.invite` users to a chat, not to a Private Message") 14 | else: 15 | if not event.is_channel and event.is_group: 16 | # https://lonamiwebs.github.io/Telethon/methods/messages/add_chat_user.html 17 | for user_id in to_add_users.split(" "): 18 | try: 19 | await event.client( 20 | functions.messages.AddChatUserRequest( 21 | chat_id=event.chat_id, user_id=user_id, fwd_limit=1000000 22 | ) 23 | ) 24 | except Exception as e: 25 | await event.edit(str(e)) 26 | return 27 | else: 28 | # https://lonamiwebs.github.io/Telethon/methods/channels/invite_to_channel.html 29 | for user_id in to_add_users.split(" "): 30 | try: 31 | await event.client( 32 | functions.channels.InviteToChannelRequest( 33 | channel=event.chat_id, users=[user_id] 34 | ) 35 | ) 36 | except Exception as e: 37 | await event.edit(str(e)) 38 | return 39 | 40 | await event.edit("`Invited Successfully`") 41 | 42 | 43 | CMD_HELP.update( 44 | { 45 | "invite": "\n\n`>.invite [or id user]`" 46 | "\nUsage: Invite user or bots if u want." 47 | } 48 | ) 49 | -------------------------------------------------------------------------------- /userbot/utils/chrome.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Adek Maulana 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | import os 19 | 20 | from selenium import webdriver 21 | from selenium.webdriver.chrome.options import Options 22 | 23 | from userbot import TEMP_DOWNLOAD_DIRECTORY, GOOGLE_CHROME_BIN, CHROME_DRIVER 24 | 25 | 26 | async def chrome(chrome_options=None): 27 | if chrome_options is None: 28 | chrome_options = await options() 29 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 30 | os.mkdir(TEMP_DOWNLOAD_DIRECTORY) 31 | prefs = {'download.default_directory': TEMP_DOWNLOAD_DIRECTORY} 32 | chrome_options.add_experimental_option('prefs', prefs) 33 | return webdriver.Chrome(executable_path=CHROME_DRIVER, 34 | options=chrome_options) 35 | 36 | 37 | async def options(): 38 | chrome_options = Options() 39 | chrome_options.binary_location = GOOGLE_CHROME_BIN 40 | chrome_options.add_argument("--headless") 41 | chrome_options.add_argument("--window-size=1920x1080") 42 | chrome_options.add_argument("--disable-dev-shm-usage") 43 | chrome_options.add_argument("--no-sandbox") 44 | chrome_options.add_argument("--disable-gpu") 45 | return chrome_options 46 | -------------------------------------------------------------------------------- /userbot/modules/figlet.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.d (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import pyfiglet 8 | 9 | from userbot import CMD_HELP 10 | from userbot.events import register 11 | 12 | 13 | @register(outgoing=True, pattern=r"^\.fg(?: |$)(.*)") 14 | async def figlet(e): 15 | if e.fwd_from: 16 | return 17 | CMD_FIG = { 18 | "slant": "slant", 19 | "3D": "3-d", 20 | "5line": "5lineoblique", 21 | "alpha": "alphabet", 22 | "banner": "banner3-D", 23 | "doh": "doh", 24 | "iso": "isometric1", 25 | "letter": "letters", 26 | "allig": "alligator", 27 | "dotm": "dotmatrix", 28 | "bubble": "bubble", 29 | "bulb": "bulbhead", 30 | "digi": "digital", 31 | } 32 | input_str = e.pattern_match.group(1) 33 | if "." in input_str: 34 | text, cmd = input_str.split(".", maxsplit=1) 35 | elif input_str is not None: 36 | cmd = None 37 | text = input_str 38 | else: 39 | await e.edit("`Please add some text to figlet`") 40 | return 41 | if cmd is not None: 42 | try: 43 | font = CMD_FIG[cmd] 44 | except KeyError: 45 | await e.edit("`Invalid selected font.`") 46 | return 47 | result = pyfiglet.figlet_format(text, font=font) 48 | else: 49 | result = pyfiglet.figlet_format(text) 50 | await e.respond("‌‌‎`{}`".format(result)) 51 | await e.delete() 52 | 53 | 54 | CMD_HELP.update( 55 | { 56 | "figlet": ">`.fg`" 57 | "\nUsage: Enhance ur text to strip line with anvil." 58 | "\n\nExample: `.figlet TEXT.STYLE`" 59 | "\nSTYLE LIST: `slant`, `3D`, `5line`, `alpha`, `banner`, `doh`, `iso`, `letter`, `allig`, `dotm`, `bubble`, `bulb`, `digi`" 60 | } 61 | ) 62 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/notes_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | from sqlalchemy import Column, UnicodeText, Numeric, String 6 | 7 | 8 | class Notes(BASE): 9 | __tablename__ = "notes" 10 | chat_id = Column(String(14), primary_key=True) 11 | keyword = Column(UnicodeText, primary_key=True, nullable=False) 12 | reply = Column(UnicodeText) 13 | f_mesg_id = Column(Numeric) 14 | 15 | def __init__(self, chat_id, keyword, reply, f_mesg_id): 16 | self.chat_id = str(chat_id) 17 | self.keyword = keyword 18 | self.reply = reply 19 | self.f_mesg_id = f_mesg_id 20 | 21 | 22 | Notes.__table__.create(checkfirst=True) 23 | 24 | 25 | def get_note(chat_id, keyword): 26 | try: 27 | return SESSION.query(Notes).get((str(chat_id), keyword)) 28 | finally: 29 | SESSION.close() 30 | 31 | 32 | def get_notes(chat_id): 33 | try: 34 | return SESSION.query(Notes).filter(Notes.chat_id == str(chat_id)).all() 35 | finally: 36 | SESSION.close() 37 | 38 | 39 | def add_note(chat_id, keyword, reply, f_mesg_id): 40 | to_check = get_note(chat_id, keyword) 41 | if not to_check: 42 | adder = Notes(str(chat_id), keyword, reply, f_mesg_id) 43 | SESSION.add(adder) 44 | SESSION.commit() 45 | return True 46 | else: 47 | rem = SESSION.query(Notes).get((str(chat_id), keyword)) 48 | SESSION.delete(rem) 49 | SESSION.commit() 50 | adder = Notes(str(chat_id), keyword, reply, f_mesg_id) 51 | SESSION.add(adder) 52 | SESSION.commit() 53 | return False 54 | 55 | 56 | def rm_note(chat_id, keyword): 57 | to_check = get_note(chat_id, keyword) 58 | if not to_check: 59 | return False 60 | else: 61 | rem = SESSION.query(Notes).get((str(chat_id), keyword)) 62 | SESSION.delete(rem) 63 | SESSION.commit() 64 | return True 65 | -------------------------------------------------------------------------------- /userbot/modules/adzan.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import requests 4 | 5 | from userbot import CMD_HELP 6 | from userbot.events import register 7 | 8 | PLACE = "" 9 | 10 | 11 | @register(pattern=r"^\.adzan(?: |$)(.*)") 12 | async def get_adzan(adzan): 13 | if not adzan.pattern_match.group(1): 14 | LOCATION = PLACE 15 | if not LOCATION: 16 | await adzan.edit("Please specify a city or a state.") 17 | return 18 | else: 19 | LOCATION = adzan.pattern_match.group(1) 20 | 21 | # url = f'http://muslimsalat.com/{LOKASI}.json?key=bd099c5825cbedb9aa934e255a81a5fc' 22 | url = f"https://api.pray.zone/v2/times/today.json?city={LOCATION}" 23 | request = requests.get(url) 24 | if request.status_code == 500: 25 | return await adzan.edit(f"Couldn't find city `{LOCATION}`") 26 | 27 | parsed = json.loads(request.text) 28 | 29 | city = parsed["results"]["location"]["city"] 30 | country = parsed["results"]["location"]["country"] 31 | timezone = parsed["results"]["location"]["timezone"] 32 | date = parsed["results"]["datetime"][0]["date"]["gregorian"] 33 | 34 | imsak = parsed["results"]["datetime"][0]["times"]["Imsak"] 35 | subuh = parsed["results"]["datetime"][0]["times"]["Fajr"] 36 | zuhur = parsed["results"]["datetime"][0]["times"]["Dhuhr"] 37 | ashar = parsed["results"]["datetime"][0]["times"]["Asr"] 38 | maghrib = parsed["results"]["datetime"][0]["times"]["Maghrib"] 39 | isya = parsed["results"]["datetime"][0]["times"]["Isha"] 40 | 41 | result = ( 42 | f"**Jadwal Sholat**:\n" 43 | f"📅 `{date} | {timezone}`\n" 44 | f"🌏 `{city} | {country}`\n\n" 45 | f"**Imsak :** `{imsak}`\n" 46 | f"**Subuh :** `{subuh}`\n" 47 | f"**Zuhur :** `{zuhur}`\n" 48 | f"**Ashar :** `{ashar}`\n" 49 | f"**Maghrib :** `{maghrib}`\n" 50 | f"**Isya :** `{isya}`\n" 51 | ) 52 | 53 | await adzan.edit(result) 54 | 55 | 56 | CMD_HELP.update( 57 | {"adzan": "\n\n`>.adzan `" "\nUsage: Gets the prayer time for moslem."} 58 | ) 59 | -------------------------------------------------------------------------------- /userbot/modules/nhentai.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 KeselekPermen69 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.d (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from asyncio.exceptions import TimeoutError 8 | 9 | from telethon import events 10 | from telethon.errors.rpcerrorlist import YouBlockedUserError 11 | 12 | from userbot import CMD_HELP, bot 13 | from userbot.events import register 14 | 15 | 16 | @register(outgoing=True, pattern=r"^\.nhentai(?: |$)(.*)") 17 | async def _(hentai): 18 | if hentai.fwd_from: 19 | return 20 | link = hentai.pattern_match.group(1) 21 | if not link: 22 | return await hentai.edit("`I can't search nothing`") 23 | chat = "@nHentaiBot" 24 | await hentai.edit("```Processing```") 25 | try: 26 | async with bot.conversation(chat) as conv: 27 | try: 28 | response = conv.wait_event( 29 | events.NewMessage(incoming=True, from_users=424466890) 30 | ) 31 | msg = await bot.send_message(chat, link) 32 | response = await response 33 | await bot.send_read_acknowledge(conv.chat_id) 34 | except YouBlockedUserError: 35 | await hentai.reply("```Please unblock @nHentaiBot and try again```") 36 | return 37 | if response.text.startswith("**Sorry I couldn't get manga from**"): 38 | await hentai.edit("```I think this is not the right link```") 39 | else: 40 | await hentai.delete() 41 | await bot.send_message(hentai.chat_id, response.message) 42 | await bot.send_read_acknowledge(hentai.chat_id) 43 | await hentai.client.delete_messages(conv.chat_id, [msg.id, response.id]) 44 | except TimeoutError: 45 | await hentai.edit("`@nHentaiBot isnt responding..`") 46 | await hentai.client.delete_messages(conv.chat_id, [msg.id]) 47 | 48 | 49 | CMD_HELP.update( 50 | {"nhentai": "`.nhentai` " "\nUsage: view nhentai in telegra.ph :v"} 51 | ) 52 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/filter_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | from sqlalchemy import Column, UnicodeText, Numeric, String 6 | 7 | 8 | class Filters(BASE): 9 | __tablename__ = "filters" 10 | chat_id = Column(String(14), primary_key=True) 11 | keyword = Column(UnicodeText, primary_key=True, nullable=False) 12 | reply = Column(UnicodeText) 13 | f_mesg_id = Column(Numeric) 14 | 15 | def __init__(self, chat_id, keyword, reply, f_mesg_id): 16 | self.chat_id = str(chat_id) 17 | self.keyword = keyword 18 | self.reply = reply 19 | self.f_mesg_id = f_mesg_id 20 | 21 | def __eq__(self, other): 22 | return bool( 23 | isinstance(other, Filters) and self.chat_id == other.chat_id 24 | and self.keyword == other.keyword) 25 | 26 | 27 | Filters.__table__.create(checkfirst=True) 28 | 29 | 30 | def get_filter(chat_id, keyword): 31 | try: 32 | return SESSION.query(Filters).get((str(chat_id), keyword)) 33 | finally: 34 | SESSION.close() 35 | 36 | 37 | def get_filters(chat_id): 38 | try: 39 | return SESSION.query(Filters).filter( 40 | Filters.chat_id == str(chat_id)).all() 41 | finally: 42 | SESSION.close() 43 | 44 | 45 | def add_filter(chat_id, keyword, reply, f_mesg_id): 46 | to_check = get_filter(chat_id, keyword) 47 | if not to_check: 48 | adder = Filters(str(chat_id), keyword, reply, f_mesg_id) 49 | SESSION.add(adder) 50 | SESSION.commit() 51 | return True 52 | else: 53 | rem = SESSION.query(Filters).get((str(chat_id), keyword)) 54 | SESSION.delete(rem) 55 | SESSION.commit() 56 | adder = Filters(str(chat_id), keyword, reply, f_mesg_id) 57 | SESSION.add(adder) 58 | SESSION.commit() 59 | return False 60 | 61 | 62 | def remove_filter(chat_id, keyword): 63 | to_check = get_filter(chat_id, keyword) 64 | if not to_check: 65 | return False 66 | else: 67 | rem = SESSION.query(Filters).get((str(chat_id), keyword)) 68 | SESSION.delete(rem) 69 | SESSION.commit() 70 | return True 71 | -------------------------------------------------------------------------------- /userbot/modules/ocr.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | 6 | import os 7 | 8 | import requests 9 | 10 | from userbot import CMD_HELP, OCR_SPACE_API_KEY, TEMP_DOWNLOAD_DIRECTORY, bot 11 | from userbot.events import register 12 | 13 | 14 | async def ocr_space_file( 15 | filename, overlay=False, api_key=OCR_SPACE_API_KEY, language="eng" 16 | ): 17 | 18 | payload = { 19 | "isOverlayRequired": overlay, 20 | "apikey": api_key, 21 | "language": language, 22 | } 23 | with open(filename, "rb") as f: 24 | r = requests.post( 25 | "https://api.ocr.space/parse/image", 26 | files={filename: f}, 27 | data=payload, 28 | ) 29 | return r.json() 30 | 31 | 32 | @register(pattern=r"^\.ocr (.*)", outgoing=True) 33 | async def ocr(event): 34 | if not OCR_SPACE_API_KEY: 35 | return await event.edit( 36 | "`Error: OCR.Space API key is missing! Add it to environment variables or config.env.`" 37 | ) 38 | await event.edit("`Reading...`") 39 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 40 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 41 | lang_code = event.pattern_match.group(1) 42 | downloaded_file_name = await bot.download_media( 43 | await event.get_reply_message(), TEMP_DOWNLOAD_DIRECTORY 44 | ) 45 | test_file = await ocr_space_file(filename=downloaded_file_name, language=lang_code) 46 | try: 47 | ParsedText = test_file["ParsedResults"][0]["ParsedText"] 48 | except BaseException: 49 | await event.edit("`Couldn't read it.`\n`I guess I need new glasses.`") 50 | else: 51 | await event.edit(f"`Here's what I could read from it:`\n\n{ParsedText}") 52 | os.remove(downloaded_file_name) 53 | 54 | 55 | CMD_HELP.update( 56 | { 57 | "ocr": ">`.ocr `" 58 | "\nUsage: Reply to an image or sticker to extract text from it." 59 | "\n\nGet language codes from [here](https://ocr.space/OCRAPI#PostParameters)" 60 | } 61 | ) 62 | -------------------------------------------------------------------------------- /userbot/utils/progress.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Adek Maulana 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | import time 19 | import math 20 | 21 | from .tools import humanbytes, time_formatter 22 | from .exceptions import CancelProcess 23 | 24 | 25 | async def progress( 26 | current, total, gdrive, start, prog_type, file_name=None, is_cancelled=False 27 | ): 28 | now = time.time() 29 | diff = now - start 30 | if is_cancelled is True: 31 | raise CancelProcess 32 | 33 | if round(diff % 10.00) == 0 or current == total: 34 | percentage = current * 100 / total 35 | speed = current / diff 36 | elapsed_time = round(diff) 37 | eta = round((total - current) / speed) 38 | if "upload" in prog_type.lower(): 39 | status = "Uploading" 40 | elif "download" in prog_type.lower(): 41 | status = "Downloading" 42 | else: 43 | status = "Unknown" 44 | progress_str = "[{0}{1}] `{2}%`".format( 45 | "".join("█" for i in range(math.floor(percentage / 10))), 46 | "".join("░" for i in range(10 - math.floor(percentage / 10))), 47 | round(percentage, 2), 48 | ) 49 | tmp = ( 50 | f"{progress_str} - {status}\n" 51 | f"`Size:` {humanbytes(current)} of {humanbytes(total)}\n" 52 | f"`Speed:` {humanbytes(speed)}\n" 53 | f"`ETA:` {time_formatter(eta)}\n" 54 | f"`Duration:` {time_formatter(elapsed_time)}" 55 | ) 56 | await gdrive.edit(f"`{prog_type}`\n\n" f"`Status`\n{tmp}") 57 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/welcome_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | 6 | from sqlalchemy import BigInteger, Column, Numeric, String, UnicodeText 7 | 8 | 9 | class Welcome(BASE): 10 | __tablename__ = "welcome" 11 | chat_id = Column(String(14), primary_key=True) 12 | previous_welcome = Column(BigInteger) 13 | reply = Column(UnicodeText) 14 | f_mesg_id = Column(Numeric) 15 | 16 | def __init__(self, chat_id, previous_welcome, reply, f_mesg_id): 17 | self.chat_id = str(chat_id) 18 | self.previous_welcome = previous_welcome 19 | self.reply = reply 20 | self.f_mesg_id = f_mesg_id 21 | 22 | 23 | Welcome.__table__.create(checkfirst=True) 24 | 25 | 26 | def get_welcome(chat_id): 27 | try: 28 | return SESSION.query(Welcome).get(str(chat_id)) 29 | finally: 30 | SESSION.close() 31 | 32 | 33 | def get_current_welcome_settings(chat_id): 34 | try: 35 | return SESSION.query(Welcome).filter( 36 | Welcome.chat_id == str(chat_id)).one() 37 | except BaseException: 38 | return None 39 | finally: 40 | SESSION.close() 41 | 42 | 43 | def add_welcome_setting(chat_id, previous_welcome, reply, f_mesg_id): 44 | to_check = get_welcome(chat_id) 45 | if not to_check: 46 | adder = Welcome(chat_id, previous_welcome, reply, f_mesg_id) 47 | SESSION.add(adder) 48 | SESSION.commit() 49 | return True 50 | else: 51 | rem = SESSION.query(Welcome).get(str(chat_id)) 52 | SESSION.delete(rem) 53 | SESSION.commit() 54 | adder = Welcome(chat_id, previous_welcome, reply, f_mesg_id) 55 | SESSION.commit() 56 | return False 57 | 58 | 59 | def rm_welcome_setting(chat_id): 60 | try: 61 | rem = SESSION.query(Welcome).get(str(chat_id)) 62 | if rem: 63 | SESSION.delete(rem) 64 | SESSION.commit() 65 | return True 66 | except BaseException: 67 | return False 68 | 69 | 70 | def update_previous_welcome(chat_id, previous_welcome): 71 | row = SESSION.query(Welcome).get(str(chat_id)) 72 | row.previous_welcome = previous_welcome 73 | SESSION.commit() 74 | -------------------------------------------------------------------------------- /userbot/utils/tools.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Adek Maulana 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | import re 19 | import hashlib 20 | 21 | 22 | async def md5(fname: str) -> str: 23 | hash_md5 = hashlib.md5() 24 | with open(fname, "rb") as f: 25 | for chunk in iter(lambda: f.read(4096), b""): 26 | hash_md5.update(chunk) 27 | return hash_md5.hexdigest() 28 | 29 | 30 | def humanbytes(size: int) -> str: 31 | if size is None or isinstance(size, str): 32 | return "" 33 | 34 | power = 2**10 35 | raised_to_pow = 0 36 | dict_power_n = {0: "", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"} 37 | while size > power: 38 | size /= power 39 | raised_to_pow += 1 40 | return str(round(size, 2)) + " " + dict_power_n[raised_to_pow] + "B" 41 | 42 | 43 | def time_formatter(seconds: int) -> str: 44 | minutes, seconds = divmod(seconds, 60) 45 | hours, minutes = divmod(minutes, 60) 46 | days, hours = divmod(hours, 24) 47 | tmp = ( 48 | ((str(days) + " day(s), ") if days else "") + 49 | ((str(hours) + " hour(s), ") if hours else "") + 50 | ((str(minutes) + " minute(s), ") if minutes else "") + 51 | ((str(seconds) + " second(s), ") if seconds else "") 52 | ) 53 | return tmp[:-2] 54 | 55 | 56 | def human_to_bytes(size: str) -> int: 57 | units = { 58 | "M": 2**20, "MB": 2**20, 59 | "G": 2**30, "GB": 2**30, 60 | "T": 2**40, "TB": 2**40 61 | } 62 | 63 | size = size.upper() 64 | if not re.match(r' ', size): 65 | size = re.sub(r'([KMGT])', r' \1', size) 66 | number, unit = [string.strip() for string in size.split()] 67 | return int(float(number) * units[unit]) 68 | -------------------------------------------------------------------------------- /userbot/modules/ssvideo.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Alfiananda P.A 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.d (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import asyncio 8 | import os 9 | import time 10 | 11 | from telethon.tl.types import DocumentAttributeFilename 12 | 13 | from userbot import CMD_HELP, bot 14 | from userbot.events import register 15 | from userbot.utils import progress 16 | 17 | 18 | @register(outgoing=True, pattern=r"^\.ssvideo(?: |$)(.*)") 19 | async def ssvideo(event): 20 | if not event.reply_to_msg_id: 21 | await event.edit("`Reply to any media..`") 22 | return 23 | reply_message = await event.get_reply_message() 24 | if not reply_message.media: 25 | await event.edit("`reply to a video..`") 26 | return 27 | try: 28 | frame = int(event.pattern_match.group(1)) 29 | if frame > 10: 30 | return await event.edit("`hey..dont put that much`") 31 | except BaseException: 32 | return await event.edit("`Please input number of frame!`") 33 | if reply_message.photo: 34 | return await event.edit("`Hey..this is an image!`") 35 | if ( 36 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 37 | in reply_message.media.document.attributes 38 | ): 39 | return await event.edit("`Unsupported files..`") 40 | elif ( 41 | DocumentAttributeFilename(file_name="sticker.webp") 42 | in reply_message.media.document.attributes 43 | ): 44 | return await event.edit("`Unsupported files..`") 45 | c_time = time.time() 46 | await event.edit("`Downloading media..`") 47 | ss = await bot.download_media( 48 | reply_message, 49 | "anu.mp4", 50 | progress_callback=lambda d, t: asyncio.get_event_loop().create_task( 51 | progress(d, t, event, c_time, "[DOWNLOAD]") 52 | ), 53 | ) 54 | try: 55 | await event.edit("`Processing..`") 56 | command = f"vcsi -g {frame}x{frame} {ss} -o ss.png " 57 | os.system(command) 58 | await event.client.send_file( 59 | event.chat_id, 60 | "ss.png", 61 | reply_to=event.reply_to_msg_id, 62 | ) 63 | await event.delete() 64 | os.system("rm *.png *.mp4") 65 | except BaseException as e: 66 | os.system("rm *.png *.mp4") 67 | return await event.edit(f"{e}") 68 | 69 | 70 | CMD_HELP.update( 71 | {"ssvideo": "`>.ssvideo `" "\nUsage: to ss video frame per frame"} 72 | ) 73 | -------------------------------------------------------------------------------- /userbot/modules/spotifynow.py: -------------------------------------------------------------------------------- 1 | # Ported by Aidil Aryanto 2 | 3 | import os 4 | from asyncio.exceptions import TimeoutError 5 | 6 | from telethon.errors.rpcerrorlist import YouBlockedUserError 7 | 8 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY, bot 9 | from userbot.events import register 10 | 11 | 12 | @register(outgoing=True, pattern=r"^\.spotnow(:? |$)(.*)?") 13 | async def _(event): 14 | if event.fwd_from: 15 | return 16 | chat = "@SpotifyNowBot" 17 | await event.edit("`Processing...`") 18 | try: 19 | async with event.client.conversation(chat) as conv: 20 | now = "/now" 21 | try: 22 | msg = await conv.send_message(now) 23 | response = await conv.get_response() 24 | await bot.send_read_acknowledge(conv.chat_id) 25 | except YouBlockedUserError: 26 | await event.reply("`Please unblock` @SpotifyNowBot`...`") 27 | return 28 | if response.text.startswith("You're"): 29 | await event.edit( 30 | "`You're not listening to anything on Spotify at the moment`" 31 | ) 32 | await event.client.delete_messages(conv.chat_id, [msg.id, response.id]) 33 | return 34 | if response.text.startswith("Ads."): 35 | await event.edit("`You're listening to those annoying ads.`") 36 | await event.client.delete_messages(conv.chat_id, [msg.id, response.id]) 37 | return 38 | else: 39 | downloaded_file_name = await event.client.download_media( 40 | response.media, TEMP_DOWNLOAD_DIRECTORY 41 | ) 42 | link = response.reply_markup.rows[0].buttons[0].url 43 | await event.client.send_file( 44 | event.chat_id, 45 | downloaded_file_name, 46 | force_document=False, 47 | caption=f"[Play on Spotify]({link})", 48 | ) 49 | await event.client.delete_messages(conv.chat_id, [msg.id, response.id]) 50 | await event.delete() 51 | return os.remove(downloaded_file_name) 52 | except TimeoutError: 53 | await event.edit("`@SpotifyNowBot isnt responding..`") 54 | await event.client.delete_messages(conv.chat_id, [msg.id]) 55 | 56 | 57 | CMD_HELP.update( 58 | { 59 | "spotifynow": ">`.spotnow`" 60 | "\nUsage: Show what you're listening on spotify." 61 | "\n@SpotifyNowBot" 62 | } 63 | ) 64 | -------------------------------------------------------------------------------- /userbot/modules/covid.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.d (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # Port to UserBot by @MoveAngel 7 | 8 | from covid import Covid 9 | 10 | from userbot import CMD_HELP 11 | from userbot.events import register 12 | 13 | 14 | @register(outgoing=True, pattern=r"^\.covid(?: |$)(.*)") 15 | async def corona(event): 16 | await event.edit("`Processing...`") 17 | query = event.pattern_match.group(1) 18 | if query: 19 | country = query 20 | else: 21 | country = "world" 22 | covid = Covid(source="worldometers") 23 | try: 24 | country_data = covid.get_status_by_country_name(country) 25 | output_text = ( 26 | f"`Confirmed : {format_integer(country_data['confirmed'])}`\n" 27 | + f"`Active : {format_integer(country_data['active'])}`\n" 28 | + f"`Deaths : {format_integer(country_data['deaths'])}`\n" 29 | + f"`Recovered : {format_integer(country_data['recovered'])}`\n\n" 30 | + f"`New Cases : {format_integer(country_data['new_cases'])}`\n" 31 | + f"`New Deaths : {format_integer(country_data['new_deaths'])}`\n" 32 | + f"`Critical : {format_integer(country_data['critical'])}`\n" 33 | + f"`Total Tests : {format_integer(country_data['total_tests'])}`\n\n" 34 | + f"Data provided by [Worldometer](https://www.worldometers.info/coronavirus/country/{country})" 35 | ) 36 | await event.edit(f"Corona Virus Info in {country}:\n\n{output_text}") 37 | except ValueError: 38 | await event.edit( 39 | f"No information found for: {country}!\nCheck your spelling and try again." 40 | ) 41 | 42 | 43 | def format_integer(number, thousand_separator="."): 44 | def reverse(string): 45 | string = "".join(reversed(string)) 46 | return string 47 | 48 | s = reverse(str(number)) 49 | count = 0 50 | result = "" 51 | for char in s: 52 | count = count + 1 53 | if count % 3 == 0: 54 | if len(s) == count: 55 | result = char + result 56 | else: 57 | result = thousand_separator + char + result 58 | else: 59 | result = char + result 60 | return result 61 | 62 | 63 | CMD_HELP.update( 64 | { 65 | "covid": ">`.covid` **country**" 66 | "\nUsage: Get an information about data covid-19 in your country.\n" 67 | } 68 | ) 69 | -------------------------------------------------------------------------------- /userbot/modules/lyrics.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # 7 | 8 | import codecs 9 | import os 10 | 11 | import lyricsgenius 12 | import requests 13 | from pylast import User 14 | 15 | from userbot import CMD_HELP, GENIUS, LASTFM_USERNAME, lastfm 16 | from userbot.events import register 17 | 18 | if GENIUS is not None: 19 | genius = lyricsgenius.Genius(GENIUS) 20 | 21 | 22 | @register(outgoing=True, pattern=r"^\.lyrics (?:(now)|(.*) - (.*))") 23 | async def lyrics(lyric): 24 | await lyric.edit("`Getting information...`") 25 | if GENIUS is None: 26 | await lyric.edit("`Provide genius access token to Heroku ConfigVars...`") 27 | return False 28 | if lyric.pattern_match.group(1) == "now": 29 | playing = User(LASTFM_USERNAME, lastfm).get_now_playing() 30 | if playing is None: 31 | await lyric.edit("`No information current lastfm scrobbling...`") 32 | return False 33 | artist = playing.get_artist() 34 | song = playing.get_title() 35 | else: 36 | artist = lyric.pattern_match.group(2) 37 | song = lyric.pattern_match.group(3) 38 | await lyric.edit(f"`Searching lyrics for {artist} - {song}...`") 39 | songs = genius.search_song(song, artist) 40 | if songs is None: 41 | await lyric.edit(f"`Song` **{artist} - {song}** `not found...`") 42 | return False 43 | if len(songs.lyrics) > 4096: 44 | await lyric.edit("`Lyrics is too big, pasted lyrics to Nekobin. please wait.`") 45 | with open("lyrics.txt", "w+") as f: 46 | f.write(f"Search query: \n{artist} - {song}\n\n{songs.lyrics}") 47 | lirik = codecs.open("lyrics.txt", "r", encoding="utf-8") 48 | data = lirik.read() 49 | key = ( 50 | requests.post("https://nekobin.com/api/documents", json={"content": data}) 51 | .json() 52 | .get("result") 53 | .get("key") 54 | ) 55 | url = f"https://nekobin.com/raw/{key}" 56 | await lyric.edit(f"`Here the lyrics:`\n\nPasted to: [Nekobin]({url})") 57 | os.remove("lyrics.txt") 58 | else: 59 | await lyric.edit( 60 | f"**Search query**:\n`{artist}` - `{song}`" f"\n\n```{songs.lyrics}```" 61 | ) 62 | 63 | return True 64 | 65 | 66 | CMD_HELP.update( 67 | { 68 | "lyrics": ">`.lyrics` ** - **" 69 | "\nUsage: Get lyrics matched artist and song." 70 | "\n\n>`.lyrics now`" 71 | "\nUsage: Get lyrics artist and song from current lastfm scrobbling." 72 | } 73 | ) 74 | -------------------------------------------------------------------------------- /userbot/modules/hash.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from subprocess import PIPE 8 | from subprocess import run as runapp 9 | 10 | import pybase64 11 | 12 | from userbot import CMD_HELP 13 | from userbot.events import register 14 | 15 | 16 | @register(outgoing=True, pattern=r"^\.hash (.*)") 17 | async def gethash(hash_q): 18 | hashtxt_ = hash_q.pattern_match.group(1) 19 | hashtxt = open("hashdis.txt", "w+") 20 | hashtxt.write(hashtxt_) 21 | hashtxt.close() 22 | md5 = runapp(["md5sum", "hashdis.txt"], stdout=PIPE) 23 | md5 = md5.stdout.decode() 24 | sha1 = runapp(["sha1sum", "hashdis.txt"], stdout=PIPE) 25 | sha1 = sha1.stdout.decode() 26 | sha256 = runapp(["sha256sum", "hashdis.txt"], stdout=PIPE) 27 | sha256 = sha256.stdout.decode() 28 | sha512 = runapp(["sha512sum", "hashdis.txt"], stdout=PIPE) 29 | runapp(["rm", "hashdis.txt"], stdout=PIPE) 30 | sha512 = sha512.stdout.decode() 31 | ans = ( 32 | "Text: `" 33 | + hashtxt_ 34 | + "`\nMD5: `" 35 | + md5 36 | + "`SHA1: `" 37 | + sha1 38 | + "`SHA256: `" 39 | + sha256 40 | + "`SHA512: `" 41 | + sha512[:-1] 42 | + "`" 43 | ) 44 | if len(ans) > 4096: 45 | hashfile = open("hashes.txt", "w+") 46 | hashfile.write(ans) 47 | hashfile.close() 48 | await hash_q.client.send_file( 49 | hash_q.chat_id, 50 | "hashes.txt", 51 | reply_to=hash_q.id, 52 | caption="`It's too big, sending a text file instead. `", 53 | ) 54 | runapp(["rm", "hashes.txt"], stdout=PIPE) 55 | else: 56 | await hash_q.reply(ans) 57 | 58 | 59 | @register(outgoing=True, pattern=r"^\.base64 (en|de) (.*)") 60 | async def endecrypt(query): 61 | if query.pattern_match.group(1) == "en": 62 | lething = str(pybase64.b64encode(bytes(query.pattern_match.group(2), "utf-8")))[ 63 | 2: 64 | ] 65 | await query.reply("Encoded: `" + lething[:-1] + "`") 66 | else: 67 | lething = str( 68 | pybase64.b64decode( 69 | bytes(query.pattern_match.group(2), "utf-8"), validate=True 70 | ) 71 | )[2:] 72 | await query.reply("Decoded: `" + lething[:-1] + "`") 73 | 74 | 75 | CMD_HELP.update( 76 | { 77 | "hash": ">`.hash`" 78 | "\nUsage: Find the md5, sha1, sha256, sha512 of the string when written into a txt file.", 79 | "base64": ">`.base64 [en or de]`" 80 | "\nUsage: Find the base64 encoding of the given string or decode it.", 81 | } 82 | ) 83 | -------------------------------------------------------------------------------- /userbot/modules/www.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from datetime import datetime 8 | 9 | from speedtest import Speedtest 10 | from telethon import functions 11 | 12 | from userbot import CMD_HELP 13 | from userbot.events import register 14 | 15 | 16 | @register(outgoing=True, pattern=r"^\.speed$") 17 | async def speedtst(spd): 18 | await spd.edit("`Running speed test . . .`") 19 | test = Speedtest() 20 | 21 | test.get_best_server() 22 | test.download() 23 | test.upload() 24 | test.results.share() 25 | result = test.results.dict() 26 | 27 | output = f"Started at `{result['timestamp']}`\n\n" 28 | output += "`Client:`\n" 29 | output += f"ISP: `{result['client']['isp']}`\n" 30 | output += f"Country: `{result['client']['country']}`\n\n" 31 | output += "`Server:`\n" 32 | output += f"Name: `{result['server']['name']}`\n" 33 | output += f"Country: `{result['server']['country']}, {result['server']['cc']}`\n" 34 | output += f"Sponsor: `{result['server']['sponsor']}`\n" 35 | output += f"Latency: `{result['server']['latency']}`\n\n" 36 | output += "`Speed:`\n" 37 | output += f"Ping: `{result['ping']}`\n" 38 | output += f"Download: `{speed_convert(result['download'])}`\n" 39 | output += f"Upload: `{speed_convert(result['upload'])}` " 40 | await spd.delete() 41 | await spd.client.send_message(spd.chat_id, output) 42 | 43 | 44 | def speed_convert(size): 45 | power = 2 ** 10 46 | zero = 0 47 | units = {0: "", 1: "Kb/s", 2: "Mb/s", 3: "Gb/s", 4: "Tb/s"} 48 | while size > power: 49 | size /= power 50 | zero += 1 51 | return f"{round(size, 2)} {units[zero]}" 52 | 53 | 54 | @register(outgoing=True, pattern=r"^\.dc$") 55 | async def neardc(event): 56 | result = await event.client(functions.help.GetNearestDcRequest()) 57 | await event.edit( 58 | f"Country : `{result.country}`\n" 59 | f"Nearest Datacenter : `{result.nearest_dc}`\n" 60 | f"This Datacenter : `{result.this_dc}`" 61 | ) 62 | 63 | 64 | @register(outgoing=True, pattern=r"^\.ping$") 65 | async def pingme(pong): 66 | start = datetime.now() 67 | await pong.edit("`Pong!`") 68 | end = datetime.now() 69 | duration = (end - start).microseconds / 1000 70 | await pong.edit("`Pong!\n%sms`" % (duration)) 71 | 72 | 73 | CMD_HELP.update( 74 | { 75 | "speed": ">`.speed`" "\nUsage: Does a speedtest and shows the results.", 76 | "dc": ">`.dc`" "\nUsage: Finds the nearest datacenter from your server.", 77 | "ping": ">`.ping`" "\nUsage: Shows how long it takes to ping your bot.", 78 | } 79 | ) 80 | -------------------------------------------------------------------------------- /userbot/modules/sticklet.py: -------------------------------------------------------------------------------- 1 | # Random RGB Sticklet by @PhycoNinja13b 2 | # modified by @AnggaR96s 3 | 4 | import io 5 | import os 6 | import random 7 | import textwrap 8 | 9 | from PIL import Image, ImageDraw, ImageFont 10 | from telethon.tl.types import InputMessagesFilterDocument 11 | 12 | from userbot import CMD_HELP 13 | from userbot.events import register 14 | 15 | 16 | @register(outgoing=True, pattern=r"^\.rgb (.*)") 17 | async def sticklet(event): 18 | R = random.randint(0, 256) 19 | G = random.randint(0, 256) 20 | B = random.randint(0, 256) 21 | 22 | # get the input text 23 | # the text on which we would like to do the magic on 24 | sticktext = event.pattern_match.group(1) 25 | 26 | # delete the userbot command, 27 | # i don't know why this is required 28 | await event.delete() 29 | 30 | # https://docs.python.org/3/library/textwrap.html#textwrap.wrap 31 | sticktext = textwrap.wrap(sticktext, width=10) 32 | # converts back the list to a string 33 | sticktext = "\n".join(sticktext) 34 | 35 | image = Image.new("RGBA", (512, 512), (255, 255, 255, 0)) 36 | draw = ImageDraw.Draw(image) 37 | fontsize = 230 38 | 39 | FONT_FILE = await get_font_file(event.client, "@FontRes") 40 | 41 | font = ImageFont.truetype(FONT_FILE, size=fontsize) 42 | 43 | while draw.multiline_textsize(sticktext, font=font) > (512, 512): 44 | fontsize -= 3 45 | font = ImageFont.truetype(FONT_FILE, size=fontsize) 46 | 47 | width, height = draw.multiline_textsize(sticktext, font=font) 48 | draw.multiline_text( 49 | ((512 - width) / 2, (512 - height) / 2), sticktext, font=font, fill=(R, G, B) 50 | ) 51 | 52 | image_stream = io.BytesIO() 53 | image_stream.name = "dclxvi.webp" 54 | image.save(image_stream, "WebP") 55 | image_stream.seek(0) 56 | 57 | # finally, reply the sticker 58 | await event.client.send_file( 59 | event.chat_id, 60 | image_stream, 61 | force_document=False, 62 | reply_to=event.message.reply_to_msg_id, 63 | ) 64 | 65 | # cleanup 66 | try: 67 | os.remove(FONT_FILE) 68 | except BaseException: 69 | pass 70 | 71 | 72 | async def get_font_file(client, channel_id): 73 | # first get the font messages 74 | font_file_message_s = await client.get_messages( 75 | entity=channel_id, 76 | filter=InputMessagesFilterDocument, 77 | # this might cause FLOOD WAIT, 78 | # if used too many times 79 | limit=None, 80 | ) 81 | # get a random font from the list of fonts 82 | # https://docs.python.org/3/library/random.html#random.choice 83 | font_file_message = random.choice(font_file_message_s) 84 | # download and return the file path 85 | return await client.download_media(font_file_message) 86 | 87 | 88 | CMD_HELP.update({"sticklet": ">`.rgb` " "\nUsage: Create RGB sticker."}) 89 | -------------------------------------------------------------------------------- /userbot/modules/mention.py: -------------------------------------------------------------------------------- 1 | # Ported by @KenHV 2 | # TG-UserBot - A modular Telegram UserBot script for Python. 3 | # Copyright (C) 2019 Kandarp 4 | # 5 | # TG-UserBot is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # TG-UserBot is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with TG-UserBot. If not, see . 17 | 18 | import re 19 | 20 | from telethon.tl import types 21 | 22 | from userbot import CMD_HELP, bot 23 | from userbot.events import register 24 | 25 | usernexp = re.compile(r"@(\w{3,32})\[(.+?)\]") 26 | nameexp = re.compile(r"\[([\w\S]+)\]\(tg://user\?id=(\d+)\)\[(.+?)\]") 27 | 28 | 29 | @register(outgoing=True, ignore_unsafe=True, disable_errors=True) 30 | async def mention(event): 31 | newstr = event.text 32 | if event.entities: 33 | newstr = nameexp.sub(r'\3', newstr, 0) 34 | for match in usernexp.finditer(newstr): 35 | user = match.group(1) 36 | text = match.group(2) 37 | name, entities = await bot._parse_message_text(text, "md") 38 | rep = f'{name}' 39 | if entities: 40 | for e in entities: 41 | tag = None 42 | if isinstance(e, types.MessageEntityBold): 43 | tag = "{}" 44 | elif isinstance(e, types.MessageEntityItalic): 45 | tag = "{}" 46 | elif isinstance(e, types.MessageEntityCode): 47 | tag = "{}" 48 | elif isinstance(e, types.MessageEntityStrike): 49 | tag = "{}" 50 | elif isinstance(e, types.MessageEntityPre): 51 | tag = "
{}
" 52 | elif isinstance(e, types.MessageEntityUnderline): 53 | tag = "{}" 54 | if tag: 55 | rep = tag.format(rep) 56 | newstr = re.sub(re.escape(match.group(0)), rep, newstr) 57 | if newstr != event.text: 58 | await event.edit(newstr, parse_mode="html") 59 | 60 | 61 | CMD_HELP.update( 62 | { 63 | "mention": "Mention users with a custom name." 64 | "\nUsage: `Hi @ender1324[bluid boi]`" 65 | "\nResult: Hi [bluid boi](tg://resolve?domain=ender1324)" 66 | } 67 | ) 68 | -------------------------------------------------------------------------------- /userbot/modules/create.py: -------------------------------------------------------------------------------- 1 | # this module original created by @spechide 2 | # port to userbot by @afdulfauzan 3 | 4 | from telethon.tl import functions 5 | 6 | from userbot import CMD_HELP 7 | from userbot.events import register 8 | 9 | 10 | @register(outgoing=True, pattern=r"^\.create (b|g|c)(?: |$)(.*)") 11 | async def telegraphs(grop): 12 | if grop.text[0].isalpha() or grop.text[0] in ("/", "#", "@", "!"): 13 | return 14 | if grop.fwd_from: 15 | return 16 | type_of_group = grop.pattern_match.group(1) 17 | group_name = grop.pattern_match.group(2) 18 | if type_of_group == "b": 19 | try: 20 | result = await grop.client( 21 | functions.messages.CreateChatRequest( # pylint:disable=E0602 22 | users=["@sanaTWICEbot"], 23 | # Not enough users (to create a chat, for example) 24 | # Telegram, no longer allows creating a chat with ourselves 25 | title=group_name, 26 | ) 27 | ) 28 | created_chat_id = result.chats[0].id 29 | result = await grop.client( 30 | functions.messages.ExportChatInviteRequest( 31 | peer=created_chat_id, 32 | ) 33 | ) 34 | await grop.edit( 35 | "Your Group Created Successfully. Click [{}]({}) to join".format( 36 | group_name, result.link 37 | ) 38 | ) 39 | except Exception as e: # pylint:disable=C0103,W0703 40 | await grop.edit(str(e)) 41 | elif type_of_group in ["g", "c"]: 42 | try: 43 | r = await grop.client( 44 | functions.channels.CreateChannelRequest( # pylint:disable=E0602 45 | title=group_name, 46 | about="Welcome to this Channel", 47 | megagroup=False if type_of_group == "c" else True, 48 | ) 49 | ) 50 | created_chat_id = r.chats[0].id 51 | result = await grop.client( 52 | functions.messages.ExportChatInviteRequest( 53 | peer=created_chat_id, 54 | ) 55 | ) 56 | await grop.edit( 57 | "Your Group/Channel Created Successfully. Click [{}]({}) to join".format( 58 | group_name, result.link 59 | ) 60 | ) 61 | except Exception as e: # pylint:disable=C0103,W0703 62 | await grop.edit(str(e)) 63 | 64 | 65 | CMD_HELP.update( 66 | { 67 | "create": "Create" 68 | "\nUsage: Create Channel, Group & Group With Bot." 69 | "\n\n`>.create g `" 70 | "\nUsage: Create a Private Group." 71 | "\n\n`>.create b `" 72 | "\nUsage: Create a Group with Bot." 73 | "\n\n`>.create c `" 74 | "\nUsage: Create a Channel." 75 | } 76 | ) 77 | -------------------------------------------------------------------------------- /userbot/modules/screencapture.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # The entire source code is OSSRPL except 'screencapture' which is MPL 7 | # License: MPL and OSSRPL 8 | 9 | import io 10 | from asyncio import sleep 11 | from re import match 12 | 13 | from userbot import CMD_HELP 14 | from userbot.events import register 15 | from userbot.utils import chrome, options 16 | 17 | 18 | @register(pattern=r"^\.ss (.*)", outgoing=True) 19 | async def capture(url): 20 | await url.edit("`Processing...`") 21 | chrome_options = await options() 22 | chrome_options.add_argument("--test-type") 23 | chrome_options.add_argument("--ignore-certificate-errors") 24 | chrome_options.arguments.remove("--window-size=1920x1080") 25 | driver = await chrome(chrome_options=chrome_options) 26 | input_str = url.pattern_match.group(1) 27 | link_match = match(r"\bhttps?://.*\.\S+", input_str) 28 | if link_match: 29 | link = link_match.group() 30 | else: 31 | return await url.edit("`I need a valid link to take screenshots from.`") 32 | driver.get(link) 33 | height = driver.execute_script( 34 | "return Math.max(document.body.scrollHeight, document.body.offsetHeight, " 35 | "document.documentElement.clientHeight, document.documentElement.scrollHeight, " 36 | "document.documentElement.offsetHeight);" 37 | ) 38 | width = driver.execute_script( 39 | "return Math.max(document.body.scrollWidth, document.body.offsetWidth, " 40 | "document.documentElement.clientWidth, document.documentElement.scrollWidth, " 41 | "document.documentElement.offsetWidth);" 42 | ) 43 | driver.set_window_size(width + 125, height + 125) 44 | wait_for = height / 1000 45 | await url.edit( 46 | "`Generating screenshot of the page...`" 47 | f"\n`Height of page = {height}px`" 48 | f"\n`Width of page = {width}px`" 49 | f"\n`Waiting ({int(wait_for)}s) for the page to load.`" 50 | ) 51 | await sleep(int(wait_for)) 52 | im_png = driver.get_screenshot_as_png() 53 | # saves screenshot of entire page 54 | driver.quit() 55 | message_id = url.message.id 56 | if url.reply_to_msg_id: 57 | message_id = url.reply_to_msg_id 58 | with io.BytesIO(im_png) as out_file: 59 | out_file.name = "screencapture.png" 60 | await url.edit("`Uploading screenshot as file..`") 61 | await url.client.send_file( 62 | url.chat_id, 63 | out_file, 64 | caption=input_str, 65 | force_document=True, 66 | reply_to=message_id, 67 | ) 68 | 69 | 70 | CMD_HELP.update( 71 | { 72 | "ss": ">`.ss `" 73 | "\nUsage: Takes a screenshot of a website and sends the screenshot." 74 | "\nExample of a valid URL : `https://www.google.com`" 75 | } 76 | ) 77 | -------------------------------------------------------------------------------- /userbot/modules/webupload.py: -------------------------------------------------------------------------------- 1 | # Kanged from UniBorg 2 | # Modified by AnggaR96s 3 | 4 | import asyncio 5 | import json 6 | import os 7 | 8 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 9 | from userbot.events import register 10 | 11 | 12 | @register( 13 | outgoing=True, 14 | pattern=r"^\.web ?(.+?|) (anonfiles|transfer|filebin|anonymousfiles|megaupload|bayfiles|letsupload|0x0)", 15 | ) 16 | async def _(event): 17 | await event.edit("`Processing ...`") 18 | input_str = event.pattern_match.group(1) 19 | selected_transfer = event.pattern_match.group(2) 20 | if input_str: 21 | file_name = input_str 22 | else: 23 | reply = await event.get_reply_message() 24 | file_name = await event.client.download_media( 25 | reply.media, TEMP_DOWNLOAD_DIRECTORY 26 | ) 27 | 28 | CMD_WEB = { 29 | "anonfiles": 'curl -F "file=@{full_file_path}" https://anonfiles.com/api/upload', 30 | "transfer": 'curl --upload-file "{full_file_path}" https://transfer.sh/{bare_local_name}', 31 | "filebin": 'curl -X POST --data-binary "@{full_file_path}" -H "filename: {bare_local_name}" "https://filebin.net"', 32 | "anonymousfiles": 'curl -F file="@{full_file_path}" https://api.anonymousfiles.io/', 33 | "megaupload": 'curl -F "file=@{full_file_path}" https://megaupload.is/api/upload', 34 | "bayfiles": 'curl -F "file=@{full_file_path}" https://bayfiles.com/api/upload', 35 | "letsupload": 'curl -F "file=@{full_file_path}" https://api.letsupload.cc/upload', 36 | "0x0": 'curl -F "file=@{full_file_path}" https://0x0.st', 37 | } 38 | filename = os.path.basename(file_name) 39 | try: 40 | selected_one = CMD_WEB[selected_transfer].format( 41 | full_file_path=file_name, bare_local_name=filename 42 | ) 43 | except KeyError: 44 | await event.edit("`Invalid selected Transfer.`") 45 | return 46 | cmd = selected_one 47 | # start the subprocess $SHELL 48 | process = await asyncio.create_subprocess_shell( 49 | cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE 50 | ) 51 | stdout, stderr = await process.communicate() 52 | stderr.decode().strip() 53 | # logger.info(e_response) 54 | t_response = stdout.decode().strip() 55 | # logger.info(t_response) 56 | """if e_response: 57 | await event.edit(f"**FAILED** to __transload__: `{e_response}`") 58 | return""" 59 | if t_response: 60 | try: 61 | t_response = json.dumps(json.loads(t_response), sort_keys=True, indent=4) 62 | except Exception: 63 | # some sites don't return valid JSONs 64 | pass 65 | # assuming, the return values won't be longer than 66 | # 4096 characters 67 | await event.edit(t_response) 68 | 69 | 70 | CMD_HELP.update( 71 | { 72 | "webupload": ">`.web` **File** **Server**" 73 | "\nServer List: anonfiles|transfer|filebin|anonymousfiles|megaupload|bayfiles|lestupload|0x0" 74 | "\nUsage: Upload file to web." 75 | } 76 | ) 77 | -------------------------------------------------------------------------------- /userbot/modules/spam.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | 6 | import asyncio 7 | from asyncio import sleep 8 | 9 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP 10 | from userbot.events import register 11 | 12 | 13 | @register(outgoing=True, pattern=r"^\.cspam (.*)") 14 | async def tmeme(e): 15 | cspam = str(e.pattern_match.group(1)) 16 | message = cspam.replace(" ", "") 17 | await e.delete() 18 | for letter in message: 19 | await e.respond(letter) 20 | if BOTLOG: 21 | await e.client.send_message( 22 | BOTLOG_CHATID, "#CSPAM\n" "TSpam was executed successfully" 23 | ) 24 | 25 | 26 | @register(outgoing=True, pattern=r"^\.wspam (.*)") 27 | async def t_meme(e): 28 | wspam = str(e.pattern_match.group(1)) 29 | message = wspam.split() 30 | await e.delete() 31 | for word in message: 32 | await e.respond(word) 33 | if BOTLOG: 34 | await e.client.send_message( 35 | BOTLOG_CHATID, "#WSPAM\n" "WSpam was executed successfully" 36 | ) 37 | 38 | 39 | @register(outgoing=True, pattern=r"^\.spam (.*)") 40 | async def spammers(e): 41 | counter = int(e.pattern_match.group(1).split(" ", 1)[0]) 42 | spam_message = str(e.pattern_match.group(1).split(" ", 1)[1]) 43 | await e.delete() 44 | await asyncio.wait([e.respond(spam_message) for i in range(counter)]) 45 | if BOTLOG: 46 | await e.client.send_message( 47 | BOTLOG_CHATID, "#SPAM\n" "Spam was executed successfully" 48 | ) 49 | 50 | 51 | @register(outgoing=True, pattern=r"^\.picspam") 52 | async def tiny_pic_spam(e): 53 | message = e.text 54 | text = message.split() 55 | counter = int(text[1]) 56 | link = str(text[2]) 57 | await e.delete() 58 | for _ in range(1, counter): 59 | await e.client.send_file(e.chat_id, link) 60 | if BOTLOG: 61 | await e.client.send_message( 62 | BOTLOG_CHATID, "#PICSPAM\n" "PicSpam was executed successfully" 63 | ) 64 | 65 | 66 | @register(outgoing=True, pattern=r"^\.delayspam (.*)") 67 | async def spammer(e): 68 | spamDelay = float(e.pattern_match.group(1).split(" ", 2)[0]) 69 | counter = int(e.pattern_match.group(1).split(" ", 2)[1]) 70 | spam_message = str(e.pattern_match.group(1).split(" ", 2)[2]) 71 | await e.delete() 72 | for _ in range(1, counter): 73 | await e.respond(spam_message) 74 | await sleep(spamDelay) 75 | if BOTLOG: 76 | await e.client.send_message( 77 | BOTLOG_CHATID, "#DelaySPAM\n" "DelaySpam was executed successfully" 78 | ) 79 | 80 | 81 | CMD_HELP.update( 82 | { 83 | "spam": ">`.cspam `" 84 | "\nUsage: Spam the text letter by letter." 85 | "\n\n>`.spam `" 86 | "\nUsage: Floods text in the chat !!" 87 | "\n\n>`.wspam `" 88 | "\nUsage: Spam the text word by word." 89 | "\n\n>`.picspam `" 90 | "\nUsage: As if text spam was not enough !!" 91 | "\n\n>`.delayspam `" 92 | "\nUsage: .bigspam but with custom delay." 93 | "\n\n\nNOTE : Spam at your own risk !!" 94 | } 95 | ) 96 | -------------------------------------------------------------------------------- /userbot/modules/wordcloud.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Alfiananda P.A 2 | # 3 | # Licensed under the General Public License, Version 3.0; 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import os 8 | 9 | import numpy as np 10 | from hachoir.metadata import extractMetadata 11 | from hachoir.parser import createParser 12 | from PIL import Image 13 | from scipy.ndimage import gaussian_gradient_magnitude 14 | from telethon.tl.types import DocumentAttributeFilename 15 | from wordcloud import ImageColorGenerator, WordCloud 16 | 17 | from userbot import CMD_HELP, bot 18 | from userbot.events import register 19 | 20 | 21 | @register(outgoing=True, pattern=r"^\.(wc)$") 22 | async def _(event): 23 | if not event.reply_to_msg_id: 24 | await event.edit("`Reply to Any media..`") 25 | return 26 | reply_message = await event.get_reply_message() 27 | if not reply_message.media: 28 | await event.edit("`reply to a image/sticker/video`") 29 | return 30 | await event.edit("`Downloading Media..`") 31 | if reply_message.photo: 32 | await bot.download_media( 33 | reply_message, 34 | "wc.png", 35 | ) 36 | elif ( 37 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 38 | in reply_message.media.document.attributes 39 | ): 40 | await bot.download_media( 41 | reply_message, 42 | "wc.tgs", 43 | ) 44 | os.system("lottie_convert.py wc.tgs wc.png") 45 | elif reply_message.video: 46 | video = await bot.download_media( 47 | reply_message, 48 | "wc.mp4", 49 | ) 50 | extractMetadata(createParser(video)) 51 | os.system("ffmpeg -i wc.mp4 -vframes 1 -an -s 480x360 -ss 1 wc.png") 52 | else: 53 | await bot.download_media( 54 | reply_message, 55 | "wc.png", 56 | ) 57 | try: 58 | await event.edit("`Processing..`") 59 | text = open("resources/alice.txt", encoding="utf-8").read() 60 | image_color = np.array(Image.open("wc.png")) 61 | image_color = image_color[::1, ::1] 62 | image_mask = image_color.copy() 63 | image_mask[image_mask.sum(axis=2) == 0] = 255 64 | edges = np.mean( 65 | [ 66 | gaussian_gradient_magnitude(image_color[:, :, i] / 255.0, 2) 67 | for i in range(3) 68 | ], 69 | axis=0, 70 | ) 71 | image_mask[edges > 0.08] = 255 72 | wc = WordCloud( 73 | max_words=2000, 74 | mask=image_mask, 75 | max_font_size=40, 76 | random_state=42, 77 | relative_scaling=0, 78 | ) 79 | wc.generate(text) 80 | image_colors = ImageColorGenerator(image_color) 81 | wc.recolor(color_func=image_colors) 82 | wc.to_file("wc.png") 83 | await event.client.send_file( 84 | event.chat_id, 85 | "wc.png", 86 | reply_to=event.reply_to_msg_id, 87 | ) 88 | await event.delete() 89 | os.system("rm *.png *.mp4 *.tgs *.webp") 90 | except BaseException as e: 91 | os.system("rm *.png *.mp4 *.tgs *.webp") 92 | return await event.edit(str(e)) 93 | 94 | 95 | CMD_HELP.update({"wordcloud": ">`.wc`\n" "Usage: create wordcloud art from media\n\n"}) 96 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/blacklist_sql.py: -------------------------------------------------------------------------------- 1 | try: 2 | from userbot.modules.sql_helper import SESSION, BASE 3 | except ImportError: 4 | raise AttributeError 5 | from sqlalchemy import Column, String, UnicodeText 6 | import threading 7 | 8 | 9 | class BlackListFilters(BASE): 10 | __tablename__ = "blacklist" 11 | chat_id = Column(String(14), primary_key=True) 12 | trigger = Column(UnicodeText, primary_key=True, nullable=False) 13 | 14 | def __init__(self, chat_id, trigger): 15 | self.chat_id = str(chat_id) # ensure string 16 | self.trigger = trigger 17 | 18 | def __repr__(self): 19 | return "" % (self.trigger, self.chat_id) 20 | 21 | def __eq__(self, other): 22 | return bool(isinstance(other, BlackListFilters) 23 | and self.chat_id == other.chat_id 24 | and self.trigger == other.trigger) 25 | 26 | 27 | BlackListFilters.__table__.create(checkfirst=True) 28 | 29 | BLACKLIST_FILTER_INSERTION_LOCK = threading.RLock() 30 | 31 | CHAT_BLACKLISTS = {} 32 | 33 | 34 | def add_to_blacklist(chat_id, trigger): 35 | with BLACKLIST_FILTER_INSERTION_LOCK: 36 | blacklist_filt = BlackListFilters(str(chat_id), trigger) 37 | 38 | SESSION.merge(blacklist_filt) # merge to avoid duplicate key issues 39 | SESSION.commit() 40 | CHAT_BLACKLISTS.setdefault(str(chat_id), set()).add(trigger) 41 | 42 | 43 | def rm_from_blacklist(chat_id, trigger): 44 | with BLACKLIST_FILTER_INSERTION_LOCK: 45 | blacklist_filt = SESSION.query( 46 | BlackListFilters).get((str(chat_id), trigger)) 47 | if blacklist_filt: 48 | if trigger in CHAT_BLACKLISTS.get( 49 | str(chat_id), set()): # sanity check 50 | CHAT_BLACKLISTS.get(str(chat_id), set()).remove(trigger) 51 | 52 | SESSION.delete(blacklist_filt) 53 | SESSION.commit() 54 | return True 55 | 56 | SESSION.close() 57 | return False 58 | 59 | 60 | def get_chat_blacklist(chat_id): 61 | return CHAT_BLACKLISTS.get(str(chat_id), set()) 62 | 63 | 64 | def num_blacklist_filters(): 65 | try: 66 | return SESSION.query(BlackListFilters).count() 67 | finally: 68 | SESSION.close() 69 | 70 | 71 | def num_blacklist_chat_filters(chat_id): 72 | try: 73 | return SESSION.query(BlackListFilters.chat_id).filter( 74 | BlackListFilters.chat_id == str(chat_id)).count() 75 | finally: 76 | SESSION.close() 77 | 78 | 79 | def num_blacklist_filter_chats(): 80 | try: 81 | return SESSION.query( 82 | func.count( 83 | distinct( 84 | BlackListFilters.chat_id))).scalar() 85 | finally: 86 | SESSION.close() 87 | 88 | 89 | def __load_chat_blacklists(): 90 | global CHAT_BLACKLISTS 91 | try: 92 | chats = SESSION.query(BlackListFilters.chat_id).distinct().all() 93 | for (chat_id,) in chats: # remove tuple by ( ,) 94 | CHAT_BLACKLISTS[chat_id] = [] 95 | 96 | all_filters = SESSION.query(BlackListFilters).all() 97 | for x in all_filters: 98 | CHAT_BLACKLISTS[x.chat_id] += [x.trigger] 99 | 100 | CHAT_BLACKLISTS = {x: set(y) for x, y in CHAT_BLACKLISTS.items()} 101 | 102 | finally: 103 | SESSION.close() 104 | 105 | 106 | __load_chat_blacklists() 107 | -------------------------------------------------------------------------------- /userbot/modules/sed.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # The entire source code is OSSRPL except 'sed' which is GPLv3 7 | # License: GPLv3 and OSSRPL 8 | 9 | import re 10 | from sre_constants import error as sre_err 11 | 12 | from userbot import CMD_HELP 13 | from userbot.events import register 14 | 15 | DELIMITERS = ("/", ":", "|", "_") 16 | 17 | 18 | async def separate_sed(sed_string): 19 | 20 | if len(sed_string) < 2: 21 | return 22 | 23 | if sed_string[2] in DELIMITERS and sed_string.count(sed_string[2]) >= 2: 24 | delim = sed_string[2] 25 | start = counter = 3 26 | while counter < len(sed_string): 27 | if sed_string[counter] == "\\": 28 | counter += 1 29 | 30 | elif sed_string[counter] == delim: 31 | replace = sed_string[start:counter] 32 | counter += 1 33 | start = counter 34 | break 35 | 36 | counter += 1 37 | 38 | else: 39 | return None 40 | 41 | while counter < len(sed_string): 42 | if ( 43 | sed_string[counter] == "\\" 44 | and counter + 1 < len(sed_string) 45 | and sed_string[counter + 1] == delim 46 | ): 47 | sed_string = sed_string[:counter] + sed_string[counter + 1 :] 48 | 49 | elif sed_string[counter] == delim: 50 | replace_with = sed_string[start:counter] 51 | counter += 1 52 | break 53 | 54 | counter += 1 55 | else: 56 | return replace, sed_string[start:], "" 57 | 58 | flags = "" 59 | if counter < len(sed_string): 60 | flags = sed_string[counter:] 61 | return replace, replace_with, flags.lower() 62 | return None 63 | 64 | 65 | @register(outgoing=True, pattern=r"^\.s") 66 | async def sed(command): 67 | sed_result = await separate_sed(command.text) 68 | textx = await command.get_reply_message() 69 | if sed_result: 70 | if textx: 71 | to_fix = textx.text 72 | else: 73 | return await command.edit( 74 | "`Master, I don't have brains. Well you too don't I guess.`" 75 | ) 76 | 77 | repl, repl_with, flags = sed_result 78 | 79 | if not repl: 80 | return await command.edit( 81 | "`Master, I don't have brains. Well you too don't I guess.`" 82 | ) 83 | 84 | try: 85 | check = re.match(repl, to_fix, flags=re.IGNORECASE) 86 | if check and check.group(0).lower() == to_fix.lower(): 87 | return await command.edit("`Boi!, that's a reply. Don't use sed`") 88 | 89 | if "i" in flags and "g" in flags: 90 | text = re.sub(repl, repl_with, to_fix, flags=re.I).strip() 91 | elif "i" in flags: 92 | text = re.sub(repl, repl_with, to_fix, count=1, flags=re.I).strip() 93 | elif "g" in flags: 94 | text = re.sub(repl, repl_with, to_fix).strip() 95 | else: 96 | text = re.sub(repl, repl_with, to_fix, count=1).strip() 97 | except sre_err: 98 | return await command.edit("B O I! [Learn Regex](https://regexone.com)") 99 | if text: 100 | await command.edit(f"Did you mean? \n\n{text}") 101 | 102 | 103 | CMD_HELP.update( 104 | { 105 | "sed": ">`.s`" 106 | "\nUsage: Replaces a word or words using sed." 107 | "\nDelimiters: `/, :, |, _`" 108 | } 109 | ) 110 | -------------------------------------------------------------------------------- /userbot/modules/blacklist.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.d (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | 6 | # port to userbot from uniborg by @keselekpermen69 7 | 8 | 9 | import io 10 | import re 11 | 12 | import userbot.modules.sql_helper.blacklist_sql as sql 13 | from userbot import CMD_HELP 14 | from userbot.events import register 15 | 16 | 17 | @register(incoming=True, disable_edited=True, disable_errors=True) 18 | async def on_new_message(event): 19 | # TODO: exempt admins from locks 20 | name = event.raw_text 21 | snips = sql.get_chat_blacklist(event.chat_id) 22 | for snip in snips: 23 | pattern = r"( |^|[^\w])" + re.escape(snip) + r"( |$|[^\w])" 24 | if re.search(pattern, name, flags=re.IGNORECASE): 25 | try: 26 | await event.delete() 27 | except Exception: 28 | await event.reply("I do not have DELETE permission in this chat") 29 | await sleep(1) 30 | await reply.delete() 31 | sql.rm_from_blacklist(event.chat_id, snip.lower()) 32 | break 33 | 34 | 35 | @register(outgoing=True, pattern=r"^\.addbl(?: |$)(.*)") 36 | async def on_add_black_list(addbl): 37 | text = addbl.pattern_match.group(1) 38 | to_blacklist = list( 39 | {trigger.strip() for trigger in text.split("\n") if trigger.strip()} 40 | ) 41 | 42 | for trigger in to_blacklist: 43 | sql.add_to_blacklist(addbl.chat_id, trigger.lower()) 44 | await addbl.edit( 45 | "`Added` **{}** `to the blacklist in the current chat`".format(text) 46 | ) 47 | 48 | 49 | @register(outgoing=True, pattern=r"^\.listbl(?: |$)(.*)") 50 | async def on_view_blacklist(listbl): 51 | all_blacklisted = sql.get_chat_blacklist(listbl.chat_id) 52 | OUT_STR = "Blacklists in the Current Chat:\n" 53 | if len(all_blacklisted) > 0: 54 | for trigger in all_blacklisted: 55 | OUT_STR += f"`{trigger}`\n" 56 | else: 57 | OUT_STR = "`There are no blacklist in current chat.`" 58 | if len(OUT_STR) > 4096: 59 | with io.BytesIO(str.encode(OUT_STR)) as out_file: 60 | out_file.name = "blacklist.text" 61 | await listbl.client.send_file( 62 | listbl.chat_id, 63 | out_file, 64 | force_document=True, 65 | allow_cache=False, 66 | caption="BlackLists in the Current Chat", 67 | reply_to=listbl, 68 | ) 69 | await listbl.delete() 70 | else: 71 | await listbl.edit(OUT_STR) 72 | 73 | 74 | @register(outgoing=True, pattern=r"^\.rmbl(?: |$)(.*)") 75 | async def on_delete_blacklist(rmbl): 76 | text = rmbl.pattern_match.group(1) 77 | to_unblacklist = list( 78 | {trigger.strip() for trigger in text.split("\n") if trigger.strip()} 79 | ) 80 | 81 | successful = 0 82 | for trigger in to_unblacklist: 83 | if sql.rm_from_blacklist(rmbl.chat_id, trigger.lower()): 84 | successful += 1 85 | if not successful: 86 | await rmbl.edit("`Blacklist` **{}** `doesn't exist.`".format(text)) 87 | else: 88 | await rmbl.edit("`Blacklist` **{}** `was deleted successfully`".format(text)) 89 | 90 | 91 | CMD_HELP.update( 92 | { 93 | "blacklist": ">`.listbl`" 94 | "\nUsage: Lists all active userbot blacklist in a chat." 95 | "\n\n>`.addbl `" 96 | "\nUsage: Saves the message to the 'blacklist keyword'." 97 | "\nThe bot will delete to the message whenever 'blacklist keyword' is mentioned." 98 | "\n\n>`.rmbl `" 99 | "\nUsage: Stops the specified blacklist." 100 | } 101 | ) 102 | -------------------------------------------------------------------------------- /userbot/modules/remove_bg.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | 6 | # (c) Shrimadhav U K - UniBorg 7 | # Thanks to Prakasaka for porting. 8 | 9 | import io 10 | import os 11 | 12 | import requests 13 | from telethon.tl.types import MessageMediaPhoto 14 | 15 | from userbot import CMD_HELP, REM_BG_API_KEY, TEMP_DOWNLOAD_DIRECTORY 16 | from userbot.events import register 17 | 18 | 19 | @register(outgoing=True, pattern=r"^\.rbg(?: |$)(.*)") 20 | async def kbg(remob): 21 | if REM_BG_API_KEY is None: 22 | return await remob.edit( 23 | "`Error: Remove.BG API key missing! Add it to environment vars or config.env.`" 24 | ) 25 | input_str = remob.pattern_match.group(1) 26 | message_id = remob.message.id 27 | if remob.reply_to_msg_id: 28 | message_id = remob.reply_to_msg_id 29 | reply_message = await remob.get_reply_message() 30 | await remob.edit("`Processing..`") 31 | try: 32 | if isinstance( 33 | reply_message.media, MessageMediaPhoto 34 | ) or "image" in reply_message.media.document.mime_type.split("/"): 35 | downloaded_file_name = await remob.client.download_media( 36 | reply_message, TEMP_DOWNLOAD_DIRECTORY 37 | ) 38 | await remob.edit("`Removing background from this image..`") 39 | output_file_name = await ReTrieveFile(downloaded_file_name) 40 | os.remove(downloaded_file_name) 41 | else: 42 | await remob.edit("`How do I remove the background from this ?`") 43 | except Exception as e: 44 | return await remob.edit(str(e)) 45 | elif input_str: 46 | await remob.edit( 47 | f"`Removing background from online image hosted at`\n{input_str}" 48 | ) 49 | output_file_name = await ReTrieveURL(input_str) 50 | else: 51 | return await remob.edit("`I need something to remove the background from.`") 52 | contentType = output_file_name.headers.get("content-type") 53 | if "image" in contentType: 54 | with io.BytesIO(output_file_name.content) as remove_bg_image: 55 | remove_bg_image.name = "removed_bg.png" 56 | await remob.client.send_file( 57 | remob.chat_id, 58 | remove_bg_image, 59 | caption="Background removed using remove.bg", 60 | force_document=True, 61 | reply_to=message_id, 62 | ) 63 | await remob.delete() 64 | else: 65 | await remob.edit( 66 | "**Error (Invalid API key, I guess ?)**\n`{}`".format( 67 | output_file_name.content.decode("UTF-8") 68 | ) 69 | ) 70 | 71 | 72 | # this method will call the API, and return in the appropriate format 73 | # with the name provided. 74 | async def ReTrieveFile(input_file_name): 75 | headers = { 76 | "X-API-Key": REM_BG_API_KEY, 77 | } 78 | files = { 79 | "image_file": (input_file_name, open(input_file_name, "rb")), 80 | } 81 | return requests.post( 82 | "https://api.remove.bg/v1.0/removebg", 83 | headers=headers, 84 | files=files, 85 | allow_redirects=True, 86 | stream=True, 87 | ) 88 | 89 | 90 | async def ReTrieveURL(input_url): 91 | headers = { 92 | "X-API-Key": REM_BG_API_KEY, 93 | } 94 | data = {"image_url": input_url} 95 | return requests.post( 96 | "https://api.remove.bg/v1.0/removebg", 97 | headers=headers, 98 | data=data, 99 | allow_redirects=True, 100 | stream=True, 101 | ) 102 | 103 | 104 | CMD_HELP.update( 105 | { 106 | "rbg": ">`.rbg or reply to any image (Warning: does not work on stickers.)`" 107 | "\nUsage: Removes the background of images, using remove.bg API" 108 | } 109 | ) 110 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All participants of RaphielGang are expected to abide by our Code of Conduct, 4 | both online and during in-person events that are hosted and/or associated with RaphielGang. 5 | 6 | 7 | ### The Pledge 8 | 9 | In the interest of fostering an open and welcoming environment, we pledge to make participation 10 | in our project and our community a harassment-free experience for everyone, regardless of age, 11 | body size, disability, ethnicity, gender identity and expression, level of experience, 12 | nationality, personal appearance, race, religion, or sexual identity and orientation. 13 | 14 | 15 | ### The Standards 16 | 17 | Examples of behaviour that contributes to creating a positive environment include: 18 | 19 | * **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. 20 | * **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. 21 | * **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. 22 | * **Gracefully accepting constructive criticism**: Not everyone are perfect, you can get some critism of your works from us, but it's not means that we don't accepting your contribution, we just want you to fixing it and making it better. 23 | * **Referring to people by their preferred pronouns/words**, but we do not have standardized gender-neutral pronouns/words, so your milleage may vary. 24 | * **Do not attack somebody because you have a different opinion** All opinions are accepted as long as they are reasonable, and everyone have right to shouting their opinion. 25 | * **Just chill :D** 26 | * **Don't forget, nobody is perfect, mistakes can be made** 27 | * **Equality is not a privilege, it's a rule!** 28 | 29 | ### Examples of unacceptable behaviour by participants include: 30 | 31 | * **Trolling, insulting/derogatory comments, public or private harassment** 32 | * **Publishing others' private information (Doxing)** such as a physical or electronic address, without explicit permission 33 | * **Not being respectful to reasonable communication boundaries** such as 'leave me alone,' 'go away,' or 'Fuck off.' 34 | * **The usage of sexualised language or imagery and unwelcome sexual attention or advances** 35 | * **Demonstrating the graphics or any other content you know may be considered disturbing** 36 | * **Assuming or promoting any kind of inequality** including but not limited to: age, body size, disability, ethnicity, gender identity and expression, nationality and race, personal appearance, religion, or sexual identity and orientation 37 | * **Drug promotion of any kind** 38 | * **Attacking personal tastes** 39 | * **Other conduct which you know could reasonably be considered inappropriate in a professional setting** 40 | 41 | 42 | ### Enforcement 43 | 44 | Violations of the Code of Conduct may be reported by sending an email to [raphielscape@outlook.com](mailto:raphielscape@outlook.com). 45 | All reports will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. 46 | Further details of specific enforcement policies may be posted separately. 47 | 48 | We hold the right and responsibility to remove comments or other contributions that 49 | are not aligned to this Code of Conduct, or to ban temporarily or permanently any members 50 | for other behaviours that they deem inappropriate, threatening, offensive, or harmful. -------------------------------------------------------------------------------- /userbot/modules/telegraph.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import datetime 3 | 4 | from PIL import Image 5 | from telegraph import Telegraph, exceptions, upload_file 6 | 7 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY, bot 8 | from userbot.events import register 9 | 10 | telegraph = Telegraph() 11 | r = telegraph.create_account(short_name="telegraph") 12 | auth_url = r["auth_url"] 13 | 14 | 15 | @register(outgoing=True, pattern=r"^\.tg (m|t)$") 16 | async def telegraphs(graph): 17 | await graph.edit("`Processing...`") 18 | if not graph.text[0].isalpha() and graph.text[0] not in ("/", "#", "@", "!"): 19 | if graph.fwd_from: 20 | return 21 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 22 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 23 | if graph.reply_to_msg_id: 24 | start = datetime.now() 25 | r_message = await graph.get_reply_message() 26 | input_str = graph.pattern_match.group(1) 27 | if input_str == "m": 28 | downloaded_file_name = await bot.download_media( 29 | r_message, TEMP_DOWNLOAD_DIRECTORY 30 | ) 31 | end = datetime.now() 32 | ms = (end - start).seconds 33 | await graph.edit( 34 | "Downloaded to {} in {} seconds.".format(downloaded_file_name, ms) 35 | ) 36 | try: 37 | if downloaded_file_name.endswith((".webp")): 38 | resize_image(downloaded_file_name) 39 | except AttributeError: 40 | return await graph.edit("`No media provided`") 41 | try: 42 | start = datetime.now() 43 | media_urls = upload_file(downloaded_file_name) 44 | except exceptions.TelegraphException as exc: 45 | await graph.edit("ERROR: " + str(exc)) 46 | os.remove(downloaded_file_name) 47 | else: 48 | end = datetime.now() 49 | ms_two = (end - start).seconds 50 | os.remove(downloaded_file_name) 51 | await graph.edit( 52 | "Successfully Uploaded to [telegra.ph](https://telegra.ph{}).".format( 53 | media_urls[0], (ms + ms_two) 54 | ), 55 | link_preview=True, 56 | ) 57 | elif input_str == "t": 58 | user_object = await bot.get_entity(r_message.from_id) 59 | title_of_page = user_object.first_name # + " " + user_object.last_name 60 | # apparently, all Users do not have last_name field 61 | page_content = r_message.message 62 | if r_message.media: 63 | if page_content != "": 64 | title_of_page = page_content 65 | downloaded_file_name = await bot.download_media( 66 | r_message, TEMP_DOWNLOAD_DIRECTORY 67 | ) 68 | m_list = None 69 | with open(downloaded_file_name, "rb") as fd: 70 | m_list = fd.readlines() 71 | for m in m_list: 72 | page_content += m.decode("UTF-8") + "\n" 73 | os.remove(downloaded_file_name) 74 | page_content = page_content.replace("\n", "
") 75 | response = telegraph.create_page( 76 | title_of_page, html_content=page_content 77 | ) 78 | end = datetime.now() 79 | ms = (end - start).seconds 80 | await graph.edit( 81 | "Successfully uploaded to [telegra.ph](https://telegra.ph/{}).".format( 82 | response["path"], ms 83 | ), 84 | link_preview=True, 85 | ) 86 | else: 87 | await graph.edit("`Reply to a message to get a permanent telegra.ph link.`") 88 | 89 | 90 | def resize_image(image): 91 | im = Image.open(image) 92 | im.save(image, "PNG") 93 | 94 | 95 | CMD_HELP.update( 96 | {"telegraph": ">`.tg` " "\nUsage: Upload t(text) or m(media) on Telegraph."} 97 | ) 98 | -------------------------------------------------------------------------------- /userbot/modules/justwatch.py: -------------------------------------------------------------------------------- 1 | # Uniborg Plugin for getting list of sites where you can watch a particular Movie or TV-Show 2 | # Author: Sumanjay (https://github.com/cyberboysumanjay) (@cyberboysumanjay) 3 | # All rights reserved. 4 | 5 | from justwatch import JustWatch, justwatchapi 6 | 7 | from userbot import CMD_HELP, WATCH_COUNTRY 8 | from userbot.events import register 9 | 10 | justwatchapi.__dict__["HEADER"] = { 11 | "User-Agent": "JustWatch client (github.com/dawoudt/JustWatchAPI)" 12 | } 13 | 14 | 15 | def get_stream_data(query): 16 | stream_data = {} 17 | 18 | # Compatibility for Current Userge Users 19 | try: 20 | country = WATCH_COUNTRY 21 | except Exception: 22 | country = "ID" 23 | 24 | # Cooking Data 25 | just_watch = JustWatch(country=country) 26 | results = just_watch.search_for_item(query=query) 27 | movie = results["items"][0] 28 | stream_data["title"] = movie["title"] 29 | stream_data["movie_thumb"] = ( 30 | "https://images.justwatch.com" 31 | + movie["poster"].replace("{profile}", "") 32 | + "s592" 33 | ) 34 | stream_data["release_year"] = movie["original_release_year"] 35 | try: 36 | print(movie["cinema_release_date"]) 37 | stream_data["release_date"] = movie["cinema_release_date"] 38 | except KeyError: 39 | try: 40 | stream_data["release_date"] = movie["localized_release_date"] 41 | except KeyError: 42 | stream_data["release_date"] = None 43 | 44 | stream_data["type"] = movie["object_type"] 45 | 46 | available_streams = {} 47 | for provider in movie["offers"]: 48 | provider_ = get_provider(provider["urls"]["standard_web"]) 49 | available_streams[provider_] = provider["urls"]["standard_web"] 50 | 51 | stream_data["providers"] = available_streams 52 | 53 | scoring = {} 54 | for scorer in movie["scoring"]: 55 | if scorer["provider_type"] == "tmdb:score": 56 | scoring["tmdb"] = scorer["value"] 57 | 58 | if scorer["provider_type"] == "imdb:score": 59 | scoring["imdb"] = scorer["value"] 60 | stream_data["score"] = scoring 61 | return stream_data 62 | 63 | 64 | # Helper Functions 65 | 66 | 67 | def pretty(name): 68 | if name == "play": 69 | name = "Google Play Movies" 70 | return name[0].upper() + name[1:] 71 | 72 | 73 | def get_provider(url): 74 | url = url.replace("https://www.", "") 75 | url = url.replace("https://", "") 76 | url = url.replace("http://www.", "") 77 | url = url.replace("http://", "") 78 | url = url.split(".")[0] 79 | return url 80 | 81 | 82 | @register(outgoing=True, pattern=r"^\.watch (.*)") 83 | async def _(event): 84 | if event.fwd_from: 85 | return 86 | query = event.pattern_match.group(1) 87 | await event.edit("`Finding Sites...`") 88 | try: 89 | streams = get_stream_data(query) 90 | except Exception as e: 91 | return await event.edit(f"**Error :** `{str(e)}`") 92 | title = streams["title"] 93 | thumb_link = streams["movie_thumb"] 94 | release_year = streams["release_year"] 95 | release_date = streams["release_date"] 96 | scores = streams["score"] 97 | try: 98 | imdb_score = scores["imdb"] 99 | except KeyError: 100 | imdb_score = None 101 | 102 | try: 103 | tmdb_score = scores["tmdb"] 104 | except KeyError: 105 | tmdb_score = None 106 | 107 | stream_providers = streams["providers"] 108 | if release_date is None: 109 | release_date = release_year 110 | 111 | output_ = f"**Movie:**\n`{title}`\n**Release Date:**\n`{release_date}`" 112 | if imdb_score: 113 | output_ = output_ + f"\n**IMDB: **{imdb_score}" 114 | if tmdb_score: 115 | output_ = output_ + f"\n**TMDB: **{tmdb_score}" 116 | 117 | output_ = output_ + "\n\n**Available on:**\n" 118 | for provider, link in stream_providers.items(): 119 | if "sonyliv" in link: 120 | link = link.replace(" ", "%20") 121 | output_ += f"[{pretty(provider)}]({link})\n" 122 | 123 | await event.client.send_file( 124 | event.chat_id, 125 | caption=output_, 126 | file=thumb_link, 127 | force_document=False, 128 | allow_cache=False, 129 | silent=True, 130 | ) 131 | await event.delete() 132 | 133 | 134 | CMD_HELP.update( 135 | { 136 | "watch": ">`.watch` **Movies or TV Show" 137 | "\nUsage: Find data about Movies or TV Show at `justwatch.com`." 138 | } 139 | ) 140 | -------------------------------------------------------------------------------- /userbot/modules/snips.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | 6 | from userbot import BOTLOG_CHATID, CMD_HELP 7 | from userbot.events import register 8 | 9 | 10 | @register(outgoing=True, pattern=r"\$\w*", ignore_unsafe=True, disable_errors=True) 11 | async def on_snip(event): 12 | try: 13 | from userbot.modules.sql_helper.snips_sql import get_snip 14 | except AttributeError: 15 | return 16 | name = event.text[1:] 17 | snip = get_snip(name) 18 | message_id_to_reply = event.message.reply_to_msg_id 19 | if not message_id_to_reply: 20 | message_id_to_reply = None 21 | if snip: 22 | if snip.f_mesg_id: 23 | msg_o = await event.client.get_messages( 24 | entity=BOTLOG_CHATID, ids=int(snip.f_mesg_id) 25 | ) 26 | await event.client.send_message( 27 | event.chat_id, 28 | msg_o.message, 29 | reply_to=message_id_to_reply, 30 | file=msg_o.media, 31 | ) 32 | elif snip.reply: 33 | await event.client.send_message( 34 | event.chat_id, snip.reply, reply_to=message_id_to_reply 35 | ) 36 | 37 | 38 | @register(outgoing=True, pattern=r"^\.snip (\w*)") 39 | async def on_snip_save(event): 40 | try: 41 | from userbot.modules.sql_helper.snips_sql import add_snip 42 | except AttributeError: 43 | return await event.edit("`Running on Non-SQL mode!`") 44 | keyword = event.pattern_match.group(1) 45 | string = event.text.partition(keyword)[2] 46 | msg = await event.get_reply_message() 47 | msg_id = None 48 | if msg and msg.media and not string: 49 | if BOTLOG_CHATID: 50 | await event.client.send_message( 51 | BOTLOG_CHATID, 52 | f"#SNIP\nKEYWORD: {keyword}" 53 | "\n\nThe following message is saved as the data for the snip, " 54 | "please do NOT delete it !!", 55 | ) 56 | msg_o = await event.client.forward_messages( 57 | entity=BOTLOG_CHATID, messages=msg, from_peer=event.chat_id, silent=True 58 | ) 59 | msg_id = msg_o.id 60 | else: 61 | return await event.edit( 62 | "`Saving snips with media requires the BOTLOG_CHATID to be set.`" 63 | ) 64 | elif event.reply_to_msg_id and not string: 65 | rep_msg = await event.get_reply_message() 66 | string = rep_msg.text 67 | success = "`Snip {} successfully. Use` **${}** `anywhere to get it`" 68 | if add_snip(keyword, string, msg_id) is False: 69 | await event.edit(success.format("updated", keyword)) 70 | else: 71 | await event.edit(success.format("saved", keyword)) 72 | 73 | 74 | @register(outgoing=True, pattern=r"^\.snips$") 75 | async def on_snip_list(event): 76 | try: 77 | from userbot.modules.sql_helper.snips_sql import get_snips 78 | except AttributeError: 79 | return await event.edit("`Running on Non-SQL mode!`") 80 | 81 | message = "`No snips available right now.`" 82 | all_snips = get_snips() 83 | for a_snip in all_snips: 84 | if message == "`No snips available right now.`": 85 | message = "Available snips:\n" 86 | message += f"`${a_snip.snip}`\n" 87 | await event.edit(message) 88 | 89 | 90 | @register(outgoing=True, pattern=r"^\.remsnip (\w*)") 91 | async def on_snip_delete(event): 92 | try: 93 | from userbot.modules.sql_helper.snips_sql import remove_snip 94 | except AttributeError: 95 | return await event.edit("`Running on Non-SQL mode!`") 96 | name = event.pattern_match.group(1) 97 | if remove_snip(name) is True: 98 | await event.edit(f"`Successfully deleted snip:` **{name}**") 99 | else: 100 | await event.edit(f"`Couldn't find snip:` **{name}**") 101 | 102 | 103 | CMD_HELP.update( 104 | { 105 | "snips": ">`$`" 106 | "\nUsage: Gets the specified snip, anywhere." 107 | "\n\n>`.snip or reply to a message with .snip `" 108 | "\nUsage: Saves the message as a snip (global note) with the name." 109 | " (Works with pics, docs, and stickers too!)" 110 | "\n\n>`.snips`" 111 | "\nUsage: Gets all saved snips." 112 | "\n\n>`.remsnip `" 113 | "\nUsage: Deletes the specified snip." 114 | } 115 | ) 116 | -------------------------------------------------------------------------------- /userbot/modules/weather.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import json 8 | from datetime import datetime 9 | 10 | from pytz import country_names as c_n 11 | from pytz import country_timezones as c_tz 12 | from pytz import timezone as tz 13 | from requests import get 14 | 15 | from userbot import CMD_HELP 16 | from userbot import OPEN_WEATHER_MAP_APPID as OWM_API 17 | from userbot import WEATHER_DEFCITY 18 | from userbot.events import register 19 | 20 | # ===== CONSTANT ===== 21 | DEFCITY = WEATHER_DEFCITY if WEATHER_DEFCITY else None 22 | # ==================== 23 | 24 | 25 | async def get_tz(con): 26 | for c_code in c_n: 27 | if con == c_n[c_code]: 28 | return tz(c_tz[c_code][0]) 29 | try: 30 | if c_n[con]: 31 | return tz(c_tz[con][0]) 32 | except KeyError: 33 | return 34 | 35 | 36 | @register(outgoing=True, pattern=r"^\.weather(?: |$)(.*)") 37 | async def get_weather(weather): 38 | 39 | if not OWM_API: 40 | return await weather.edit( 41 | "`Get an API key from` https://openweathermap.org/ `first.`" 42 | ) 43 | 44 | APPID = OWM_API 45 | 46 | if not weather.pattern_match.group(1): 47 | CITY = DEFCITY 48 | if not CITY: 49 | return await weather.edit( 50 | "`Please specify a city or set one as default using the WEATHER_DEFCITY config variable.`" 51 | ) 52 | else: 53 | CITY = weather.pattern_match.group(1) 54 | 55 | timezone_countries = { 56 | timezone: country 57 | for country, timezones in c_tz.items() 58 | for timezone in timezones 59 | } 60 | 61 | if "," in CITY: 62 | newcity = CITY.split(",") 63 | if len(newcity[1]) == 2: 64 | CITY = newcity[0].strip() + "," + newcity[1].strip() 65 | else: 66 | country = await get_tz((newcity[1].strip()).title()) 67 | try: 68 | countrycode = timezone_countries[f"{country}"] 69 | except KeyError: 70 | return await weather.edit("`Invalid country.`") 71 | CITY = newcity[0].strip() + "," + countrycode.strip() 72 | 73 | url = f"https://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={APPID}" 74 | request = get(url) 75 | result = json.loads(request.text) 76 | 77 | if request.status_code != 200: 78 | return await weather.edit("`Invalid country.`") 79 | 80 | cityname = result["name"] 81 | curtemp = result["main"]["temp"] 82 | humidity = result["main"]["humidity"] 83 | min_temp = result["main"]["temp_min"] 84 | max_temp = result["main"]["temp_max"] 85 | desc = result["weather"][0] 86 | desc = desc["main"] 87 | country = result["sys"]["country"] 88 | sunrise = result["sys"]["sunrise"] 89 | sunset = result["sys"]["sunset"] 90 | wind = result["wind"]["speed"] 91 | winddir = result["wind"]["deg"] 92 | 93 | ctimezone = tz(c_tz[country][0]) 94 | time = datetime.now(ctimezone).strftime("%A, %I:%M %p") 95 | fullc_n = c_n[f"{country}"] 96 | 97 | dirs = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] 98 | 99 | div = 360 / len(dirs) 100 | funmath = int((winddir + (div / 2)) / div) 101 | findir = dirs[funmath % len(dirs)] 102 | kmph = str(wind * 3.6).split(".") 103 | mph = str(wind * 2.237).split(".") 104 | 105 | def fahrenheit(f): 106 | temp = str(((f - 273.15) * 9 / 5 + 32)).split(".") 107 | return temp[0] 108 | 109 | def celsius(c): 110 | temp = str((c - 273.15)).split(".") 111 | return temp[0] 112 | 113 | def sun(unix): 114 | return datetime.fromtimestamp(unix, tz=ctimezone).strftime("%I:%M %p") 115 | 116 | await weather.edit( 117 | f"**Temperature:** `{celsius(curtemp)}°C | {fahrenheit(curtemp)}°F`\n" 118 | + f"**Min. Temp.:** `{celsius(min_temp)}°C | {fahrenheit(min_temp)}°F`\n" 119 | + f"**Max. Temp.:** `{celsius(max_temp)}°C | {fahrenheit(max_temp)}°F`\n" 120 | + f"**Humidity:** `{humidity}%`\n" 121 | + f"**Wind:** `{kmph[0]} kmh | {mph[0]} mph, {findir}`\n" 122 | + f"**Sunrise:** `{sun(sunrise)}`\n" 123 | + f"**Sunset:** `{sun(sunset)}`\n\n" 124 | + f"**{desc}**\n" 125 | + f"`{cityname}, {fullc_n}`\n" 126 | + f"`{time}`" 127 | ) 128 | 129 | 130 | CMD_HELP.update( 131 | { 132 | "weather": ">`.weather or .weather , `" 133 | "\nUsage: Gets the weather of a city." 134 | } 135 | ) 136 | -------------------------------------------------------------------------------- /userbot/modules/filemanager.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | import os.path 4 | import time 5 | from os.path import exists, isdir 6 | 7 | from userbot import CMD_HELP 8 | from userbot.events import register 9 | from userbot.utils import humanbytes 10 | 11 | MAX_MESSAGE_SIZE_LIMIT = 4095 12 | 13 | 14 | @register(outgoing=True, pattern=r"^\.ls ?(.*)") 15 | async def lst(event): 16 | if event.fwd_from: 17 | return 18 | cat = event.pattern_match.group(1) 19 | path = cat if cat else os.getcwd() 20 | if not exists(path): 21 | await event.edit( 22 | f"**There is no such directory or file with the name `{cat}` check again!**" 23 | ) 24 | return 25 | if isdir(path): 26 | if cat: 27 | msg = "**Folders and Files in `{}`** :\n\n".format(path) 28 | else: 29 | msg = "**Folders and Files in Current Directory** :\n\n" 30 | lists = os.listdir(path) 31 | files = "" 32 | folders = "" 33 | for contents in sorted(lists): 34 | catpath = path + "/" + contents 35 | if not isdir(catpath): 36 | size = os.stat(catpath).st_size 37 | if contents.endswith((".mp3", ".flac", ".wav", ".m4a")): 38 | files += "🎵 " + f"`{contents}`\n" 39 | if contents.endswith((".opus")): 40 | files += "🎙 " + f"`{contents}`\n" 41 | elif contents.endswith( 42 | (".mkv", ".mp4", ".webm", ".avi", ".mov", ".flv") 43 | ): 44 | files += "🎞 " + f"`{contents}`\n" 45 | elif contents.endswith( 46 | (".zip", ".tar", ".tar.gz", ".rar", ".7z", ".xz") 47 | ): 48 | files += "🗜 " + f"`{contents}`\n" 49 | elif contents.endswith( 50 | (".jpg", ".jpeg", ".png", ".gif", ".bmp", ".ico", ".webp") 51 | ): 52 | files += "🖼 " + f"`{contents}`\n" 53 | elif contents.endswith((".exe", ".deb")): 54 | files += "⚙️ " + f"`{contents}`\n" 55 | elif contents.endswith((".iso", ".img")): 56 | files += "💿 " + f"`{contents}`\n" 57 | elif contents.endswith((".apk", ".xapk")): 58 | files += "📱 " + f"`{contents}`\n" 59 | elif contents.endswith((".py")): 60 | files += "🐍 " + f"`{contents}`\n" 61 | else: 62 | files += "📄 " + f"`{contents}`\n" 63 | else: 64 | folders += f"📁 `{contents}`\n" 65 | msg = msg + folders + files if files or folders else msg + "__empty path__" 66 | else: 67 | size = os.stat(path).st_size 68 | msg = "**The details of given file** :\n\n" 69 | if path.endswith((".mp3", ".flac", ".wav", ".m4a")): 70 | mode = "🎵 " 71 | if path.endswith((".opus")): 72 | mode = "🎙 " 73 | elif path.endswith((".mkv", ".mp4", ".webm", ".avi", ".mov", ".flv")): 74 | mode = "🎞 " 75 | elif path.endswith((".zip", ".tar", ".tar.gz", ".rar", ".7z", ".xz")): 76 | mode = "🗜 " 77 | elif path.endswith((".jpg", ".jpeg", ".png", ".gif", ".bmp", ".ico", ".webp")): 78 | mode = "🖼 " 79 | elif path.endswith((".exe", ".deb")): 80 | mode = "⚙️ " 81 | elif path.endswith((".iso", ".img")): 82 | mode = "💿 " 83 | elif path.endswith((".apk", ".xapk")): 84 | mode = "📱 " 85 | elif path.endswith((".py")): 86 | mode = "🐍 " 87 | else: 88 | mode = "📄 " 89 | time.ctime(os.path.getctime(path)) 90 | time2 = time.ctime(os.path.getmtime(path)) 91 | time3 = time.ctime(os.path.getatime(path)) 92 | msg += f"**Location :** `{path}`\n" 93 | msg += f"**Icon :** `{mode}`\n" 94 | msg += f"**Size :** `{humanbytes(size)}`\n" 95 | msg += f"**Last Modified Time:** `{time2}`\n" 96 | msg += f"**Last Accessed Time:** `{time3}`" 97 | 98 | if len(msg) > MAX_MESSAGE_SIZE_LIMIT: 99 | with io.BytesIO(str.encode(msg)) as out_file: 100 | out_file.name = "ls.txt" 101 | await event.client.send_file( 102 | event.chat_id, 103 | out_file, 104 | force_document=True, 105 | allow_cache=False, 106 | caption=path, 107 | ) 108 | await event.delete() 109 | else: 110 | await event.edit(msg) 111 | 112 | 113 | CMD_HELP.update( 114 | {"file": ">`.ls` " "\nUsage: Get list file inside directory.\n"} 115 | ) 116 | -------------------------------------------------------------------------------- /userbot/modules/reverse.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Thanks to @kandnub, for this awesome module !! 4 | # 5 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # 8 | 9 | import io 10 | import os 11 | import re 12 | import urllib 13 | 14 | import requests 15 | from bs4 import BeautifulSoup 16 | from PIL import Image 17 | 18 | from userbot import CMD_HELP, bot 19 | from userbot.events import register 20 | 21 | opener = urllib.request.build_opener() 22 | useragent = ( 23 | "Mozilla/5.0 (Linux; Android 10; SM-G975F) " 24 | "AppleWebKit/537.36 (KHTML, like Gecko) " 25 | "Chrome/80.0.3987.149 Mobile Safari/537.36" 26 | ) 27 | opener.addheaders = [("User-agent", useragent)] 28 | 29 | 30 | @register(outgoing=True, pattern=r"^\.reverse(?: |$)(\d*)") 31 | async def okgoogle(img): 32 | if os.path.isfile("okgoogle.png"): 33 | os.remove("okgoogle.png") 34 | 35 | message = await img.get_reply_message() 36 | if message and message.media: 37 | photo = io.BytesIO() 38 | await bot.download_media(message, photo) 39 | else: 40 | return await img.edit("`Reply to photo or sticker nigger.`") 41 | 42 | if photo: 43 | await img.edit("`Processing...`") 44 | try: 45 | image = Image.open(photo) 46 | except OSError: 47 | return await img.edit("`Unsupported sexuality, most likely.`") 48 | name = "okgoogle.png" 49 | image.save(name, "PNG") 50 | image.close() 51 | # https://stackoverflow.com/questions/23270175/google-reverse-image-search-using-post-request#28792943 52 | searchUrl = "https://www.google.com/searchbyimage/upload" 53 | multipart = {"encoded_image": (name, open(name, "rb")), "image_content": ""} 54 | response = requests.post(searchUrl, files=multipart, allow_redirects=False) 55 | fetchUrl = response.headers["Location"] 56 | 57 | if response != 400: 58 | await img.edit( 59 | "`Image successfully uploaded to Google. Maybe.`" 60 | "\n`Parsing source now. Maybe.`" 61 | ) 62 | else: 63 | return await img.edit("`Google told me to fuck off.`") 64 | 65 | os.remove(name) 66 | match = await ParseSauce(fetchUrl + "&preferences?hl=en&fg=1#languages") 67 | guess = match["best_guess"] 68 | imgspage = match["similar_images"] 69 | 70 | if guess and imgspage: 71 | await img.edit(f"[{guess}]({fetchUrl})\n\n`Looking for images...`") 72 | else: 73 | return await img.edit("`Couldn't find anything for your uglyass.`") 74 | 75 | lim = img.pattern_match.group(1) if img.pattern_match.group(1) else 3 76 | images = await scam(match, lim) 77 | yeet = [] 78 | for i in images: 79 | k = requests.get(i) 80 | yeet.append(k.content) 81 | try: 82 | await img.client.send_file( 83 | entity=await img.client.get_input_entity(img.chat_id), 84 | file=yeet, 85 | reply_to=img, 86 | ) 87 | except TypeError: 88 | pass 89 | await img.edit( 90 | f"[{guess}]({fetchUrl})\n\n[Visually similar images]({imgspage})" 91 | ) 92 | 93 | 94 | async def ParseSauce(googleurl): 95 | 96 | source = opener.open(googleurl).read() 97 | soup = BeautifulSoup(source, "html.parser") 98 | 99 | results = {"similar_images": "", "best_guess": ""} 100 | 101 | try: 102 | for similar_image in soup.findAll("input", {"class": "gLFyf"}): 103 | url = "https://www.google.com/search?tbm=isch&q=" + urllib.parse.quote_plus( 104 | similar_image.get("value") 105 | ) 106 | results["similar_images"] = url 107 | except BaseException: 108 | pass 109 | 110 | for best_guess in soup.findAll("div", attrs={"class": "r5a77d"}): 111 | results["best_guess"] = best_guess.get_text() 112 | 113 | return results 114 | 115 | 116 | async def scam(results, lim): 117 | 118 | single = opener.open(results["similar_images"]).read() 119 | decoded = single.decode("utf-8") 120 | 121 | imglinks = [] 122 | counter = 0 123 | 124 | pattern = r"^,\[\"(.*[.png|.jpg|.jpeg])\",[0-9]+,[0-9]+\]$" 125 | oboi = re.findall(pattern, decoded, re.I | re.M) 126 | 127 | for imglink in oboi: 128 | counter += 1 129 | if not counter >= int(lim): 130 | imglinks.append(imglink) 131 | else: 132 | break 133 | 134 | return imglinks 135 | 136 | 137 | CMD_HELP.update( 138 | { 139 | "reverse": ">`.reverse`" 140 | "\nUsage: Reply to a pic/sticker to revers-search it on Google Images !!" 141 | } 142 | ) 143 | -------------------------------------------------------------------------------- /userbot/modules/purge.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from asyncio import sleep 8 | 9 | from telethon.errors import rpcbaseerrors 10 | 11 | from userbot import CMD_HELP 12 | from userbot.events import register 13 | 14 | 15 | @register(outgoing=True, pattern=r"^\.purge$") 16 | async def fastpurger(purg): 17 | chat = await purg.get_input_chat() 18 | msgs = [] 19 | itermsg = purg.client.iter_messages(chat, min_id=purg.reply_to_msg_id) 20 | count = 0 21 | 22 | if purg.reply_to_msg_id is not None: 23 | async for msg in itermsg: 24 | msgs.append(msg) 25 | count += 1 26 | msgs.append(purg.reply_to_msg_id) 27 | if len(msgs) == 100: 28 | await purg.client.delete_messages(chat, msgs) 29 | msgs = [] 30 | else: 31 | return await purg.edit("`I need a mesasge to start purging from.`") 32 | 33 | if msgs: 34 | await purg.client.delete_messages(chat, msgs) 35 | done = await purg.client.send_message( 36 | purg.chat_id, "`Fast purge complete!`" f"\nPurged {str(count)} messages" 37 | ) 38 | """ 39 | if BOTLOG: 40 | await purg.client.send_message( 41 | BOTLOG_CHATID, 42 | "Purge of " + str(count) + " messages done successfully.") 43 | """ 44 | await sleep(2) 45 | await done.delete() 46 | 47 | 48 | @register(outgoing=True, pattern=r"^\.purgeme") 49 | async def purgeme(delme): 50 | message = delme.text 51 | count = int(message[9:]) 52 | i = 1 53 | 54 | async for message in delme.client.iter_messages(delme.chat_id, from_user="me"): 55 | if i > count + 1: 56 | break 57 | i += 1 58 | await message.delete() 59 | 60 | smsg = await delme.client.send_message( 61 | delme.chat_id, 62 | "`Purge complete!` Purged " + str(count) + " messages.", 63 | ) 64 | """ 65 | if BOTLOG: 66 | await delme.client.send_message( 67 | BOTLOG_CHATID, 68 | "Purge of " + str(count) + " messages done successfully.") 69 | """ 70 | await sleep(2) 71 | i = 1 72 | await smsg.delete() 73 | 74 | 75 | @register(outgoing=True, pattern=r"^\.del$") 76 | async def delete_it(delme): 77 | msg_src = await delme.get_reply_message() 78 | if delme.reply_to_msg_id: 79 | try: 80 | await msg_src.delete() 81 | await delme.delete() 82 | """ 83 | if BOTLOG: 84 | await delme.client.send_message( 85 | BOTLOG_CHATID, "Deletion of message was successful") 86 | """ 87 | except rpcbaseerrors.BadRequestError: 88 | await delme.edit("Well, I can't delete a message") 89 | """ 90 | if BOTLOG: 91 | await delme.client.send_message( 92 | BOTLOG_CHATID, "Well, I can't delete a message") 93 | """ 94 | 95 | 96 | @register(outgoing=True, pattern=r"^\.edit") 97 | async def editer(edit): 98 | message = edit.text 99 | chat = await edit.get_input_chat() 100 | self_id = await edit.client.get_peer_id("me") 101 | string = str(message[6:]) 102 | i = 1 103 | async for message in edit.client.iter_messages(chat, self_id): 104 | if i == 2: 105 | await message.edit(string) 106 | await edit.delete() 107 | break 108 | i += 1 109 | """ 110 | if BOTLOG: 111 | await edit.client.send_message(BOTLOG_CHATID, 112 | "Edit query was executed successfully") 113 | """ 114 | 115 | 116 | @register(outgoing=True, pattern=r"^\.sd") 117 | async def selfdestruct(destroy): 118 | message = destroy.text 119 | counter = int(message[4:6]) 120 | text = str(destroy.text[6:]) 121 | await destroy.delete() 122 | smsg = await destroy.client.send_message(destroy.chat_id, text) 123 | await sleep(counter) 124 | await smsg.delete() 125 | """ 126 | if BOTLOG: 127 | await destroy.client.send_message(BOTLOG_CHATID, 128 | "sd query done successfully") 129 | """ 130 | 131 | 132 | CMD_HELP.update( 133 | { 134 | "purge": ">`.purge`" "\nUsage: Purges all messages starting from the reply.", 135 | "purgeme": ">`.purgeme `" 136 | "\nUsage: Deletes x amount of your latest messages.", 137 | "del": ">`.del`" "\nUsage: Deletes the message you replied to.", 138 | "edit": ">`.edit `" 139 | "\nUsage: Replace your last message with .", 140 | "sd": ">`.sd `" 141 | "\nUsage: Creates a message that selfdestructs in x seconds." 142 | "\nKeep the seconds under 100 since it puts your bot to sleep.", 143 | } 144 | ) 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProjectAlf UserBot 2 | 3 |

4 | Failcheck 5 | Pylint 6 | Codacy 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

15 | 16 | ``` 17 | /** 18 | Your Telegram account may get banned. 19 | I am not responsible for any improper use of this bot 20 | This bot is intended for the purpose of having fun with memes, 21 | as well as efficiently managing groups. 22 | You ended up spamming groups, getting reported left and right, 23 | and you ended up in a Finale Battle with Telegram and at the end 24 | Telegram Team deleted your account? 25 | And after that, then you pointed your fingers at us 26 | for getting your acoount deleted? 27 | I will be rolling on the floor laughing at you. 28 | /** 29 | ``` 30 | 31 | A modular Telegram userbot running on Python3 with sqlalchemy database. 32 | 33 | Based on RaphielGang's [Telegram-Paperplane](https://github.com/RaphielGang/Telegram-Paperplane) And [ProjectDils](https://github.com/aidilaryanto/ProjectDils) 34 | 35 | ## How To Host 36 | The easiest way to deploy this userbot 37 |

38 | 39 | ## Generate String 40 | Generate string using repl.it 41 |

42 | 43 | ## Usefull guides 44 | How to deploy this UserBot 45 |

46 | 47 | ## Groups and Support 48 | Join [Userbot Indonesia Channel](https://t.me/userbotindocloud) for update notifications or announcement. 49 | 50 | Join [Userbotindo Support Group](https://t.me/userbotindo) for discussion, bug reporting, and help. 51 | 52 | ## Credits 53 | * [RaphielGang](https://github.com/RaphielGang) - Telegram-Paperplane 54 | * [AvinashReddy3108](https://github.com/AvinashReddy3108) - PaperplaneExtended 55 | * [Mkaraniya](https://github.com/mkaraniya) & [Dev73](https://github.com/Devp73) - OpenUserBot 56 | * [Mr.Miss](https://github.com/keselekpermen69) - UserButt 57 | * [adekmaulana](https://github.com/adekmaulana) - ProjectBish 58 | * [MoveAngel](https://github.com/MoveAngel) - One4uBot 59 | * [AidilAryanto](https://github.com/aidilaryanto) - ProjectDils 60 | * [AnggaR69s](https://github.com/GengKapak/DCLXVI) - DCLXVI 61 | * [others](https://github.com/alfianandaa/ProjectAlf/graphs/contributors) that help to make this userbot awesome. 62 | 63 | ## License 64 | Licensed under [Raphielscape Public License](https://github.com/alfianandaa/ProjectAlf/blob/master/LICENSE) - Version 1.d, February 2020 65 | -------------------------------------------------------------------------------- /userbot/modules/github.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from datetime import datetime 4 | 5 | import aiohttp 6 | from github import Github 7 | 8 | from userbot import CMD_HELP, GIT_REPO_NAME, GITHUB_ACCESS_TOKEN, bot 9 | from userbot.events import register 10 | 11 | GIT_TEMP_DIR = "./projectalf/temp/" 12 | 13 | 14 | @register(pattern=r"\.git (.*)", outgoing=True) 15 | async def github(event): 16 | URL = f"https://api.github.com/users/{event.pattern_match.group(1)}" 17 | await event.get_chat() 18 | async with aiohttp.ClientSession() as session: 19 | async with session.get(URL) as request: 20 | if request.status == 404: 21 | return await event.reply( 22 | "`" + event.pattern_match.group(1) + " not found`" 23 | ) 24 | 25 | result = await request.json() 26 | 27 | url = result.get("html_url", None) 28 | name = result.get("name", None) 29 | company = result.get("company", None) 30 | bio = result.get("bio", None) 31 | created_at = result.get("created_at", "Not Found") 32 | 33 | REPLY = ( 34 | f"GitHub Info for `{event.pattern_match.group(1)}`" 35 | f"\nUsername: `{name}`\nBio: `{bio}`\nURL: {url}" 36 | f"\nCompany: `{company}`\nCreated at: `{created_at}`" 37 | ) 38 | 39 | if not result.get("repos_url", None): 40 | return await event.edit(REPLY) 41 | async with session.get(result.get("repos_url", None)) as request: 42 | result = request.json 43 | if request.status == 404: 44 | return await event.edit(REPLY) 45 | 46 | result = await request.json() 47 | 48 | REPLY += "\nRepos:\n" 49 | 50 | for nr in range(len(result)): 51 | REPLY += f"[{result[nr].get('name', None)}]({result[nr].get('html_url', None)})\n" 52 | 53 | await event.edit(REPLY) 54 | 55 | 56 | @register(outgoing=True, pattern=r"^\.commit(?: |$)(.*)") 57 | async def download(event): 58 | if event.fwd_from: 59 | return 60 | if GITHUB_ACCESS_TOKEN is None: 61 | await event.edit("`Please ADD Proper Access Token from github.com`") 62 | return 63 | if GIT_REPO_NAME is None: 64 | await event.edit("`Please ADD Proper Github Repo Name of your userbot`") 65 | return 66 | mone = await event.reply("Processing ...") 67 | if not os.path.isdir(GIT_TEMP_DIR): 68 | os.makedirs(GIT_TEMP_DIR) 69 | start = datetime.now() 70 | reply_message = await event.get_reply_message() 71 | try: 72 | time.time() 73 | print("Downloading to TEMP directory") 74 | downloaded_file_name = await bot.download_media( 75 | reply_message.media, GIT_TEMP_DIR 76 | ) 77 | except Exception as e: 78 | await mone.edit(str(e)) 79 | else: 80 | end = datetime.now() 81 | ms = (end - start).seconds 82 | await event.delete() 83 | await mone.edit( 84 | "Downloaded to `{}` in {} seconds.".format(downloaded_file_name, ms) 85 | ) 86 | await mone.edit("Committing to Github....") 87 | await git_commit(downloaded_file_name, mone) 88 | 89 | 90 | async def git_commit(file_name, mone): 91 | content_list = [] 92 | access_token = GITHUB_ACCESS_TOKEN 93 | g = Github(access_token) 94 | file = open(file_name, "r", encoding="utf-8") 95 | commit_data = file.read() 96 | repo = g.get_repo(GIT_REPO_NAME) 97 | print(repo.name) 98 | create_file = True 99 | contents = repo.get_contents("") 100 | for content_file in contents: 101 | content_list.append(str(content_file)) 102 | print(content_file) 103 | for i in content_list: 104 | create_file = True 105 | if i == 'ContentFile(path="' + file_name + '")': 106 | return await mone.edit("`File Already Exists`") 107 | file_name = "userbot/modules/" + file_name 108 | if create_file: 109 | file_name = file_name.replace("./projectalf/temp/", "") 110 | print(file_name) 111 | try: 112 | repo.create_file( 113 | file_name, "ProjectAlf: Add new module", commit_data, branch="master" 114 | ) 115 | print("Committed File") 116 | ccess = GIT_REPO_NAME 117 | ccess = ccess.strip() 118 | await mone.edit( 119 | f"`Commited On UserBot Repo`\n\n[Your Modules](https://github.com/{ccess}/tree/master/{file_name})" 120 | ) 121 | except BaseException: 122 | print("Cannot Create Module") 123 | await mone.edit("Cannot Upload Module") 124 | else: 125 | return await mone.edit("`Committed Suicide`") 126 | 127 | 128 | CMD_HELP.update( 129 | { 130 | "github": ">`.git `" 131 | "\nUsage: Like .whois but for GitHub usernames." 132 | "\n\n>`.commit `" 133 | "\nUsage: GITHUB File Uploader." 134 | } 135 | ) 136 | -------------------------------------------------------------------------------- /userbot/modules/ascii.py: -------------------------------------------------------------------------------- 1 | # based on https://gist.github.com/wshanshan/c825efca4501a491447056849dd207d6 2 | # Ported for ProjectAlf by Alfiananda P.A 3 | 4 | import os 5 | import random 6 | 7 | import numpy as np 8 | from colour import Color 9 | from hachoir.metadata import extractMetadata 10 | from hachoir.parser import createParser 11 | from PIL import Image, ImageDraw, ImageFont 12 | from telethon.tl.types import DocumentAttributeFilename 13 | 14 | from userbot import CMD_HELP, bot 15 | from userbot.events import register 16 | 17 | bground = "black" 18 | 19 | 20 | @register(outgoing=True, pattern=r"^\.(ascii|asciis)$") 21 | async def ascii(event): 22 | if not event.reply_to_msg_id: 23 | await event.edit("`Reply to Any media..`") 24 | return 25 | reply_message = await event.get_reply_message() 26 | if not reply_message.media: 27 | await event.edit("`reply to a image/sticker/video`") 28 | return 29 | await event.edit("`Downloading Media..`") 30 | if reply_message.photo: 31 | IMG = await bot.download_media( 32 | reply_message, 33 | "ascii.png", 34 | ) 35 | elif ( 36 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 37 | in reply_message.media.document.attributes 38 | ): 39 | await bot.download_media( 40 | reply_message, 41 | "ASCII.tgs", 42 | ) 43 | os.system("lottie_convert.py ASCII.tgs ascii.png") 44 | IMG = "ascii.png" 45 | elif reply_message.video: 46 | video = await bot.download_media( 47 | reply_message, 48 | "ascii.mp4", 49 | ) 50 | extractMetadata(createParser(video)) 51 | os.system("ffmpeg -i ascii.mp4 -vframes 1 -an -s 480x360 -ss 1 ascii.png") 52 | IMG = "ascii.png" 53 | else: 54 | IMG = await bot.download_media( 55 | reply_message, 56 | "ascii.png", 57 | ) 58 | try: 59 | await event.edit("`Processing..`") 60 | list = await random_color() 61 | color1 = list[0] 62 | color2 = list[1] 63 | bgcolor = bground 64 | await asciiart(IMG, color1, color2, bgcolor) 65 | cmd = event.pattern_match.group(1) 66 | if cmd == "asciis": 67 | os.system("cp ascii.png ascii.webp") 68 | ascii_file = "ascii.webp" 69 | else: 70 | ascii_file = "ascii.png" 71 | await event.client.send_file( 72 | event.chat_id, 73 | ascii_file, 74 | force_document=False, 75 | reply_to=event.reply_to_msg_id, 76 | ) 77 | await event.delete() 78 | os.system("rm *.png *.webp *.mp4 *.tgs") 79 | except BaseException as e: 80 | os.system("rm *.png *.webp *.mp4 *.tgs") 81 | return await event.edit(str(e)) 82 | 83 | 84 | async def asciiart(IMG, color1, color2, bgcolor): 85 | chars = np.asarray(list(" .,:irs?@9B&#")) 86 | font = ImageFont.load_default() 87 | letter_width = font.getsize("x")[0] 88 | letter_height = font.getsize("x")[1] 89 | WCF = letter_height / letter_width 90 | img = Image.open(IMG) 91 | widthByLetter = round(img.size[0] * 0.15 * WCF) 92 | heightByLetter = round(img.size[1] * 0.15) 93 | S = (widthByLetter, heightByLetter) 94 | img = img.resize(S) 95 | img = np.sum(np.asarray(img), axis=2) 96 | img -= img.min() 97 | img = (1.0 - img / img.max()) ** 2.2 * (chars.size - 1) 98 | lines = ("\n".join(("".join(r) for r in chars[img.astype(int)]))).split("\n") 99 | nbins = len(lines) 100 | colorRange = list(Color(color1).range_to(Color(color2), nbins)) 101 | newImg_width = letter_width * widthByLetter 102 | newImg_height = letter_height * heightByLetter 103 | newImg = Image.new("RGBA", (newImg_width, newImg_height), bgcolor) 104 | draw = ImageDraw.Draw(newImg) 105 | leftpadding = 0 106 | y = 0 107 | lineIdx = 0 108 | for line in lines: 109 | color = colorRange[lineIdx] 110 | lineIdx += 1 111 | draw.text((leftpadding, y), line, color.hex, font=font) 112 | y += letter_height 113 | IMG = newImg.save("ascii.png") 114 | return IMG 115 | 116 | 117 | # this is from userge 118 | async def random_color(): 119 | color = [ 120 | "#" + "".join([random.choice("0123456789ABCDEF") for k in range(6)]) 121 | for i in range(2) 122 | ] 123 | return color 124 | 125 | 126 | @register(outgoing=True, pattern=r"^\.asciibg(?: |$)(.*)") 127 | async def _(event): 128 | BG = event.pattern_match.group(1) 129 | if BG.isnumeric(): 130 | return await event.edit("`Please input a color not a number!`") 131 | elif BG: 132 | global bground 133 | bground = BG 134 | else: 135 | return await event.edit("`please insert bg of ascii`") 136 | await event.edit(f"`Successfully set bg of ascii to` **{BG}**") 137 | 138 | 139 | CMD_HELP.update( 140 | { 141 | "ascii": ">`.ascii`\n" 142 | "Usage: create ascii art from media\n\n" 143 | ">`.asciis`\n" 144 | "Usage: same but upload the result as sticker\n\n" 145 | ">`.asciibg `\n" 146 | "Usage: to change background color of this ascii module" 147 | } 148 | ) 149 | -------------------------------------------------------------------------------- /userbot/modules/qrcode.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # The entire source code is OSSRPL except 'makeqr and getqr' which is MPL 7 | # License: MPL and OSSRPL 8 | 9 | import asyncio 10 | import os 11 | 12 | import barcode 13 | import qrcode 14 | from barcode.writer import ImageWriter 15 | from bs4 import BeautifulSoup 16 | 17 | from userbot import CMD_HELP, LOGS 18 | from userbot.events import register 19 | 20 | 21 | @register(pattern=r"^\.decode$", outgoing=True) 22 | async def parseqr(qr_e): 23 | downloaded_file_name = await qr_e.client.download_media( 24 | await qr_e.get_reply_message() 25 | ) 26 | # parse the Official ZXing webpage to decode the QRCode 27 | command_to_exec = [ 28 | "curl", 29 | "-X", 30 | "POST", 31 | "-F", 32 | "f=@" + downloaded_file_name + "", 33 | "https://zxing.org/w/decode", 34 | ] 35 | process = await asyncio.create_subprocess_exec( 36 | *command_to_exec, 37 | # stdout must a pipe to be accessible as process.stdout 38 | stdout=asyncio.subprocess.PIPE, 39 | stderr=asyncio.subprocess.PIPE, 40 | ) 41 | # Wait for the subprocess to finish 42 | stdout, stderr = await process.communicate() 43 | e_response = stderr.decode().strip() 44 | t_response = stdout.decode().strip() 45 | os.remove(downloaded_file_name) 46 | if not t_response: 47 | LOGS.info(e_response) 48 | LOGS.info(t_response) 49 | return await qr_e.edit("Failed to decode.") 50 | soup = BeautifulSoup(t_response, "html.parser") 51 | qr_contents = soup.find_all("pre")[0].text 52 | await qr_e.edit(qr_contents) 53 | 54 | 55 | @register(pattern=r"\.barcode(?: |$)([\s\S]*)", outgoing=True) 56 | async def bq(event): 57 | await event.edit("`Processing..`") 58 | input_str = event.pattern_match.group(1) 59 | message = "SYNTAX: `.barcode `" 60 | reply_msg_id = event.message.id 61 | if input_str: 62 | message = input_str 63 | elif event.reply_to_msg_id: 64 | previous_message = await event.get_reply_message() 65 | reply_msg_id = previous_message.id 66 | if previous_message.media: 67 | downloaded_file_name = await event.client.download_media(previous_message) 68 | m_list = None 69 | with open(downloaded_file_name, "rb") as fd: 70 | m_list = fd.readlines() 71 | message = "" 72 | for m in m_list: 73 | message += m.decode("UTF-8") + "\r\n" 74 | os.remove(downloaded_file_name) 75 | else: 76 | message = previous_message.message 77 | else: 78 | return event.edit("SYNTAX: `.barcode `") 79 | 80 | bar_code_type = "code128" 81 | try: 82 | bar_code_mode_f = barcode.get(bar_code_type, message, writer=ImageWriter()) 83 | filename = bar_code_mode_f.save(bar_code_type) 84 | await event.client.send_file(event.chat_id, filename, reply_to=reply_msg_id) 85 | os.remove(filename) 86 | except Exception as e: 87 | return await event.edit(str(e)) 88 | await event.delete() 89 | 90 | 91 | @register(pattern=r"\.makeqr(?: |$)([\s\S]*)", outgoing=True) 92 | async def make_qr(makeqr): 93 | input_str = makeqr.pattern_match.group(1) 94 | message = "SYNTAX: `.makeqr `" 95 | reply_msg_id = None 96 | if input_str: 97 | message = input_str 98 | elif makeqr.reply_to_msg_id: 99 | previous_message = await makeqr.get_reply_message() 100 | reply_msg_id = previous_message.id 101 | if previous_message.media: 102 | downloaded_file_name = await makeqr.client.download_media(previous_message) 103 | m_list = None 104 | with open(downloaded_file_name, "rb") as file: 105 | m_list = file.readlines() 106 | message = "" 107 | for media in m_list: 108 | message += media.decode("UTF-8") + "\r\n" 109 | os.remove(downloaded_file_name) 110 | else: 111 | message = previous_message.message 112 | 113 | qr = qrcode.QRCode( 114 | version=1, 115 | error_correction=qrcode.constants.ERROR_CORRECT_L, 116 | box_size=10, 117 | border=4, 118 | ) 119 | qr.add_data(message) 120 | qr.make(fit=True) 121 | img = qr.make_image(fill_color="black", back_color="white") 122 | img.save("img_file.webp", "PNG") 123 | await makeqr.client.send_file( 124 | makeqr.chat_id, "img_file.webp", reply_to=reply_msg_id 125 | ) 126 | os.remove("img_file.webp") 127 | await makeqr.delete() 128 | 129 | 130 | CMD_HELP.update( 131 | { 132 | "qr": ">`.makeqr `" 133 | "\nUsage: Make a QR Code from the given content." 134 | "\nExample: .makeqr www.google.com" 135 | "\nNote: use `.decode ` to get decoded content.", 136 | "barcode": ">`.barcode `" 137 | "\nUsage: Make a BarCode from the given content." 138 | "\nExample: .barcode www.google.com" 139 | "\nNote: use `.decode ` to get decoded content.", 140 | } 141 | ) 142 | -------------------------------------------------------------------------------- /userbot/modules/time.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from datetime import datetime as dt 8 | 9 | from pytz import country_names as c_n 10 | from pytz import country_timezones as c_tz 11 | from pytz import timezone as tz 12 | 13 | from userbot import CMD_HELP, COUNTRY, TZ_NUMBER 14 | from userbot.events import register 15 | 16 | 17 | async def get_tz(con): 18 | if "(Uk)" in con: 19 | con = con.replace("Uk", "UK") 20 | if "(Us)" in con: 21 | con = con.replace("Us", "US") 22 | if " Of " in con: 23 | con = con.replace(" Of ", " of ") 24 | if "(Western)" in con: 25 | con = con.replace("(Western)", "(western)") 26 | if "Minor Outlying Islands" in con: 27 | con = con.replace("Minor Outlying Islands", "minor outlying islands") 28 | if "Nl" in con: 29 | con = con.replace("Nl", "NL") 30 | 31 | for c_code in c_n: 32 | if con == c_n[c_code]: 33 | return c_tz[c_code] 34 | try: 35 | if c_n[con]: 36 | return c_tz[con] 37 | except KeyError: 38 | return 39 | 40 | 41 | @register(outgoing=True, pattern=r"^\.time(?: |$)(.*)(? 4: 50 | try: 51 | c_name = c_n[con] 52 | except KeyError: 53 | c_name = con 54 | timezones = await get_tz(con) 55 | elif COUNTRY: 56 | c_name = COUNTRY 57 | tz_num = TZ_NUMBER 58 | timezones = await get_tz(COUNTRY) 59 | else: 60 | return await tdata.edit(f"`It's` **{dt.now().strftime(t_form)}** `here.`") 61 | 62 | if not timezones: 63 | return await tdata.edit("`Invaild country.`") 64 | 65 | if len(timezones) == 1: 66 | time_zone = timezones[0] 67 | elif len(timezones) > 1: 68 | if tz_num: 69 | tz_num = int(tz_num) 70 | time_zone = timezones[tz_num - 1] 71 | else: 72 | return_str = f"`{c_name} has multiple timezones:`\n\n" 73 | 74 | for i, item in enumerate(timezones): 75 | return_str += f"`{i+1}. {item}`\n" 76 | 77 | return_str += "\n`Choose one by typing the number " 78 | return_str += "in the command.`\n" 79 | return_str += f"`Example: .time {c_name} 2`" 80 | 81 | return await tdata.edit(return_str) 82 | 83 | dtnow = dt.now(tz(time_zone)).strftime(t_form) 84 | 85 | if c_name != COUNTRY: 86 | return await tdata.edit( 87 | f"`It's` **{dtnow}** `in {c_name}({time_zone} timezone).`" 88 | ) 89 | elif COUNTRY: 90 | return await tdata.edit( 91 | f"`It's` **{dtnow}** `here, in {COUNTRY}" f"({time_zone} timezone).`" 92 | ) 93 | 94 | 95 | @register(outgoing=True, pattern=r"^\.date(?: |$)(.*)(? 4: 104 | try: 105 | c_name = c_n[con] 106 | except KeyError: 107 | c_name = con 108 | timezones = await get_tz(con) 109 | elif COUNTRY: 110 | c_name = COUNTRY 111 | tz_num = TZ_NUMBER 112 | timezones = await get_tz(COUNTRY) 113 | else: 114 | return await dat.edit(f"`It's` **{dt.now().strftime(d_form)}** `here.`") 115 | 116 | if not timezones: 117 | return await dat.edit("`Invaild country.`") 118 | 119 | if len(timezones) == 1: 120 | time_zone = timezones[0] 121 | elif len(timezones) > 1: 122 | if tz_num: 123 | tz_num = int(tz_num) 124 | time_zone = timezones[tz_num - 1] 125 | else: 126 | return_str = f"`{c_name} has multiple timezones:`\n" 127 | 128 | for i, item in enumerate(timezones): 129 | return_str += f"`{i+1}. {item}`\n" 130 | 131 | return_str += "\n`Choose one by typing the number " 132 | return_str += "in the command.`\n" 133 | return_str += f"Example: .date {c_name} 2" 134 | 135 | return await dat.edit(return_str) 136 | 137 | dtnow = dt.now(tz(time_zone)).strftime(d_form) 138 | 139 | if c_name != COUNTRY: 140 | return await dat.edit( 141 | f"`It's` **{dtnow}** `in {c_name}({time_zone} timezone).`" 142 | ) 143 | elif COUNTRY: 144 | return await dat.edit( 145 | f"`It's` **{dtnow}** `here, in {COUNTRY}" f"({time_zone} timezone).`" 146 | ) 147 | 148 | 149 | CMD_HELP.update( 150 | { 151 | "time": ">`.time `" 152 | "\nUsage: Get the time of a country. If a country has " 153 | "multiple timezones, it will list all of them and let you select one.", 154 | "date": ">`.date `" 155 | "\nUsage: Get the date of a country. If a country has " 156 | "multiple timezones, it will list all of them and let you select one.", 157 | } 158 | ) 159 | -------------------------------------------------------------------------------- /userbot/modules/torrent_search.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 GengKapak and AnggaR96s. 2 | # All rights reserved. 3 | import codecs 4 | import json 5 | import os 6 | 7 | import requests 8 | from bs4 import BeautifulSoup as bs 9 | 10 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 11 | from userbot.events import register 12 | 13 | 14 | @register(outgoing=True, pattern=r"^\.ts (.*)") 15 | async def gengkapak(e): 16 | await e.edit("`Please wait, fetching results...`") 17 | query = e.pattern_match.group(1) 18 | response = requests.get( 19 | f"https://sjprojectsapi.herokuapp.com/torrent/?query={query}" 20 | ) 21 | ts = json.loads(response.text) 22 | if ts != response.json(): 23 | await e.edit("**Some error occured**\n`Try Again Later`") 24 | return 25 | listdata = "" 26 | run = 0 27 | while True: 28 | try: 29 | run += 1 30 | r1 = ts[run] 31 | list1 = "<-----{}----->\nName: {}\nSeeders: {}\nSize: {}\nAge: {}\n<--Magnet Below-->\n{}\n\n\n".format( 32 | run, r1["name"], r1["seeder"], r1["size"], r1["age"], r1["magnet"] 33 | ) 34 | listdata += list1 35 | except BaseException: 36 | break 37 | 38 | if not listdata: 39 | return await e.edit("`Error: No results found`") 40 | 41 | tsfileloc = f"{TEMP_DOWNLOAD_DIRECTORY}/{query}.txt" 42 | with open(tsfileloc, "w+", encoding="utf8") as out_file: 43 | out_file.write(str(listdata)) 44 | fd = codecs.open(tsfileloc, "r", encoding="utf-8") 45 | data = fd.read() 46 | key = ( 47 | requests.post("https://nekobin.com/api/documents", json={"content": data}) 48 | .json() 49 | .get("result") 50 | .get("key") 51 | ) 52 | url = f"https://nekobin.com/raw/{key}" 53 | caption = ( 54 | f"`Here the results for the query: {query}`\n\nPasted to: [Nekobin]({url})" 55 | ) 56 | os.remove(tsfileloc) 57 | await e.edit(caption, link_preview=False) 58 | 59 | 60 | def dogbin(magnets): 61 | counter = 0 62 | urls = [] 63 | while counter != len(magnets): 64 | message = magnets[counter] 65 | url = "https://del.dog/documents" 66 | r = requests.post(url, data=message.encode("UTF-8")).json() 67 | url = f"https://del.dog/raw/{r['key']}" 68 | urls.append(url) 69 | counter += 1 70 | return urls 71 | 72 | 73 | @register(outgoing=True, pattern=r"^\.tos(?: |$)(.*)") 74 | async def tor_search(event): 75 | if event.fwd_from: 76 | return 77 | headers = { 78 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" 79 | } 80 | 81 | search_str = event.pattern_match.group(1) 82 | 83 | print(search_str) 84 | await event.edit("Searching for " + search_str + ".....") 85 | if " " in search_str: 86 | search_str = search_str.replace(" ", "+") 87 | print(search_str) 88 | res = requests.get( 89 | "https://www.torrentdownloads.me/search/?new=1&s_cat=0&search=" 90 | + search_str, 91 | headers, 92 | ) 93 | 94 | else: 95 | res = requests.get( 96 | "https://www.torrentdownloads.me/search/?search=" + search_str, headers 97 | ) 98 | 99 | source = bs(res.text, "lxml") 100 | urls = [] 101 | magnets = [] 102 | titles = [] 103 | counter = 0 104 | for div in source.find_all("div", {"class": "grey_bar3 back_none"}): 105 | # print("https://www.torrentdownloads.me"+a['href']) 106 | try: 107 | title = div.p.a["title"] 108 | title = title[20:] 109 | titles.append(title) 110 | urls.append("https://www.torrentdownloads.me" + div.p.a["href"]) 111 | except KeyError: 112 | pass 113 | except TypeError: 114 | pass 115 | except AttributeError: 116 | pass 117 | if counter == 11: 118 | break 119 | counter += 1 120 | if not urls: 121 | await event.edit("Either the Keyword was restricted or not found..") 122 | return 123 | 124 | print("Found URLS...") 125 | for url in urls: 126 | res = requests.get(url, headers) 127 | # print("URl: "+url) 128 | source = bs(res.text, "lxml") 129 | for div in source.find_all("div", {"class": "grey_bar1 back_none"}): 130 | try: 131 | mg = div.p.a["href"] 132 | magnets.append(mg) 133 | except Exception: 134 | pass 135 | print("Found Magnets...") 136 | shorted_links = dogbin(magnets) 137 | print("Dogged Magnets to del.dog...") 138 | msg = "" 139 | try: 140 | search_str = search_str.replace("+", " ") 141 | except BaseException: 142 | pass 143 | msg = "**Torrent Search Query**\n`{}`".format(search_str) + "\n**Results**\n" 144 | counter = 0 145 | while counter != len(titles): 146 | msg = ( 147 | msg 148 | + "⁍ [{}]".format(titles[counter]) 149 | + "({})".format(shorted_links[counter]) 150 | + "\n\n" 151 | ) 152 | counter += 1 153 | await event.edit(msg, link_preview=False) 154 | 155 | 156 | CMD_HELP.update( 157 | { 158 | "torrent": ">`.ts` Search query." 159 | "\nUsage: Search for torrent query and post to dogbin.\n\n" 160 | ">`.tos` Search query." 161 | "\nUsage: Search for torrent magnet from query." 162 | } 163 | ) 164 | -------------------------------------------------------------------------------- /userbot/modules/misc.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # You can find misc modules, which dont fit in anything xD 7 | 8 | import io 9 | import sys 10 | from os import execl 11 | from random import randint 12 | from time import sleep 13 | 14 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, bot 15 | from userbot.events import register 16 | from userbot.utils import time_formatter 17 | 18 | 19 | @register(outgoing=True, pattern=r"^\.random") 20 | async def randomise(items): 21 | itemo = (items.text[8:]).split() 22 | if len(itemo) < 2: 23 | return await items.edit( 24 | "`2 or more items are required! Check .help random for more info.`" 25 | ) 26 | index = randint(1, len(itemo) - 1) 27 | await items.edit( 28 | "**Query: **\n`" + items.text[8:] + "`\n**Output: **\n`" + itemo[index] + "`" 29 | ) 30 | 31 | 32 | @register(outgoing=True, pattern=r"^\.sleep ([0-9]+)$") 33 | async def sleepybot(time): 34 | counter = int(time.pattern_match.group(1)) 35 | await time.edit("`I am sulking and snoozing...`") 36 | if BOTLOG: 37 | str_counter = time_formatter(counter) 38 | await time.client.send_message( 39 | BOTLOG_CHATID, 40 | f"You put the bot to sleep for {str_counter}.", 41 | ) 42 | sleep(counter) 43 | await time.edit("`OK, I'm awake now.`") 44 | 45 | 46 | @register(outgoing=True, pattern=r"^\.shutdown$") 47 | async def killthebot(event): 48 | await event.edit("`Goodbye...`") 49 | if BOTLOG: 50 | await event.client.send_message(BOTLOG_CHATID, "#SHUTDOWN \n" "Bot shut down") 51 | await bot.disconnect() 52 | 53 | 54 | @register(outgoing=True, pattern=r"^\.restart$") 55 | async def killdabot(event): 56 | await event.edit("`*i would be back in a moment*`") 57 | if BOTLOG: 58 | await event.client.send_message(BOTLOG_CHATID, "#RESTART \n" "Bot Restarted") 59 | await bot.disconnect() 60 | # Spin a new instance of bot 61 | execl(sys.executable, sys.executable, *sys.argv) 62 | # Shut the existing one down 63 | sys.exit() 64 | 65 | 66 | @register(outgoing=True, pattern=r"^\.readme$") 67 | async def reedme(e): 68 | await e.edit( 69 | "Here's something for you to read:\n" 70 | "\n[ProjectAlf's README.md file](https://github.com/alfianandaa/ProjectAlf/blob/master/README.md)" 71 | "\n[Setup Guide - Basic](https://telegra.ph/How-to-host-a-Telegram-Userbot-11-02)" 72 | "\n[Setup Guide - Google Drive](https://telegra.ph/How-To-Setup-Google-Drive-04-03)" 73 | "\n[Setup Guide - LastFM Module](https://telegra.ph/How-to-set-up-LastFM-module-for-Paperplane-userbot-11-02)" 74 | "\n[Video Tutorial - 576p](https://mega.nz/#!ErwCESbJ!1ZvYAKdTEfb6y1FnqqiLhHH9vZg4UB2QZNYL9fbQ9vs)" 75 | "\n[Video Tutorial - 1080p](https://mega.nz/#!x3JVhYwR!u7Uj0nvD8_CyyARrdKrFqlZEBFTnSVEiqts36HBMr-o)" 76 | "\n[Special - Note](https://telegra.ph/Special-Note-11-02)" 77 | ) 78 | 79 | 80 | # Copyright (c) Gegham Zakaryan | 2019 81 | @register(outgoing=True, pattern=r"^\.repeat (.*)") 82 | async def repeat(rep): 83 | cnt, txt = rep.pattern_match.group(1).split(" ", 1) 84 | replyCount = int(cnt) 85 | toBeRepeated = txt 86 | 87 | replyText = toBeRepeated + "\n" 88 | 89 | for _ in range(replyCount - 1): 90 | replyText += toBeRepeated + "\n" 91 | 92 | await rep.edit(replyText) 93 | 94 | 95 | @register(outgoing=True, pattern=r"^\.repo$") 96 | async def repo_is_here(wannasee): 97 | await wannasee.edit( 98 | "[Here](https://github.com/alfianandaa/ProjectAlf) is ProjectAlf repo." 99 | ) 100 | 101 | 102 | @register(outgoing=True, pattern=r"^\.raw$") 103 | async def raw(event): 104 | the_real_message = None 105 | reply_to_id = None 106 | if event.reply_to_msg_id: 107 | previous_message = await event.get_reply_message() 108 | the_real_message = previous_message.stringify() 109 | reply_to_id = event.reply_to_msg_id 110 | else: 111 | the_real_message = event.stringify() 112 | reply_to_id = event.message.id 113 | with io.BytesIO(str.encode(the_real_message)) as out_file: 114 | out_file.name = "raw_message_data.txt" 115 | await event.edit("`Check the userbot log for the decoded message data !!`") 116 | await event.client.send_file( 117 | BOTLOG_CHATID, 118 | out_file, 119 | force_document=True, 120 | allow_cache=False, 121 | reply_to=reply_to_id, 122 | caption="`Here's the decoded message data !!`", 123 | ) 124 | 125 | 126 | CMD_HELP.update( 127 | { 128 | "random": ">`.random ... `" 129 | "\nUsage: Get a random item from the list of items.", 130 | "sleep": ">`.sleep `" "\nUsage: Let yours snooze for a few seconds.", 131 | "shutdown": ">`.shutdown`" "\nUsage: Shutdown bot", 132 | "repo": ">`.repo`" "\nUsage: Github Repo of this bot", 133 | "readme": ">`.readme`" 134 | "\nUsage: Provide links to setup the userbot and it's modules.", 135 | "repeat": ">`.repeat `" 136 | "\nUsage: Repeats the text for a number of times. Don't confuse this with spam tho.", 137 | "restart": ">`.restart`" "\nUsage: Restarts the bot !!", 138 | "raw": ">`.raw`" 139 | "\nUsage: Get detailed JSON-like formatted data about replied message.", 140 | } 141 | ) 142 | -------------------------------------------------------------------------------- /userbot/modules/transform.py: -------------------------------------------------------------------------------- 1 | # Authored by @Khrisna_Singhal 2 | # Ported from Userge by Alfiananda P.A 3 | 4 | import os 5 | 6 | from hachoir.metadata import extractMetadata 7 | from hachoir.parser import createParser 8 | from PIL import Image, ImageOps 9 | from telethon.tl.types import DocumentAttributeFilename 10 | 11 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY, bot 12 | from userbot.events import register 13 | 14 | Converted = TEMP_DOWNLOAD_DIRECTORY + "sticker.webp" 15 | 16 | 17 | @register(outgoing=True, pattern=r"^\.(mirror|flip|ghost|bw|poster)$") 18 | async def transform(event): 19 | if not event.reply_to_msg_id: 20 | await event.edit("`Reply to Any media..`") 21 | return 22 | reply_message = await event.get_reply_message() 23 | if not reply_message.media: 24 | await event.edit("`reply to a image/sticker`") 25 | return 26 | await event.edit("`Downloading Media..`") 27 | if reply_message.photo: 28 | transform = await bot.download_media( 29 | reply_message, 30 | "transform.png", 31 | ) 32 | elif ( 33 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 34 | in reply_message.media.document.attributes 35 | ): 36 | await bot.download_media( 37 | reply_message, 38 | "transform.tgs", 39 | ) 40 | os.system("lottie_convert.py transform.tgs transform.png") 41 | transform = "transform.png" 42 | elif reply_message.video: 43 | video = await bot.download_media( 44 | reply_message, 45 | "transform.mp4", 46 | ) 47 | extractMetadata(createParser(video)) 48 | os.system( 49 | "ffmpeg -i transform.mp4 -vframes 1 -an -s 480x360 -ss 1 transform.png" 50 | ) 51 | transform = "transform.png" 52 | else: 53 | transform = await bot.download_media( 54 | reply_message, 55 | "transform.png", 56 | ) 57 | try: 58 | await event.edit("`Transforming this media..`") 59 | cmd = event.pattern_match.group(1) 60 | im = Image.open(transform).convert("RGB") 61 | if cmd == "mirror": 62 | IMG = ImageOps.mirror(im) 63 | elif cmd == "flip": 64 | IMG = ImageOps.flip(im) 65 | elif cmd == "ghost": 66 | IMG = ImageOps.invert(im) 67 | elif cmd == "bw": 68 | IMG = ImageOps.grayscale(im) 69 | elif cmd == "poster": 70 | IMG = ImageOps.posterize(im, 2) 71 | IMG.save(Converted, quality=95) 72 | await event.client.send_file( 73 | event.chat_id, Converted, reply_to=event.reply_to_msg_id 74 | ) 75 | await event.delete() 76 | os.system("rm *.mp4 *.tgs") 77 | os.remove(transform) 78 | os.remove(Converted) 79 | except BaseException: 80 | return 81 | 82 | 83 | @register(outgoing=True, pattern=r"^\.rotate(?: |$)(.*)") 84 | async def rotate(event): 85 | if not event.reply_to_msg_id: 86 | await event.edit("`Reply to any media..`") 87 | return 88 | reply_message = await event.get_reply_message() 89 | if not reply_message.media: 90 | await event.edit("`reply to a image/sticker`") 91 | return 92 | await event.edit("`Downloading Media..`") 93 | if reply_message.photo: 94 | rotate = await bot.download_media( 95 | reply_message, 96 | "transform.png", 97 | ) 98 | elif ( 99 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 100 | in reply_message.media.document.attributes 101 | ): 102 | await bot.download_media( 103 | reply_message, 104 | "transform.tgs", 105 | ) 106 | os.system("lottie_convert.py transform.tgs transform.png") 107 | rotate = "transform.png" 108 | elif reply_message.video: 109 | video = await bot.download_media( 110 | reply_message, 111 | "transform.mp4", 112 | ) 113 | extractMetadata(createParser(video)) 114 | os.system( 115 | "ffmpeg -i transform.mp4 -vframes 1 -an -s 480x360 -ss 1 transform.png" 116 | ) 117 | rotate = "transform.png" 118 | else: 119 | rotate = await bot.download_media( 120 | reply_message, 121 | "transform.png", 122 | ) 123 | try: 124 | value = int(event.pattern_match.group(1)) 125 | if value > 360: 126 | raise ValueError 127 | except ValueError: 128 | value = 90 129 | await event.edit("`Rotating your media..`") 130 | im = Image.open(rotate).convert("RGB") 131 | IMG = im.rotate(value, expand=1) 132 | IMG.save(Converted, quality=95) 133 | await event.client.send_file( 134 | event.chat_id, Converted, reply_to=event.reply_to_msg_id 135 | ) 136 | await event.delete() 137 | os.system("rm *.mp4 *.tgs") 138 | os.remove(rotate) 139 | os.remove(Converted) 140 | 141 | 142 | CMD_HELP.update( 143 | { 144 | "transform": ">`.ghost`" 145 | "\nUsage: Enchance your image to become a ghost!." 146 | "\n\n>`.flip`" 147 | "\nUsage: To flip your image" 148 | "\n\n>`.mirror`" 149 | "\nUsage: To mirror your image" 150 | "\n\n>`.bw`" 151 | "\nUsage: To Change your colorized image to b/w image!" 152 | "\n\n>`.poster`" 153 | "\nUsage: To posterize your image!" 154 | "\n\n>`.rotate `" 155 | "\nUsage: To rotate your image\n* The value is range 1-360 if not it'll give default value which is 90" 156 | } 157 | ) 158 | -------------------------------------------------------------------------------- /userbot/modules/whois.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | # The entire source code is OSSRPL except 'whois' which is MPL 7 | # License: MPL and OSSRPL 8 | 9 | import os 10 | 11 | from telethon.tl.functions.photos import GetUserPhotosRequest 12 | from telethon.tl.functions.users import GetFullUserRequest 13 | from telethon.tl.types import MessageEntityMentionName 14 | from telethon.utils import get_input_location 15 | 16 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 17 | from userbot.events import register 18 | 19 | 20 | @register(pattern=r"^\.whois(?: |$)(.*)", outgoing=True) 21 | async def who(event): 22 | 23 | await event.edit( 24 | "`Sit tight while I steal some data from *Global Network Zone*...`" 25 | ) 26 | 27 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 28 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 29 | 30 | replied_user = await get_user(event) 31 | if replied_user is None: 32 | await event.edit( 33 | "`This is anonymous admin in this group.\nCan't fetch the info`" 34 | ) 35 | return 36 | 37 | try: 38 | photo, caption = await fetch_info(replied_user, event) 39 | except AttributeError: 40 | return await event.edit("`Could not fetch info of that user.`") 41 | 42 | message_id_to_reply = event.message.reply_to_msg_id 43 | 44 | if not message_id_to_reply: 45 | message_id_to_reply = None 46 | 47 | try: 48 | await event.client.send_file( 49 | event.chat_id, 50 | photo, 51 | caption=caption, 52 | link_preview=False, 53 | force_document=False, 54 | reply_to=message_id_to_reply, 55 | parse_mode="html", 56 | ) 57 | 58 | if not photo.startswith("http"): 59 | os.remove(photo) 60 | await event.delete() 61 | 62 | except TypeError: 63 | await event.edit(caption, parse_mode="html") 64 | 65 | 66 | async def get_user(event): 67 | if event.reply_to_msg_id and not event.pattern_match.group(1): 68 | previous_message = await event.get_reply_message() 69 | if previous_message.from_id is None: # Anonymous admin seems don't have id attr 70 | return None 71 | replied_user = await event.client(GetFullUserRequest(previous_message.from_id)) 72 | else: 73 | user = event.pattern_match.group(1) 74 | 75 | if user.isnumeric(): 76 | user = int(user) 77 | 78 | if not user: 79 | self_user = await event.client.get_me() 80 | user = self_user.id 81 | 82 | if event.message.entities is not None: 83 | probable_user_mention_entity = event.message.entities[0] 84 | 85 | if isinstance(probable_user_mention_entity, MessageEntityMentionName): 86 | user_id = probable_user_mention_entity.user_id 87 | replied_user = await event.client(GetFullUserRequest(user_id)) 88 | return replied_user 89 | try: 90 | user_object = await event.client.get_entity(user) 91 | replied_user = await event.client(GetFullUserRequest(user_object.id)) 92 | except (TypeError, ValueError) as err: 93 | return await event.edit(str(err)) 94 | 95 | return replied_user 96 | 97 | 98 | async def fetch_info(replied_user, event): 99 | replied_user_profile_photos = await event.client( 100 | GetUserPhotosRequest( 101 | user_id=replied_user.user.id, offset=42, max_id=0, limit=80 102 | ) 103 | ) 104 | replied_user_profile_photos_count = ( 105 | "Person needs help with uploading profile picture." 106 | ) 107 | try: 108 | replied_user_profile_photos_count = replied_user_profile_photos.count 109 | except AttributeError: 110 | pass 111 | user_id = replied_user.user.id 112 | first_name = replied_user.user.first_name 113 | last_name = replied_user.user.last_name 114 | try: 115 | dc_id, location = get_input_location(replied_user.profile_photo) 116 | except Exception as e: 117 | dc_id = "Couldn't fetch DC ID!" 118 | str(e) 119 | common_chat = replied_user.common_chats_count 120 | username = replied_user.user.username 121 | user_bio = replied_user.about 122 | is_bot = replied_user.user.bot 123 | restricted = replied_user.user.restricted 124 | verified = replied_user.user.verified 125 | photo = await event.client.download_profile_photo( 126 | user_id, TEMP_DOWNLOAD_DIRECTORY + str(user_id) + ".jpg", download_big=True 127 | ) 128 | first_name = ( 129 | first_name.replace("\u2060", "") 130 | if first_name 131 | else ("This User has no First Name") 132 | ) 133 | last_name = ( 134 | last_name.replace("\u2060", "") if last_name else ("This User has no Last Name") 135 | ) 136 | username = "@{}".format(username) if username else ("This User has no Username") 137 | user_bio = "This User has no About" if not user_bio else user_bio 138 | 139 | caption = "USER INFO:\n\n" 140 | caption += f"First Name: {first_name}\n" 141 | caption += f"Last Name: {last_name}\n" 142 | caption += f"Username: {username}\n" 143 | caption += f"Data Centre ID: {dc_id}\n" 144 | caption += f"Number of Profile Pics: {replied_user_profile_photos_count}\n" 145 | caption += f"Is Bot: {is_bot}\n" 146 | caption += f"Is Restricted: {restricted}\n" 147 | caption += f"Is Verified by Telegram: {verified}\n" 148 | caption += f"ID: {user_id}\n\n" 149 | caption += f"Bio: \n{user_bio}\n\n" 150 | caption += f"Common Chats with this user: {common_chat}\n" 151 | caption += "Permanent Link To Profile: " 152 | caption += f'{first_name}' 153 | 154 | return photo, caption 155 | 156 | 157 | CMD_HELP.update( 158 | { 159 | "whois": ">`.whois or reply to someones text with .whois`" 160 | "\nUsage: Gets info of an user." 161 | } 162 | ) 163 | -------------------------------------------------------------------------------- /userbot/modules/notes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from asyncio import sleep 8 | 9 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP 10 | from userbot.events import register 11 | 12 | 13 | @register(outgoing=True, pattern=r"^\.notes$") 14 | async def notes_active(svd): 15 | try: 16 | from userbot.modules.sql_helper.notes_sql import get_notes 17 | except AttributeError: 18 | return await svd.edit("`Running on Non-SQL mode!`") 19 | message = "`There are no saved notes in this chat`" 20 | notes = get_notes(svd.chat_id) 21 | for note in notes: 22 | if message == "`There are no saved notes in this chat`": 23 | message = "Notes saved in this chat:\n" 24 | message += "`#{}`\n".format(note.keyword) 25 | await svd.edit(message) 26 | 27 | 28 | @register(outgoing=True, pattern=r"^\.clear (\w*)") 29 | async def remove_notes(clr): 30 | try: 31 | from userbot.modules.sql_helper.notes_sql import rm_note 32 | except AttributeError: 33 | return await clr.edit("`Running on Non-SQL mode!`") 34 | notename = clr.pattern_match.group(1) 35 | if rm_note(clr.chat_id, notename) is False: 36 | return await clr.edit("`Couldn't find note:` **{}**".format(notename)) 37 | else: 38 | return await clr.edit("`Successfully deleted note:` **{}**".format(notename)) 39 | 40 | 41 | @register(outgoing=True, pattern=r"^\.save (\w*)") 42 | async def add_note(fltr): 43 | try: 44 | from userbot.modules.sql_helper.notes_sql import add_note 45 | except AttributeError: 46 | return await fltr.edit("`Running on Non-SQL mode!`") 47 | keyword = fltr.pattern_match.group(1) 48 | string = fltr.text.partition(keyword)[2] 49 | msg = await fltr.get_reply_message() 50 | msg_id = None 51 | if msg and msg.media and not string: 52 | if BOTLOG_CHATID: 53 | await fltr.client.send_message( 54 | BOTLOG_CHATID, 55 | f"#NOTE\nCHAT ID: {fltr.chat_id}\nKEYWORD: {keyword}" 56 | "\n\nThe following message is saved as the note's reply data for the chat, please do NOT delete it !!", 57 | ) 58 | msg_o = await fltr.client.forward_messages( 59 | entity=BOTLOG_CHATID, messages=msg, from_peer=fltr.chat_id, silent=True 60 | ) 61 | msg_id = msg_o.id 62 | else: 63 | return await fltr.edit( 64 | "`Saving media as data for the note requires the BOTLOG_CHATID to be set.`" 65 | ) 66 | elif fltr.reply_to_msg_id and not string: 67 | rep_msg = await fltr.get_reply_message() 68 | string = rep_msg.text 69 | success = "`Note {} successfully. Use` #{} `to get it`" 70 | if add_note(str(fltr.chat_id), keyword, string, msg_id) is False: 71 | return await fltr.edit(success.format("updated", keyword)) 72 | else: 73 | return await fltr.edit(success.format("added", keyword)) 74 | 75 | 76 | @register(pattern=r"#\w*", disable_edited=True, disable_errors=True, ignore_unsafe=True) 77 | async def incom_note(getnt): 78 | try: 79 | if not (await getnt.get_sender()).bot: 80 | try: 81 | from userbot.modules.sql_helper.notes_sql import get_note 82 | except AttributeError: 83 | return 84 | notename = getnt.text[1:] 85 | note = get_note(getnt.chat_id, notename) 86 | message_id_to_reply = getnt.message.reply_to_msg_id 87 | if not message_id_to_reply: 88 | message_id_to_reply = None 89 | if note: 90 | if note.f_mesg_id: 91 | msg_o = await getnt.client.get_messages( 92 | entity=BOTLOG_CHATID, ids=int(note.f_mesg_id) 93 | ) 94 | await getnt.client.send_message( 95 | getnt.chat_id, 96 | msg_o.mesage, 97 | reply_to=message_id_to_reply, 98 | file=msg_o.media, 99 | ) 100 | elif note.reply: 101 | await getnt.client.send_message( 102 | getnt.chat_id, note.reply, reply_to=message_id_to_reply 103 | ) 104 | except AttributeError: 105 | pass 106 | 107 | 108 | @register(outgoing=True, pattern=r"^\.rmbotnotes (.*)") 109 | async def kick_marie_notes(kick): 110 | bot_type = kick.pattern_match.group(1).lower() 111 | if bot_type not in ["marie", "rose"]: 112 | return await kick.edit("`That bot is not yet supported!`") 113 | await kick.edit("```Will be kicking away all Notes!```") 114 | await sleep(3) 115 | resp = await kick.get_reply_message() 116 | filters = resp.text.split("-")[1:] 117 | for i in filters: 118 | if bot_type == "marie": 119 | await kick.reply("/clear %s" % (i.strip())) 120 | if bot_type == "rose": 121 | i = i.replace("`", "") 122 | await kick.reply("/clear %s" % (i.strip())) 123 | await sleep(0.3) 124 | await kick.respond("```Successfully purged bots notes yaay!```\n Gimme cookies!") 125 | if BOTLOG: 126 | await kick.client.send_message( 127 | BOTLOG_CHATID, "I cleaned all Notes at " + str(kick.chat_id) 128 | ) 129 | 130 | 131 | CMD_HELP.update( 132 | { 133 | "notes": "`#`" 134 | "\nUsage: Gets the specified note." 135 | "\n\n>`.save ` or reply to a message with >`.save `" 136 | "\nUsage: Saves the replied message as a note with the notename. " 137 | "(Works with pics, docs, and stickers too!)" 138 | "\n\n>`.notes`" 139 | "\nUsage: Gets all saved notes in a chat." 140 | "\n\n>`.clear `" 141 | "\nUsage: Deletes the specified note." 142 | "\n\n>`.rmbotnotes `" 143 | "\nUsage: Removes all notes of admin bots" 144 | " (Currently supported: Marie, Rose and their clones.) in the chat." 145 | } 146 | ) 147 | -------------------------------------------------------------------------------- /userbot/modules/locks.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | 6 | from telethon.tl.functions.messages import EditChatDefaultBannedRightsRequest 7 | from telethon.tl.types import ChatBannedRights 8 | 9 | from userbot import CMD_HELP 10 | from userbot.events import register 11 | 12 | 13 | @register(outgoing=True, pattern=r"^\.lock ?(.*)") 14 | async def locks(event): 15 | input_str = event.pattern_match.group(1).lower() 16 | peer_id = event.chat_id 17 | msg = None 18 | media = None 19 | sticker = None 20 | gif = None 21 | gamee = None 22 | ainline = None 23 | gpoll = None 24 | adduser = None 25 | cpin = None 26 | changeinfo = None 27 | if input_str == "msg": 28 | msg = True 29 | what = "messages" 30 | elif input_str == "media": 31 | media = True 32 | what = "media" 33 | elif input_str == "sticker": 34 | sticker = True 35 | what = "stickers" 36 | elif input_str == "gif": 37 | gif = True 38 | what = "GIFs" 39 | elif input_str == "game": 40 | gamee = True 41 | what = "games" 42 | elif input_str == "inline": 43 | ainline = True 44 | what = "inline bots" 45 | elif input_str == "poll": 46 | gpoll = True 47 | what = "polls" 48 | elif input_str == "invite": 49 | adduser = True 50 | what = "invites" 51 | elif input_str == "pin": 52 | cpin = True 53 | what = "pins" 54 | elif input_str == "info": 55 | changeinfo = True 56 | what = "chat info" 57 | elif input_str == "all": 58 | msg = True 59 | media = True 60 | sticker = True 61 | gif = True 62 | gamee = True 63 | ainline = True 64 | gpoll = True 65 | adduser = True 66 | cpin = True 67 | changeinfo = True 68 | what = "everything" 69 | else: 70 | if not input_str: 71 | return await event.edit("`I can't lock nothing !!`") 72 | else: 73 | return await event.edit(f"`Invalid lock type:` {input_str}") 74 | 75 | lock_rights = ChatBannedRights( 76 | until_date=None, 77 | send_messages=msg, 78 | send_media=media, 79 | send_stickers=sticker, 80 | send_gifs=gif, 81 | send_games=gamee, 82 | send_inline=ainline, 83 | send_polls=gpoll, 84 | invite_users=adduser, 85 | pin_messages=cpin, 86 | change_info=changeinfo, 87 | ) 88 | try: 89 | await event.client( 90 | EditChatDefaultBannedRightsRequest(peer=peer_id, banned_rights=lock_rights) 91 | ) 92 | await event.edit(f"`Locked {what} for this chat !!`") 93 | except BaseException as e: 94 | return await event.edit( 95 | f"`Do I have proper rights for that ??`\n**Error:** {str(e)}" 96 | ) 97 | 98 | 99 | @register(outgoing=True, pattern=r"^\.unlock ?(.*)") 100 | async def rem_locks(event): 101 | input_str = event.pattern_match.group(1).lower() 102 | peer_id = event.chat_id 103 | msg = None 104 | media = None 105 | sticker = None 106 | gif = None 107 | gamee = None 108 | ainline = None 109 | gpoll = None 110 | adduser = None 111 | cpin = None 112 | changeinfo = None 113 | if input_str == "msg": 114 | msg = False 115 | what = "messages" 116 | elif input_str == "media": 117 | media = False 118 | what = "media" 119 | elif input_str == "sticker": 120 | sticker = False 121 | what = "stickers" 122 | elif input_str == "gif": 123 | gif = False 124 | what = "GIFs" 125 | elif input_str == "game": 126 | gamee = False 127 | what = "games" 128 | elif input_str == "inline": 129 | ainline = False 130 | what = "inline bots" 131 | elif input_str == "poll": 132 | gpoll = False 133 | what = "polls" 134 | elif input_str == "invite": 135 | adduser = False 136 | what = "invites" 137 | elif input_str == "pin": 138 | cpin = False 139 | what = "pins" 140 | elif input_str == "info": 141 | changeinfo = False 142 | what = "chat info" 143 | elif input_str == "all": 144 | msg = False 145 | media = False 146 | sticker = False 147 | gif = False 148 | gamee = False 149 | ainline = False 150 | gpoll = False 151 | adduser = False 152 | cpin = False 153 | changeinfo = False 154 | what = "everything" 155 | else: 156 | if not input_str: 157 | return await event.edit("`I can't unlock nothing !!`") 158 | else: 159 | return await event.edit(f"`Invalid unlock type:` {input_str}") 160 | 161 | unlock_rights = ChatBannedRights( 162 | until_date=None, 163 | send_messages=msg, 164 | send_media=media, 165 | send_stickers=sticker, 166 | send_gifs=gif, 167 | send_games=gamee, 168 | send_inline=ainline, 169 | send_polls=gpoll, 170 | invite_users=adduser, 171 | pin_messages=cpin, 172 | change_info=changeinfo, 173 | ) 174 | try: 175 | await event.client( 176 | EditChatDefaultBannedRightsRequest( 177 | peer=peer_id, banned_rights=unlock_rights 178 | ) 179 | ) 180 | await event.edit(f"`Unlocked {what} for this chat !!`") 181 | except BaseException as e: 182 | return await event.edit( 183 | f"`Do I have proper rights for that ??`\n**Error:** {str(e)}" 184 | ) 185 | 186 | 187 | CMD_HELP.update( 188 | { 189 | "locks": ">`.lock ` or >`.unlock `" 190 | "\nUsage: Allows you to lock/unlock some common message types in the chat." 191 | "\n[NOTE: Requires proper admin rights in the chat !!]" 192 | "\n\nAvailable message types to lock/unlock are: " 193 | "\n`all, msg, media, sticker, gif, game, inline, poll, invite, pin, info`" 194 | } 195 | ) 196 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | RAPHIELSCAPE PUBLIC LICENSE 2 | Version 1.d, February 2020 3 | 4 | Copyright (C) 2020 Devscapes Open Source Holding GmbH. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, and changing it is prohibited. 8 | 9 | RAPHIELSCAPE PUBLIC LICENSE 10 | A-1. DEFINITIONS 11 | 12 | 0. “This License” refers to version 1.d of the Raphielscape Public License. 13 | 14 | 1. “Copyright” also means copyright-like laws that apply to other kinds of works. 15 | 16 | 2. “The Work" refers to any copyrightable work licensed under this License. 17 | Each licensee is addressed as “you”. “Licensees” and “recipients” may be 18 | individuals or organizations. 19 | 20 | 3. To “modify” a work means to copy from or adapt all or part of the work 21 | in a fashion requiring copyright permission, other than the making of 22 | an exact copy. The resulting work is called a “modified version” of 23 | the earlier work or a work “based on” the earlier work. 24 | 25 | 4. Source Form. The “source form” for a work means the preferred form 26 | of the work for making modifications to it. “Object code” means any 27 | non-source form of a work. 28 | 29 | The “Corresponding Source” for a work in object code form means all 30 | the source code needed to generate, install, and (for an executable work) 31 | run the object code and to modify the work, including scripts to control 32 | those activities. 33 | 34 | The Corresponding Source need not include anything that users can 35 | regenerate automatically from other parts of the Corresponding Source. 36 | The Corresponding Source for a work in source code form is that same work. 37 | 38 | 5. "The author" refers to "author" of the code, which is the one that made 39 | the particular code that exists inside of the Corresponding Source. 40 | 41 | 6. "Owner" refers to any parties which are owning the Corresponding Source. 42 | 43 | 7. "Maintainers" refers to any parties which are keeping in existence or 44 | continuance, preserving and retaining The Work and the Corresponding Source. 45 | 46 | 8. “Deprecation” refers to an act of The author and Owner without Maintainers' 47 | agreement to discontinuing the maintainership of The Work. 48 | 49 | 9. "Discontinuation" refers to all Maintainers, The Author, and Owner to 50 | discontinuing the maintainership of The Work. 51 | 52 | 10. "Upstream" refers to the place or site where The Work and the 53 | Corresponding Source getting worked on and where all Maintainers, 54 | The Author, and Owner keeping the existence, continuance, preservation, 55 | and retainment of The Work and Corresponding Source. 56 | 57 | A-2. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 58 | 59 | 0. You must give any other recipients of the Work or Derivative 60 | Works a copy of this License; and 61 | 62 | 1. You must cause any modified files to carry prominent notices 63 | stating that You changed the files; and 64 | 65 | 2. You must retain, in the Source form of any Derivative Works 66 | that You distribute, this license, all copyright, patent, trademark, 67 | authorships, and attribution notices from the Source form of the Work; and 68 | 69 | 3. You must cause the maintainers of the works to democratically 70 | selecting the new Owner in case of Deprecation with the Signoffs from 71 | all Maintainers and final Signoff from The Author of The Work and the 72 | Corresponding Source. 73 | 74 | If the works are Discontinued, the Owner should archive The Work and 75 | the Corresponding Source or optionally removing The Work entirely and 76 | may stop the distribution of The Work and the Corresponding Source. 77 | 78 | The Owner or The Author may give The Work or the Corresponding Source 79 | to a specific person for a new maintainership structure in case 80 | The Owner, Author, and The Maintainers failed to democratically 81 | selecting a new Owner to continuing, preserving and retaining 82 | The Work and the Corresponding Source; and 83 | 84 | 4. Respecting the author and owner of works that are distributed in 85 | any way. In the means that decisions that are taken by Upstream are 86 | immediately imposed on both Upstream and Modified Version of 87 | The Works and Corresponding Source. 88 | 89 | Any use, reproduction, or distribution of Your modifications, or 90 | for any such Derivative Works as a whole, provided Your use, reproduction, 91 | and distribution of the Work should comply with the conditions stated in 92 | this License. 93 | 94 | B. DISCLAIMER OF WARRANTY 95 | 96 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' 97 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 98 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 99 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR 100 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 101 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 102 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 103 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 104 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 105 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 106 | 107 | 108 | C. REVISED VERSION OF THIS LICENSE 109 | 110 | The Devscapes Open Source Holding GmbH. may publish revised and/or new versions 111 | of the Raphielscape Public License from time to time. Such new versions will be 112 | similar in spirit to the present version but may differ in detail to address new 113 | problems or concerns. 114 | 115 | Each version is given a distinguishing version number. If the Program specifies 116 | that a certain numbered version of the Raphielscape Public License 117 | "or any later version" applies to it, you have the option of following the terms 118 | and conditions either of that numbered version or of any later version published 119 | by the Devscapes Open Source Holding GmbH. If the Program does not specify a 120 | version number of the Raphielscape Public License, you may use the latest version 121 | published by the Devscapes Open Source Holding GmbH. 122 | 123 | END OF LICENSE 124 | -------------------------------------------------------------------------------- /userbot/modules/filter.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | from asyncio import sleep 8 | from re import IGNORECASE, escape, search 9 | 10 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP 11 | from userbot.events import register 12 | 13 | 14 | @register(incoming=True, disable_edited=True, disable_errors=True) 15 | async def filter_incoming_handler(handler): 16 | try: 17 | if not (await handler.get_sender()).bot: 18 | try: 19 | from userbot.modules.sql_helper.filter_sql import get_filters 20 | except AttributeError: 21 | await handler.edit("`Running on Non-SQL mode!`") 22 | return 23 | name = handler.raw_text 24 | filters = get_filters(handler.chat_id) 25 | if not filters: 26 | return 27 | for trigger in filters: 28 | pattern = r"( |^|[^\w])" + escape(trigger.keyword) + r"( |$|[^\w])" 29 | pro = search(pattern, name, flags=IGNORECASE) 30 | if pro: 31 | if trigger.f_mesg_id: 32 | msg_o = await handler.client.get_messages( 33 | entity=BOTLOG_CHATID, ids=int(trigger.f_mesg_id) 34 | ) 35 | await handler.reply(msg_o.message, file=msg_o.media) 36 | elif trigger.reply: 37 | await handler.reply(trigger.reply) 38 | except AttributeError: 39 | pass 40 | 41 | 42 | @register(outgoing=True, pattern=r"^\.filter (.*)") 43 | async def add_new_filter(new_handler): 44 | try: 45 | from userbot.modules.sql_helper.filter_sql import add_filter 46 | except AttributeError: 47 | await new_handler.edit("`Running on Non-SQL mode!`") 48 | return 49 | value = new_handler.pattern_match.group(1).split(None, 1) 50 | keyword = value[0] 51 | try: 52 | string = value[1] 53 | except IndexError: 54 | string = None 55 | msg = await new_handler.get_reply_message() 56 | msg_id = None 57 | if msg and msg.media and not string: 58 | if BOTLOG_CHATID: 59 | await new_handler.client.send_message( 60 | BOTLOG_CHATID, 61 | f"#FILTER\nCHAT ID: {new_handler.chat_id}\nTRIGGER: {keyword}" 62 | "\n\nThe following message is saved as the filter's reply data for the chat, please do NOT delete it !!", 63 | ) 64 | msg_o = await new_handler.client.forward_messages( 65 | entity=BOTLOG_CHATID, 66 | messages=msg, 67 | from_peer=new_handler.chat_id, 68 | silent=True, 69 | ) 70 | msg_id = msg_o.id 71 | else: 72 | return await new_handler.edit( 73 | "`Saving media as reply to the filter requires the BOTLOG_CHATID to be set.`" 74 | ) 75 | elif new_handler.reply_to_msg_id and not string: 76 | rep_msg = await new_handler.get_reply_message() 77 | string = rep_msg.text 78 | success = "`Filter` **{}** `{} successfully`." 79 | if add_filter(str(new_handler.chat_id), keyword, string, msg_id) is True: 80 | await new_handler.edit(success.format(keyword, "added")) 81 | else: 82 | await new_handler.edit(success.format(keyword, "updated")) 83 | 84 | 85 | @register(outgoing=True, pattern=r"^\.stop (.*)") 86 | async def remove_a_filter(r_handler): 87 | try: 88 | from userbot.modules.sql_helper.filter_sql import remove_filter 89 | except AttributeError: 90 | return await r_handler.edit("`Running on Non-SQL mode!`") 91 | filt = r_handler.pattern_match.group(1) 92 | if not remove_filter(r_handler.chat_id, filt): 93 | await r_handler.edit("`Filter` **{}** `doesn't exist`.".format(filt)) 94 | else: 95 | await r_handler.edit( 96 | "`Filter` **{}** `was deleted successfully`.".format(filt) 97 | ) 98 | 99 | 100 | @register(outgoing=True, pattern=r"^\.rmbotfilters (.*)") 101 | async def kick_marie_filter(event): 102 | event.text[0] 103 | bot_type = event.pattern_match.group(1).lower() 104 | if bot_type not in ["marie", "rose"]: 105 | return await event.edit("`That bot is not yet supported!`") 106 | await event.edit("```Will be kicking away all Filters!```") 107 | await sleep(3) 108 | resp = await event.get_reply_message() 109 | filters = resp.text.split("-")[1:] 110 | for i in filters: 111 | if bot_type.lower() == "marie": 112 | await event.reply("/stop %s" % (i.strip())) 113 | if bot_type.lower() == "rose": 114 | i = i.replace("`", "") 115 | await event.reply("/stop %s" % (i.strip())) 116 | await sleep(0.3) 117 | await event.respond("```Successfully purged bots filters yaay!```\n Gimme cookies!") 118 | if BOTLOG: 119 | await event.client.send_message( 120 | BOTLOG_CHATID, "I cleaned all filters at " + str(event.chat_id) 121 | ) 122 | 123 | 124 | @register(outgoing=True, pattern=r"^\.filters$") 125 | async def filters_active(event): 126 | try: 127 | from userbot.modules.sql_helper.filter_sql import get_filters 128 | except AttributeError: 129 | return await event.edit("`Running on Non-SQL mode!`") 130 | transact = "`There are no filters in this chat.`" 131 | filters = get_filters(event.chat_id) 132 | for filt in filters: 133 | if transact == "`There are no filters in this chat.`": 134 | transact = "Active filters in this chat:\n" 135 | transact += "`{}`\n".format(filt.keyword) 136 | await event.edit(transact) 137 | 138 | 139 | CMD_HELP.update( 140 | { 141 | "filter": ">`.filters`" 142 | "\nUsage: Lists all active userbot filters in a chat." 143 | "\n\n>`.filter ` or reply to a message with >`.filter `" 144 | "\nUsage: Saves the replied message as a reply to the 'keyword'." 145 | "\nThe bot will reply to the message whenever 'keyword' is mentioned." 146 | "\nWorks with everything from files to stickers." 147 | "\n\n>`.stop `" 148 | "\nUsage: Stops the specified filter." 149 | "\n\n>`.rmbotfilters `" 150 | "\nUsage: Removes all filters of admin bots (Currently supported: Marie, Rose and their clones.) in the chat." 151 | } 152 | ) 153 | -------------------------------------------------------------------------------- /userbot/modules/dogbin.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # 6 | 7 | import os 8 | 9 | from requests import exceptions, get, post 10 | 11 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 12 | from userbot.events import register 13 | 14 | DOGBIN_URL = "https://del.dog/" 15 | NEKOBIN_URL = "https://nekobin.com/" 16 | 17 | 18 | @register(outgoing=True, pattern=r"^\.paste(?: |$)([\s\S]*)") 19 | async def paste(pstl): 20 | dogbin_final_url = "" 21 | match = pstl.pattern_match.group(1).strip() 22 | reply_id = pstl.reply_to_msg_id 23 | 24 | if not match and not reply_id: 25 | return await pstl.edit("`Elon Musk said I cannot paste void.`") 26 | 27 | if match: 28 | message = match 29 | elif reply_id: 30 | message = await pstl.get_reply_message() 31 | if message.media: 32 | downloaded_file_name = await pstl.client.download_media( 33 | message, 34 | TEMP_DOWNLOAD_DIRECTORY, 35 | ) 36 | m_list = None 37 | with open(downloaded_file_name, "rb") as fd: 38 | m_list = fd.readlines() 39 | message = "" 40 | for m in m_list: 41 | message += m.decode("UTF-8") 42 | os.remove(downloaded_file_name) 43 | else: 44 | message = message.message 45 | 46 | # Dogbin 47 | await pstl.edit("`Pasting text . . .`") 48 | resp = post(DOGBIN_URL + "documents", data=message.encode("utf-8")) 49 | 50 | if resp.status_code == 200: 51 | response = resp.json() 52 | key = response["key"] 53 | dogbin_final_url = DOGBIN_URL + key 54 | 55 | if response["isUrl"]: 56 | reply_text = ( 57 | "`Pasted successfully!`\n\n" 58 | f"[Shortened URL]({dogbin_final_url})\n\n" 59 | "`Original(non-shortened) URLs`\n" 60 | f"[Dogbin URL]({DOGBIN_URL}v/{key})\n" 61 | f"[View RAW]({DOGBIN_URL}raw/{key})" 62 | ) 63 | else: 64 | reply_text = ( 65 | "`Pasted successfully!`\n\n" 66 | f"[Dogbin URL]({dogbin_final_url})\n" 67 | f"[View RAW]({DOGBIN_URL}raw/{key})" 68 | ) 69 | else: 70 | reply_text = "`Failed to reach Dogbin`" 71 | 72 | await pstl.edit(reply_text) 73 | if BOTLOG: 74 | await pstl.client.send_message( 75 | BOTLOG_CHATID, 76 | "Paste query was executed successfully", 77 | ) 78 | 79 | 80 | @register(outgoing=True, pattern=r"^\.getpaste(?: |$)(.*)") 81 | async def get_dogbin_content(dog_url): 82 | textx = await dog_url.get_reply_message() 83 | message = dog_url.pattern_match.group(1) 84 | await dog_url.edit("`Getting dogbin content...`") 85 | 86 | if textx: 87 | message = str(textx.message) 88 | 89 | format_normal = f"{DOGBIN_URL}" 90 | format_view = f"{DOGBIN_URL}v/" 91 | 92 | if message.startswith(format_view): 93 | message = message[len(format_view) :] 94 | elif message.startswith(format_normal): 95 | message = message[len(format_normal) :] 96 | elif message.startswith("del.dog/"): 97 | message = message[len("del.dog/") :] 98 | else: 99 | return await dog_url.edit("`Is that even a dogbin url?`") 100 | 101 | resp = get(f"{DOGBIN_URL}raw/{message}") 102 | 103 | try: 104 | resp.raise_for_status() 105 | except exceptions.HTTPError as HTTPErr: 106 | await dog_url.edit( 107 | "Request returned an unsuccessful status code.\n\n" + str(HTTPErr) 108 | ) 109 | return 110 | except exceptions.Timeout as TimeoutErr: 111 | await dog_url.edit("Request timed out." + str(TimeoutErr)) 112 | return 113 | except exceptions.TooManyRedirects as RedirectsErr: 114 | await dog_url.edit( 115 | "Request exceeded the configured number of maximum redirections." 116 | + str(RedirectsErr) 117 | ) 118 | return 119 | 120 | reply_text = ( 121 | "`Fetched dogbin URL content successfully!`" "\n\n`Content:` " + resp.text 122 | ) 123 | 124 | await dog_url.edit(reply_text) 125 | if BOTLOG: 126 | await dog_url.client.send_message( 127 | BOTLOG_CHATID, 128 | "Get dogbin content query was executed successfully", 129 | ) 130 | 131 | 132 | @register(outgoing=True, pattern=r"^\.neko(?: |$)([\s\S]*)") 133 | async def neko(nekobin): 134 | """For .paste command, pastes the text directly to dogbin.""" 135 | nekobin_final_url = "" 136 | match = nekobin.pattern_match.group(1).strip() 137 | reply_id = nekobin.reply_to_msg_id 138 | 139 | if not match and not reply_id: 140 | return await pstl.edit("`Cannot paste text.`") 141 | 142 | if match: 143 | message = match 144 | elif reply_id: 145 | message = await nekobin.get_reply_message() 146 | if message.media: 147 | downloaded_file_name = await nekobin.client.download_media( 148 | message, 149 | TEMP_DOWNLOAD_DIRECTORY, 150 | ) 151 | m_list = None 152 | with open(downloaded_file_name, "rb") as fd: 153 | m_list = fd.readlines() 154 | message = "" 155 | for m in m_list: 156 | message += m.decode("UTF-8") 157 | os.remove(downloaded_file_name) 158 | else: 159 | message = message.text 160 | 161 | # Nekobin 162 | await nekobin.edit("`Pasting text . . .`") 163 | resp = post(NEKOBIN_URL + "api/documents", json={"content": message}) 164 | 165 | if resp.status_code == 201: 166 | response = resp.json() 167 | key = response["result"]["key"] 168 | nekobin_final_url = NEKOBIN_URL + key 169 | reply_text = ( 170 | "`Pasted successfully!`\n\n" 171 | f"[Nekobin URL]({nekobin_final_url})\n" 172 | f"[View RAW]({NEKOBIN_URL}raw/{key})" 173 | ) 174 | else: 175 | reply_text = "`Failed to reach Nekobin`" 176 | 177 | await nekobin.edit(reply_text) 178 | if BOTLOG: 179 | await nekobin.client.send_message( 180 | BOTLOG_CHATID, 181 | "Paste query was executed successfully", 182 | ) 183 | 184 | 185 | CMD_HELP.update( 186 | { 187 | "dogbin": ">`.paste `" 188 | "\nUsage: Create a paste or a shortened url using dogbin (https://del.dog/)" 189 | "\n\n>`.getpaste`" 190 | "\nUsage: Gets the content of a paste or shortened url from dogbin (https://del.dog/)" 191 | "\n\n>`.neko `" 192 | "\nUsage: Create a paste or a shortened url using nekobin (https://nekobin.com/)" 193 | } 194 | ) 195 | --------------------------------------------------------------------------------