├── 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 | 
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 |
--------------------------------------------------------------------------------