├── runtime.txt ├── Procfile ├── heroku.yml ├── 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 │ │ ├── snips_sql.py │ │ ├── notes_sql.py │ │ ├── filter_sql.py │ │ ├── welcome_sql.py │ │ ├── blacklist_sql.py │ │ └── warns_sql.py │ ├── __init__.py │ ├── api.py │ ├── stickers.py │ ├── person.py │ └── system.py ├── __main__.py ├── events.py └── __init__.py ├── .gitignore ├── windows_startup_script.py ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── README.md ├── generate_session_file.py ├── string_session.py ├── requirements.txt ├── Dockerfile ├── sample_config.env ├── CODE_OF_CONDUCT ├── LICENSE ├── app.json └── .apt └── usr └── bin └── config └── config.conf /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.7.6 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 -m userbot 2 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile 4 | run: 5 | worker: python3 -m userbot 6 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/javes/master/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 | -------------------------------------------------------------------------------- /windows_startup_script.py: -------------------------------------------------------------------------------- 1 | from telethon import TelegramClient, events 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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Additional context** 14 | Add any other context or screenshots about the feature request here. 15 | 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Project Javes

2 |

A modular Telegram userbot running on Python

3 |

 

4 |

How To Install

5 |
Make desktop side , Fock my repo then Tap this image to deploy in heroku!
6 |

Deploy to Heroku

7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 13 | with TelegramClient(StringSession(), API_KEY, API_HASH) as client: 14 | print("Here is your userbot srting, copy it to a safe place !!") 15 | print("") 16 | print(client.session.save()) 17 | print("") 18 | print("") 19 | print("Enjoy your userbot !!") 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Python Version** 24 | Provide exact python version used 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | 29 | -------------------------------------------------------------------------------- /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 | """ Init file which loads all of the modules """ 7 | from userbot import LOGS 8 | 9 | 10 | def __list_all_modules(): 11 | from os.path import dirname, basename, isfile 12 | import glob 13 | 14 | mod_paths = glob.glob(dirname(__file__) + "/*.py") 15 | all_modules = [ 16 | basename(f)[:-3] for f in mod_paths 17 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") 18 | ] 19 | return all_modules 20 | 21 | 22 | ALL_MODULES = sorted(__list_all_modules()) 23 | LOGS.info("Modules to load: %s", str(ALL_MODULES)) 24 | __all__ = ALL_MODULES + ["ALL_MODULES"] 25 | -------------------------------------------------------------------------------- /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, UnicodeText 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/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | """ Userbot start point """ 3 | 4 | from importlib import import_module 5 | from sys import argv 6 | from os import execle 7 | 8 | from telethon.errors.rpcerrorlist import PhoneNumberInvalidError 9 | from userbot import LOGS, bot 10 | from userbot.modules import ALL_MODULES 11 | 12 | 13 | INVALID_PH = '\nERROR: The Phone No. entered is INVALID' \ 14 | '\nTip: Use Country Code along with number.' \ 15 | '\nor check your phone number and try again !' 16 | 17 | try: 18 | bot.start() 19 | except PhoneNumberInvalidError: 20 | print(INVALID_PH) 21 | exit(1) 22 | 23 | for module_name in ALL_MODULES: 24 | imported_module = import_module("userbot.modules." + module_name) 25 | 26 | LOGS.info("You are running Javes [v1.2]") 27 | 28 | LOGS.info("Congratulations, javes is now running !!\ 29 | \nTest it by typing !javes in any chat.") 30 | 31 | if len(argv) not in (1, 3, 4): 32 | bot.disconnect() 33 | else: 34 | bot.run_until_disconnected() 35 | -------------------------------------------------------------------------------- /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, UnicodeText, Boolean, Integer, distinct, func 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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Pillow 2 | PyGithub 3 | aiofiles 4 | aiohttp 5 | aria2p 6 | async_generator 7 | beautifulsoup4 8 | bs4 9 | bwb 10 | cfscrape 11 | coffeehouse 12 | cowpy 13 | dnspython 14 | covid 15 | emoji 16 | telethon 17 | gTTS-token 18 | gTTS 19 | gitpython 20 | google-api-python-client 21 | google-auth-oauthlib 22 | google_images_download 23 | googletrans 24 | gsearch 25 | hachoir 26 | heroku3 27 | httplib2 28 | humanize 29 | lxml 30 | oauth2client 31 | psycopg2 32 | psycopg2-binary 33 | pySmartDL 34 | pybase64 35 | pyfiglet 36 | pylast 37 | pymongo 38 | python-barcode 39 | python-dotenv 40 | python-magic 41 | pytube 42 | pytz 43 | qrcode 44 | regex 45 | requests 46 | search-engine-parser 47 | selenium 48 | speedtest-cli 49 | sqlalchemy 50 | telegraph 51 | asyncurban 52 | urbandict 53 | wikipedia 54 | youtube-dl 55 | aiohttp 56 | aria2p 57 | async_generator 58 | bs4 59 | cowpy 60 | # cryptg 61 | cffi 62 | dnspython 63 | emoji 64 | gitpython 65 | google-api-python-client 66 | google-auth-oauthlib 67 | googletrans 68 | google_images_download 69 | gTTS 70 | gTTS-token 71 | hachoir 72 | heroku 73 | heroku3 74 | httplib2 75 | humanize 76 | lxml 77 | lyricsgenius 78 | oauth2client 79 | Pillow 80 | psycopg2 81 | psycopg2-binary 82 | pybase64 83 | pyfiglet 84 | pylast 85 | pySmartDL 86 | python-barcode 87 | python-dotenv 88 | youtube-dl 89 | pytz 90 | qrcode 91 | requests 92 | search-engine-parser 93 | speedtest-cli 94 | sqlalchemy 95 | 96 | telegraph 97 | PyGithub 98 | python-dateutil 99 | -------------------------------------------------------------------------------- /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, UnicodeText, LargeBinary, Numeric 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/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 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # We're using Alpine Edge 2 | FROM alpine:edge 3 | 4 | # We have to uncomment Community repo for some packages 5 | RUN sed -e 's;^#http\(.*\)/edge/community;http\1/edge/community;g' -i /etc/apk/repositories 6 | 7 | # install ca-certificates so that HTTPS works consistently 8 | # other runtime dependencies for Python are installed later 9 | RUN apk add --no-cache ca-certificates 10 | RUN apk add --no-cache g++ freetype-dev jpeg-dev 11 | RUN apk add nodejs 12 | 13 | # Installing Packages 14 | RUN apk add --no-cache \ 15 | bash \ 16 | build-base \ 17 | bzip2-dev \ 18 | curl \ 19 | coreutils \ 20 | figlet \ 21 | gcc \ 22 | g++ \ 23 | git \ 24 | aria2 \ 25 | util-linux \ 26 | libevent \ 27 | libjpeg-turbo-dev \ 28 | chromium \ 29 | chromium-chromedriver \ 30 | jpeg-dev \ 31 | libc-dev \ 32 | libffi-dev \ 33 | libpq \ 34 | libwebp-dev \ 35 | libxml2-dev \ 36 | libxslt-dev \ 37 | linux-headers \ 38 | musl-dev \ 39 | neofetch \ 40 | openssl-dev \ 41 | postgresql-client \ 42 | postgresql-dev \ 43 | pv \ 44 | jq \ 45 | wget \ 46 | python3-dev \ 47 | readline-dev \ 48 | ffmpeg \ 49 | sqlite-dev \ 50 | sudo \ 51 | zlib-dev \ 52 | python-dev 53 | 54 | 55 | RUN python3 -m ensurepip \ 56 | && pip3 install --upgrade pip setuptools \ 57 | && rm -r /usr/lib/python*/ensurepip && \ 58 | if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi && \ 59 | if [[ ! -e /usr/bin/python ]]; then ln -sf /usr/bin/python3 /usr/bin/python; fi && \ 60 | rm -r /root/.cache 61 | 62 | # 63 | # Clone repo and prepare working directory 64 | RUN git clone https://github.com/rekcah-pavi/javes /root/userbot 65 | RUN mkdir /root/userbot/bin/ 66 | WORKDIR /root/userbot/ 67 | 68 | # 69 | # Copies session and config (if it exists) 70 | # 71 | COPY ./sample_config.env ./userbot.session* ./config.env* /root/userbot/ 72 | 73 | # 74 | # Install requirements 75 | # 76 | RUN pip3 install -r requirements.txt 77 | CMD ["python3","-m","userbot"] 78 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /sample_config.env: -------------------------------------------------------------------------------- 1 | # Remove this line first before doing anything 2 | ___________PLOX_______REMOVE_____THIS_____LINE__________=True 3 | 4 | # Get these from https://my.telegram.org/ 5 | API_KEY = "YOUR API KEY" 6 | API_HASH = "YOUR API HASH" 7 | 8 | # OpenWeather Map API Key for .weather command 9 | # Get from https://openweathermap.org/ 10 | OPEN_WEATHER_MAP_APPID = "" 11 | WEATHER_DEFCITY = "" 12 | 13 | # Location of ChromeDriver for .carbon module 14 | # Example for Linux Machines : "/usr/bin/chromedriver" 15 | CHROME_DRIVER = "" 16 | 17 | # Get this value by running python3 string_session.py locally 18 | STRING_SESSION = "" 19 | 20 | # Headless GoogleChrome location for .carbon module 21 | # Example for Linux Machines : "/usr/bin/chromium-browser" 22 | GOOGLE_CHROME_BIN = "" 23 | 24 | # OCR Space API Key for .ocr command 25 | # Get from https://ocr.space/ocrapi 26 | OCR_SPACE_API_KEY = "" 27 | 28 | # remove.bg API Key for .rbg command 29 | # Get from https://www.remove.bg/api 30 | REM_BG_API_KEY = "" 31 | 32 | # ChatID for the Log group 33 | # Add a Hypen or a Negative Sign before ID 34 | # This is a integer, Please don't use Strings 35 | BOTLOG_CHATID = # this is an integer, please don't use quotes. 36 | 37 | # Incase you want to turn off logging, put this to false 38 | BOTLOG = True 39 | 40 | # Set this to True if you want the error logs to be stored in 41 | # the userbot log, rather than spamming other chats with it. 42 | # Note that this requires a valid BOTLOG_CHATID to be set. 43 | LOGSPAMMER = True 44 | 45 | # If you need Verbosity on the Logging 46 | CONSOLE_LOGGER_VERBOSE = False 47 | 48 | # PM Auto-Ban Feature Switch 49 | PM_AUTO_BAN = False 50 | 51 | # Custom Default name for .alive 52 | ALIVE_NAME = None 53 | 54 | # Your Database URL 55 | # Example: 'postgres://userbot:userbot@localhost:5432/userbot' 56 | DATABASE_URL = "" 57 | 58 | # YouTube Data API Key for .yt command 59 | # Get from https://console.cloud.google.com 60 | YOUTUBE_API_KEY = "" 61 | 62 | # Country and Time Zone setup for 63 | # .time and .date modules 64 | COUNTRY = "" 65 | TZ_NUMBER = # this is an integer, please don't use quotes. 66 | 67 | # Google Drive Credentials 68 | # for .gdrive module. 69 | # Get from https://console.cloud.google.com 70 | G_DRIVE_CLIENT_ID = "" 71 | G_DRIVE_CLIENT_SECRET = "" 72 | G_DRIVE_AUTH_TOKEN_DATA = "" 73 | TEMP_DOWNLOAD_DIRECTORY = "" 74 | 75 | # You have to have your own unique two values for API_KEY and API_SECRET 76 | # Obtain yours from https://www.last.fm/api/account/create for Last.fm 77 | LASTFM_API = None 78 | LASTFM_SECRET = None 79 | LASTFM_USERNAME = None # Your last.fm username 80 | LASTFM_PASSWORD = "Your last.fm password" 81 | 82 | # Bot will add before song name. For last.fm module. 83 | # Example: GitHub: MacTavishAO : Skillet - Feel Invincible 84 | BIO_PREFIX = "" 85 | 86 | # default bio message 87 | DEFAULT_BIO = "" 88 | 89 | # Report or kick some known spammer bots after 90 | # they joins 91 | ANTI_SPAMBOT = False 92 | ANTI_SPAMBOT_SHOUT = False 93 | -------------------------------------------------------------------------------- /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, UnicodeText, Numeric, String 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(BlackListFilters).get((str(chat_id), trigger)) 46 | if blacklist_filt: 47 | if trigger in CHAT_BLACKLISTS.get(str(chat_id), set()): # sanity check 48 | CHAT_BLACKLISTS.get(str(chat_id), set()).remove(trigger) 49 | 50 | SESSION.delete(blacklist_filt) 51 | SESSION.commit() 52 | return True 53 | 54 | SESSION.close() 55 | return False 56 | 57 | 58 | def get_chat_blacklist(chat_id): 59 | return CHAT_BLACKLISTS.get(str(chat_id), set()) 60 | 61 | 62 | def num_blacklist_filters(): 63 | try: 64 | return SESSION.query(BlackListFilters).count() 65 | finally: 66 | SESSION.close() 67 | 68 | 69 | def num_blacklist_chat_filters(chat_id): 70 | try: 71 | return SESSION.query(BlackListFilters.chat_id).filter(BlackListFilters.chat_id == str(chat_id)).count() 72 | finally: 73 | SESSION.close() 74 | 75 | 76 | def num_blacklist_filter_chats(): 77 | try: 78 | return SESSION.query(func.count(distinct(BlackListFilters.chat_id))).scalar() 79 | finally: 80 | SESSION.close() 81 | 82 | 83 | def __load_chat_blacklists(): 84 | global CHAT_BLACKLISTS 85 | try: 86 | chats = SESSION.query(BlackListFilters.chat_id).distinct().all() 87 | for (chat_id,) in chats: # remove tuple by ( ,) 88 | CHAT_BLACKLISTS[chat_id] = [] 89 | 90 | all_filters = SESSION.query(BlackListFilters).all() 91 | for x in all_filters: 92 | CHAT_BLACKLISTS[x.chat_id] += [x.trigger] 93 | 94 | CHAT_BLACKLISTS = {x: set(y) for x, y in CHAT_BLACKLISTS.items()} 95 | 96 | finally: 97 | SESSION.close() 98 | 99 | 100 | __load_chat_blacklists() 101 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | RAPHIELSCAPE PUBLIC LICENSE 2 | Version 1.c, June 2019 3 | 4 | Copyright (C) 2019 Raphielscape LLC. 5 | Copyright (C) 2019 Devscapes Open Source Holding GmbH. 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | RAPHIELSCAPE PUBLIC LICENSE 12 | A-1. DEFINITIONS 13 | 14 | 0. “This License” refers to version 1.c of the Raphielscape Public License. 15 | 16 | 1. “Copyright” also means copyright-like laws that apply to other kinds of works. 17 | 18 | 2. “The Work" refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. 19 | “Licensees” and “recipients” may be individuals or organizations. 20 | 21 | 3. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, 22 | other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work 23 | or a work “based on” the earlier work. 24 | 25 | 4. Source Form. The “source form” for a work means the preferred form of the work for making modifications to it. 26 | “Object code” means any non-source form of a work. 27 | 28 | The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and 29 | (for an executable work) run the object code and to modify the work, including scripts to control those activities. 30 | 31 | The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. 32 | The Corresponding Source for a work in source code form is that same work. 33 | 34 | 5. "The author" refers to "author" of the code, which is the one that made the particular code which exists inside of 35 | the Corresponding Source. 36 | 37 | 6. "Owner" refers to any parties which is made the early form of the Corresponding Source. 38 | 39 | A-2. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 40 | 41 | 0. You must give any other recipients of the Work or Derivative Works a copy of this License; and 42 | 43 | 1. You must cause any modified files to carry prominent notices stating that You changed the files; and 44 | 45 | 2. You must retain, in the Source form of any Derivative Works that You distribute, 46 | this license, all copyright, patent, trademark, authorships and attribution notices 47 | from the Source form of the Work; and 48 | 49 | 3. Respecting the author and owner of works that are distributed in any way. 50 | 51 | You may add Your own copyright statement to Your modifications and may provide 52 | additional or different license terms and conditions for use, reproduction, 53 | or distribution of Your modifications, or for any such Derivative Works as a whole, 54 | provided Your use, reproduction, and distribution of the Work otherwise complies 55 | with the conditions stated in this License. 56 | 57 | B. DISCLAIMER OF WARRANTY 58 | 59 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 60 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 61 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 62 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 63 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 64 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 65 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 66 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 67 | 68 | 69 | C. REVISED VERSION OF THIS LICENSE 70 | 71 | The Devscapes Open Source Holding GmbH. may publish revised and/or new versions of the 72 | Raphielscape Public License from time to time. Such new versions will be similar in spirit 73 | to the present version, but may differ in detail to address new problems or concerns. 74 | 75 | Each version is given a distinguishing version number. If the Program specifies that a 76 | certain numbered version of the Raphielscape Public License "or any later version" applies to it, 77 | you have the option of following the terms and conditions either of that numbered version or of 78 | any later version published by the Devscapes Open Source Holding GmbH. If the Program does not specify a 79 | version number of the Raphielscape Public License, you may choose any version ever published 80 | by the Devscapes Open Source Holding GmbH. 81 | 82 | END OF LICENSE 83 | -------------------------------------------------------------------------------- /userbot/events.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import sys 4 | from asyncio import create_subprocess_shell as asyncsubshell 5 | from asyncio import subprocess as asyncsub 6 | from os import remove 7 | from time import gmtime, strftime 8 | from traceback import format_exc 9 | 10 | from telethon import events 11 | 12 | from userbot import bot, BOTLOG_CHATID, LOGSPAMMER 13 | 14 | 15 | def javes05(**args): 16 | """ Register a new event. """ 17 | pattern = args.get('pattern', None) 18 | disable_edited = args.get('disable_edited', False) 19 | groups_only = args.get('groups_only', False) 20 | trigger_on_fwd = args.get('trigger_on_fwd', False) 21 | disable_errors = args.get('disable_errors', False) 22 | 23 | if pattern is not None and not pattern.startswith('(?i)'): 24 | args['pattern'] = '(?i)' + pattern 25 | 26 | if "disable_edited" in args: 27 | del args['disable_edited'] 28 | 29 | if "groups_only" in args: 30 | del args['groups_only'] 31 | 32 | if "disable_errors" in args: 33 | del args['disable_errors'] 34 | 35 | if "trigger_on_fwd" in args: 36 | del args['trigger_on_fwd'] 37 | 38 | def decorator(func): 39 | async def wrapper(check): 40 | if LOGSPAMMER: 41 | send_to = BOTLOG_CHATID 42 | 43 | if not trigger_on_fwd and check.fwd_from: 44 | return 45 | 46 | if groups_only and not check.is_group: 47 | await check.respond("`I don't think this is a group.`") 48 | return 49 | 50 | try: 51 | await func(check) 52 | 53 | # Thanks to @kandnub for this HACK. 54 | # Raise StopPropagation to Raise StopPropagation 55 | # This needed for AFK to working properly 56 | 57 | except events.StopPropagation: 58 | raise events.StopPropagation 59 | # This is a gay exception and must be passed out. So that it doesnt spam chats 60 | except KeyboardInterrupt: 61 | pass 62 | except BaseException: 63 | 64 | # Check if we have to disable it. 65 | # If not silence the log spam on the console, 66 | # with a dumb except. 67 | 68 | if not disable_errors: 69 | date = strftime("%Y-%m-%d %H:%M:%S", gmtime()) 70 | 71 | text = "**JAVES ERROR REPORT**\n" 72 | text += "Send this to @rekcah05 if you cant find issue\n" 73 | 74 | ftext = "========== DISCLAIMER ==========" 75 | ftext += "\nThis file uploaded ONLY here," 76 | ftext += "\nyou may not report this error if you've" 77 | ftext += "\nany confidential data here, no one will see your data\n" 78 | ftext += "================================\n\n" 79 | ftext += "--------BEGIN USERBOT TRACEBACK LOG--------\n" 80 | ftext += "\nDate: " + date 81 | ftext += "\nChat ID: " + str(check.chat_id) 82 | ftext += "\nSender ID: " + str(check.sender_id) 83 | ftext += "\n\nEvent Trigger:\n" 84 | ftext += str(check.text) 85 | ftext += "\n\nTraceback info:\n" 86 | ftext += str(format_exc()) 87 | ftext += "\n\nError text:\n" 88 | ftext += str(sys.exc_info()[1]) 89 | ftext += "\n\n--------END USERBOT TRACEBACK LOG--------" 90 | 91 | command = "git log --pretty=format:\"%an: %s\" -10" 92 | 93 | ftext += "\n\n\nLast 10 commits:\n" 94 | 95 | process = await asyncsubshell(command, 96 | stdout=asyncsub.PIPE, 97 | stderr=asyncsub.PIPE) 98 | stdout, stderr = await process.communicate() 99 | result = str(stdout.decode().strip()) \ 100 | + str(stderr.decode().strip()) 101 | 102 | ftext += result 103 | 104 | file = open("error.log", "w+") 105 | file.write(ftext) 106 | file.close() 107 | 108 | if LOGSPAMMER: 109 | await check.respond("`Error 4O4`") 110 | 111 | await check.client.send_file(send_to, 112 | "error.log", 113 | caption=text) 114 | remove("error.log") 115 | else: 116 | pass 117 | 118 | if not disable_edited: 119 | bot.add_event_handler(wrapper, events.MessageEdited(**args)) 120 | bot.add_event_handler(wrapper, events.NewMessage(**args)) 121 | return wrapper 122 | 123 | return decorator 124 | 125 | 126 | -------------------------------------------------------------------------------- /userbot/modules/sql_helper/warns_sql.py: -------------------------------------------------------------------------------- 1 | 2 | try: 3 | from userbot.modules.sql_helper import SESSION, BASE 4 | except ImportError: 5 | raise AttributeError 6 | 7 | from sqlalchemy import Column, String 8 | import threading 9 | from sqlalchemy import Integer, Column, String, UnicodeText, func, distinct, Boolean 10 | import os 11 | import asyncio 12 | 13 | import qrcode 14 | import barcode 15 | from barcode.writer import ImageWriter 16 | 17 | 18 | class Warns(BASE): 19 | __tablename__ = "warns" 20 | 21 | user_id = Column(Integer, primary_key=True) 22 | chat_id = Column(String(14), primary_key=True) 23 | num_warns = Column(Integer, default=0) 24 | reasons = Column(UnicodeText) 25 | 26 | def __init__(self, user_id, chat_id): 27 | self.user_id = user_id 28 | self.chat_id = str(chat_id) 29 | self.num_warns = 0 30 | self.reasons = "" 31 | 32 | def __repr__(self): 33 | return "<{} warns for {} in {} for reasons {}>".format(self.num_warns, self.user_id, self.chat_id, self.reasons) 34 | 35 | 36 | class WarnSettings(BASE): 37 | __tablename__ = "warn_settings" 38 | chat_id = Column(String(14), primary_key=True) 39 | warn_limit = Column(Integer, default=3) 40 | soft_warn = Column(Boolean, default=False) 41 | 42 | def __init__(self, chat_id, warn_limit=3, soft_warn=False): 43 | self.chat_id = str(chat_id) 44 | self.warn_limit = warn_limit 45 | self.soft_warn = soft_warn 46 | 47 | def __repr__(self): 48 | return "<{} has {} possible warns.>".format(self.chat_id, self.warn_limit) 49 | 50 | 51 | 52 | Warns.__table__.create(checkfirst=True) 53 | WarnSettings.__table__.create(checkfirst=True) 54 | 55 | 56 | WARN_INSERTION_LOCK = threading.RLock() 57 | WARN_SETTINGS_LOCK = threading.RLock() 58 | 59 | 60 | def warn_user(user_id, chat_id, reason=None): 61 | with WARN_INSERTION_LOCK: 62 | warned_user = SESSION.query(Warns).get((user_id, str(chat_id))) 63 | if not warned_user: 64 | warned_user = Warns(user_id, str(chat_id)) 65 | 66 | warned_user.num_warns += 1 67 | if reason: 68 | warned_user.reasons = warned_user.reasons + "\r\n\r\n" + reason # TODO:: double check this wizardry 69 | 70 | reasons = warned_user.reasons 71 | num = warned_user.num_warns 72 | 73 | SESSION.add(warned_user) 74 | SESSION.commit() 75 | 76 | return num, reasons 77 | 78 | 79 | def remove_warn(user_id, chat_id): 80 | with WARN_INSERTION_LOCK: 81 | removed = False 82 | warned_user = SESSION.query(Warns).get((user_id, str(chat_id))) 83 | 84 | if warned_user and warned_user.num_warns > 0: 85 | warned_user.num_warns -= 1 86 | 87 | SESSION.add(warned_user) 88 | SESSION.commit() 89 | removed = True 90 | 91 | SESSION.close() 92 | return removed 93 | 94 | 95 | def reset_warns(user_id, chat_id): 96 | with WARN_INSERTION_LOCK: 97 | warned_user = SESSION.query(Warns).get((user_id, str(chat_id))) 98 | if warned_user: 99 | warned_user.num_warns = 0 100 | warned_user.reasons = "" 101 | 102 | SESSION.add(warned_user) 103 | SESSION.commit() 104 | SESSION.close() 105 | 106 | 107 | def get_warns(user_id, chat_id): 108 | try: 109 | user = SESSION.query(Warns).get((user_id, str(chat_id))) 110 | if not user: 111 | return None 112 | reasons = user.reasons 113 | num = user.num_warns 114 | return num, reasons 115 | finally: 116 | SESSION.close() 117 | 118 | 119 | def set_warn_limit(chat_id, warn_limit): 120 | with WARN_SETTINGS_LOCK: 121 | curr_setting = SESSION.query(WarnSettings).get(str(chat_id)) 122 | if not curr_setting: 123 | curr_setting = WarnSettings(chat_id, warn_limit=warn_limit) 124 | 125 | curr_setting.warn_limit = warn_limit 126 | 127 | SESSION.add(curr_setting) 128 | SESSION.commit() 129 | 130 | 131 | def set_warn_strength(chat_id, soft_warn): 132 | with WARN_SETTINGS_LOCK: 133 | curr_setting = SESSION.query(WarnSettings).get(str(chat_id)) 134 | if not curr_setting: 135 | curr_setting = WarnSettings(chat_id, soft_warn=soft_warn) 136 | 137 | curr_setting.soft_warn = soft_warn 138 | 139 | SESSION.add(curr_setting) 140 | SESSION.commit() 141 | 142 | 143 | def get_warn_setting(chat_id): 144 | try: 145 | setting = SESSION.query(WarnSettings).get(str(chat_id)) 146 | if setting: 147 | return setting.warn_limit, setting.soft_warn 148 | else: 149 | return 3, False 150 | 151 | finally: 152 | SESSION.close() 153 | 154 | 155 | def num_warns(): 156 | try: 157 | return SESSION.query(func.sum(Warns.num_warns)).scalar() or 0 158 | finally: 159 | SESSION.close() 160 | 161 | 162 | def num_warn_chats(): 163 | try: 164 | return SESSION.query(func.count(distinct(Warns.chat_id))).scalar() 165 | finally: 166 | SESSION.close() 167 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Javes", 3 | "description": "Javes is a Telegram userbot that running on Python , It help you to manage your telegram easily ", 4 | "logo": "https://i.imgur.com/ATSG4w3.png", 5 | "keywords": [ 6 | "telegram", 7 | "userbot", 8 | "plugin", 9 | "modular", 10 | "productivity" 11 | ], 12 | "repository": "https://github.com/rekcah-pavi/javes", 13 | "website": "https://t.me/javes05", 14 | "success_url": "https://t.me/rekcah05", 15 | "stack": "container", 16 | "env": { 17 | "TELEGRAM_API_KEY": { 18 | "description": "Get this value from my.telegram.org." 19 | }, 20 | "TELEGRAM_API_HASH": { 21 | "description": "Get this value from my.telegram.org." 22 | }, 23 | "TELEGRAM_STRING_SESSION": { 24 | "description": "Get this value by running [python3 string_session.py] in Termux or heroku" 25 | }, 26 | "HEROKU_APIKEY": { 27 | "description": "very inportant for !update command to make javes up-to-date , get it from 'https://dashboard.heroku.com/account.", 28 | "value": "" 29 | }, 30 | "HEROKU_APPNAME": { 31 | "description": "enter this app name agin here, very inportant for !update comand to make javes up-to-date ,", 32 | "value": "" 33 | 34 | }, 35 | "GENIUS_API_TOKEN": { 36 | "description": "need for !lyrics comand , Get your own api token from https://genius.com/developers", 37 | "required": false, 38 | "value": "Enter genius api here if you need " 39 | 40 | 41 | }, 42 | "COUNTRY": { 43 | "description": "Set your Country to be used in the .time and .date commands.", 44 | "value": "Sri Lanka", 45 | "required": false 46 | }, 47 | "TZ_NUMBER": { 48 | "description": "Change this value in case your country has multiple Time Zones.", 49 | "value": "1", 50 | "required": false 51 | }, 52 | "CHROME_DRIVER": { 53 | "description": "ChromeDriver location for selenium based modules.", 54 | "value": "/usr/bin/chromedriver", 55 | "required": false 56 | }, 57 | "GOOGLE_CHROME_BIN": { 58 | "description": "Google Chrome (or) Chromium binary location for selenium based modules.", 59 | "value": "/usr/bin/chromium-browser", 60 | "required": false 61 | }, 62 | "OPEN_WEATHER_MAP_APPID": { 63 | "description": "need for !weather command, (API key)from https://api.openweathermap.org", 64 | "value": "Enter api here if you need ", 65 | "required": false 66 | 67 | }, 68 | "BOTLOG": { 69 | "description": "Recommed to true ,BOTLOG_CHATID must be filled correct if you set it true", 70 | "value": "False" 71 | }, 72 | "BOTLOG_CHATID": { 73 | "description": "important for wark some plugins,bot logs , make super group with @missrose_bot then type /id to get this value", 74 | "value": "0" 75 | }, 76 | "CONSOLE_LOGGER_VERBOSE": { 77 | "description": "BOTLOG_CHATID must be filled correct if you set it true", 78 | "value": "False" 79 | }, 80 | "PM_PROTECTOR": { 81 | "description": "Prevent unknown people to spam your pm , type !allow to allow them to pm", 82 | "value": "true" 83 | }, 84 | "YOUTUBE_API_KEY": { 85 | "description": "YouTube Data API Key for !youtube command. Get from https://console.cloud.google.com", 86 | "value": "Enter api here if you need ", 87 | "required": false 88 | }, 89 | "OCR_SPACE_API_KEY": { 90 | "description": "OCR API Key for !read (read photo's text)command. Get from https://ocr.space/ocrapi", 91 | "value": "Enter api here if you need ", 92 | "required": false 93 | }, 94 | "REM_BG_API_KEY": { 95 | "description": "API Key for .rbg(remove background picture) command. Get from https://www.remove.bg/api", 96 | "value": "Enter api here if you need ", 97 | "required": false 98 | }, 99 | "ANTI_SPAMBOT": { 100 | "description": "BOTLOG_CHATID must be filled correct if you set it true", 101 | "value": "False" 102 | }, 103 | "ANTI_SPAMBOT_SHOUT": { 104 | "description": "BOTLOG_CHATID must be filled correct if you set it true", 105 | "value": "False" 106 | }, 107 | "TMP_DOWNLOAD_DIRECTORY": { 108 | "description": "for use GDrive, .download etc..)", 109 | "value": "./downloads/" 110 | }, 111 | "CLEAN_WELCOME": { 112 | "description": "When a new person joins, the old welcome message is deleted.", 113 | "value": "True" 114 | }, 115 | "G_DRIVE_CLIENT_ID": { 116 | "description": "Enter Your Client ID for Google Drive.", 117 | "value": "Enter vlaue here if you need ", 118 | "required": false 119 | }, 120 | "LASTFM_API": { 121 | "description": "API Key for Last.FM module. [Get one from - https://www.last.fm/api/account/create].", 122 | "value": "Enter api here if you need ", 123 | "required": false 124 | }, 125 | "LASTFM_SECRET": { 126 | "description": "SECRET Key for Last.FM module. [Get one from - https://www.last.fm/api/account/create].", 127 | "value": "Enter vlaue here if you need ", 128 | "required": false 129 | 130 | }, 131 | "DEFAULT_BIO": { 132 | "description": "Default profile bio.", 133 | "value": "Hi there iam using Javes yoooo!", 134 | "required": false 135 | }, 136 | "YOUR_SHORT_NAME": { 137 | "description": "Name to show in !javes message,less then 5 letters recommed :p", 138 | "value": "your name", 139 | "required": true 140 | }, 141 | "G_DRIVE_CLIENT_SECRET": { 142 | "description": "Enter Your Client Secret for Google Drive.", 143 | "required": false 144 | }, 145 | "G_DRIVE_AUTH_TOKEN_DATA": { 146 | "description": "Enter the Google Drive authentication data, as a JSON structure.", 147 | "required": false 148 | }, 149 | "WEATHER_DEFCITY": { 150 | "description": "Set the default city for the userbot's !weather module.", 151 | "value": "enter your city ", 152 | "required": false 153 | }, 154 | "LOGSPAMMER": { 155 | "description": "BOTLOG_CHATID must be filled correct if you set it true", 156 | "value": "false" 157 | } 158 | }, 159 | "addons": [ 160 | { 161 | "plan": "heroku-postgresql", 162 | "options": { 163 | "version": "9.5" 164 | } 165 | } 166 | ] 167 | } 168 | -------------------------------------------------------------------------------- /userbot/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ Userbot initialization. """ 3 | 4 | import os 5 | 6 | from sys import version_info 7 | from logging import basicConfig, getLogger, INFO, DEBUG 8 | from distutils.util import strtobool as sb 9 | 10 | from pylast import LastFMNetwork, md5 11 | from pySmartDL import SmartDL 12 | from dotenv import load_dotenv 13 | from requests import get 14 | from telethon import TelegramClient 15 | from telethon.sessions import StringSession 16 | 17 | load_dotenv("config.env") 18 | 19 | # Bot Logs setup: 20 | CONSOLE_LOGGER_VERBOSE = sb(os.environ.get("CONSOLE_LOGGER_VERBOSE", "False")) 21 | 22 | if CONSOLE_LOGGER_VERBOSE: 23 | basicConfig( 24 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", 25 | level=DEBUG, 26 | ) 27 | else: 28 | basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", 29 | level=INFO) 30 | LOGS = getLogger(__name__) 31 | 32 | if version_info[0] < 3 or version_info[1] < 6: 33 | LOGS.info("You MUST have a python version of at least 3.6." 34 | "Multiple features depend on this. Bot quitting.") 35 | quit(1) 36 | 37 | # Check if the config was edited by using the already used variable. 38 | # Basically, its the 'virginity check' for the config file ;) 39 | CONFIG_CHECK = os.environ.get( 40 | "___________PLOX_______REMOVE_____THIS_____LINE__________", None) 41 | 42 | if CONFIG_CHECK: 43 | LOGS.info( 44 | "Please remove the line mentioned in the first hashtag from the config.env file" 45 | ) 46 | quit(1) 47 | 48 | # Telegram App KEY and HASH 49 | API_KEY = os.environ.get("TELEGRAM_API_KEY", None) 50 | API_HASH = os.environ.get("TELEGRAM_API_HASH", None) 51 | 52 | # Userbot Session String 53 | STRING_SESSION = os.environ.get("TELEGRAM_STRING_SESSION", None) 54 | 55 | # Logging channel/group ID configuration. 56 | BOTLOG_CHATID = int(os.environ.get("BOTLOG_CHATID", None)) 57 | 58 | # Userbot logging feature switch. 59 | BOTLOG = sb(os.environ.get("BOTLOG", "False")) 60 | LOGSPAMMER = sb(os.environ.get("LOGSPAMMER", "False")) 61 | 62 | # Genius lyrics API Token 63 | GENIUS = os.environ.get("GENIUS_API_TOKEN", None) 64 | GENIUS_API_TOKEN = os.environ.get("GENIUS_API_TOKEN", None) 65 | 66 | # Bleep Blop, this is a bot ;) 67 | PM_AUTO_BAN = sb(os.environ.get("PM_PROTECTOR", "True")) 68 | 69 | # Heroku Credentials for updater. 70 | HEROKU_APPNAME = os.environ.get("HEROKU_APPNAME", None) 71 | HEROKU_APP_NAME = os.environ.get("HEROKU_APPNAME", None) 72 | HEROKU_APIKEY = os.environ.get("HEROKU_APIKEY", None) 73 | HEROKU_API_KEY = os.environ.get("HEROKU_APIKEY", None) 74 | 75 | 76 | UPSTREAM_REPO_URL = os.environ.get( 77 | "UPSTREAM_REPO_URL", 78 | "https://github.com/rekcah-pavi/javes") 79 | 80 | 81 | TELEGRAPH_SHORT_NAME = os.environ.get( 82 | "TELEGRAPH_SHORT_NAME", 83 | "Javes") 84 | 85 | # Console verbose logging 86 | CONSOLE_LOGGER_VERBOSE = sb(os.environ.get("CONSOLE_LOGGER_VERBOSE", "False")) 87 | 88 | # SQL Database URI 89 | DB_URI = os.environ.get("DATABASE_URL", None) 90 | 91 | # OCR API key 92 | OCR_SPACE_API_KEY = os.environ.get("OCR_SPACE_API_KEY", None) 93 | 94 | # remove.bg API key 95 | REM_BG_API_KEY = os.environ.get("REM_BG_API_KEY", None) 96 | 97 | # Chrome Driver and Headless Google Chrome Binaries 98 | CHROME_DRIVER = os.environ.get("CHROME_DRIVER", None) 99 | GOOGLE_CHROME_BIN = os.environ.get("GOOGLE_CHROME_BIN", None) 100 | 101 | # OpenWeatherMap API Key 102 | OPEN_WEATHER_MAP_APPID = os.environ.get("OPEN_WEATHER_MAP_APPID", None) 103 | WEATHER_DEFCITY = os.environ.get("WEATHER_DEFCITY", None) 104 | 105 | # Anti Spambot Config 106 | ANTI_SPAMBOT = sb(os.environ.get("ANTI_SPAMBOT", "False")) 107 | ANTI_SPAMBOT_SHOUT = sb(os.environ.get("ANTI_SPAMBOT_SHOUT", "False")) 108 | 109 | # Youtube API key 110 | YOUTUBE_API_KEY = os.environ.get("YOUTUBE_API_KEY", None) 111 | 112 | # Default .alive name 113 | ALIVE_NAME = os.environ.get("YOUR_SHORT_NAME", None) 114 | 115 | 116 | 117 | # Time & Date - Country and Time Zone 118 | COUNTRY = str(os.environ.get("COUNTRY", "")) 119 | TZ_NUMBER = int(os.environ.get("TZ_NUMBER", 1)) 120 | 121 | # Clean Welcome 122 | CLEAN_WELCOME = sb(os.environ.get("CLEAN_WELCOME", "True")) 123 | 124 | # Last.fm Module 125 | BIO_PREFIX = os.environ.get("BIO_PREFIX", None) 126 | DEFAULT_BIO = os.environ.get("DEFAULT_BIO", None) 127 | 128 | LASTFM_API = os.environ.get("LASTFM_API", None) 129 | LASTFM_SECRET = os.environ.get("LASTFM_SECRET", None) 130 | LASTFM_USERNAME = os.environ.get("LASTFM_USERNAME", None) 131 | LASTFM_PASSWORD_PLAIN = os.environ.get("LASTFM_PASSWORD", None) 132 | LASTFM_PASS = md5(LASTFM_PASSWORD_PLAIN) 133 | if LASTFM_API and LASTFM_SECRET and LASTFM_USERNAME and LASTFM_PASS: 134 | lastfm = LastFMNetwork(api_key=LASTFM_API, 135 | api_secret=LASTFM_SECRET, 136 | username=LASTFM_USERNAME, 137 | password_hash=LASTFM_PASS) 138 | else: 139 | lastfm = None 140 | 141 | # Google Drive Module 142 | G_DRIVE_CLIENT_ID = os.environ.get("G_DRIVE_CLIENT_ID", None) 143 | G_DRIVE_CLIENT_SECRET = os.environ.get("G_DRIVE_CLIENT_SECRET", None) 144 | G_DRIVE_AUTH_TOKEN_DATA = os.environ.get("G_DRIVE_AUTH_TOKEN_DATA", None) 145 | GDRIVE_FOLDER_ID = os.environ.get("GDRIVE_FOLDER_ID", None) 146 | TEMP_DOWNLOAD_DIRECTORY = os.environ.get("TMP_DOWNLOAD_DIRECTORY", 147 | "./downloads") 148 | 149 | # Setting Up CloudMail.ru and MEGA.nz extractor binaries, 150 | # and giving them correct perms to work properly. 151 | if not os.path.exists('bin'): 152 | os.mkdir('bin') 153 | 154 | binaries = { 155 | "https://raw.githubusercontent.com/yshalsager/megadown/master/megadown": 156 | "bin/megadown", 157 | "https://raw.githubusercontent.com/yshalsager/cmrudl.py/master/cmrudl.py": 158 | "bin/cmrudl" 159 | } 160 | 161 | for binary, path in binaries.items(): 162 | downloader = SmartDL(binary, path, progress_bar=False) 163 | downloader.start() 164 | os.chmod(path, 0o755) 165 | 166 | # 'bot' variable 167 | if STRING_SESSION: 168 | # pylint: disable=invalid-name 169 | bot = TelegramClient(StringSession(STRING_SESSION), 170 | API_KEY, 171 | API_HASH, 172 | connection_retries=None, 173 | auto_reconnect=False, 174 | lang_code='en') 175 | else: 176 | # pylint: disable=invalid-name 177 | bot = TelegramClient("userbot", 178 | API_KEY, 179 | API_HASH, 180 | connection_retries=None, 181 | auto_reconnect=False, 182 | lang_code='en') 183 | 184 | 185 | async def check_botlog_chatid(): 186 | if not BOTLOG_CHATID and LOGSPAMMER: 187 | LOGS.info( 188 | "You must set up the BOTLOG_CHATID variable in the config.env or environment variables, for the private error log storage to work." 189 | ) 190 | quit(1) 191 | 192 | elif not BOTLOG_CHATID and BOTLOG: 193 | LOGS.info( 194 | "You must set up the BOTLOG_CHATID variable in the config.env or environment variables, for the userbot logging feature to work." 195 | ) 196 | quit(1) 197 | 198 | elif not BOTLOG or not LOGSPAMMER: 199 | return 200 | 201 | entity = await bot.get_entity(BOTLOG_CHATID) 202 | if not entity.creator: 203 | if entity.default_banned_rights.send_messages: 204 | LOGS.info( 205 | "Your account doesn't have rights to send messages to BOTLOG_CHATID " 206 | "group. Check if you typed the Chat ID correctly.") 207 | quit(1) 208 | 209 | 210 | with bot: 211 | try: 212 | bot.loop.run_until_complete(check_botlog_chatid()) 213 | except: 214 | LOGS.info( 215 | "BOTLOG_CHATID environment variable isn't a " 216 | "valid entity. Check your environment variables/config.env file.") 217 | quit(1) 218 | 219 | # Global Variables 220 | COUNT_MSG = 0 221 | USERS = {} 222 | COUNT_PM = {} 223 | LASTMSG = {} 224 | CMD_HELP = {} 225 | ISAFK = False 226 | AFKREASON = None 227 | -------------------------------------------------------------------------------- /userbot/modules/api.py: -------------------------------------------------------------------------------- 1 | import os 2 | import io 3 | import json 4 | from requests import get 5 | from datetime import datetime 6 | from pytz import country_timezones as c_tz 7 | from pytz import timezone as tz 8 | from pytz import country_names as c_n 9 | from userbot import CMD_HELP, WEATHER_DEFCITY 10 | from userbot import OPEN_WEATHER_MAP_APPID as OWM_API 11 | import requests 12 | from telethon.tl.types import MessageMediaPhoto 13 | from userbot import CMD_HELP, REM_BG_API_KEY, TEMP_DOWNLOAD_DIRECTORY 14 | import time 15 | from telethon import events 16 | import os 17 | import requests 18 | import logging 19 | from userbot import bot, OCR_SPACE_API_KEY, CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 20 | import asyncio 21 | import shutil 22 | from bs4 import BeautifulSoup 23 | import re 24 | from time import sleep 25 | from html import unescape 26 | from userbot.events import javes05 27 | from re import findall 28 | from selenium import webdriver 29 | from urllib.parse import quote_plus 30 | from urllib.error import HTTPError 31 | from selenium.webdriver.support.ui import Select 32 | from selenium.webdriver.chrome.options import Options 33 | from wikipedia import summary 34 | from wikipedia.exceptions import DisambiguationError, PageError 35 | import asyncurban 36 | from requests import get 37 | from search_engine_parser import GoogleSearch 38 | from google_images_download import google_images_download 39 | from googleapiclient.discovery import build 40 | from googleapiclient.errors import HttpError 41 | from googletrans import LANGUAGES, Translator 42 | from gtts import gTTS 43 | from gtts.lang import tts_langs 44 | from emoji import get_emoji_regexp 45 | from youtube_dl import YoutubeDL 46 | from youtube_dl.utils import (DownloadError, ContentTooShortError,ExtractorError, GeoRestrictedError,MaxDownloadsReached, PostProcessingError,UnavailableVideoError, XAttrMetadataError) 47 | from asyncio import sleep 48 | from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID, YOUTUBE_API_KEY, CHROME_DRIVER, GOOGLE_CHROME_BIN 49 | from telethon.tl.types import DocumentAttributeAudio 50 | from userbot.modules.system import progress, humanbytes, time_formatter 51 | 52 | 53 | @javes05(pattern=r"^\!read (.*)", outgoing=True) 54 | async def ocr(event): 55 | await event.edit("`Reading...`") 56 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 57 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 58 | lang_code = event.pattern_match.group(1) 59 | downloaded_file_name = await bot.download_media( 60 | await event.get_reply_message(), TEMP_DOWNLOAD_DIRECTORY) 61 | test_file = await ocr_space_file(filename=downloaded_file_name, 62 | language=lang_code) 63 | try: 64 | ParsedText = test_file["ParsedResults"][0]["ParsedText"] 65 | except BaseException: 66 | await event.edit("`Couldn't read it.`\n may ocr key missing Get from https://ocr.space/ocrapi") 67 | else: 68 | await event.edit(f"`Here's what I could read from it:`\n\n{ParsedText}" 69 | ) 70 | os.remove(downloaded_file_name) 71 | 72 | @javes05(outgoing=True, pattern="^\!rbg(?: |$)(.*)") 73 | async def kbg(remob): 74 | """ For .rbg command, Remove Image Background. """ 75 | if REM_BG_API_KEY is None: 76 | await remob.edit( 77 | "`Error: Remove.BG API key missing! Add it to environment vars or config.env.`" 78 | ) 79 | return 80 | input_str = remob.pattern_match.group(1) 81 | message_id = remob.message.id 82 | if remob.reply_to_msg_id: 83 | message_id = remob.reply_to_msg_id 84 | reply_message = await remob.get_reply_message() 85 | await remob.edit("`Processing..`") 86 | try: 87 | if isinstance( 88 | reply_message.media, MessageMediaPhoto 89 | ) or "image" in reply_message.media.document.mime_type.split('/'): 90 | downloaded_file_name = await remob.client.download_media( 91 | reply_message, TEMP_DOWNLOAD_DIRECTORY) 92 | await remob.edit("`Removing background from this image..`") 93 | output_file_name = await ReTrieveFile(downloaded_file_name) 94 | os.remove(downloaded_file_name) 95 | else: 96 | await remob.edit("`How do I remove the background from this ?`" 97 | ) 98 | except Exception as e: 99 | await remob.edit(str(e)) 100 | return 101 | elif input_str: 102 | await remob.edit( 103 | f"`Removing background from online image hosted at`\n{input_str}") 104 | output_file_name = await ReTrieveURL(input_str) 105 | else: 106 | await remob.edit("`I need something to remove the background from.`") 107 | return 108 | contentType = output_file_name.headers.get("content-type") 109 | if "image" in contentType: 110 | with io.BytesIO(output_file_name.content) as remove_bg_image: 111 | remove_bg_image.name = "removed_bg.png" 112 | await remob.client.send_file( 113 | remob.chat_id, 114 | remove_bg_image, 115 | caption="Background removed using remove.bg", 116 | force_document=True, 117 | reply_to=message_id) 118 | await remob.delete() 119 | else: 120 | await remob.edit("**Error (Invalid API key, I guess ?)**\n`{}`".format( 121 | output_file_name.content.decode("UTF-8"))) 122 | 123 | 124 | # this method will call the API, and return in the appropriate format 125 | # with the name provided. 126 | async def ReTrieveFile(input_file_name): 127 | headers = { 128 | "X-API-Key": REM_BG_API_KEY, 129 | } 130 | files = { 131 | "image_file": (input_file_name, open(input_file_name, "rb")), 132 | } 133 | r = requests.post("https://api.remove.bg/v1.0/removebg", 134 | headers=headers, 135 | files=files, 136 | allow_redirects=True, 137 | stream=True) 138 | return r 139 | 140 | 141 | async def ReTrieveURL(input_url): 142 | headers = { 143 | "X-API-Key": REM_BG_API_KEY, 144 | } 145 | data = {"image_url": input_url} 146 | r = requests.post("https://api.remove.bg/v1.0/removebg", 147 | headers=headers, 148 | data=data, 149 | allow_redirects=True, 150 | stream=True) 151 | return r 152 | 153 | 154 | # ===== CONSTANT ===== 155 | if WEATHER_DEFCITY: 156 | DEFCITY = WEATHER_DEFCITY 157 | else: 158 | DEFCITY = None 159 | # ==================== 160 | 161 | 162 | async def get_tz(con): 163 | """ Get time zone of the given country. """ 164 | """ Credits: @aragon12 and @zakaryan2004. """ 165 | for c_code in c_n: 166 | if con == c_n[c_code]: 167 | return tz(c_tz[c_code][0]) 168 | try: 169 | if c_n[con]: 170 | return tz(c_tz[con][0]) 171 | except KeyError: 172 | return 173 | 174 | 175 | @javes05(outgoing=True, pattern="^!weather(?: |$)(.*)") 176 | async def get_weather(weather): 177 | """ For .weather command, gets the current weather of a city. """ 178 | 179 | if not OWM_API: 180 | await weather.edit( 181 | "`Get an API key from` https://openweathermap.org/ `first.`") 182 | return 183 | 184 | APPID = OWM_API 185 | 186 | if not weather.pattern_match.group(1): 187 | CITY = DEFCITY 188 | if not CITY: 189 | await weather.edit( 190 | "`Please specify a city or set one as default using the WEATHER_DEFCITY config variable.`" 191 | ) 192 | return 193 | else: 194 | CITY = weather.pattern_match.group(1) 195 | 196 | timezone_countries = { 197 | timezone: country 198 | for country, timezones in c_tz.items() for timezone in timezones 199 | } 200 | 201 | if "," in CITY: 202 | newcity = CITY.split(",") 203 | if len(newcity[1]) == 2: 204 | CITY = newcity[0].strip() + "," + newcity[1].strip() 205 | else: 206 | country = await get_tz((newcity[1].strip()).title()) 207 | try: 208 | countrycode = timezone_countries[f'{country}'] 209 | except KeyError: 210 | await weather.edit("`Invalid country.`") 211 | return 212 | CITY = newcity[0].strip() + "," + countrycode.strip() 213 | 214 | url = f'https://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={APPID}' 215 | request = get(url) 216 | result = json.loads(request.text) 217 | 218 | if request.status_code != 200: 219 | await weather.edit(f"`Invalid country.`") 220 | return 221 | 222 | cityname = result['name'] 223 | curtemp = result['main']['temp'] 224 | humidity = result['main']['humidity'] 225 | min_temp = result['main']['temp_min'] 226 | max_temp = result['main']['temp_max'] 227 | desc = result['weather'][0] 228 | desc = desc['main'] 229 | country = result['sys']['country'] 230 | sunrise = result['sys']['sunrise'] 231 | sunset = result['sys']['sunset'] 232 | wind = result['wind']['speed'] 233 | winddir = result['wind']['deg'] 234 | 235 | ctimezone = tz(c_tz[country][0]) 236 | time = datetime.now(ctimezone).strftime("%A, %I:%M %p") 237 | fullc_n = c_n[f"{country}"] 238 | 239 | dirs = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] 240 | 241 | div = (360 / len(dirs)) 242 | funmath = int((winddir + (div / 2)) / div) 243 | findir = dirs[funmath % len(dirs)] 244 | kmph = str(wind * 3.6).split(".") 245 | mph = str(wind * 2.237).split(".") 246 | 247 | def fahrenheit(f): 248 | temp = str(((f - 273.15) * 9 / 5 + 32)).split(".") 249 | return temp[0] 250 | 251 | def celsius(c): 252 | temp = str((c - 273.15)).split(".") 253 | return temp[0] 254 | 255 | def sun(unix): 256 | xx = datetime.fromtimestamp(unix, tz=ctimezone).strftime("%I:%M %p") 257 | return xx 258 | 259 | await weather.edit( 260 | f"**Temperature:** `{celsius(curtemp)}°C | {fahrenheit(curtemp)}°F`\n" 261 | + 262 | f"**Min. Temp.:** `{celsius(min_temp)}°C | {fahrenheit(min_temp)}°F`\n" 263 | + 264 | f"**Max. Temp.:** `{celsius(max_temp)}°C | {fahrenheit(max_temp)}°F`\n" 265 | + f"**Humidity:** `{humidity}%`\n" + 266 | f"**Wind:** `{kmph[0]} kmh | {mph[0]} mph, {findir}`\n" + 267 | f"**Sunrise:** `{sun(sunrise)}`\n" + 268 | f"**Sunset:** `{sun(sunset)}`\n\n" + f"**{desc}**\n" + 269 | f"`{cityname}, {fullc_n}`\n" + f"`{time}`") 270 | 271 | 272 | CMD_HELP.update({ 273 | "weather": 274 | ".weather or .weather , \ 275 | \nUsage: Gets the weather of a city." 276 | }) 277 | 278 | 279 | @javes05(outgoing=True, pattern="^\!youtube (.*)") 280 | async def yt_search(video_q): 281 | """ For .yt command, do a YouTube search from Telegram. """ 282 | query = video_q.pattern_match.group(1) 283 | result = '' 284 | 285 | if not YOUTUBE_API_KEY: 286 | await video_q.edit( 287 | "`Error: YouTube API key missing! Add it to environment vars or config.env.`" 288 | ) 289 | return 290 | 291 | await video_q.edit("```Processing...```") 292 | 293 | full_response = await youtube_search(query) 294 | videos_json = full_response[1] 295 | 296 | for video in videos_json: 297 | title = f"{unescape(video['snippet']['title'])}" 298 | link = f"https://youtu.be/{video['id']['videoId']}" 299 | result += f"{title}\n{link}\n\n" 300 | 301 | reply_text = f"**Search Query:**\n`{query}`\n\n**Results:**\n\n{result}" 302 | 303 | await video_q.edit(reply_text) 304 | 305 | 306 | async def youtube_search(query, 307 | order="relevance", 308 | token=None, 309 | location=None, 310 | location_radius=None): 311 | """ Do a YouTube search. """ 312 | youtube = build('youtube', 313 | 'v3', 314 | developerKey=YOUTUBE_API_KEY, 315 | cache_discovery=False) 316 | search_response = youtube.search().list( 317 | q=query, 318 | type="video", 319 | pageToken=token, 320 | order=order, 321 | part="id,snippet", 322 | maxResults=10, 323 | location=location, 324 | locationRadius=location_radius).execute() 325 | 326 | videos = [] 327 | 328 | for search_result in search_response.get("items", []): 329 | if search_result["id"]["kind"] == "youtube#video": 330 | videos.append(search_result) 331 | try: 332 | nexttok = search_response["nextPageToken"] 333 | return (nexttok, videos) 334 | except HttpError: 335 | nexttok = "last_page" 336 | return (nexttok, videos) 337 | except KeyError: 338 | nexttok = "KeyError, try again." 339 | return (nexttok, videos) 340 | 341 | async def ocr_space_file(filename, 342 | overlay=False, 343 | api_key=OCR_SPACE_API_KEY, 344 | language='eng'): 345 | """ OCR.space API request with local file. 346 | Python3.5 - not tested on 2.7 347 | :param filename: Your file path & name. 348 | :param overlay: Is OCR.space overlay required in your response. 349 | Defaults to False. 350 | :param api_key: OCR.space API key. 351 | Defaults to 'helloworld'. 352 | :param language: Language code to be used in OCR. 353 | List of available language codes can be found on https://ocr.space/OCRAPI 354 | Defaults to 'en'. 355 | :return: Result in JSON format. 356 | """ 357 | 358 | payload = { 359 | 'isOverlayRequired': overlay, 360 | 'apikey': api_key, 361 | 'language': language, 362 | } 363 | with open(filename, 'rb') as f: 364 | r = requests.post( 365 | 'https://api.ocr.space/parse/image', 366 | files={filename: f}, 367 | data=payload, 368 | ) 369 | return r.json() 370 | 371 | 372 | -------------------------------------------------------------------------------- /userbot/modules/stickers.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from telethon import events 3 | from telethon.errors.rpcerrorlist import YouBlockedUserError 4 | from telethon.tl.functions.account import UpdateNotifySettingsRequest 5 | 6 | from userbot import bot, CMD_HELP 7 | import io 8 | import math 9 | import urllib.request 10 | from os import remove 11 | from userbot.events import javes05 12 | import io 13 | import os 14 | import random 15 | import textwrap 16 | from PIL import Image, ImageDraw, ImageFont 17 | from telethon.tl.types import InputMessagesFilterDocument 18 | 19 | from PIL import Image 20 | import random 21 | from telethon.tl.types import DocumentAttributeFilename, MessageMediaPhoto 22 | from userbot import bot, CMD_HELP 23 | import io 24 | import os 25 | import random 26 | import textwrap 27 | from PIL import Image, ImageDraw, ImageFont 28 | from telethon.tl.types import InputMessagesFilterDocument 29 | from telethon.tl.functions.messages import GetStickerSetRequest 30 | from telethon.tl.types import InputStickerSetID 31 | from telethon.tl.types import DocumentAttributeSticker 32 | 33 | PACK_FULL = "Whoa! That's probably enough stickers for one pack, give it a break. \ 34 | A pack can't have more than 120 stickers at the moment." 35 | 36 | KANGING_STR = [ 37 | 38 | "Kanging this sticker...", 39 | "Hey that's a nice sticker!\ 40 | \nMind if I kang?!..", 41 | 42 | "Kanging this sticker ... ", 43 | ] 44 | 45 | 46 | @javes05(outgoing=True, pattern="^\!kang") 47 | async def kang(args): 48 | """ For .kang command, kangs stickers or creates new ones. """ 49 | kang_meme = random.choice(KANGING_STR) 50 | user = await bot.get_me() 51 | if not user.username: 52 | user.username = user.first_name 53 | message = await args.get_reply_message() 54 | photo = None 55 | emojibypass = False 56 | is_anim = False 57 | emoji = None 58 | 59 | if message and message.media: 60 | if isinstance(message.media, MessageMediaPhoto): 61 | await args.edit(f"`{kang_meme}`") 62 | photo = io.BytesIO() 63 | photo = await bot.download_media(message.photo, photo) 64 | elif "image" in message.media.document.mime_type.split('/'): 65 | await args.edit(f"`{kang_meme}`") 66 | photo = io.BytesIO() 67 | await bot.download_file(message.media.document, photo) 68 | if (DocumentAttributeFilename(file_name='sticker.webp') in 69 | message.media.document.attributes): 70 | emoji = message.media.document.attributes[1].alt 71 | emojibypass = True 72 | elif "tgsticker" in message.media.document.mime_type: 73 | await args.edit(f"`{kang_meme}`") 74 | await bot.download_file(message.media.document, 75 | 'AnimatedSticker.tgs') 76 | 77 | attributes = message.media.document.attributes 78 | for attribute in attributes: 79 | if isinstance(attribute, DocumentAttributeSticker): 80 | emoji = attribute.alt 81 | 82 | emojibypass = True 83 | is_anim = True 84 | photo = 1 85 | else: 86 | await args.edit("`Unsupported File!`") 87 | return 88 | else: 89 | await args.edit("`I can't kang that...`") 90 | return 91 | 92 | if photo: 93 | splat = args.text.split() 94 | if not emojibypass: 95 | emoji = "🤔" 96 | pack = 1 97 | if len(splat) == 3: 98 | pack = splat[2] # User sent both 99 | emoji = splat[1] 100 | elif len(splat) == 2: 101 | if splat[1].isnumeric(): 102 | # User wants to push into different pack, but is okay with 103 | # thonk as emote. 104 | pack = int(splat[1]) 105 | else: 106 | # User sent just custom emote, wants to push to default 107 | # pack 108 | emoji = splat[1] 109 | 110 | packname = f"a{user.id}_by_{user.username}_{pack}" 111 | packnick = f"@{user.username}'s pack Vol.{pack}" 112 | cmd = '/newpack' 113 | file = io.BytesIO() 114 | 115 | if not is_anim: 116 | image = await resize_photo(photo) 117 | file.name = "sticker.png" 118 | image.save(file, "PNG") 119 | else: 120 | packname += "_anim" 121 | packnick += " (Animated)" 122 | cmd = '/newanimated' 123 | 124 | response = urllib.request.urlopen( 125 | urllib.request.Request(f'http://t.me/addstickers/{packname}')) 126 | htmlstr = response.read().decode("utf8").split('\n') 127 | 128 | if " A Telegram user has created the Sticker Set." not in htmlstr: 129 | async with bot.conversation('Stickers') as conv: 130 | await conv.send_message('/addsticker') 131 | await conv.get_response() 132 | # Ensure user doesn't get spamming notifications 133 | await bot.send_read_acknowledge(conv.chat_id) 134 | await conv.send_message(packname) 135 | x = await conv.get_response() 136 | while x.text == PACK_FULL: 137 | pack += 1 138 | packname = f"a{user.id}_by_{user.username}_{pack}" 139 | packnick = f"@{user.username}'s pack Vol.{pack}" 140 | await args.edit(f"`{kang_meme}\ 141 | \nMoving on to Vol.{str(pack)}..`") 142 | await conv.send_message(packname) 143 | x = await conv.get_response() 144 | if x.text == "Invalid pack selected.": 145 | await conv.send_message(cmd) 146 | await conv.get_response() 147 | # Ensure user doesn't get spamming notifications 148 | await bot.send_read_acknowledge(conv.chat_id) 149 | await conv.send_message(packnick) 150 | await conv.get_response() 151 | # Ensure user doesn't get spamming notifications 152 | await bot.send_read_acknowledge(conv.chat_id) 153 | if is_anim: 154 | await conv.send_file('AnimatedSticker.tgs') 155 | remove('AnimatedSticker.tgs') 156 | else: 157 | file.seek(0) 158 | await conv.send_file(file, force_document=True) 159 | await conv.get_response() 160 | await conv.send_message(emoji) 161 | # Ensure user doesn't get spamming notifications 162 | await bot.send_read_acknowledge(conv.chat_id) 163 | await conv.get_response() 164 | await conv.send_message("/publish") 165 | if is_anim: 166 | await conv.get_response() 167 | await conv.send_message(f"<{packnick}>") 168 | # Ensure user doesn't get spamming notifications 169 | await conv.get_response() 170 | await bot.send_read_acknowledge(conv.chat_id) 171 | await conv.send_message("/skip") 172 | # Ensure user doesn't get spamming notifications 173 | await bot.send_read_acknowledge(conv.chat_id) 174 | await conv.get_response() 175 | await conv.send_message(packname) 176 | # Ensure user doesn't get spamming notifications 177 | await bot.send_read_acknowledge(conv.chat_id) 178 | await conv.get_response() 179 | # Ensure user doesn't get spamming notifications 180 | await bot.send_read_acknowledge(conv.chat_id) 181 | await args.edit(f"`Haha, yes. New kang pack unlocked!\ 182 | \nPack can be found [here](t.me/addstickers/{packname})", 183 | parse_mode='md') 184 | return 185 | if is_anim: 186 | await conv.send_file('AnimatedSticker.tgs') 187 | remove('AnimatedSticker.tgs') 188 | else: 189 | file.seek(0) 190 | await conv.send_file(file, force_document=True) 191 | rsp = await conv.get_response() 192 | if "Sorry, the file type is invalid." in rsp.text: 193 | await args.edit( 194 | "`Failed to add sticker, use` @Stickers `bot to add the sticker manually.`" 195 | ) 196 | return 197 | await conv.send_message(emoji) 198 | # Ensure user doesn't get spamming notifications 199 | await bot.send_read_acknowledge(conv.chat_id) 200 | await conv.get_response() 201 | await conv.send_message('/done') 202 | await conv.get_response() 203 | # Ensure user doesn't get spamming notifications 204 | await bot.send_read_acknowledge(conv.chat_id) 205 | else: 206 | await args.edit("`Brewing a new Pack...`") 207 | async with bot.conversation('Stickers') as conv: 208 | await conv.send_message(cmd) 209 | await conv.get_response() 210 | # Ensure user doesn't get spamming notifications 211 | await bot.send_read_acknowledge(conv.chat_id) 212 | await conv.send_message(packnick) 213 | await conv.get_response() 214 | # Ensure user doesn't get spamming notifications 215 | await bot.send_read_acknowledge(conv.chat_id) 216 | if is_anim: 217 | await conv.send_file('AnimatedSticker.tgs') 218 | remove('AnimatedSticker.tgs') 219 | else: 220 | file.seek(0) 221 | await conv.send_file(file, force_document=True) 222 | rsp = await conv.get_response() 223 | if "Sorry, the file type is invalid." in rsp.text: 224 | await args.edit( 225 | "`Failed to add sticker, use` @Stickers `bot to add the sticker manually.`" 226 | ) 227 | return 228 | await conv.send_message(emoji) 229 | # Ensure user doesn't get spamming notifications 230 | await bot.send_read_acknowledge(conv.chat_id) 231 | await conv.get_response() 232 | await conv.send_message("/publish") 233 | if is_anim: 234 | await conv.get_response() 235 | await conv.send_message(f"<{packnick}>") 236 | # Ensure user doesn't get spamming notifications 237 | await conv.get_response() 238 | await bot.send_read_acknowledge(conv.chat_id) 239 | await conv.send_message("/skip") 240 | # Ensure user doesn't get spamming notifications 241 | await bot.send_read_acknowledge(conv.chat_id) 242 | await conv.get_response() 243 | await conv.send_message(packname) 244 | # Ensure user doesn't get spamming notifications 245 | await bot.send_read_acknowledge(conv.chat_id) 246 | await conv.get_response() 247 | # Ensure user doesn't get spamming notifications 248 | await bot.send_read_acknowledge(conv.chat_id) 249 | 250 | await args.edit(f"`Sticker kanged successfully!`\ 251 | \nPack can be found [here](t.me/addstickers/{packname})", 252 | parse_mode='md') 253 | 254 | 255 | async def resize_photo(photo): 256 | """ Resize the given photo to 512x512 """ 257 | image = Image.open(photo) 258 | maxsize = (512, 512) 259 | if (image.width and image.height) < 512: 260 | size1 = image.width 261 | size2 = image.height 262 | if image.width > image.height: 263 | scale = 512 / size1 264 | size1new = 512 265 | size2new = size2 * scale 266 | else: 267 | scale = 512 / size2 268 | size1new = size1 * scale 269 | size2new = 512 270 | size1new = math.floor(size1new) 271 | size2new = math.floor(size2new) 272 | sizenew = (size1new, size2new) 273 | image = image.resize(sizenew) 274 | else: 275 | image.thumbnail(maxsize) 276 | 277 | return image 278 | 279 | 280 | @javes05(outgoing=True, pattern="^\!stickerinfo$") 281 | async def get_pack_info(event): 282 | if not event.is_reply: 283 | await event.edit("`I can't fetch info from nothing, can I ?!`") 284 | return 285 | 286 | rep_msg = await event.get_reply_message() 287 | if not rep_msg.document: 288 | await event.edit("`Reply to a sticker to get the pack details`") 289 | return 290 | 291 | try: 292 | stickerset_attr = rep_msg.document.attributes[1] 293 | await event.edit( 294 | "`Fetching details of the sticker pack, please wait..`") 295 | except BaseException: 296 | await event.edit("`This is not a sticker. Reply to a sticker.`") 297 | return 298 | 299 | if not isinstance(stickerset_attr, DocumentAttributeSticker): 300 | await event.edit("`This is not a sticker. Reply to a sticker.`") 301 | return 302 | 303 | get_stickerset = await bot( 304 | GetStickerSetRequest( 305 | InputStickerSetID( 306 | id=stickerset_attr.stickerset.id, 307 | access_hash=stickerset_attr.stickerset.access_hash))) 308 | pack_emojis = [] 309 | for document_sticker in get_stickerset.packs: 310 | if document_sticker.emoticon not in pack_emojis: 311 | pack_emojis.append(document_sticker.emoticon) 312 | 313 | OUTPUT = f"**Sticker Title:** `{get_stickerset.set.title}\n`" \ 314 | f"**Sticker Short Name:** `{get_stickerset.set.short_name}`\n" \ 315 | f"**Official:** `{get_stickerset.set.official}`\n" \ 316 | f"**Archived:** `{get_stickerset.set.archived}`\n" \ 317 | f"**Stickers In Pack:** `{len(get_stickerset.packs)}`\n" \ 318 | f"**Emojis In Pack:**\n{' '.join(pack_emojis)}" 319 | 320 | await event.edit(OUTPUT) 321 | 322 | @javes05(outgoing=True, pattern="^!ss(?: |$)(.*)") 323 | async def _(event): 324 | if event.fwd_from: 325 | return 326 | if not event.reply_to_msg_id: 327 | await event.edit("```Reply to any user message.```") 328 | return 329 | reply_message = await event.get_reply_message() 330 | if not reply_message.text: 331 | await event.edit("```Reply to text message```") 332 | return 333 | chat = "@QuotLyBot" 334 | sender = reply_message.sender 335 | if reply_message.sender.bot: 336 | await event.edit("```javes: Can't scan bot meaage```") 337 | return 338 | await event.edit("```Making.....```") 339 | async with bot.conversation(chat) as conv: 340 | try: 341 | response = conv.wait_event(events.NewMessage(incoming=True,from_users=1031952739)) 342 | await bot.forward_messages(chat, reply_message) 343 | response = await response 344 | except YouBlockedUserError: 345 | await event.reply("```Please unblock @QuotLyBot and try again```") 346 | return 347 | if response.text.startswith("Hi!"): 348 | await event.edit("```javes: This user have forward privacy```") 349 | else: 350 | await event.delete() 351 | await bot.forward_messages(event.chat_id, response.message) 352 | 353 | @javes05 (outgoing=True, pattern="^!text(?: |$)(.*)") 354 | async def sticklet(event): 355 | R = random.randint(0,256) 356 | G = random.randint(0,256) 357 | B = random.randint(0,256) 358 | 359 | # get the input text 360 | # the text on which we would like to do the magic on 361 | sticktext = event.pattern_match.group(1) 362 | 363 | # delete the userbot command, 364 | # i don't know why this is required 365 | await event.delete() 366 | 367 | # https://docs.python.org/3/library/textwrap.html#textwrap.wrap 368 | sticktext = textwrap.wrap(sticktext, width=10) 369 | # converts back the list to a string 370 | sticktext = '\n'.join(sticktext) 371 | 372 | image = Image.new("RGBA", (512, 512), (255, 255, 255, 0)) 373 | draw = ImageDraw.Draw(image) 374 | fontsize = 230 375 | 376 | FONT_FILE = await get_font_file(event.client, "@FontRes") 377 | 378 | font = ImageFont.truetype(FONT_FILE, size=fontsize) 379 | 380 | while draw.multiline_textsize(sticktext, font=font) > (512, 512): 381 | fontsize -= 3 382 | font = ImageFont.truetype(FONT_FILE, size=fontsize) 383 | 384 | width, height = draw.multiline_textsize(sticktext, font=font) 385 | draw.multiline_text(((512-width)/2,(512-height)/2), sticktext, font=font, fill=(R, G, B)) 386 | 387 | image_stream = io.BytesIO() 388 | image_stream.name = "Javes.webp" 389 | image.save(image_stream, "WebP") 390 | image_stream.seek(0) 391 | 392 | # finally, reply the sticker 393 | #await event.reply( file=image_stream, reply_to=event.message.reply_to_msg_id) 394 | #replacing upper line with this to get reply tags 395 | 396 | await event.client.send_file(event.chat_id, image_stream, reply_to=event.message.reply_to_msg_id) 397 | # cleanup 398 | try: 399 | os.remove(FONT_FILE) 400 | except: 401 | pass 402 | 403 | 404 | async def get_font_file(client, channel_id): 405 | # first get the font messages 406 | font_file_message_s = await client.get_messages( 407 | entity=channel_id, 408 | filter=InputMessagesFilterDocument, 409 | # this might cause FLOOD WAIT, 410 | # if used too many times 411 | limit=None 412 | ) 413 | # get a random font from the list of fonts 414 | # https://docs.python.org/3/library/random.html#random.choice 415 | font_file_message = random.choice(font_file_message_s) 416 | # download and return the file path 417 | return await client.download_media(font_file_message) 418 | 419 | 420 | -------------------------------------------------------------------------------- /.apt/usr/bin/config/config.conf: -------------------------------------------------------------------------------- 1 | # Neofetch config file 2 | # https://github.com/dylanaraps/neofetch 3 | 4 | 5 | # See this wiki page for more info: 6 | # https://github.com/dylanaraps/neofetch/wiki/Customizing-Info 7 | print_info() { 8 | info title 9 | info underline 10 | 11 | info "OS" distro 12 | info "Host" model 13 | info "Kernel" kernel 14 | info "Uptime" uptime 15 | info "Packages" packages 16 | info "Shell" shell 17 | info "Resolution" resolution 18 | info "DE" de 19 | info "WM" wm 20 | info "WM Theme" wm_theme 21 | info "Theme" theme 22 | info "Icons" icons 23 | info "Terminal" term 24 | info "Terminal Font" term_font 25 | info "CPU" cpu 26 | info "GPU" gpu 27 | info "Memory" memory 28 | 29 | # info "GPU Driver" gpu_driver # Linux/macOS only 30 | # info "CPU Usage" cpu_usage 31 | # info "Disk" disk 32 | # info "Battery" battery 33 | # info "Font" font 34 | # info "Song" song 35 | # info "Local IP" local_ip 36 | # info "Public IP" public_ip 37 | # info "Users" users 38 | # info "Install Date" install_date 39 | # info "Locale" locale # This only works on glibc systems. 40 | 41 | info line_break 42 | info cols 43 | info line_break 44 | } 45 | 46 | 47 | # Kernel 48 | 49 | 50 | # Shorten the output of the kernel function. 51 | # 52 | # Default: 'on' 53 | # Values: 'on', 'off' 54 | # Flag: --kernel_shorthand 55 | # Supports: Everything except *BSDs (except PacBSD and PC-BSD) 56 | # 57 | # Example: 58 | # on: '4.8.9-1-ARCH' 59 | # off: 'Linux 4.8.9-1-ARCH' 60 | kernel_shorthand="off" 61 | 62 | 63 | # Distro 64 | 65 | 66 | # Shorten the output of the distro function 67 | # 68 | # Default: 'off' 69 | # Values: 'on', 'off', 'tiny' 70 | # Flag: --distro_shorthand 71 | # Supports: Everything except Windows and Haiku 72 | distro_shorthand="off" 73 | 74 | # Show/Hide OS Architecture. 75 | # Show 'x86_64', 'x86' and etc in 'Distro:' output. 76 | # 77 | # Default: 'on' 78 | # Values: 'on', 'off' 79 | # Flag: --os_arch 80 | # 81 | # Example: 82 | # on: 'Arch Linux x86_64' 83 | # off: 'Arch Linux' 84 | os_arch="on" 85 | 86 | 87 | # Uptime 88 | 89 | 90 | # Shorten the output of the uptime function 91 | # 92 | # Default: 'on' 93 | # Values: 'on', 'off', 'tiny' 94 | # Flag: --uptime_shorthand 95 | # 96 | # Example: 97 | # on: '2 days, 10 hours, 3 mins' 98 | # off: '2 days, 10 hours, 3 minutes' 99 | # tiny: '2d 10h 3m' 100 | uptime_shorthand="tiny" 101 | 102 | 103 | # Shell 104 | 105 | 106 | # Show the path to $SHELL 107 | # 108 | # Default: 'off' 109 | # Values: 'on', 'off' 110 | # Flag: --shell_path 111 | # 112 | # Example: 113 | # on: '/bin/bash' 114 | # off: 'bash' 115 | shell_path="on" 116 | 117 | # Show $SHELL version 118 | # 119 | # Default: 'on' 120 | # Values: 'on', 'off' 121 | # Flag: --shell_version 122 | # 123 | # Example: 124 | # on: 'bash 4.4.5' 125 | # off: 'bash' 126 | shell_version="on" 127 | 128 | 129 | # CPU 130 | 131 | 132 | # CPU speed type 133 | # 134 | # Default: 'bios_limit' 135 | # Values: 'scaling_cur_freq', 'scaling_min_freq', 'scaling_max_freq', 'bios_limit'. 136 | # Flag: --speed_type 137 | # Supports: Linux with 'cpufreq' 138 | # NOTE: Any file in '/sys/devices/system/cpu/cpu0/cpufreq' can be used as a value. 139 | speed_type="bios_limit" 140 | 141 | # CPU speed shorthand 142 | # 143 | # Default: 'off' 144 | # Values: 'on', 'off'. 145 | # Flag: --speed_shorthand. 146 | # NOTE: This flag is not supported in systems with CPU speed less than 1 GHz 147 | # 148 | # Example: 149 | # on: 'i7-6500U (4) @ 3.1GHz' 150 | # off: 'i7-6500U (4) @ 3.100GHz' 151 | speed_shorthand="off" 152 | 153 | # Enable/Disable CPU brand in output. 154 | # 155 | # Default: 'on' 156 | # Values: 'on', 'off' 157 | # Flag: --cpu_brand 158 | # 159 | # Example: 160 | # on: 'Intel i7-6500U' 161 | # off: 'i7-6500U (4)' 162 | cpu_brand="off" 163 | 164 | # CPU Speed 165 | # Hide/Show CPU speed. 166 | # 167 | # Default: 'on' 168 | # Values: 'on', 'off' 169 | # Flag: --cpu_speed 170 | # 171 | # Example: 172 | # on: 'Intel i7-6500U (4) @ 3.1GHz' 173 | # off: 'Intel i7-6500U (4)' 174 | cpu_speed="off" 175 | 176 | # CPU Cores 177 | # Display CPU cores in output 178 | # 179 | # Default: 'logical' 180 | # Values: 'logical', 'physical', 'off' 181 | # Flag: --cpu_cores 182 | # Support: 'physical' doesn't work on BSD. 183 | # 184 | # Example: 185 | # logical: 'Intel i7-6500U (4) @ 3.1GHz' (All virtual cores) 186 | # physical: 'Intel i7-6500U (2) @ 3.1GHz' (All physical cores) 187 | # off: 'Intel i7-6500U @ 3.1GHz' 188 | cpu_cores="off" 189 | 190 | # CPU Temperature 191 | # Hide/Show CPU temperature. 192 | # Note the temperature is added to the regular CPU function. 193 | # 194 | # Default: 'off' 195 | # Values: 'C', 'F', 'off' 196 | # Flag: --cpu_temp 197 | # Supports: Linux, BSD 198 | # NOTE: For FreeBSD and NetBSD-based systems, you'll need to enable 199 | # coretemp kernel module. This only supports newer Intel processors. 200 | # 201 | # Example: 202 | # C: 'Intel i7-6500U (4) @ 3.1GHz [27.2°C]' 203 | # F: 'Intel i7-6500U (4) @ 3.1GHz [82.0°F]' 204 | # off: 'Intel i7-6500U (4) @ 3.1GHz' 205 | cpu_temp="off" 206 | 207 | 208 | # GPU 209 | 210 | 211 | # Enable/Disable GPU Brand 212 | # 213 | # Default: 'on' 214 | # Values: 'on', 'off' 215 | # Flag: --gpu_brand 216 | # 217 | # Example: 218 | # on: 'AMD HD 7950' 219 | # off: 'HD 7950' 220 | gpu_brand="off" 221 | 222 | # Which GPU to display 223 | # 224 | # Default: 'all' 225 | # Values: 'all', 'dedicated', 'integrated' 226 | # Flag: --gpu_type 227 | # Supports: Linux 228 | # 229 | # Example: 230 | # all: 231 | # GPU1: AMD HD 7950 232 | # GPU2: Intel Integrated Graphics 233 | # 234 | # dedicated: 235 | # GPU1: AMD HD 7950 236 | # 237 | # integrated: 238 | # GPU1: Intel Integrated Graphics 239 | gpu_type="dedicated" 240 | 241 | 242 | # Resolution 243 | 244 | 245 | # Display refresh rate next to each monitor 246 | # Default: 'off' 247 | # Values: 'on', 'off' 248 | # Flag: --refresh_rate 249 | # Supports: Doesn't work on Windows. 250 | # 251 | # Example: 252 | # on: '1920x1080 @ 60Hz' 253 | # off: '1920x1080' 254 | refresh_rate="on" 255 | 256 | 257 | # Gtk Theme / Icons / Font 258 | 259 | 260 | # Shorten output of GTK Theme / Icons / Font 261 | # 262 | # Default: 'off' 263 | # Values: 'on', 'off' 264 | # Flag: --gtk_shorthand 265 | # 266 | # Example: 267 | # on: 'Numix, Adwaita' 268 | # off: 'Numix [GTK2], Adwaita [GTK3]' 269 | gtk_shorthand="on" 270 | 271 | 272 | # Enable/Disable gtk2 Theme / Icons / Font 273 | # 274 | # Default: 'on' 275 | # Values: 'on', 'off' 276 | # Flag: --gtk2 277 | # 278 | # Example: 279 | # on: 'Numix [GTK2], Adwaita [GTK3]' 280 | # off: 'Adwaita [GTK3]' 281 | gtk2="off" 282 | 283 | # Enable/Disable gtk3 Theme / Icons / Font 284 | # 285 | # Default: 'on' 286 | # Values: 'on', 'off' 287 | # Flag: --gtk3 288 | # 289 | # Example: 290 | # on: 'Numix [GTK2], Adwaita [GTK3]' 291 | # off: 'Numix [GTK2]' 292 | gtk3="off" 293 | 294 | 295 | # IP Address 296 | 297 | 298 | # Website to ping for the public IP 299 | # 300 | # Default: 'http://ident.me' 301 | # Values: 'url' 302 | # Flag: --ip_host 303 | public_ip_host="http://ident.me" 304 | 305 | 306 | # Disk 307 | 308 | 309 | # Which disks to display. 310 | # The values can be any /dev/sdXX, mount point or directory. 311 | # NOTE: By default we only show the disk info for '/'. 312 | # 313 | # Default: '/' 314 | # Values: '/', '/dev/sdXX', '/path/to/drive'. 315 | # Flag: --disk_show 316 | # 317 | # Example: 318 | # disk_show=('/' '/dev/sdb1'): 319 | # 'Disk (/): 74G / 118G (66%)' 320 | # 'Disk (/mnt/Videos): 823G / 893G (93%)' 321 | # 322 | # disk_show=('/'): 323 | # 'Disk (/): 74G / 118G (66%)' 324 | # 325 | disk_show=('/') 326 | 327 | # Disk subtitle. 328 | # What to append to the Disk subtitle. 329 | # 330 | # Default: 'mount' 331 | # Values: 'mount', 'name', 'dir' 332 | # Flag: --disk_subtitle 333 | # 334 | # Example: 335 | # name: 'Disk (/dev/sda1): 74G / 118G (66%)' 336 | # 'Disk (/dev/sdb2): 74G / 118G (66%)' 337 | # 338 | # mount: 'Disk (/): 74G / 118G (66%)' 339 | # 'Disk (/mnt/Local Disk): 74G / 118G (66%)' 340 | # 'Disk (/mnt/Videos): 74G / 118G (66%)' 341 | # 342 | # dir: 'Disk (/): 74G / 118G (66%)' 343 | # 'Disk (Local Disk): 74G / 118G (66%)' 344 | # 'Disk (Videos): 74G / 118G (66%)' 345 | disk_subtitle="mount" 346 | 347 | 348 | # Song 349 | 350 | 351 | # Manually specify a music player. 352 | # 353 | # Default: 'auto' 354 | # Values: 'auto', 'player-name' 355 | # Flag: --music_player 356 | # 357 | # Available values for 'player-name': 358 | # 359 | # Google Play 360 | # Spotify 361 | # amarok 362 | # audacious 363 | # banshee 364 | # bluemindo 365 | # clementine 366 | # cmus 367 | # deadbeef 368 | # deepin-music 369 | # elisa 370 | # exaile 371 | # gnome-music 372 | # guayadeque 373 | # iTunes$ 374 | # juk 375 | # lollypop 376 | # mocp 377 | # mopidy 378 | # mpd 379 | # pogo 380 | # pragha 381 | # qmmp 382 | # quodlibet 383 | # rhythmbox 384 | # spotify 385 | # tomahawk 386 | # xmms2d 387 | # yarock 388 | music_player="auto" 389 | 390 | # Print the Artist and Title on separate lines 391 | # 392 | # Default: 'off' 393 | # Values: 'on', 'off' 394 | # Flag: --song_shorthand 395 | # 396 | # Example: 397 | # on: 'Artist: The Fratellis' 398 | # 'Song: Chelsea Dagger' 399 | # 400 | # off: 'Song: The Fratellis - Chelsea Dagger' 401 | song_shorthand="off" 402 | 403 | 404 | # Install Date 405 | 406 | 407 | # Whether to show the time in the output 408 | # 409 | # Default: 'on' 410 | # Values: 'on', 'off' 411 | # Flag: --install_time 412 | # 413 | # Example: 414 | # on: 'Thu 14 Apr 2016 11:50 PM' 415 | # off: 'Thu 14 Apr 2016' 416 | install_time="on" 417 | 418 | # Set time format in the output 419 | # 420 | # Default: '24h' 421 | # Values: '12h', '24h' 422 | # Flag: --install_time_format 423 | # 424 | # Example: 425 | # 12h: 'Thu 14 Apr 2016 11:50 PM' 426 | # 24h: 'Thu 14 Apr 2016 23:50' 427 | install_time_format="12h" 428 | 429 | 430 | # Text Colors 431 | 432 | 433 | # Text Colors 434 | # 435 | # Default: 'distro' 436 | # Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' 437 | # Flag: --colors 438 | # 439 | # Each number represents a different part of the text in 440 | # this order: 'title', '@', 'underline', 'subtitle', 'colon', 'info' 441 | # 442 | # Example: 443 | # colors=(distro) - Text is colored based on Distro colors. 444 | # colors=(4 6 1 8 8 6) - Text is colored in the order above. 445 | colors=(distro) 446 | 447 | 448 | # Text Options 449 | 450 | 451 | # Toggle bold text 452 | # 453 | # Default: 'on' 454 | # Values: 'on', 'off' 455 | # Flag: --bold 456 | bold="on" 457 | 458 | # Enable/Disable Underline 459 | # 460 | # Default: 'on' 461 | # Values: 'on', 'off' 462 | # Flag: --underline 463 | underline_enabled="on" 464 | 465 | # Underline character 466 | # 467 | # Default: '-' 468 | # Values: 'string' 469 | # Flag: --underline_char 470 | underline_char="-" 471 | 472 | 473 | # Color Blocks 474 | 475 | 476 | # Color block range 477 | # The range of colors to print. 478 | # 479 | # Default: '0', '7' 480 | # Values: 'num' 481 | # Flag: --block_range 482 | # 483 | # Example: 484 | # 485 | # Display colors 0-7 in the blocks. (8 colors) 486 | # neofetch --block_range 0 7 487 | # 488 | # Display colors 0-15 in the blocks. (16 colors) 489 | # neofetch --block_range 0 15 490 | block_range=(0 15) 491 | 492 | # Toggle color blocks 493 | # 494 | # Default: 'on' 495 | # Values: 'on', 'off' 496 | # Flag: --color_blocks 497 | color_blocks="on" 498 | 499 | # Color block width in spaces 500 | # 501 | # Default: '3' 502 | # Values: 'num' 503 | # Flag: --block_width 504 | block_width=3 505 | 506 | # Color block height in lines 507 | # 508 | # Default: '1' 509 | # Values: 'num' 510 | # Flag: --block_height 511 | block_height=1 512 | 513 | 514 | # Progress Bars 515 | 516 | 517 | # Bar characters 518 | # 519 | # Default: '-', '=' 520 | # Values: 'string', 'string' 521 | # Flag: --bar_char 522 | # 523 | # Example: 524 | # neofetch --bar_char 'elapsed' 'total' 525 | # neofetch --bar_char '-' '=' 526 | bar_char_elapsed="-" 527 | bar_char_total="=" 528 | 529 | # Toggle Bar border 530 | # 531 | # Default: 'on' 532 | # Values: 'on', 'off' 533 | # Flag: --bar_border 534 | bar_border="on" 535 | 536 | # Progress bar length in spaces 537 | # Number of chars long to make the progress bars. 538 | # 539 | # Default: '15' 540 | # Values: 'num' 541 | # Flag: --bar_length 542 | bar_length=15 543 | 544 | # Progress bar colors 545 | # When set to distro, uses your distro's logo colors. 546 | # 547 | # Default: 'distro', 'distro' 548 | # Values: 'distro', 'num' 549 | # Flag: --bar_colors 550 | # 551 | # Example: 552 | # neofetch --bar_colors 3 4 553 | # neofetch --bar_colors distro 5 554 | bar_color_elapsed="distro" 555 | bar_color_total="distro" 556 | 557 | 558 | # Info display 559 | # Display a bar with the info. 560 | # 561 | # Default: 'off' 562 | # Values: 'bar', 'infobar', 'barinfo', 'off' 563 | # Flags: --cpu_display 564 | # --memory_display 565 | # --battery_display 566 | # --disk_display 567 | # 568 | # Example: 569 | # bar: '[---=======]' 570 | # infobar: 'info [---=======]' 571 | # barinfo: '[---=======] info' 572 | # off: 'info' 573 | cpu_display="off" 574 | memory_display="off" 575 | battery_display="off" 576 | disk_display="off" 577 | 578 | 579 | # Backend Settings 580 | 581 | 582 | # Image backend. 583 | # 584 | # Default: 'ascii' 585 | # Values: 'ascii', 'caca', 'catimg', 'jp2a', 'iterm2', 'off', 'termpix', 'pixterm', 'tycat', 'w3m' 586 | # Flag: --backend 587 | image_backend="ascii" 588 | 589 | # Image Source 590 | # 591 | # Which image or ascii file to display. 592 | # 593 | # Default: 'auto' 594 | # Values: 'auto', 'ascii', 'wallpaper', '/path/to/img', '/path/to/ascii', '/path/to/dir/' 595 | # Flag: --source 596 | # 597 | # NOTE: 'auto' will pick the best image source for whatever image backend is used. 598 | # In ascii mode, distro ascii art will be used and in an image mode, your 599 | # wallpaper will be used. 600 | image_source="auto" 601 | 602 | 603 | # Ascii Options 604 | 605 | 606 | # Ascii distro 607 | # Which distro's ascii art to display. 608 | # 609 | # Default: 'auto' 610 | # Values: 'auto', 'distro_name' 611 | # Flag: --ascii_distro 612 | # 613 | # NOTE: Arch and Ubuntu have 'old' logo variants. 614 | # Change this to 'arch_old' or 'ubuntu_old' to use the old logos. 615 | # NOTE: Ubuntu has flavor variants. 616 | # Change this to 'Lubuntu', 'Xubuntu', 'Ubuntu-GNOME' or 'Ubuntu-Budgie' to use the flavors. 617 | # NOTE: Arch, Crux and Gentoo have a smaller logo variant. 618 | # Change this to 'arch_small', 'crux_small' or 'gentoo_small' to use the small logos. 619 | ascii_distro="LinuxMint" 620 | 621 | # Ascii Colors 622 | # 623 | # Default: 'distro' 624 | # Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' 625 | # Flag: --ascii_colors 626 | # 627 | # Example: 628 | # ascii_colors=(distro) - Ascii is colored based on Distro colors. 629 | # ascii_colors=(4 6 1 8 8 6) - Ascii is colored using these colors. 630 | ascii_colors=(distro) 631 | 632 | # Bold ascii logo 633 | # Whether or not to bold the ascii logo. 634 | # 635 | # Default: 'on' 636 | # Values: 'on', 'off' 637 | # Flag: --ascii_bold 638 | ascii_bold="on" 639 | 640 | 641 | # Image Options 642 | 643 | 644 | # Image loop 645 | # Setting this to on will make neofetch redraw the image constantly until 646 | # Ctrl+C is pressed. This fixes display issues in some terminal emulators. 647 | # 648 | # Default: 'off' 649 | # Values: 'on', 'off' 650 | # Flag: --loop 651 | image_loop="off" 652 | 653 | # Thumbnail directory 654 | # 655 | # Default: '~/.cache/thumbnails/neofetch' 656 | # Values: 'dir' 657 | thumbnail_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/thumbnails/neofetch" 658 | 659 | # Crop mode 660 | # 661 | # Default: 'normal' 662 | # Values: 'normal', 'fit', 'fill' 663 | # Flag: --crop_mode 664 | # 665 | # See this wiki page to learn about the fit and fill options. 666 | # https://github.com/dylanaraps/neofetch/wiki/What-is-Waifu-Crop%3F 667 | crop_mode="normal" 668 | 669 | # Crop offset 670 | # Note: Only affects 'normal' crop mode. 671 | # 672 | # Default: 'center' 673 | # Values: 'northwest', 'north', 'northeast', 'west', 'center' 674 | # 'east', 'southwest', 'south', 'southeast' 675 | # Flag: --crop_offset 676 | crop_offset="center" 677 | 678 | # Image size 679 | # The image is half the terminal width by default. 680 | # 681 | # Default: 'auto' 682 | # Values: 'auto', '00px', '00%', 'none' 683 | # Flags: --image_size 684 | # --size 685 | image_size="auto" 686 | 687 | # Gap between image and text 688 | # 689 | # Default: '3' 690 | # Values: 'num', '-num' 691 | # Flag: --gap 692 | gap=3 693 | 694 | # Image offsets 695 | # Only works with the w3m backend. 696 | # 697 | # Default: '0' 698 | # Values: 'px' 699 | # Flags: --xoffset 700 | # --yoffset 701 | yoffset=0 702 | xoffset=0 703 | 704 | # Image background color 705 | # Only works with the w3m backend. 706 | # 707 | # Default: '' 708 | # Values: 'color', 'blue' 709 | # Flag: --bg_color 710 | background_color= 711 | 712 | 713 | # Scrot Options 714 | 715 | 716 | # Whether or not to always take a screenshot 717 | # You can manually take a screenshot with "--scrot" or "-s" 718 | # 719 | # Default: 'off' 720 | # Values: 'on', 'off' 721 | # Flags: --scrot 722 | # -s 723 | scrot="off" 724 | 725 | # Screenshot Program 726 | # Neofetch will automatically use whatever screenshot tool 727 | # is installed on your system. 728 | # 729 | # If 'neofetch -v' says that it couldn't find a screenshot 730 | # tool or you're using a custom tool then you can change 731 | # the option below to a custom command. 732 | # 733 | # Default: 'auto' 734 | # Values: 'auto' 'cmd -flags' 735 | # Flag: --scrot_cmd 736 | scrot_cmd="auto" 737 | 738 | # Screenshot Filename 739 | # What to name the screenshots 740 | # 741 | # Default: 'neofetch-$(date +%F-%I-%M-%S-${RANDOM}).png' 742 | # Values: 'string' 743 | # Flag: --scrot_name 744 | scrot_name="neofetch-$(date +%F-%I-%M-%S-${RANDOM}).png" 745 | 746 | # Image upload host 747 | # Where to upload the image. 748 | # 749 | # Default: 'teknik' 750 | # Values: 'imgur', 'teknik' 751 | # Flag: --image_host 752 | # 753 | # NOTE: If you'd like another image host to be added to Neofetch. 754 | # Open an issue on github. 755 | image_host="teknik" 756 | 757 | 758 | # Misc Options 759 | 760 | # Stdout mode 761 | # Turn off all colors and disables image backend (ASCII/Image). 762 | # Useful for piping into another command. 763 | # Default: 'off' 764 | # Values: 'on', 'off' 765 | stdout="off" 766 | 767 | # Config version. 768 | # 769 | # NOTE: Don't change this value, neofetch reads this to determine 770 | # how to handle backwards compatibility. 771 | config_version="3.4.0" 772 | 773 | -------------------------------------------------------------------------------- /userbot/modules/person.py: -------------------------------------------------------------------------------- 1 | from telethon.tl.functions.contacts import BlockRequest, UnblockRequest 2 | from telethon.tl.functions.messages import ReportSpamRequest 3 | from telethon.tl.types import User 4 | from datetime import datetime 5 | from asyncio import sleep 6 | import datetime 7 | from telethon import events 8 | from telethon.errors.rpcerrorlist import YouBlockedUserError 9 | from telethon.tl.functions.account import UpdateNotifySettingsRequest 10 | from random import choice, randint 11 | from asyncio import sleep 12 | 13 | from telethon.events import StopPropagation 14 | 15 | from userbot import (AFKREASON, COUNT_MSG, CMD_HELP, ISAFK, BOTLOG, 16 | BOTLOG_CHATID, USERS, PM_AUTO_BAN) 17 | from userbot.events import javes05 18 | from userbot import bot, CMD_HELP 19 | from telethon.errors import rpcbaseerrors 20 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP 21 | 22 | import os 23 | 24 | from userbot import CMD_HELP, BOTLOG_CHATID 25 | from telethon.tl.functions.photos import GetUserPhotosRequest 26 | from telethon.tl.functions.users import GetFullUserRequest 27 | from telethon.tl.types import MessageEntityMentionName 28 | from telethon.utils import get_input_location 29 | from userbot import CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 30 | from speedtest import Speedtest 31 | from telethon import functions 32 | from os import remove, execle, path, makedirs, getenv, environ 33 | from shutil import rmtree 34 | import asyncio 35 | import json 36 | from random import choice, randint 37 | from asyncio import sleep 38 | from telethon.events import StopPropagation 39 | from userbot import (AFKREASON, COUNT_MSG, CMD_HELP, ISAFK, BOTLOG,BOTLOG_CHATID, USERS, PM_AUTO_BAN) 40 | 41 | from asyncio import sleep 42 | from telethon.errors import rpcbaseerrors 43 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP 44 | 45 | import os 46 | import subprocess 47 | import time 48 | import math 49 | from pySmartDL import SmartDL 50 | import asyncio 51 | from hachoir.metadata import extractMetadata 52 | from hachoir.parser import createParser 53 | from telethon.tl.types import DocumentAttributeVideo 54 | from userbot import LOGS, CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 55 | import sys 56 | from git import Repo 57 | from git.exc import GitCommandError, InvalidGitRepositoryError, NoSuchPathError 58 | from userbot import CMD_HELP, bot, HEROKU_APIKEY, HEROKU_APPNAME, UPSTREAM_REPO_URL 59 | 60 | from asyncio import create_subprocess_shell as asyncrunapp 61 | from asyncio.subprocess import PIPE as asyncPIPE 62 | from platform import python_version, uname 63 | from shutil import which 64 | from os import remove 65 | from telethon import version 66 | from userbot import CMD_HELP, ALIVE_NAME 67 | 68 | from sqlalchemy.exc import IntegrityError 69 | from userbot import (COUNT_PM, CMD_HELP, BOTLOG, BOTLOG_CHATID, PM_AUTO_BAN,LASTMSG, LOGS) 70 | 71 | DEFAULTUSER = str(ALIVE_NAME) if ALIVE_NAME else uname().node 72 | # ========================= CONSTANTS ============================ 73 | UNAPPROVED_MSG = ( 74 | "`Javes: `Hello! Sir\n" 75 | f"I can't allow you to {DEFAULTUSER}'s PM without his permissions please be patient,Thankyou") 76 | 77 | 78 | @javes05(incoming=True, disable_edited=True, disable_errors=True) 79 | async def permitpm(event): 80 | """ Prohibits people from PMing you without approval. \ 81 | Will block retarded nibbas automatically. """ 82 | if PM_AUTO_BAN: 83 | self_user = await event.client.get_me() 84 | if event.is_private and event.chat_id != 777000 and event.chat_id != self_user.id and not ( 85 | await event.get_sender()).bot: 86 | try: 87 | from userbot.modules.sql_helper.pm_permit_sql import is_approved 88 | from userbot.modules.sql_helper.globals import gvarstatus 89 | except AttributeError: 90 | return 91 | apprv = is_approved(event.chat_id) 92 | notifsoff = gvarstatus("NOTIF_OFF") 93 | 94 | # This part basically is a sanity check 95 | # If the message that sent before is Unapproved Message 96 | # then stop sending it again to prevent FloodHit 97 | if not apprv and event.text != UNAPPROVED_MSG: 98 | if event.chat_id in LASTMSG: 99 | prevmsg = LASTMSG[event.chat_id] 100 | # If the message doesn't same as previous one 101 | # Send the Unapproved Message again 102 | if event.text != prevmsg: 103 | async for message in event.client.iter_messages( 104 | event.chat_id, 105 | from_user='me', 106 | search=UNAPPROVED_MSG): 107 | await message.delete() 108 | await event.reply(UNAPPROVED_MSG) 109 | LASTMSG.update({event.chat_id: event.text}) 110 | else: 111 | await event.reply(UNAPPROVED_MSG) 112 | LASTMSG.update({event.chat_id: event.text}) 113 | 114 | if notifsoff: 115 | await event.client.send_read_acknowledge(event.chat_id) 116 | if event.chat_id not in COUNT_PM: 117 | COUNT_PM.update({event.chat_id: 1}) 118 | else: 119 | COUNT_PM[event.chat_id] = COUNT_PM[event.chat_id] + 1 120 | 121 | if COUNT_PM[event.chat_id] > 4: 122 | await event.respond( 123 | f"`javes`: I am not going to allow you to spam {DEFAULTUSER}'s PM, Good bye!") 124 | 125 | 126 | try: 127 | del COUNT_PM[event.chat_id] 128 | del LASTMSG[event.chat_id] 129 | except KeyError: 130 | if BOTLOG: 131 | await event.client.send_message( 132 | BOTLOG_CHATID, 133 | "Count PM is seemingly going retard, plis restart bot!", 134 | ) 135 | LOGS.info("CountPM wen't rarted boi") 136 | return 137 | 138 | await event.client(BlockRequest(event.chat_id)) 139 | await event.client(ReportSpamRequest(peer=event.chat_id)) 140 | 141 | if BOTLOG: 142 | name = await event.client.get_entity(event.chat_id) 143 | name0 = str(name.first_name) 144 | await event.client.send_message( 145 | BOTLOG_CHATID, 146 | "[" + name0 + "](tg://user?id=" + 147 | str(event.chat_id) + ")" + 148 | " blocked for spam your PM", 149 | ) 150 | 151 | 152 | @javes05(disable_edited=True, outgoing=True, disable_errors=True) 153 | async def auto_accept(event): 154 | """ Will approve automatically if you texted them first. """ 155 | if not PM_AUTO_BAN: 156 | return 157 | self_user = await event.client.get_me() 158 | if event.is_private and event.chat_id != 777000 and event.chat_id != self_user.id and not ( 159 | await event.get_sender()).bot: 160 | try: 161 | from userbot.modules.sql_helper.pm_permit_sql import is_approved 162 | from userbot.modules.sql_helper.pm_permit_sql import approve 163 | except AttributeError: 164 | return 165 | 166 | chat = await event.get_chat() 167 | if isinstance(chat, User): 168 | if is_approved(event.chat_id) or chat.bot: 169 | return 170 | async for message in event.client.iter_messages(event.chat_id, 171 | reverse=True, 172 | limit=1): 173 | if message.message is not UNAPPROVED_MSG and message.from_id == self_user.id: 174 | try: 175 | approve(event.chat_id) 176 | except IntegrityError: 177 | return 178 | 179 | if is_approved(event.chat_id) and BOTLOG: 180 | await event.client.send_message( 181 | BOTLOG_CHATID, 182 | "#AUTO-APPROVED\n" + "User: " + 183 | f"[{chat.first_name}](tg://user?id={chat.id})", 184 | ) 185 | 186 | 187 | @javes05(outgoing=True, pattern="^\!notifoff$") 188 | async def notifoff(noff_event): 189 | """ For .notifoff command, stop getting notifications from unapproved PMs. """ 190 | try: 191 | from userbot.modules.sql_helper.globals import addgvar 192 | except AttributeError: 193 | await noff_event.edit("`Running on Non-SQL mode!`") 194 | return 195 | addgvar("NOTIF_OFF", True) 196 | await noff_event.edit("`Notifications from unapproved PM's are silenced!`") 197 | 198 | 199 | @javes05(outgoing=True, pattern="^\!notifon$") 200 | async def notifon(non_event): 201 | """ For .notifoff command, get notifications from unapproved PMs. """ 202 | try: 203 | from userbot.modules.sql_helper.globals import delgvar 204 | except AttributeError: 205 | await non_event.edit("`Running on Non-SQL mode!`") 206 | return 207 | delgvar("NOTIF_OFF") 208 | await non_event.edit("`Notifications from unapproved PM's unmuted!`") 209 | 210 | 211 | @javes05(outgoing=True, pattern="^\!allow$") 212 | async def approvepm(apprvpm): 213 | """ For .approve command, give someone the permissions to PM you. """ 214 | try: 215 | from userbot.modules.sql_helper.pm_permit_sql import approve 216 | except AttributeError: 217 | await apprvpm.edit("`Running `") 218 | return 219 | 220 | if apprvpm.reply_to_msg_id: 221 | reply = await apprvpm.get_reply_message() 222 | replied_user = await apprvpm.client.get_entity(reply.from_id) 223 | aname = replied_user.id 224 | name0 = str(replied_user.first_name) 225 | uid = replied_user.id 226 | 227 | else: 228 | aname = await apprvpm.client.get_entity(apprvpm.chat_id) 229 | name0 = str(aname.first_name) 230 | uid = apprvpm.chat_id 231 | 232 | try: 233 | approve(uid) 234 | except IntegrityError: 235 | await apprvpm.edit("You allowed to pm!") 236 | return 237 | 238 | await apprvpm.edit(f"[{name0}](tg://user?id={uid}) `approved to PM!`") 239 | 240 | async for message in apprvpm.client.iter_messages(apprvpm.chat_id, 241 | from_user='me', 242 | search=UNAPPROVED_MSG): 243 | await message.delete() 244 | 245 | if BOTLOG: 246 | await apprvpm.client.send_message( 247 | BOTLOG_CHATID, 248 | "#APPROVED\n" + "User: " + f"[{name0}](tg://user?id={uid})", 249 | ) 250 | 251 | 252 | @javes05(outgoing=True, pattern="^\!disallow$") 253 | async def disapprovepm(disapprvpm): 254 | try: 255 | from userbot.modules.sql_helper.pm_permit_sql import dissprove 256 | except BaseException: 257 | await disapprvpm.edit("`Running on Non-SQL mode!`") 258 | return 259 | 260 | if disapprvpm.reply_to_msg_id: 261 | reply = await disapprvpm.get_reply_message() 262 | replied_user = await disapprvpm.client.get_entity(reply.from_id) 263 | aname = replied_user.id 264 | name0 = str(replied_user.first_name) 265 | dissprove(replied_user.id) 266 | else: 267 | dissprove(disapprvpm.chat_id) 268 | aname = await disapprvpm.client.get_entity(disapprvpm.chat_id) 269 | name0 = str(aname.first_name) 270 | 271 | await disapprvpm.edit( 272 | f"[{name0}](tg://user?id={disapprvpm.chat_id}) ` Disaproved to PM!`") 273 | 274 | if BOTLOG: 275 | await disapprvpm.client.send_message( 276 | BOTLOG_CHATID, 277 | f"[{name0}](tg://user?id={disapprvpm.chat_id})" 278 | " was disapproved to PM you.", 279 | ) 280 | 281 | 282 | @javes05(outgoing=True, pattern="^\!block$") 283 | async def blockpm(block): 284 | """ For .block command, block people from PMing you! """ 285 | if block.reply_to_msg_id: 286 | reply = await block.get_reply_message() 287 | replied_user = await block.client.get_entity(reply.from_id) 288 | aname = replied_user.id 289 | name0 = str(replied_user.first_name) 290 | await block.client(BlockRequest(replied_user.id)) 291 | await block.edit("`Javes: You've been blocked!`") 292 | uid = replied_user.id 293 | else: 294 | await block.client(BlockRequest(block.chat_id)) 295 | aname = await block.client.get_entity(block.chat_id) 296 | await block.edit("`javes: You've been blocked!`") 297 | name0 = str(aname.first_name) 298 | uid = block.chat_id 299 | 300 | try: 301 | from userbot.modules.sql_helper.pm_permit_sql import dissprove 302 | dissprove(uid) 303 | except AttributeError: 304 | pass 305 | 306 | if BOTLOG: 307 | await block.client.send_message( 308 | BOTLOG_CHATID, 309 | "#BLOCKED\n" + "User: " + f"[{name0}](tg://user?id={uid})", 310 | ) 311 | 312 | 313 | @javes05(outgoing=True, pattern="^\!unblock$") 314 | async def unblockpm(unblock): 315 | """ For .unblock command, let people PMing you again! """ 316 | if unblock.reply_to_msg_id: 317 | reply = await unblock.get_reply_message() 318 | replied_user = await unblock.client.get_entity(reply.from_id) 319 | name0 = str(replied_user.first_name) 320 | await unblock.client(UnblockRequest(replied_user.id)) 321 | await unblock.edit("`Javes: You have been unblocked.`") 322 | 323 | if BOTLOG: 324 | await unblock.client.send_message( 325 | BOTLOG_CHATID, 326 | f"[{name0}](tg://user?id={replied_user.id})" 327 | " was unblocc'd!.", 328 | ) 329 | 330 | """ Userbot module which contains afk-related commands """ 331 | 332 | 333 | 334 | try: 335 | from userbot.modules.sql_helper.globals import gvarstatus, addgvar, delgvar 336 | afk_db = True 337 | except AttributeError: 338 | afk_db = False 339 | 340 | # ========================= CONSTANTS ============================ 341 | AFKSTR = [f"`Javes: Hello! Sir` {DEFAULTUSER} is offline just leave your message i will tell him,Thankyou \n"] 342 | # ================================================================= 343 | 344 | 345 | @javes05(incoming=True, disable_errors=True) 346 | async def mention_afk(mention): 347 | """ This function takes care of notifying the people who mention you that you are AFK.""" 348 | global COUNT_MSG 349 | global USERS 350 | global ISAFK 351 | global AFFKREASON 352 | ISAFK_SQL = False 353 | AFKREASON_SQL = None 354 | if afk_db: 355 | ISAFK_SQL = gvarstatus("AFK_STATUS") 356 | AFKREASON_SQL = gvarstatus("AFK_REASON") 357 | EXCUSE = AFKREASON_SQL if afk_db else AFKREASON 358 | if mention.message.mentioned and not (await mention.get_sender()).bot: 359 | if ISAFK or ISAFK_SQL: 360 | if mention.sender_id not in USERS: 361 | if EXCUSE: 362 | await mention.reply(f"`Javes: `Hello! Sir {DEFAULTUSER} AFK right now.\ 363 | \nReason: `{EXCUSE}`") 364 | else: 365 | await mention.reply(str(choice(AFKSTR))) 366 | USERS.update({mention.sender_id: 1}) 367 | COUNT_MSG = COUNT_MSG + 1 368 | elif mention.sender_id in USERS: 369 | if USERS[mention.sender_id] % randint(2, 4) == 0: 370 | if EXCUSE: 371 | await mention.reply( 372 | f"`Javes: ` In case you didn't notice, {DEFAULTUSER} still AFK.\ 373 | \nReason: `{EXCUSE}`") 374 | else: 375 | await mention.reply(str(choice(AFKSTR))) 376 | USERS[mention.sender_id] = USERS[mention.sender_id] + 1 377 | COUNT_MSG = COUNT_MSG + 1 378 | else: 379 | USERS[mention.sender_id] = USERS[mention.sender_id] + 1 380 | COUNT_MSG = COUNT_MSG + 1 381 | 382 | 383 | @javes05(incoming=True, disable_errors=True) 384 | async def afk_on_pm(sender): 385 | """ Function which informs people that you are AFK in PM """ 386 | global ISAFK 387 | global AFFKREASON 388 | ISAFK_SQL = False 389 | AFKREASON_SQL = None 390 | if afk_db: 391 | ISAFK_SQL = gvarstatus("AFK_STATUS") 392 | AFKREASON_SQL = gvarstatus("AFK_REASON") 393 | global USERS 394 | global COUNT_MSG 395 | EXCUSE = AFKREASON_SQL if afk_db else AFKREASON 396 | if sender.is_private and sender.sender_id != 777000 and not ( 397 | await sender.get_sender()).bot: 398 | if PM_AUTO_BAN: 399 | try: 400 | from userbot.modules.sql_helper.pm_permit_sql import is_approved 401 | apprv = is_approved(sender.sender_id) 402 | except AttributeError: 403 | apprv = True 404 | else: 405 | apprv = True 406 | if apprv and (ISAFK or ISAFK_SQL): 407 | if sender.sender_id not in USERS: 408 | if EXCUSE: 409 | await sender.reply(f"`Javes: `Hello! Sir {DEFAULTUSER} AFK right now.\ 410 | \nReason: `{EXCUSE}`") 411 | else: 412 | await sender.reply(str(choice(AFKSTR))) 413 | USERS.update({sender.sender_id: 1}) 414 | COUNT_MSG = COUNT_MSG + 1 415 | elif apprv and sender.sender_id in USERS: 416 | if USERS[sender.sender_id] % randint(2, 4) == 0: 417 | if EXCUSE: 418 | await sender.reply( 419 | f"`Javes: ` In case you didn't notice, {DEFAULTUSER} still AFK.\ 420 | \nReason: `{EXCUSE}`") 421 | else: 422 | await sender.reply(str(choice(AFKSTR))) 423 | USERS[sender.sender_id] = USERS[sender.sender_id] + 1 424 | COUNT_MSG = COUNT_MSG + 1 425 | else: 426 | USERS[sender.sender_id] = USERS[sender.sender_id] + 1 427 | COUNT_MSG = COUNT_MSG + 1 428 | 429 | 430 | @javes05(outgoing=True, pattern="^\!afk(?: |$)(.*)", disable_errors=True) 431 | async def set_afk(afk_e): 432 | """ For .afk command, allows you to inform people that you are afk when they message you """ 433 | message = afk_e.text 434 | string = afk_e.pattern_match.group(1) 435 | global ISAFK 436 | global AFFKREASON 437 | ISAFK_SQL = False 438 | AFKREASON_SQL = None 439 | if afk_db: 440 | ISAFK_SQL = gvarstatus("AFK_STATUS") 441 | AFKREASON_SQL = gvarstatus("AFK_REASON") 442 | if string: 443 | if afk_db: 444 | addgvar("AFK_REASON", string) 445 | AFKREASON = string 446 | await afk_e.edit(f"Going AFK!\ 447 | \nReason: `{string}`") 448 | else: 449 | await afk_e.edit("Going AFK!") 450 | if BOTLOG: 451 | await afk_e.client.send_message(BOTLOG_CHATID, "#AFK\nYou went AFK!") 452 | if afk_db: 453 | addgvar("AFK_STATUS", True) 454 | ISAFK = True 455 | raise StopPropagation 456 | 457 | 458 | @javes05(outgoing=True) 459 | async def type_afk_is_not_true(notafk): 460 | """ This sets your status as not afk automatically when you write something while being afk """ 461 | global COUNT_MSG 462 | global USERS 463 | global ISAFK 464 | global AFFKREASON 465 | AFKREASON_SQL = None 466 | ISAFK_SQL = False 467 | if afk_db: 468 | ISAFK_SQL = gvarstatus("AFK_STATUS") 469 | AFKREASON_SQL = gvarstatus("AFK_REASON") 470 | if ISAFK or ISAFK_SQL: 471 | if afk_db: 472 | delgvar("AFK_STATUS") 473 | delgvar("AFK_REASON") 474 | ISAFK = False 475 | AFKREASON = None 476 | if BOTLOG: 477 | await notafk.client.send_message( 478 | BOTLOG_CHATID, 479 | "You've recieved " + str(COUNT_MSG) + " messages from " + 480 | str(len(USERS)) + " chats while you were away", 481 | ) 482 | for i in USERS: 483 | name = await notafk.client.get_entity(i) 484 | name0 = str(name.first_name) 485 | await notafk.client.send_message( 486 | BOTLOG_CHATID, 487 | "[" + name0 + "](tg://user?id=" + str(i) + ")" + 488 | " sent you " + "`" + str(USERS[i]) + " messages`", 489 | ) 490 | COUNT_MSG = 0 491 | USERS = {} 492 | 493 | @javes05(pattern="^\!whois(?: |$)(.*)", outgoing=True) 494 | async def who(event): 495 | 496 | await event.edit( 497 | "`Hacking database............`") 498 | 499 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 500 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 501 | 502 | replied_user = await get_user(event) 503 | 504 | try: 505 | photo, caption = await fetch_info(replied_user, event) 506 | except AttributeError: 507 | event.edit("`Could not fetch info of that user.`") 508 | return 509 | 510 | message_id_to_reply = event.message.reply_to_msg_id 511 | 512 | if not message_id_to_reply: 513 | message_id_to_reply = None 514 | 515 | try: 516 | await event.client.send_file(event.chat_id, 517 | photo, 518 | caption=caption, 519 | link_preview=False, 520 | force_document=False, 521 | reply_to=message_id_to_reply, 522 | parse_mode="html") 523 | 524 | if not photo.startswith("http"): 525 | os.remove(photo) 526 | await event.delete() 527 | 528 | except TypeError: 529 | await event.edit(caption, parse_mode="html") 530 | 531 | 532 | async def get_user(event): 533 | """ Get the user from argument or replied message. """ 534 | if event.reply_to_msg_id and not event.pattern_match.group(1): 535 | previous_message = await event.get_reply_message() 536 | replied_user = await event.client( 537 | GetFullUserRequest(previous_message.from_id)) 538 | else: 539 | user = event.pattern_match.group(1) 540 | 541 | if user.isnumeric(): 542 | user = int(user) 543 | 544 | if not user: 545 | self_user = await event.client.get_me() 546 | user = self_user.id 547 | 548 | if event.message.entities is not None: 549 | probable_user_mention_entity = event.message.entities[0] 550 | 551 | if isinstance(probable_user_mention_entity, 552 | MessageEntityMentionName): 553 | user_id = probable_user_mention_entity.user_id 554 | replied_user = await event.client(GetFullUserRequest(user_id)) 555 | return replied_user 556 | try: 557 | user_object = await event.client.get_entity(user) 558 | replied_user = await event.client( 559 | GetFullUserRequest(user_object.id)) 560 | except (TypeError, ValueError) as err: 561 | await event.edit(str(err)) 562 | return None 563 | 564 | return replied_user 565 | 566 | 567 | async def fetch_info(replied_user, event): 568 | """ Get details from the User object. """ 569 | replied_user_profile_photos = await event.client( 570 | GetUserPhotosRequest(user_id=replied_user.user.id, 571 | offset=42, 572 | max_id=0, 573 | limit=80)) 574 | replied_user_profile_photos_count = "Person needs help with uploading profile picture." 575 | try: 576 | replied_user_profile_photos_count = replied_user_profile_photos.count 577 | except AttributeError as e: 578 | pass 579 | user_id = replied_user.user.id 580 | first_name = replied_user.user.first_name 581 | last_name = replied_user.user.last_name 582 | try: 583 | dc_id, location = get_input_location(replied_user.profile_photo) 584 | except Exception as e: 585 | dc_id = "Couldn't fetch DC ID!" 586 | location = str(e) 587 | common_chat = replied_user.common_chats_count 588 | username = replied_user.user.username 589 | user_bio = replied_user.about 590 | is_bot = replied_user.user.bot 591 | restricted = replied_user.user.restricted 592 | verified = replied_user.user.verified 593 | photo = await event.client.download_profile_photo(user_id, 594 | TEMP_DOWNLOAD_DIRECTORY + 595 | str(user_id) + ".jpg", 596 | download_big=True) 597 | first_name = first_name.replace( 598 | "\u2060", "") if first_name else ("This User has no First Name") 599 | last_name = last_name.replace( 600 | "\u2060", "") if last_name else ("This User has no Last Name") 601 | username = "@{}".format(username) if username else ( 602 | "This User has no Username") 603 | user_bio = "This User has no About" if not user_bio else user_bio 604 | 605 | caption = "USER INFO:\n\n" 606 | caption += f"First Name: {first_name}\n" 607 | caption += f"Last Name: {last_name}\n" 608 | caption += f"Username: {username}\n" 609 | caption += f"Data Centre ID: {dc_id}\n" 610 | caption += f"Number of Profile Pics: {replied_user_profile_photos_count}\n" 611 | caption += f"Is Bot: {is_bot}\n" 612 | caption += f"Is Restricted: {restricted}\n" 613 | caption += f"Is Verified by Telegram: {verified}\n" 614 | caption += f"ID: {user_id}\n\n" 615 | caption += f"Bio: \n{user_bio}\n\n" 616 | caption += f"Common Chats with this user: {common_chat}\n" 617 | caption += f"{first_name}" 618 | 619 | return photo, caption 620 | 621 | 622 | 623 | @javes05(outgoing=True, pattern="^\!purge$") 624 | async def fastpurger(purg): 625 | """ For .purge command, purge all messages starting from the reply. """ 626 | chat = await purg.get_input_chat() 627 | msgs = [] 628 | itermsg = purg.client.iter_messages(chat, min_id=purg.reply_to_msg_id) 629 | count = 0 630 | 631 | if purg.reply_to_msg_id is not None: 632 | async for msg in itermsg: 633 | msgs.append(msg) 634 | count = count + 1 635 | msgs.append(purg.reply_to_msg_id) 636 | if len(msgs) == 100: 637 | await purg.client.delete_messages(chat, msgs) 638 | msgs = [] 639 | else: 640 | await purg.edit("`I need a mesasge to start purging from.`") 641 | return 642 | 643 | if msgs: 644 | await purg.client.delete_messages(chat, msgs) 645 | done = await purg.client.send_message( 646 | purg.chat_id, f"`Fast purge complete!`\ 647 | \nPurged {str(count)} messages") 648 | 649 | if BOTLOG: 650 | await purg.client.send_message( 651 | BOTLOG_CHATID, 652 | "Purge of " + str(count) + " messages done successfully.") 653 | await sleep(2) 654 | await done.delete() 655 | 656 | 657 | @javes05(outgoing=True, pattern="^\!purgeme") 658 | async def purgeme(delme): 659 | """ For .purgeme, delete x count of your latest message.""" 660 | message = delme.text 661 | count = int(message[9:]) 662 | i = 1 663 | 664 | async for message in delme.client.iter_messages(delme.chat_id, 665 | from_user='me'): 666 | if i > count + 1: 667 | break 668 | i = i + 1 669 | await message.delete() 670 | 671 | smsg = await delme.client.send_message( 672 | delme.chat_id, 673 | "`Purge complete!` Purged " + str(count) + " messages.", 674 | ) 675 | if BOTLOG: 676 | await delme.client.send_message( 677 | BOTLOG_CHATID, 678 | "Purge of " + str(count) + " messages done successfully.") 679 | await sleep(2) 680 | i = 1 681 | await smsg.delete() 682 | 683 | 684 | @javes05(outgoing=True, pattern="^\!del$") 685 | async def delete_it(delme): 686 | """ For .del command, delete the replied message. """ 687 | msg_src = await delme.get_reply_message() 688 | if delme.reply_to_msg_id: 689 | try: 690 | await msg_src.delete() 691 | await delme.delete() 692 | if BOTLOG: 693 | await delme.client.send_message( 694 | BOTLOG_CHATID, "Deletion of message was successful") 695 | except rpcbaseerrors.BadRequestError: 696 | if BOTLOG: 697 | await delme.client.send_message( 698 | BOTLOG_CHATID, "Well, I can't delete a message") 699 | 700 | 701 | @javes05(outgoing=True, pattern="^\!edit") 702 | async def editer(edit): 703 | """ For .editme command, edit your last message. """ 704 | message = edit.text 705 | chat = await edit.get_input_chat() 706 | self_id = await edit.client.get_peer_id('me') 707 | string = str(message[6:]) 708 | i = 1 709 | async for message in edit.client.iter_messages(chat, self_id): 710 | if i == 2: 711 | await message.edit(string) 712 | await edit.delete() 713 | break 714 | i = i + 1 715 | if BOTLOG: 716 | await edit.client.send_message(BOTLOG_CHATID, 717 | "Edit query was executed successfully") 718 | 719 | 720 | @javes05(outgoing=True, pattern="^\!sd") 721 | async def selfdestruct(destroy): 722 | """ For .sd command, make seflf-destructable messages. """ 723 | message = destroy.text 724 | counter = int(message[4:6]) 725 | text = str(destroy.text[6:]) 726 | await destroy.delete() 727 | smsg = await destroy.client.send_message(destroy.chat_id, text) 728 | await sleep(counter) 729 | await smsg.delete() 730 | if BOTLOG: 731 | await destroy.client.send_message(BOTLOG_CHATID, 732 | "sd query done successfully") 733 | 734 | @javes05(outgoing=True, pattern="^!name(?: |$)(.*)") 735 | async def _(event): 736 | if event.fwd_from: 737 | return 738 | if not event.reply_to_msg_id: 739 | await event.edit("`javes: Can't scan bot meaage`") 740 | return 741 | reply_message = await event.get_reply_message() 742 | if not reply_message.text: 743 | await event.edit("```javes: reply to a media message```") 744 | return 745 | chat = "@SangMataInfo_bot" 746 | sender = reply_message.sender 747 | if reply_message.sender.bot: 748 | await event.edit("`Reply to actual users message.`") 749 | return 750 | await event.edit("`javes: Hacking........`") 751 | async with bot.conversation(chat) as conv: 752 | try: 753 | response = conv.wait_event(events.NewMessage(incoming=True,from_users=461843263)) 754 | await bot.forward_messages(chat, reply_message) 755 | response = await response 756 | except YouBlockedUserError: 757 | await event.reply("`Please unblock @sangmatainfo_bot and try again`") 758 | return 759 | if response.text.startswith("Forward"): 760 | await event.edit("`javes: This user have forward privacy`") 761 | else: 762 | await event.edit(f"{response.message.message}") 763 | 764 | -------------------------------------------------------------------------------- /userbot/modules/system.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from random import randint 3 | from asyncio import sleep 4 | from os import execl 5 | import sys 6 | import os 7 | import io 8 | import heroku3 9 | import asyncio 10 | from asyncio import create_subprocess_shell as asyncSubprocess 11 | from asyncio.subprocess import PIPE as asyncPIPE 12 | from userbot import CMD_HELP, LOGS, HEROKU_APPNAME, HEROKU_APIKEY 13 | import sys 14 | import json 15 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, bot, UPSTREAM_REPO_URL 16 | from speedtest import Speedtest 17 | from telethon import functions 18 | from os import remove, execle, path, makedirs, getenv, environ 19 | from shutil import rmtree 20 | import asyncio 21 | import json 22 | from asyncio import sleep 23 | from telethon.errors import rpcbaseerrors 24 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP 25 | import os 26 | import subprocess 27 | import time 28 | import math 29 | from pySmartDL import SmartDL 30 | import asyncio 31 | from hachoir.metadata import extractMetadata 32 | from hachoir.parser import createParser 33 | from telethon.tl.types import DocumentAttributeVideo 34 | from userbot import LOGS, CMD_HELP, TEMP_DOWNLOAD_DIRECTORY 35 | import sys 36 | from git import Repo 37 | from git.exc import GitCommandError, InvalidGitRepositoryError, NoSuchPathError 38 | from userbot import CMD_HELP, bot, HEROKU_APIKEY, HEROKU_APPNAME, UPSTREAM_REPO_URL 39 | from userbot import CMD_HELP, LOGS, HEROKU_APP_NAME, HEROKU_API_KEY 40 | from asyncio import create_subprocess_shell as asyncrunapp 41 | from asyncio.subprocess import PIPE as asyncPIPE 42 | from platform import python_version, uname 43 | from shutil import which 44 | from os import remove 45 | from telethon import version 46 | from userbot import CMD_HELP, ALIVE_NAME 47 | from userbot.events import javes05 48 | 49 | # ================= CONSTANT ================= 50 | DEFAULTUSER = str(ALIVE_NAME) if ALIVE_NAME else uname().node 51 | # ============================================ 52 | 53 | Heroku = heroku3.from_key(HEROKU_API_KEY) 54 | 55 | 56 | async def subprocess_run(cmd, heroku): 57 | subproc = await asyncSubprocess(cmd, stdout=asyncPIPE, stderr=asyncPIPE) 58 | stdout, stderr = await subproc.communicate() 59 | exitCode = subproc.returncode 60 | if exitCode != 0: 61 | await heroku.edit( 62 | '**An error was detected while running subprocess**\n' 63 | f'```exitCode: {exitCode}\n' 64 | f'stdout: {stdout.decode().strip()}\n' 65 | f'stderr: {stderr.decode().strip()}```') 66 | return exitCode 67 | return stdout.decode().strip(), stderr.decode().strip(), exitCode 68 | 69 | 70 | 71 | @javes05(outgoing=True, pattern=r"^!heroku(?: |$)(.*)") 72 | async def heroku_manager(heroku): 73 | await heroku.edit("`Processing...`") 74 | await asyncio.sleep(3) 75 | conf = heroku.pattern_match.group(1) 76 | result = await subprocess_run(f'heroku ps -a {HEROKU_APP_NAME}', heroku) 77 | if result[2] != 0: 78 | return 79 | hours_remaining = result[0] 80 | await heroku.edit('`' + hours_remaining + '`') 81 | return 82 | 83 | 84 | 85 | @javes05(outgoing=True, pattern="^\!sysd$") 86 | async def sysdetails(sysd): 87 | """ For .sysd command, get system info using neofetch. """ 88 | try: 89 | neo = "neofetch --stdout" 90 | fetch = await asyncrunapp( 91 | neo, 92 | stdout=asyncPIPE, 93 | stderr=asyncPIPE, 94 | ) 95 | 96 | stdout, stderr = await fetch.communicate() 97 | result = str(stdout.decode().strip()) \ 98 | + str(stderr.decode().strip()) 99 | 100 | await sysd.edit("`" + result + "`") 101 | except FileNotFoundError: 102 | await sysd.edit("`Install neofetch first !!`") 103 | 104 | 105 | 106 | 107 | 108 | @javes05(outgoing=True, pattern="^\!pip(?: |$)(.*)") 109 | async def pipcheck(pip): 110 | """ For .pip command, do a pip search. """ 111 | pipmodule = pip.pattern_match.group(1) 112 | if pipmodule: 113 | await pip.edit("`Searching . . .`") 114 | invokepip = f"pip3 search {pipmodule}" 115 | pipc = await asyncrunapp( 116 | invokepip, 117 | stdout=asyncPIPE, 118 | stderr=asyncPIPE, 119 | ) 120 | 121 | stdout, stderr = await pipc.communicate() 122 | pipout = str(stdout.decode().strip()) \ 123 | + str(stderr.decode().strip()) 124 | 125 | if pipout: 126 | if len(pipout) > 4096: 127 | await pip.edit("`Output too large, sending as file`") 128 | file = open("output.txt", "w+") 129 | file.write(pipout) 130 | file.close() 131 | await pip.client.send_file( 132 | pip.chat_id, 133 | "output.txt", 134 | reply_to=pip.id, 135 | ) 136 | remove("output.txt") 137 | return 138 | await pip.edit("**Query: **\n`" 139 | f"{invokepip}" 140 | "`\n**Result: **\n`" 141 | f"{pipout}" 142 | "`") 143 | else: 144 | await pip.edit("**Query: **\n`" 145 | f"{invokepip}" 146 | "`\n**Result: **\n`No Result Returned/False`") 147 | else: 148 | await pip.edit("`Use .help pip to see an example`") 149 | 150 | 151 | @javes05(outgoing=True, pattern="^\!javes$") 152 | async def amireallyalive(alive): 153 | """ For .javes command, check if the bot is running. """ 154 | await alive.edit("`" 155 | " Javes: Stay Alert from covid-19!\n\n" 156 | f"🦠 Javes : 1.3 \n" 157 | f"🦠 Telethon : {version.__version__} \n" 158 | f"🦠 Python : {python_version()} \n" 159 | f"🦠 User: {DEFAULTUSER}" 160 | "`") 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | requirements_path = path.join( 174 | path.dirname(path.dirname(path.dirname(__file__))), 'requirements.txt') 175 | 176 | 177 | async def gen_chlog(repo, diff): 178 | ch_log = '' 179 | d_form = "%d/%m/%y" 180 | for c in repo.iter_commits(diff): 181 | ch_log += f'•[{c.committed_datetime.strftime(d_form)}]: {c.summary} <{c.author}>\n' 182 | return ch_log 183 | 184 | 185 | async def update_requirements(): 186 | reqs = str(requirements_path) 187 | try: 188 | process = await asyncio.create_subprocess_shell( 189 | ' '.join([sys.executable, "-m", "pip", "install", "-r", reqs]), 190 | stdout=asyncio.subprocess.PIPE, 191 | stderr=asyncio.subprocess.PIPE) 192 | await process.communicate() 193 | return process.returncode 194 | except Exception as e: 195 | return repr(e) 196 | 197 | 198 | @javes05(outgoing=True, pattern="^\!update(?: |$)(.*)") 199 | async def upstream(ups): 200 | "For .update command, check if the bot is up to date, update if specified" 201 | await ups.edit("`Checking for updates, please wait....`") 202 | conf = ups.pattern_match.group(1) 203 | off_repo = UPSTREAM_REPO_URL 204 | force_update = False 205 | 206 | try: 207 | txt = "`Oops.. Updater cannot continue due to " 208 | txt += "some problems occured`\n\n**LOGTRACE:**\n" 209 | repo = Repo() 210 | except NoSuchPathError as error: 211 | await ups.edit(f'{txt}\n`directory {error} is not found`') 212 | repo.__del__() 213 | return 214 | except GitCommandError as error: 215 | await ups.edit(f'{txt}\n`Early failure! {error}`') 216 | repo.__del__() 217 | return 218 | except InvalidGitRepositoryError as error: 219 | if conf != "now": 220 | await ups.edit( 221 | f"`Unfortunately, the directory {error} does not seem to be a git repository.\ 222 | \nBut we can fix that by force updating the userbot using .update now.`" 223 | ) 224 | return 225 | repo = Repo.init() 226 | origin = repo.create_remote('upstream', off_repo) 227 | origin.fetch() 228 | force_update = True 229 | repo.create_head('master', origin.refs.master) 230 | repo.heads.master.set_tracking_branch(origin.refs.master) 231 | repo.heads.master.checkout(True) 232 | 233 | ac_br = repo.active_branch.name 234 | if ac_br != 'master': 235 | await ups.edit( 236 | f'**[UPDATER]:**` Looks like you are using your own custom branch ({ac_br}). ' 237 | 'in that case, Updater is unable to identify ' 238 | 'which branch is to be merged. ' 239 | 'please checkout to any official branch`') 240 | repo.__del__() 241 | return 242 | 243 | try: 244 | repo.create_remote('upstream', off_repo) 245 | except BaseException: 246 | pass 247 | 248 | ups_rem = repo.remote('upstream') 249 | ups_rem.fetch(ac_br) 250 | 251 | changelog = await gen_chlog(repo, f'HEAD..upstream/{ac_br}') 252 | 253 | if not changelog and not force_update: 254 | await ups.edit( 255 | f'\n`Javes is` **up-to-date** \n') 256 | repo.__del__() 257 | return 258 | 259 | if conf != "now" and not force_update: 260 | changelog_str = f'**New UPDATE available for Javes\n\nCHANGELOG:**\n`{changelog}`' 261 | if len(changelog_str) > 4096: 262 | await ups.edit("`Changelog is too big, view the file to see it.`") 263 | file = open("output.txt", "w+") 264 | file.write(changelog_str) 265 | file.close() 266 | await ups.client.send_file( 267 | ups.chat_id, 268 | "output.txt", 269 | reply_to=ups.id, 270 | ) 271 | remove("output.txt") 272 | else: 273 | await ups.edit(changelog_str) 274 | await ups.respond('`do \"!update now\" to update`') 275 | return 276 | 277 | if force_update: 278 | await ups.edit( 279 | '`Force-Syncing to latest stable userbot code, please wait...`') 280 | else: 281 | await ups.edit('`Updating javes, please wait....`') 282 | # We're in a Heroku Dyno, handle it's memez. 283 | if HEROKU_APIKEY is not None: 284 | import heroku3 285 | heroku = heroku3.from_key(HEROKU_APIKEY) 286 | heroku_app = None 287 | heroku_applications = heroku.apps() 288 | if not HEROKU_APPNAME: 289 | await ups.edit( 290 | '`Please set up the HEROKU_APPNAME variable to be able to update userbot.`' 291 | ) 292 | repo.__del__() 293 | return 294 | for app in heroku_applications: 295 | if app.name == HEROKU_APPNAME: 296 | heroku_app = app 297 | break 298 | if heroku_app is None: 299 | await ups.edit( 300 | f'{txt}\n`Invalid Heroku credentials for updating userbot dyno.`' 301 | ) 302 | repo.__del__() 303 | return 304 | await ups.edit('`[Updater]\ 305 | Javes dyno build in progress, please wait for it to complete.\n It may take 10 minutes `' 306 | ) 307 | ups_rem.fetch(ac_br) 308 | repo.git.reset("--hard", "FETCH_HEAD") 309 | heroku_git_url = heroku_app.git_url.replace( 310 | "https://", "https://api:" + HEROKU_APIKEY + "@") 311 | if "heroku" in repo.remotes: 312 | remote = repo.remote("heroku") 313 | remote.set_url(heroku_git_url) 314 | else: 315 | remote = repo.create_remote("heroku", heroku_git_url) 316 | try: 317 | remote.push(refspec="HEAD:refs/heads/master", force=True) 318 | except GitCommandError as error: 319 | await ups.edit(f'{txt}\n`Here is the error log:\n{error}`') 320 | repo.__del__() 321 | return 322 | await ups.edit('Successfully Updated!\n' 323 | 'Restarting......., type !javes for check') 324 | else: 325 | # Classic Updater, pretty straightforward. 326 | try: 327 | ups_rem.pull(ac_br) 328 | except GitCommandError: 329 | repo.git.reset("--hard", "FETCH_HEAD") 330 | reqs_upgrade = await update_requirements() 331 | await ups.edit('`Successfully Updated!\n' 332 | 'javes is restarting... Wait for a second!`') 333 | # Spin a new instance of bot 334 | args = [sys.executable, "-m", "userbot"] 335 | execle(sys.executable, *args, environ) 336 | return 337 | 338 | 339 | 340 | @javes05(outgoing=True, pattern="^\!speed$") 341 | async def speedtst(spd): 342 | """ For .speed command, use SpeedTest to check server speeds. """ 343 | await spd.edit("`Running speed test . . .`") 344 | test = Speedtest() 345 | 346 | test.get_best_server() 347 | test.download() 348 | test.upload() 349 | test.results.share() 350 | result = test.results.dict() 351 | 352 | await spd.edit("`" 353 | "Started at " 354 | f"{result['timestamp']} \n\n" 355 | "Download " 356 | f"{speed_convert(result['download'])} \n" 357 | "Upload " 358 | f"{speed_convert(result['upload'])} \n" 359 | "Ping " 360 | f"{result['ping']} \n" 361 | "ISP " 362 | f"{result['client']['isp']}" 363 | "`") 364 | 365 | 366 | def speed_convert(size): 367 | """ 368 | Hi human, you can't read bytes? 369 | """ 370 | power = 2**10 371 | zero = 0 372 | units = {0: '', 1: 'Kb/s', 2: 'Mb/s', 3: 'Gb/s', 4: 'Tb/s'} 373 | while size > power: 374 | size /= power 375 | zero += 1 376 | return f"{round(size, 2)} {units[zero]}" 377 | 378 | 379 | @javes05(outgoing=True, pattern="^\!dc$") 380 | async def neardc(event): 381 | """ For .dc command, get the nearest datacenter information. """ 382 | result = await event.client(functions.help.GetNearestDcRequest()) 383 | await event.edit(f"Country : `{result.country}`\n" 384 | f"Nearest Datacenter : `{result.nearest_dc}`\n" 385 | f"This Datacenter : `{result.this_dc}`") 386 | 387 | 388 | @javes05(outgoing=True, pattern="^\!ping$") 389 | async def pingme(pong): 390 | """ For .ping command, ping the userbot from any chat. """ 391 | start = datetime.now() 392 | await pong.edit("`Pong!`") 393 | end = datetime.now() 394 | duration = (end - start).microseconds / 1000 395 | await pong.edit("`Pong!\n%sms`" % (duration)) 396 | 397 | 398 | async def progress(current, total, event, start, type_of_ps, file_name=None): 399 | """Generic progress_callback for uploads and downloads.""" 400 | now = time.time() 401 | diff = now - start 402 | if round(diff % 10.00) == 0 or current == total: 403 | percentage = current * 100 / total 404 | speed = current / diff 405 | elapsed_time = round(diff) * 1000 406 | time_to_completion = round((total - current) / speed) * 1000 407 | estimated_total_time = elapsed_time + time_to_completion 408 | progress_str = "[{0}{1}] {2}%\n".format( 409 | ''.join(["?" for i in range(math.floor(percentage / 10))]), 410 | ''.join(["?" for i in range(10 - math.floor(percentage / 10))]), 411 | round(percentage, 2)) 412 | tmp = progress_str + \ 413 | "{0} of {1}\nETA: {2}".format( 414 | humanbytes(current), 415 | humanbytes(total), 416 | time_formatter(estimated_total_time) 417 | ) 418 | if file_name: 419 | await event.edit("{}\nFile Name: `{}`\n{}".format( 420 | type_of_ps, file_name, tmp)) 421 | else: 422 | await event.edit("{}\n{}".format(type_of_ps, tmp)) 423 | 424 | 425 | def humanbytes(size): 426 | """Input size in bytes, 427 | outputs in a human readable format""" 428 | # https://stackoverflow.com/a/49361727/4723940 429 | if not size: 430 | return "" 431 | # 2 ** 10 = 1024 432 | power = 2**10 433 | raised_to_pow = 0 434 | dict_power_n = {0: "", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"} 435 | while size > power: 436 | size /= power 437 | raised_to_pow += 1 438 | return str(round(size, 2)) + " " + dict_power_n[raised_to_pow] + "B" 439 | 440 | 441 | def time_formatter(milliseconds: int) -> str: 442 | """Inputs time in milliseconds, to get beautified time, 443 | as string""" 444 | seconds, milliseconds = divmod(int(milliseconds), 1000) 445 | minutes, seconds = divmod(seconds, 60) 446 | hours, minutes = divmod(minutes, 60) 447 | days, hours = divmod(hours, 24) 448 | tmp = ((str(days) + " day(s), ") if days else "") + \ 449 | ((str(hours) + " hour(s), ") if hours else "") + \ 450 | ((str(minutes) + " minute(s), ") if minutes else "") + \ 451 | ((str(seconds) + " second(s), ") if seconds else "") + \ 452 | ((str(milliseconds) + " millisecond(s), ") if milliseconds else "") 453 | return tmp[:-2] 454 | 455 | 456 | @javes05(pattern=r"^\!download(?: |$)(.*)", outgoing=True) 457 | async def download(target_file): 458 | """ For .download command, download files to the userbot's server. """ 459 | await target_file.edit("Processing ...") 460 | input_str = target_file.pattern_match.group(1) 461 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 462 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 463 | if "|" in input_str: 464 | url, file_name = input_str.split("|") 465 | url = url.strip() 466 | # https://stackoverflow.com/a/761825/4723940 467 | file_name = file_name.strip() 468 | head, tail = os.path.split(file_name) 469 | if head: 470 | if not os.path.isdir(os.path.join(TEMP_DOWNLOAD_DIRECTORY, head)): 471 | os.makedirs(os.path.join(TEMP_DOWNLOAD_DIRECTORY, head)) 472 | file_name = os.path.join(head, tail) 473 | downloaded_file_name = TEMP_DOWNLOAD_DIRECTORY + "" + file_name 474 | downloader = SmartDL(url, downloaded_file_name, progress_bar=False) 475 | downloader.start(blocking=False) 476 | c_time = time.time() 477 | display_message = None 478 | while not downloader.isFinished(): 479 | status = downloader.get_status().capitalize() 480 | total_length = downloader.filesize if downloader.filesize else None 481 | downloaded = downloader.get_dl_size() 482 | now = time.time() 483 | diff = now - c_time 484 | percentage = downloader.get_progress() * 100 485 | speed = downloader.get_speed() 486 | elapsed_time = round(diff) * 1000 487 | progress_str = "[{0}{1}] {2}%".format( 488 | ''.join(["?" for i in range(math.floor(percentage / 10))]), 489 | ''.join(["?" 490 | for i in range(10 - math.floor(percentage / 10))]), 491 | round(percentage, 2)) 492 | estimated_total_time = downloader.get_eta(human=True) 493 | try: 494 | current_message = f"{status}..\ 495 | \nURL: {url}\ 496 | \nFile Name: {file_name}\ 497 | \n{progress_str}\ 498 | \n{humanbytes(downloaded)} of {humanbytes(total_length)}\ 499 | \nETA: {estimated_total_time}" 500 | 501 | if round(diff % 502 | 10.00) == 0 and current_message != display_message: 503 | await target_file.edit(current_message) 504 | display_message = current_message 505 | except Exception as e: 506 | LOGS.info(str(e)) 507 | if downloader.isSuccessful(): 508 | await target_file.edit("Downloaded to `{}` successfully !!".format( 509 | downloaded_file_name)) 510 | else: 511 | await target_file.edit("Incorrect URL\n{}".format(url)) 512 | elif target_file.reply_to_msg_id: 513 | try: 514 | c_time = time.time() 515 | downloaded_file_name = await target_file.client.download_media( 516 | await target_file.get_reply_message(), 517 | TEMP_DOWNLOAD_DIRECTORY, 518 | progress_callback=lambda d, t: asyncio.get_event_loop( 519 | ).create_task( 520 | progress(d, t, target_file, c_time, "Downloading..."))) 521 | except Exception as e: # pylint:disable=C0103,W0703 522 | await target_file.edit(str(e)) 523 | else: 524 | await target_file.edit("Downloaded to `{}` successfully !!".format( 525 | downloaded_file_name)) 526 | else: 527 | await target_file.edit( 528 | "Reply to a message to download to my local server.") 529 | 530 | 531 | @javes05(pattern=r"^\!uploadir (.*)", outgoing=True) 532 | async def uploadir(udir_event): 533 | """ For .uploadir command, allows you to upload everything from a folder in the server""" 534 | input_str = udir_event.pattern_match.group(1) 535 | if os.path.exists(input_str): 536 | await udir_event.edit("Processing ...") 537 | lst_of_files = [] 538 | for r, d, f in os.walk(input_str): 539 | for file in f: 540 | lst_of_files.append(os.path.join(r, file)) 541 | for file in d: 542 | lst_of_files.append(os.path.join(r, file)) 543 | LOGS.info(lst_of_files) 544 | uploaded = 0 545 | await udir_event.edit( 546 | "Found {} files. Uploading will start soon. Please wait!".format( 547 | len(lst_of_files))) 548 | for single_file in lst_of_files: 549 | if os.path.exists(single_file): 550 | # https://stackoverflow.com/a/678242/4723940 551 | caption_rts = os.path.basename(single_file) 552 | c_time = time.time() 553 | if not caption_rts.lower().endswith(".mp4"): 554 | await udir_event.client.send_file( 555 | udir_event.chat_id, 556 | single_file, 557 | caption=caption_rts, 558 | force_document=False, 559 | allow_cache=False, 560 | reply_to=udir_event.message.id, 561 | progress_callback=lambda d, t: asyncio.get_event_loop( 562 | ).create_task( 563 | progress(d, t, udir_event, c_time, "Uploading...", 564 | single_file))) 565 | else: 566 | thumb_image = os.path.join(input_str, "thumb.jpg") 567 | c_time = time.time() 568 | metadata = extractMetadata(createParser(single_file)) 569 | duration = 0 570 | width = 0 571 | height = 0 572 | if metadata.has("duration"): 573 | duration = metadata.get("duration").seconds 574 | if metadata.has("width"): 575 | width = metadata.get("width") 576 | if metadata.has("height"): 577 | height = metadata.get("height") 578 | await udir_event.client.send_file( 579 | udir_event.chat_id, 580 | single_file, 581 | caption=caption_rts, 582 | thumb=thumb_image, 583 | force_document=False, 584 | allow_cache=False, 585 | reply_to=udir_event.message.id, 586 | attributes=[ 587 | DocumentAttributeVideo( 588 | duration=duration, 589 | w=width, 590 | h=height, 591 | round_message=False, 592 | supports_streaming=True, 593 | ) 594 | ], 595 | progress_callback=lambda d, t: asyncio.get_event_loop( 596 | ).create_task( 597 | progress(d, t, udir_event, c_time, "Uploading...", 598 | single_file))) 599 | os.remove(single_file) 600 | uploaded = uploaded + 1 601 | await udir_event.edit( 602 | "Uploaded {} files successfully !!".format(uploaded)) 603 | else: 604 | await udir_event.edit("404: Directory Not Found") 605 | 606 | 607 | @javes05(pattern=r"^\!upload (.*)", outgoing=True) 608 | async def upload(u_event): 609 | """ For .upload command, allows you to upload a file from the userbot's server """ 610 | await u_event.edit("Processing ...") 611 | input_str = u_event.pattern_match.group(1) 612 | if input_str in ("userbot.session", "config.env"): 613 | await u_event.edit("`That's a dangerous operation! Not Permitted!`") 614 | return 615 | if os.path.exists(input_str): 616 | c_time = time.time() 617 | await u_event.client.send_file( 618 | u_event.chat_id, 619 | input_str, 620 | force_document=True, 621 | allow_cache=False, 622 | reply_to=u_event.message.id, 623 | progress_callback=lambda d, t: asyncio.get_event_loop( 624 | ).create_task( 625 | progress(d, t, u_event, c_time, "Uploading...", input_str))) 626 | await u_event.edit("Uploaded successfully !!") 627 | else: 628 | await u_event.edit("404: File Not Found") 629 | 630 | 631 | def get_video_thumb(file, output=None, width=90): 632 | """ Get video thumbnail """ 633 | metadata = extractMetadata(createParser(file)) 634 | popen = subprocess.Popen( 635 | [ 636 | "ffmpeg", 637 | "-i", 638 | file, 639 | "-ss", 640 | str( 641 | int((0, metadata.get("duration").seconds 642 | )[metadata.has("duration")] / 2)), 643 | "-filter:v", 644 | "scale={}:-1".format(width), 645 | "-vframes", 646 | "1", 647 | output, 648 | ], 649 | stdout=subprocess.PIPE, 650 | stderr=subprocess.DEVNULL, 651 | ) 652 | if not popen.returncode and os.path.lexists(file): 653 | return output 654 | return None 655 | 656 | 657 | def extract_w_h(file): 658 | """ Get width and height of media """ 659 | command_to_run = [ 660 | "ffprobe", 661 | "-v", 662 | "quiet", 663 | "-print_format", 664 | "json", 665 | "-show_format", 666 | "-show_streams", 667 | file, 668 | ] 669 | # https://stackoverflow.com/a/11236144/4723940 670 | try: 671 | t_response = subprocess.check_output(command_to_run, 672 | stderr=subprocess.STDOUT) 673 | except subprocess.CalledProcessError as exc: 674 | LOGS.warning(exc) 675 | else: 676 | x_reponse = t_response.decode("UTF-8") 677 | response_json = json.loads(x_reponse) 678 | width = int(response_json["streams"][0]["width"]) 679 | height = int(response_json["streams"][0]["height"]) 680 | return width, height 681 | 682 | 683 | @javes05(pattern=r"^\!uploadas(stream|vn|all) (.*)", outgoing=True) 684 | async def uploadas(uas_event): 685 | """ For .uploadas command, allows you to specify some arguments for upload. """ 686 | await uas_event.edit("Processing ...") 687 | type_of_upload = uas_event.pattern_match.group(1) 688 | supports_streaming = False 689 | round_message = False 690 | spam_big_messages = False 691 | if type_of_upload == "stream": 692 | supports_streaming = True 693 | if type_of_upload == "vn": 694 | round_message = True 695 | if type_of_upload == "all": 696 | spam_big_messages = True 697 | input_str = uas_event.pattern_match.group(2) 698 | thumb = None 699 | file_name = None 700 | if "|" in input_str: 701 | file_name, thumb = input_str.split("|") 702 | file_name = file_name.strip() 703 | thumb = thumb.strip() 704 | else: 705 | file_name = input_str 706 | thumb_path = "a_random_f_file_name" + ".jpg" 707 | thumb = get_video_thumb(file_name, output=thumb_path) 708 | if os.path.exists(file_name): 709 | metadata = extractMetadata(createParser(file_name)) 710 | duration = 0 711 | width = 0 712 | height = 0 713 | if metadata.has("duration"): 714 | duration = metadata.get("duration").seconds 715 | if metadata.has("width"): 716 | width = metadata.get("width") 717 | if metadata.has("height"): 718 | height = metadata.get("height") 719 | try: 720 | if supports_streaming: 721 | c_time = time.time() 722 | await uas_event.client.send_file( 723 | uas_event.chat_id, 724 | file_name, 725 | thumb=thumb, 726 | caption=input_str, 727 | force_document=False, 728 | allow_cache=False, 729 | reply_to=uas_event.message.id, 730 | attributes=[ 731 | DocumentAttributeVideo( 732 | duration=duration, 733 | w=width, 734 | h=height, 735 | round_message=False, 736 | supports_streaming=True, 737 | ) 738 | ], 739 | progress_callback=lambda d, t: asyncio.get_event_loop( 740 | ).create_task( 741 | progress(d, t, uas_event, c_time, "Uploading...", 742 | file_name))) 743 | elif round_message: 744 | c_time = time.time() 745 | await uas_event.client.send_file( 746 | uas_event.chat_id, 747 | file_name, 748 | thumb=thumb, 749 | allow_cache=False, 750 | reply_to=uas_event.message.id, 751 | video_note=True, 752 | attributes=[ 753 | DocumentAttributeVideo( 754 | duration=0, 755 | w=1, 756 | h=1, 757 | round_message=True, 758 | supports_streaming=True, 759 | ) 760 | ], 761 | progress_callback=lambda d, t: asyncio.get_event_loop( 762 | ).create_task( 763 | progress(d, t, uas_event, c_time, "Uploading...", 764 | file_name))) 765 | elif spam_big_messages: 766 | await uas_event.edit("TBD: Not (yet) Implemented") 767 | return 768 | os.remove(thumb) 769 | await uas_event.edit("Uploaded successfully !!") 770 | except FileNotFoundError as err: 771 | await uas_event.edit(str(err)) 772 | else: 773 | await uas_event.edit("404: File Not Found") 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | @javes05(outgoing=True, pattern="^\!random") 789 | async def randomise(items): 790 | """ For .random command, get a random item from the list of items. """ 791 | itemo = (items.text[8:]).split() 792 | if len(itemo) < 2: 793 | await items.edit( 794 | "`2 or more items are required! Check .help random for more info.`" 795 | ) 796 | return 797 | index = randint(1, len(itemo) - 1) 798 | await items.edit("**Query: **\n`" + items.text[8:] + "`\n**Output: **\n`" + 799 | itemo[index] + "`") 800 | 801 | 802 | @javes05(outgoing=True, pattern="^\.sleep( [0-9]+)?$") 803 | async def sleepybot(time): 804 | """ For .sleep command, let the userbot snooze for a few second. """ 805 | message = time.text 806 | if " " not in time.pattern_match.group(1): 807 | await time.reply("Syntax: `.sleep [seconds]`") 808 | else: 809 | counter = int(time.pattern_match.group(1)) 810 | await time.edit("`I am sulking and snoozing....`") 811 | await sleep(2) 812 | if BOTLOG: 813 | await time.client.send_message( 814 | BOTLOG_CHATID, 815 | "You put the bot to sleep for " + str(counter) + " seconds", 816 | ) 817 | await sleep(counter) 818 | await time.edit("`OK, I'm awake now.`") 819 | 820 | 821 | @javes05(outgoing=True, pattern="^\!shutdown$") 822 | async def killdabot(event): 823 | """ For .shutdown command, shut the bot down.""" 824 | await event.edit("`Goodbye `") 825 | if BOTLOG: 826 | await event.client.send_message(BOTLOG_CHATID, "#SHUTDOWN \n" 827 | "Bot shut down") 828 | await bot.disconnect() 829 | 830 | 831 | @javes05(outgoing=True, pattern="^\!restart$") 832 | async def killdabot(event): 833 | await event.edit("`Restarting.....`") 834 | if BOTLOG: 835 | await event.client.send_message(BOTLOG_CHATID, "#RESTART \n" 836 | "Bot Restarted") 837 | await bot.disconnect() 838 | # Spin a new instance of bot 839 | execl(sys.executable, sys.executable, *sys.argv) 840 | 841 | 842 | # Copyright (c) Gegham Zakaryan | 2019 843 | @javes05(outgoing=True, pattern="^\!repeat (.*)") 844 | async def repeat(rep): 845 | cnt, txt = rep.pattern_match.group(1).split(' ', 1) 846 | replyCount = int(cnt) 847 | toBeRepeated = txt 848 | 849 | replyText = toBeRepeated + "\n" 850 | 851 | for i in range(0, replyCount - 1): 852 | replyText += toBeRepeated + "\n" 853 | 854 | await rep.edit(replyText) 855 | 856 | 857 | @javes05(outgoing=True, pattern="^\!repo$") 858 | async def repo_is_here(wannasee): 859 | """ For .repo command, just returns the repo URL. """ 860 | await wannasee.edit( 861 | f"This bot just re-edit PaperplaneExtended and added more futures from uniborg\n Click [here]({UPSTREAM_REPO_URL}) to open my javes's repository.\n =>Join channel for more information @javes05") 862 | 863 | 864 | @javes05(outgoing=True, pattern="^\!raw$") 865 | async def raw(event): 866 | the_real_message = None 867 | reply_to_id = None 868 | if event.reply_to_msg_id: 869 | previous_message = await event.get_reply_message() 870 | the_real_message = previous_message.stringify() 871 | reply_to_id = event.reply_to_msg_id 872 | else: 873 | the_real_message = event.stringify() 874 | reply_to_id = event.message.id 875 | with io.BytesIO(str.encode(the_real_message)) as out_file: 876 | out_file.name = "raw_message_data.txt" 877 | await event.edit( 878 | "`javes: `i have sent decoded message data in my chat!") 879 | await event.client.send_file( 880 | BOTLOG_CHATID, 881 | out_file, 882 | force_document=True, 883 | allow_cache=False, 884 | reply_to=reply_to_id, 885 | caption="`Here's the decoded message data !!`") 886 | 887 | 888 | --------------------------------------------------------------------------------