diff --git a/.gitignore b/.gitignore
index 5c6490e0c..2a3874b40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -140,3 +140,6 @@ gen
unknown_errors.txt
logs/
bin/
+resources/base_profile_pic.jpg
+resources/mdfy_profile_pic.jpg
+pictest.py
diff --git a/README.md b/README.md
index ae9732e8d..0da9a22e4 100644
--- a/README.md
+++ b/README.md
@@ -133,7 +133,8 @@ async def testing(message: Message):
* [@uaudIth](https://t.me/uaudIth)
* [@K_E_N_W_A_Y](https://t.me/K_E_N_W_A_Y)
* [@nawwasl](https://t.me/nawwasl)
-* [@THARUKA](https://t.me/TharukaN97)
+* [@TharukaN97](https://t.me/TharukaN97)
+* [@Supun97](https://t.me/Supun97)
* [@gotstc](https://t.me/gotstc)
### Copyright & License 👮
diff --git a/app.json b/app.json
index 1044cecdf..5e4a9e51f 100644
--- a/app.json
+++ b/app.json
@@ -43,11 +43,6 @@
"description": "Your Languge ( ex: if english => 'en' )",
"required": false
},
- "SCREENSHOT_API": {
- "description": "get API key from 'https://screenshotlayer.com'",
- "required": false
-
- },
"CURRENCY_API": {
"description": "get API key from 'https://free.currencyconverterapi.com'",
"required": false
@@ -97,6 +92,12 @@
"buildpacks": [
{
"url": "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git"
+ }, {
+ "url": "https://github.com/opendoor-labs/heroku-buildpack-p7zip"
+ }, {
+ "url": "https://github.com/heroku/heroku-buildpack-google-chrome"
+ }, {
+ "url": "https://github.com/heroku/heroku-buildpack-chromedriver"
}, {
"url": "https://github.com/heroku/heroku-buildpack-apt.git"
}, {
diff --git a/config.env.sample b/config.env.sample
index d2bd1faa8..2f5abea2b 100644
--- a/config.env.sample
+++ b/config.env.sample
@@ -44,18 +44,18 @@ DOWN_PATH = "downloads/"
PREFERRED_LANGUAGE = ""
-# get API key from 'https://screenshotlayer.com'
-SCREENSHOT_API = ""
-
# get API Key from 'https://free.currencyconverterapi.com/'
CURRENCY_API = ""
+
# add default city for weather
WEATHER_DEFCITY = ""
+
# Weather API get it from 'https://openweathermap.org/'
OPEN_WEATHER_MAP = ""
+
# GDrive Folder ID
G_DRIVE_PARENT_ID = ""
diff --git a/resources/font.ttf b/resources/font.ttf
new file mode 100644
index 000000000..68d0b2907
Binary files /dev/null and b/resources/font.ttf differ
diff --git a/userge/config.py b/userge/config.py
index e00072330..29d280f9f 100644
--- a/userge/config.py
+++ b/userge/config.py
@@ -39,9 +39,7 @@
class Config:
- """
- Configs to setup Userge.
- """
+ """Configs to setup Userge"""
API_ID = int(os.environ.get("API_ID", 12345))
@@ -75,6 +73,10 @@ class Config:
G_DRIVE_IS_TD = bool(os.environ.get("G_DRIVE_IS_TD", False))
+ GOOGLE_CHROME_DRIVER = os.environ.get("GOOGLE_CHROME_DRIVER", None)
+
+ GOOGLE_CHROME_BIN = os.environ.get("GOOGLE_CHROME_BIN", None)
+
LOG_CHANNEL_ID = int(os.environ.get("LOG_CHANNEL_ID", 0))
UPSTREAM_REPO = os.environ.get("UPSTREAM_REPO", "https://github.com/UsergeTeam/Userge")
@@ -91,6 +93,8 @@ class Config:
WELCOME_DELETE_TIMEOUT = 120
+ AUTOPIC_TIMEOUT = 60
+
ALLOWED_CHATS = Filters.chat([])
CMD_TRIGGER = os.environ.get("CMD_TRIGGER", '.')
@@ -112,26 +116,19 @@ class Config:
if Config.HEROKU_API_KEY:
_LOG.info("Checking Heroku App...")
-
for heroku_app in heroku3.from_key(Config.HEROKU_API_KEY).apps():
if heroku_app and Config.HEROKU_APP_NAME and \
heroku_app.name == Config.HEROKU_APP_NAME:
-
_LOG.info("Heroku App : %s Found...", heroku_app.name)
-
Config.HEROKU_APP = heroku_app
Config.HEROKU_GIT_URL = heroku_app.git_url.replace(
"https://", "https://api:" + Config.HEROKU_API_KEY + "@")
-
if not os.path.isdir(os.path.join(os.getcwd(), '.git')):
tmp_heroku_git_path = os.path.join(os.getcwd(), 'tmp_heroku_git')
-
_LOG.info("Cloning Heroku GIT...")
-
Repo.clone_from(Config.HEROKU_GIT_URL, tmp_heroku_git_path)
shutil.move(os.path.join(tmp_heroku_git_path, '.git'), os.getcwd())
shutil.rmtree(tmp_heroku_git_path)
-
break
if not os.path.exists('bin'):
@@ -145,7 +142,6 @@ class Config:
"bin/cmrudl"}
_LOG.info("Checking BINs...")
-
for binary, path in _BINS.items():
if not os.path.exists(path):
_LOG.debug("Downloading %s...", binary)
diff --git a/userge/core/client.py b/userge/core/client.py
index 136b5dd02..1b85ebc34 100644
--- a/userge/core/client.py
+++ b/userge/core/client.py
@@ -41,6 +41,7 @@ class Userge(RawClient):
def __init__(self) -> None:
self._help_dict: Dict[str, Dict[str, str]] = {}
self._imported: List[ModuleType] = []
+ self._tasks: List[Callable[[Any], Any]] = []
self._channel = self.getCLogger(__name__)
_LOG.info(_LOG_STR, "Setting Userge Configs")
super().__init__(Config.HU_STRING_SESSION,
@@ -60,8 +61,7 @@ def getCLogger(self, name: str) -> CLogger:
def conversation(self,
chat_id: Union[str, int],
- *,
- timeout: Union[int, float] = 10,
+ *, timeout: Union[int, float] = 10,
limit: int = 10) -> Conv:
"""\nThis returns new conversation object.
@@ -87,8 +87,7 @@ async def send_read_acknowledge(self,
chat_id: Union[int, str],
message: Union[List[RawMessage],
Optional[RawMessage]] = None,
- *,
- max_id: Optional[int] = None,
+ *, max_id: Optional[int] = None,
clear_mentions: bool = False) -> bool:
"""\nMarks messages as read and optionally clears mentions.
@@ -135,7 +134,7 @@ async def send_read_acknowledge(self,
return await self.read_history(chat_id=chat_id, max_id=max_id)
return False
- async def get_user_dict(self, user_id: int) -> Dict[str, str]:
+ async def get_user_dict(self, user_id: Union[int, str]) -> Dict[str, str]:
"""This will return user `Dict` which contains
`id`(chat id), `fname`(first name), `lname`(last name),
`flname`(full name), `uname`(username) and `mention`.
@@ -307,14 +306,15 @@ def on_cmd(self,
filter_my_trigger = Filters.create(lambda _, query: \
query.text.startswith(trigger) if trigger else True)
sudo_filter = Filters.create(lambda _, query: \
- query.from_user and query.from_user.id in Config.SUDO_USERS and \
- (query.text.startswith(Config.SUDO_TRIGGER) if trigger else True))
+ (query.from_user
+ and query.from_user.id in Config.SUDO_USERS
+ and (query.text.startswith(Config.SUDO_TRIGGER) if trigger else True)))
sudo_cmd_filter = Filters.create(lambda _, __: \
cname.lstrip(trigger) in Config.ALLOWED_COMMANDS)
if filter_me:
- filters_ = filters_ & (
- ((Filters.outgoing | Filters.me) & filter_my_trigger) | \
- (Filters.incoming & sudo_filter & sudo_cmd_filter))
+ filters_ = (filters_
+ & (((Filters.outgoing | Filters.me) & filter_my_trigger)
+ | (Filters.incoming & sudo_filter & sudo_cmd_filter)))
return self._build_decorator(log=f"On {pattern}", filters=filters_,
group=group, **kwargs)
@@ -341,6 +341,11 @@ def on_left_member(self,
filters=Filters.left_chat_member & leaving_chats,
group=group)
+ def add_task(self, func: Callable[[Any], Any]) -> Callable[[Any], Any]:
+ """add tasks"""
+ self._tasks.append(func)
+ return func
+
def get_help(self,
key: str = '',
all_cmds: bool = False) -> Tuple[Union[str, List[str]], Union[bool, str]]:
@@ -349,8 +354,10 @@ def get_help(self,
"""
if not key and not all_cmds:
return sorted(list(self._help_dict)), True # names of all modules
- if not key.startswith(Config.CMD_TRIGGER) and key in self._help_dict and \
- (len(self._help_dict[key]) > 1 or list(self._help_dict[key])[0].lstrip(Config.CMD_TRIGGER) != key):
+ if (not key.startswith(Config.CMD_TRIGGER)
+ and key in self._help_dict
+ and (len(self._help_dict[key]) > 1
+ or list(self._help_dict[key])[0].lstrip(Config.CMD_TRIGGER) != key)):
return sorted(list(self._help_dict[key])), False # all commands for that module
dict_ = {x: y for _, i in self._help_dict.items() for x, y in i.items()}
@@ -443,9 +450,9 @@ def _build_decorator(self,
log: str,
filters: Filters,
group: int,
- **kwargs: Union[str, bool, Dict[
- str, Union[str, List[str], Dict[
- str, str]]]]) -> Callable[[_PYROFUNC], _PYROFUNC]:
+ **kwargs: Union[str, bool,
+ Dict[str, Union[str, List[str], Dict[str, str]]]]
+ ) -> Callable[[_PYROFUNC], _PYROFUNC]:
def _decorator(func: _PYROFUNC) -> _PYROFUNC:
async def _template(_: RawClient, __: RawMessage) -> None:
await func(Message(_, __, **kwargs))
@@ -490,7 +497,7 @@ async def reload_plugins(self) -> int:
_LOG.info(_LOG_STR, f"Reloaded {len(reloaded)} Plugins => {reloaded}")
return len(reloaded)
- async def restart(self) -> None:
+ async def restart(self, update_req: bool = False) -> None:
"""Restart the Userge"""
_LOG.info(_LOG_STR, "Restarting Userge")
await self.stop()
@@ -500,13 +507,29 @@ async def restart(self) -> None:
os.close(handler.fd)
except Exception as c_e:
_LOG.error(_LOG_STR, c_e)
+ if update_req:
+ os.system("pip3 install -r requirements.txt")
os.execl(sys.executable, sys.executable, '-m', 'userge')
sys.exit()
def begin(self) -> None:
"""This will start the Userge"""
- _LOG.info(_LOG_STR, "Starting Userge")
nest_asyncio.apply()
Conv.init(self)
- self.run()
+ loop = asyncio.get_event_loop()
+ run = loop.run_until_complete
+ _LOG.info(_LOG_STR, "Starting Userge")
+ run(self.start())
+ running_tasks: List[asyncio.Task] = []
+ for task in self._tasks:
+ running_tasks.append(loop.create_task(task()))
+ _LOG.info(_LOG_STR, "Idling Userge")
+ run(Userge.idle())
_LOG.info(_LOG_STR, "Exiting Userge")
+ for task in running_tasks:
+ task.cancel()
+ run(self.stop())
+ for task in asyncio.all_tasks():
+ task.cancel()
+ run(loop.shutdown_asyncgens())
+ loop.close()
diff --git a/userge/plugins/fun/autopic.py b/userge/plugins/fun/autopic.py
new file mode 100644
index 000000000..730109ff7
--- /dev/null
+++ b/userge/plugins/fun/autopic.py
@@ -0,0 +1,115 @@
+# Copyright (C) 2020 by UsergeTeam@Github, < https://github.com/UsergeTeam >.
+#
+# This file is part of < https://github.com/UsergeTeam/Userge > project,
+# and is released under the "GNU v3.0 License Agreement".
+# Please see < https://github.com/uaudith/Userge/blob/master/LICENSE >
+#
+# All rights reserved.
+
+
+import os
+import base64
+import asyncio
+import datetime
+import textwrap
+from shutil import copyfile
+
+import aiofiles
+from PIL import Image, ImageFont, ImageDraw
+
+from userge import userge, Message, Config, get_collection
+
+SAVED_SETTINGS = get_collection("CONFIGS")
+
+__tmp__ = SAVED_SETTINGS.find_one({'_id': 'UPDATE_PIC'})
+
+UPDATE_PIC = False
+BASE_PIC = "resources/base_profile_pic.jpg"
+MDFY_PIC = "resources/mdfy_profile_pic.jpg"
+if __tmp__:
+ UPDATE_PIC = __tmp__['on']
+ if not os.path.exists(BASE_PIC):
+ with open(BASE_PIC, "wb") as media_file_:
+ media_file_.write(base64.b64decode(__tmp__['media']))
+
+del __tmp__
+
+LOG = userge.getLogger(__name__)
+
+
+@userge.on_cmd("autopic", about={
+ 'header': "set profile picture",
+ 'usage': "{tr}autopic\n{tr}autopic [image path]\nset timeout using {tr}sappto"})
+async def autopic(message: Message):
+ global UPDATE_PIC
+ await message.edit('`processing...`')
+ if UPDATE_PIC:
+ if isinstance(UPDATE_PIC, asyncio.Task):
+ UPDATE_PIC.cancel()
+ UPDATE_PIC = False
+ SAVED_SETTINGS.update_one({'_id': 'UPDATE_PIC'},
+ {"$set": {'on': False}}, upsert=True)
+ await message.edit('auto profile picture updation has been **stopped**',
+ del_in=5, log=__name__)
+ return
+ image_path = message.input_str
+ store = False
+ if os.path.exists(BASE_PIC) and not image_path:
+ pass
+ elif not image_path:
+ profile_photo = await userge.get_profile_photos("me", limit=1)
+ if not profile_photo:
+ await message.err("sorry, couldn't find any picture!")
+ return
+ await userge.download_media(profile_photo[0], file_name=BASE_PIC)
+ store = True
+ else:
+ if not os.path.exists(image_path):
+ await message.err("input path not found!")
+ return
+ if os.path.exists(BASE_PIC):
+ os.remove(BASE_PIC)
+ copyfile(image_path, BASE_PIC)
+ store = True
+ data_dict = {'on': True}
+ if store:
+ async with aiofiles.open(BASE_PIC, "rb") as media_file:
+ media = base64.b64encode(await media_file.read())
+ data_dict['media'] = media
+ SAVED_SETTINGS.update_one({'_id': 'UPDATE_PIC'},
+ {"$set": data_dict}, upsert=True)
+ await message.edit(
+ 'auto profile picture updation has been **started**', del_in=3, log=__name__)
+ UPDATE_PIC = asyncio.create_task(apic_worker())
+
+
+@userge.add_task
+async def apic_worker():
+ user_dict = await userge.get_user_dict('me')
+ user = '@' + user_dict['uname'] if user_dict['uname'] else user_dict['flname']
+ while UPDATE_PIC:
+ img = Image.open(BASE_PIC)
+ i_width, i_height = img.size
+ s_font = ImageFont.truetype("resources/font.ttf", int((35 / 640)*i_width))
+ l_font = ImageFont.truetype("resources/font.ttf", int((50 / 640)*i_width))
+ draw = ImageDraw.Draw(img)
+ current_h, pad = 10, 0
+ for user in textwrap.wrap(user, width=20):
+ u_width, u_height = draw.textsize(user, font=l_font)
+ draw.text(xy=((i_width - u_width) / 2, int((current_h / 640)*i_width)), text=user,
+ font=l_font, fill=(255, 255, 255))
+ current_h += u_height + pad
+ tim = datetime.datetime.now(
+ tz=datetime.timezone(datetime.timedelta(minutes=30, hours=5)))
+ date_time = (f"DATE: {tim.day}.{tim.month}.{tim.year}\n"
+ f"TIME: {tim.hour}:{tim.minute}:{tim.second}\n"
+ "UTC+5:30")
+ d_width, d_height = draw.textsize(date_time, font=s_font)
+ draw.multiline_text(
+ xy=((i_width - d_width) / 2, i_height - d_height - int((20 / 640)*i_width)),
+ text=date_time, fill=(255, 255, 255), font=s_font, align="center")
+ img.convert('RGB').save(MDFY_PIC)
+ await userge.set_profile_photo(MDFY_PIC)
+ os.remove(MDFY_PIC)
+ LOG.info("profile photo has been updated!")
+ await asyncio.sleep(Config.AUTOPIC_TIMEOUT)
diff --git a/userge/plugins/fun/carbon.py b/userge/plugins/fun/carbon.py
new file mode 100644
index 000000000..0cb89257e
--- /dev/null
+++ b/userge/plugins/fun/carbon.py
@@ -0,0 +1,48 @@
+# Copyright (C) 2020 by UsergeTeam@Github, < https://github.com/UsergeTeam >.
+#
+# This file is part of < https://github.com/UsergeTeam/Userge > project,
+# and is released under the "GNU v3.0 License Agreement".
+# Please see < https://github.com/uaudith/Userge/blob/master/LICENSE >
+#
+# All rights reserved.
+
+
+import random
+import asyncio
+
+from pyrogram.errors.exceptions.bad_request_400 import YouBlockedUser
+
+from userge import userge, Message
+
+
+@userge.on_cmd("carbon", about={
+ 'header': "create a carbon",
+ 'usage': "{tr}carbon [text | reply to msg]"})
+async def carbon_(message: Message):
+ replied = message.reply_to_message
+ if replied:
+ text = replied.text
+ else:
+ text = message.input_str
+ if not text:
+ await message.err("input not found!")
+ return
+ await message.edit("`creating a carbon...`")
+ async with userge.conversation("CarbonNowShBot", timeout=30) as conv:
+ try:
+ await conv.send_message(text)
+ except YouBlockedUser:
+ await message.edit('first **unblock** @CarbonNowShBot')
+ return
+ response = await conv.get_response(mark_read=True)
+ await response.click(x=random.randint(0, 2), y=random.randint(0, 8))
+ response = await conv.get_response(mark_read=True)
+ while not response.media:
+ response = await conv.get_response(mark_read=True)
+ caption = "\n".join(response.caption.split("\n")[0:2])
+ file_id = response.document.file_id
+ await message.delete()
+ await userge.send_document(chat_id=message.chat.id,
+ document=file_id,
+ caption='`' + caption + '`',
+ reply_to_message_id=replied.message_id if replied else None)
diff --git a/userge/plugins/fun/kang.py b/userge/plugins/fun/kang.py
index 03d24bc62..f2e201442 100644
--- a/userge/plugins/fun/kang.py
+++ b/userge/plugins/fun/kang.py
@@ -15,6 +15,7 @@
from PIL import Image
from pyrogram.api.functions.messages import GetStickerSet
from pyrogram.api.types import InputStickerSetShortName
+from pyrogram.errors.exceptions.bad_request_400 import YouBlockedUser
from userge import userge, Message, Config, pool
@@ -85,7 +86,11 @@ def get_response():
if (" A Telegram user has created "
"the Sticker Set.") not in htmlstr:
async with userge.conversation('Stickers') as conv:
- await conv.send_message('/addsticker')
+ try:
+ await conv.send_message('/addsticker')
+ except YouBlockedUser:
+ await message.edit('first **unblock** @Stickers')
+ return
await conv.get_response(mark_read=True)
await conv.send_message(packname)
msg = await conv.get_response(mark_read=True)
@@ -134,7 +139,11 @@ def get_response():
else:
await message.edit("`Brewing a new Pack...`")
async with userge.conversation('Stickers') as conv:
- await conv.send_message(cmd)
+ try:
+ await conv.send_message(cmd)
+ except YouBlockedUser:
+ await message.edit('first **unblock** @Stickers')
+ return
await conv.get_response(mark_read=True)
await conv.send_message(packnick)
await conv.get_response(mark_read=True)
diff --git a/userge/plugins/fun/memes.py b/userge/plugins/fun/memes.py
index 91897fa88..2797ec6a3 100644
--- a/userge/plugins/fun/memes.py
+++ b/userge/plugins/fun/memes.py
@@ -257,11 +257,32 @@
"( ^_^)o自自o(^_^ )", "ಠ‿ಠ", "ヽ(´▽`)/", "ᵒᴥᵒ#", "( ͡° ͜ʖ ͡°)", "┬─┬ ノ( ゜-゜ノ)", "ヽ(´ー`)ノ",
"☜(⌒▽⌒)☞", "ε=ε=ε=┌(;*´Д`)ノ", "(╬ ಠ益ಠ)", "┬─┬⃰͡ (ᵔᵕᵔ͜ )", "┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻", r"¯\_(ツ)_/¯", "ʕᵔᴥᵔʔ",
"(`・ω・´)", "ʕ•ᴥ•ʔ", "ლ(`ー´ლ)", "ʕʘ̅͜ʘ̅ʔ", "( ゚Д゚)", r"¯\(°_o)/¯", "(。◕‿◕。)",
- "(ノಠ ∩ಠ)ノ彡( \\o°o)\\", "“ヽ(´▽`)ノ”",)
+ "(ノಠ ∩ಠ)ノ彡( \\o°o)\\", "“ヽ(´▽`)ノ”", "( ͡° ͜ʖ ͡°)", "¯\_(ツ)_/¯", "( ͡°( ͡° ͜ʖ( ͡° ͜ʖ ͡°)ʖ ͡°) ͡°)",
+ "ʕ•ᴥ•ʔ", "(▀̿Ĺ̯▀̿ ̿)", "(ง ͠° ͟ل͜ ͡°)ง", "༼ つ ◕_◕ ༽つ", "ಠ_ಠ", "(☞ ͡° ͜ʖ ͡°)☞",
+ "¯\_༼ ି ~ ି ༽_/¯", "c༼ ͡° ͜ʖ ͡° ༽⊃")
+HAPPY = ("( ͡° ͜ʖ ͡°)", "(ʘ‿ʘ)", "(✿´‿`)", "=͟͟͞͞٩(๑☉ᴗ☉)੭ु⁾⁾", "(*⌒▽⌒*)θ~♪",
+ "°˖✧◝(⁰▿⁰)◜✧˖°", "✌(-‿-)✌", "⌒°(❛ᴗ❛)°⌒", "(゚<|\(・ω・)/|>゚)", "ヾ(o✪‿✪o)シ")
-@userge.on_cmd(r"(?:[kK]ek|:/)$",
- about={'header': "Check yourself, hint: `:/`"}, name='kek',trigger='')
+THINKING = ("(҂⌣̀_⌣́)", "(;¬_¬)", "(-。-;", "┌[ O ʖ̯ O ]┐", "〳 ͡° Ĺ̯ ͡° 〵")
+
+WAVING = ("(ノ^∇^)", "(;-_-)/", "@(o・ェ・)@ノ", "ヾ(^-^)ノ", "ヾ(◍’౪`◍)ノ゙♡", "(ό‿ὸ)ノ", "(ヾ(´・ω・`)")
+
+WTF = ("༎ຶ‿༎ຶ", "(‿ˠ‿)", "╰U╯☜(◉ɷ◉ )", "(;´༎ຶ益༎ຶ`)♡", "╭∩╮(︶ε︶*)chu", "( ^◡^)っ (‿|‿)")
+
+LOVE = ("乂❤‿❤乂", "(。♥‿♥。)", "( ͡~ ͜ʖ ͡°)", "໒( ♥ ◡ ♥ )७", "༼♥ل͜♥༽")
+
+CONFUSED = ("(・_・ヾ", "「(゚ペ)", "﴾͡๏̯͡๏﴿", "( ̄■ ̄;)!?", "▐ ˵ ͠° (oo) °͠ ˵ ▐", "(-_-)ゞ゛")
+
+DEAD = ("(✖╭╮✖)", "✖‿✖", "(+_+)", "(✖﹏✖)", "∑(✘Д✘๑)")
+
+SAD = ("(@´_`@)", "⊙︿⊙", "(▰˘︹˘▰)", "●︿●", "( ´_ノ` )", "彡(-_-;)彡")
+
+DOG = ("-ᄒᴥᄒ-", "◖⚆ᴥ⚆◗")
+
+
+@userge.on_cmd(r"(?:Kek|:/)$",
+ about={'header': "Check yourself, hint: `:/`"}, name='Kek',trigger='')
async def kek_(message: Message):
"""kek"""
kek = ["/", "\\"]
@@ -270,8 +291,8 @@ async def kek_(message: Message):
await message.edit(":" + kek[i % 2])
-@userge.on_cmd(r"(?:[lL]ol|-_-)$",
- about={'header': "Check yourself, hint: `-_-`"}, name='lol',trigger='')
+@userge.on_cmd(r"(?:Lol|-_-)$",
+ about={'header': "Check yourself, hint: `-_-`"}, name='Lol',trigger='')
async def lol_(message: Message):
"""lol"""
lol = "-_ "
@@ -282,8 +303,8 @@ async def lol_(message: Message):
await message.edit(lol, parse_mode="html")
-@userge.on_cmd(r"(?:[fF]un|;_;)$",
- about={'header': "Check yourself, hint: `;_;`"}, name="fun", trigger='')
+@userge.on_cmd(r"(?:Fun|;_;)$",
+ about={'header': "Check yourself, hint: `;_;`"}, name="Fun", trigger='')
async def fun_(message: Message):
"""fun"""
fun = ";_ "
@@ -294,7 +315,7 @@ async def fun_(message: Message):
await message.edit(fun, parse_mode="html")
-@userge.on_cmd("[oO]of$", about={'header': "Ooooof"}, name='oof', trigger='')
+@userge.on_cmd("Oof$", about={'header': "Ooooof"}, name='Oof', trigger='')
async def Oof_(message: Message):
"""Oof"""
Oof = "Oo "
@@ -303,7 +324,7 @@ async def Oof_(message: Message):
await message.edit(Oof)
-@userge.on_cmd("[hH]mm$", about={'header': "Hmmmmm"}, name='hmm', trigger='')
+@userge.on_cmd("Hmm$", about={'header': "Hmmmmm"}, name='Hmm', trigger='')
async def Hmm_(message: Message):
"""Hmm"""
Hmm = "Hm "
@@ -312,43 +333,33 @@ async def Hmm_(message: Message):
await message.edit(Hmm)
-@userge.on_cmd("fp$", about={'header': "Facepalm :P"})
-async def facepalm_(message: Message):
- """facepalm_"""
+async def check_and_send(message: Message, *args, **kwargs):
replied = message.reply_to_message
if replied:
await asyncio.gather(
message.delete(),
- replied.reply("🤦♂")
+ replied.reply(*args, **kwargs)
)
else:
- await message.edit("🤦♂")
+ await message.edit(*args, **kwargs)
+
+
+@userge.on_cmd("fp$", about={'header': "Facepalm :P"})
+async def facepalm_(message: Message):
+ """facepalm_"""
+ await check_and_send(message, "🤦♂")
@userge.on_cmd("cry$", about={'header': "y u du dis, i cri"})
async def cry_(message: Message):
"""cry"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(CRI), parse_mode="html")
- )
- else:
- await message.edit(choice(CRI), parse_mode="html")
+ await check_and_send(message, choice(CRI), parse_mode="html")
@userge.on_cmd("insult$", about={'header': "Check yourself ;)"})
async def insult_(message: Message):
"""insult"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(INSULT_STRINGS), parse_mode="html")
- )
- else:
- await message.edit(choice(INSULT_STRINGS), parse_mode="html")
+ await check_and_send(message, choice(INSULT_STRINGS), parse_mode="html")
@userge.on_cmd("hi", about={
@@ -382,82 +393,65 @@ async def hi_(message: Message):
await message.edit(pay)
-@userge.on_cmd("react$", about={'header': "Make your userbot react to everything"})
+@userge.on_cmd("react", about={
+ 'header': "Make your userbot react to everything",
+ 'types': ['happy', 'thinking', 'waving', 'wtf', 'love', 'confused', 'dead', 'sad', 'dog'],
+ 'usage': "{tr}react [type]",
+ 'examples': ["{tr}react", "{tr}react dead"]})
async def react_(message: Message):
"""react"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(FACEREACTS), parse_mode="html")
- )
+ type_ = message.input_str
+ if "happy" in type_:
+ out = choice(HAPPY)
+ elif "thinking" in type_:
+ out = choice(THINKING)
+ elif "waving" in type_:
+ out = choice(WAVING)
+ elif "wtf" in type_:
+ out = choice(WTF)
+ elif "love" in type_:
+ out = choice(LOVE)
+ elif "confused" in type_:
+ out = choice(CONFUSED)
+ elif "dead" in type_:
+ out = choice(DEAD)
+ elif "sad" in type_:
+ out = choice(SAD)
+ elif "dog" in type_:
+ out = choice(DOG)
else:
- await message.edit(choice(FACEREACTS), parse_mode="html")
+ out = choice(FACEREACTS)
+ await check_and_send(message, out, parse_mode="html")
@userge.on_cmd("shg$", about={'header': "Shrug at it !!"})
async def shrugger(message: Message):
"""shrugger"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(SHGS), parse_mode="html")
- )
- else:
- await message.edit(choice(SHGS), parse_mode="html")
+ await check_and_send(message, choice(SHGS), parse_mode="html")
@userge.on_cmd("chase$", about={'header': "You better start running"})
async def chase_(message: Message):
"""chase"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(CHASE_STR), parse_mode="html")
- )
- else:
- await message.edit(choice(CHASE_STR), parse_mode="html")
+ await check_and_send(message, choice(CHASE_STR), parse_mode="html")
@userge.on_cmd("run$", about={'header': "Let Me Run, run, RUNNN!"})
async def run_(message: Message):
"""run"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(RUNS_STR), parse_mode="html")
- )
- else:
- await message.edit(choice(RUNS_STR), parse_mode="html")
+ await check_and_send(message, choice(RUNS_STR), parse_mode="html")
@userge.on_cmd("metoo$", about={'header': "Haha yes"})
async def metoo_(message: Message):
"""metoo"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply(choice(METOOSTR), parse_mode="html")
- )
- else:
- await message.edit(choice(METOOSTR), parse_mode="html")
+ await check_and_send(message, choice(METOOSTR), parse_mode="html")
@userge.on_cmd("10iq$", about={'header': "You retard !!"}, name="10iq")
async def iqless(message: Message):
"""iqless"""
- replied = message.reply_to_message
- if replied:
- await asyncio.gather(
- message.delete(),
- replied.reply("♿")
- )
- else:
- await message.edit("♿")
+ await check_and_send(message, "♿")
@userge.on_cmd("moon$", about={'header': "kensar moon animation"})
diff --git a/userge/plugins/utils/quote.py b/userge/plugins/fun/quote.py
similarity index 61%
rename from userge/plugins/utils/quote.py
rename to userge/plugins/fun/quote.py
index dd77dc2ff..d57d3c236 100644
--- a/userge/plugins/utils/quote.py
+++ b/userge/plugins/fun/quote.py
@@ -9,6 +9,8 @@
import asyncio
+from pyrogram.errors.exceptions.bad_request_400 import YouBlockedUser
+
from userge import userge, Message
@@ -21,12 +23,19 @@ async def quotecmd(message: Message):
args = message.input_str
replied = message.reply_to_message
async with userge.conversation('QuotLyBot') as conv:
- if replied:
- await userge.forward_messages(chat_id=conv.chat_id,
- from_chat_id=message.chat.id,
- message_ids=replied.message_id)
- else:
- await conv.send_message(args)
+ try:
+ if replied:
+ await userge.forward_messages(chat_id=conv.chat_id,
+ from_chat_id=message.chat.id,
+ message_ids=replied.message_id)
+ else:
+ if not args:
+ await message.err('input not found!')
+ return
+ await conv.send_message(args)
+ except YouBlockedUser:
+ await message.edit('first **unblock** @QuotLyBot')
+ return
quote = await conv.get_response(mark_read=True)
await userge.forward_messages(chat_id=message.chat.id,
from_chat_id=conv.chat_id,
diff --git a/userge/plugins/misc/upload.py b/userge/plugins/misc/upload.py
index ecb597662..f715fcd38 100644
--- a/userge/plugins/misc/upload.py
+++ b/userge/plugins/misc/upload.py
@@ -70,19 +70,24 @@ async def doc_upload(chat_id, path):
c_time = time.time()
thumb = await get_thumb()
await userge.send_chat_action(chat_id, "upload_document")
- msg = await userge.send_document(
- chat_id=chat_id,
- document=str(path),
- thumb=thumb,
- caption=path.name,
- parse_mode="html",
- disable_notification=True,
- progress=progress,
- progress_args=(
- "uploading", userge, message, c_time
+ try:
+ msg = await userge.send_document(
+ chat_id=chat_id,
+ document=str(path),
+ thumb=thumb,
+ caption=path.name,
+ parse_mode="html",
+ disable_notification=True,
+ progress=progress,
+ progress_args=(
+ "uploading", userge, message, c_time, str(path.name)
+ )
)
- )
- await finalize(chat_id, message, msg, start_t)
+ except Exception as u_e:
+ await message.edit(u_e)
+ raise u_e
+ else:
+ await finalize(chat_id, message, msg, start_t)
async def vid_upload(chat_id, path):
@@ -94,21 +99,26 @@ async def vid_upload(chat_id, path):
start_t = datetime.now()
c_time = time.time()
await userge.send_chat_action(chat_id, "upload_video")
- msg = await userge.send_video(
- chat_id=chat_id,
- video=strpath,
- duration=metadata.get("duration").seconds,
- thumb=thumb,
- caption=path.name,
- parse_mode="html",
- disable_notification=True,
- progress=progress,
- progress_args=(
- "uploading", userge, message, c_time
+ try:
+ msg = await userge.send_video(
+ chat_id=chat_id,
+ video=strpath,
+ duration=metadata.get("duration").seconds,
+ thumb=thumb,
+ caption=path.name,
+ parse_mode="html",
+ disable_notification=True,
+ progress=progress,
+ progress_args=(
+ "uploading", userge, message, c_time, str(path.name)
+ )
)
- )
- await remove_thumb(thumb)
- await finalize(chat_id, message, msg, start_t)
+ except Exception as u_e:
+ await message.edit(u_e)
+ raise u_e
+ else:
+ await remove_thumb(thumb)
+ await finalize(chat_id, message, msg, start_t)
async def audio_upload(chat_id, path):
@@ -126,22 +136,27 @@ async def audio_upload(chat_id, path):
if metadata.has("artist"):
artist = metadata.get("artist")
await userge.send_chat_action(chat_id, "upload_audio")
- msg = await userge.send_audio(
- chat_id=chat_id,
- audio=strpath,
- thumb=thumb,
- caption=path.name,
- title=title,
- performer=artist,
- duration=metadata.get("duration").seconds,
- parse_mode="html",
- disable_notification=True,
- progress=progress,
- progress_args=(
- "uploading", userge, message, c_time
+ try:
+ msg = await userge.send_audio(
+ chat_id=chat_id,
+ audio=strpath,
+ thumb=thumb,
+ caption=path.name,
+ title=title,
+ performer=artist,
+ duration=metadata.get("duration").seconds,
+ parse_mode="html",
+ disable_notification=True,
+ progress=progress,
+ progress_args=(
+ "uploading", userge, message, c_time, str(path.name)
+ )
)
- )
- await finalize(chat_id, message, msg, start_t)
+ except Exception as u_e:
+ await message.edit(u_e)
+ raise u_e
+ else:
+ await finalize(chat_id, message, msg, start_t)
async def get_thumb(path: str = ''):
@@ -172,4 +187,4 @@ async def finalize(chat_id: int, message: Message, msg: Message, start_t: int):
else:
end_t = datetime.now()
ms = (end_t - start_t).seconds
- await message.edit(f"Uploaded in {ms} seconds")
\ No newline at end of file
+ await message.edit(f"Uploaded in {ms} seconds")
diff --git a/userge/plugins/tools/timeout.py b/userge/plugins/tools/timeout.py
index 85ead6f0c..f8c6df885 100644
--- a/userge/plugins/tools/timeout.py
+++ b/userge/plugins/tools/timeout.py
@@ -13,6 +13,7 @@
__tmp_msg__ = SAVED_SETTINGS.find_one({'_id': 'MSG_DELETE_TIMEOUT'})
__tmp_wel__ = SAVED_SETTINGS.find_one({'_id': 'WELCOME_DELETE_TIMEOUT'})
+__tmp_pp__ = SAVED_SETTINGS.find_one({'_id': 'AUTOPIC_TIMEOUT'})
if __tmp_msg__:
Config.MSG_DELETE_TIMEOUT = __tmp_msg__['data']
@@ -20,7 +21,10 @@
if __tmp_wel__:
Config.WELCOME_DELETE_TIMEOUT = __tmp_wel__['data']
-del __tmp_msg__, __tmp_wel__
+if __tmp_pp__:
+ Config.AUTOPIC_TIMEOUT = __tmp_pp__['data']
+
+del __tmp_msg__, __tmp_wel__, __tmp_pp__
@userge.on_cmd("sdelto (\\d+)", about={
@@ -46,7 +50,7 @@ async def view_delete_timeout(message: Message):
"""view delete timeout"""
if Config.MSG_DELETE_TIMEOUT:
await message.edit(
- f"`Currently messages will be deleted after {Config.MSG_DELETE_TIMEOUT} seconds!`",
+ f"`Messages will be deleted after {Config.MSG_DELETE_TIMEOUT} seconds!`",
del_in=5)
else:
await message.edit(f"`Auto message deletion disabled!`", del_in=3)
@@ -75,7 +79,34 @@ async def view_welcome_timeout(message: Message):
"""view welcome/left timeout"""
if Config.WELCOME_DELETE_TIMEOUT:
await message.edit(
- f"`Currently welcome/left messages will be deleted after {Config.WELCOME_DELETE_TIMEOUT} seconds!`",
+ f"`Welcome/Left messages will be deleted after "
+ f"{Config.WELCOME_DELETE_TIMEOUT} seconds!`",
del_in=5)
else:
await message.edit(f"`Auto welcome/left message deletion disabled!`", del_in=3)
+
+
+@userge.on_cmd("sapicto (\\d+)", about={
+ 'header': "Set auto profile picture timeout",
+ 'usage': "{tr}sapicto [timeout in seconds]",
+ 'examples': "{tr}sapicto 60"})
+async def set_app_timeout(message: Message):
+ """set auto profile picture timeout"""
+ t_o = int(message.matches[0].group(1))
+ if t_o < 15:
+ await message.err("too short! (min > 15sec)")
+ return
+ await message.edit("`Setting auto profile picture timeout...`")
+ Config.AUTOPIC_TIMEOUT = t_o
+ SAVED_SETTINGS.update_one(
+ {'_id': 'AUTOPIC_TIMEOUT'}, {"$set": {'data': t_o}}, upsert=True)
+ await message.edit(
+ f"`Set auto profile picture timeout as {t_o} seconds!`", del_in=3)
+
+
+@userge.on_cmd("vapicto", about={'header': "View auto profile picture timeout"})
+async def view_app_timeout(message: Message):
+ """view profile picture timeout"""
+ await message.edit(
+ f"`Profile picture will be updated after {Config.AUTOPIC_TIMEOUT} seconds!`",
+ del_in=5)
diff --git a/userge/plugins/tools/updater.py b/userge/plugins/tools/updater.py
index d8ab8d0e5..db33f8685 100644
--- a/userge/plugins/tools/updater.py
+++ b/userge/plugins/tools/updater.py
@@ -91,7 +91,7 @@ async def check_update(message: Message):
await message.edit(
'**Userge Successfully Updated!**\n'
'`Now restarting... Wait for a while!`', del_in=3)
- asyncio.get_event_loop().create_task(userge.restart())
+ asyncio.get_event_loop().create_task(userge.restart(update_req=True))
return
if not Config.HEROKU_GIT_URL:
await message.err("please set heroku things...")
diff --git a/userge/plugins/utils/webss.py b/userge/plugins/utils/webss.py
index f0d4c138e..242552f85 100644
--- a/userge/plugins/utils/webss.py
+++ b/userge/plugins/utils/webss.py
@@ -8,49 +8,62 @@
import os
-from time import time
-import requests
-from userge import userge, Message, Config
+from re import match
+from asyncio import sleep
+
+import aiofiles
+from selenium import webdriver
-CHANNEL = userge.getCLogger(__name__)
+from userge import userge, Message, Config
@userge.on_cmd("webss", about={'header': "Get snapshot of a website"})
async def webss(message: Message):
- if Config.SCREENSHOT_API is None:
- await message.edit(
- "Damn!\nI forgot to get the api from (here)[https://screenshotlayer.com]",
- del_in=0)
+ link_match = match(r'\bhttps?://.*\.\S+', message.input_str)
+ if not link_match:
+ await message.err("`I need a valid link to take screenshots from.`")
return
- await message.edit("`Processing`")
- suc, data = await getimg(message.input_str)
- if suc:
- await message.edit('Uploading..')
- await userge.send_chat_action(message.chat.id, "upload_photo")
-
- msg = await userge.send_document(message.chat.id, data, caption=message.input_str)
- await CHANNEL.fwd_msg(msg)
-
- await message.delete()
- await userge.send_chat_action(message.chat.id, "cancel")
- if os.path.isfile(data):
- os.remove(data)
- else:
- await message.err(data, del_in=6)
-
-
-async def getimg(url):
- requrl = "https://api.screenshotlayer.com/api/capture"
- requrl += "?access_key={}&url={}&fullpage={}&viewport={}"
- response = requests.get(
- requrl.format(Config.SCREENSHOT_API, url, '1', "2560x1440"),
- stream=True
- )
- if 'image' in response.headers["content-type"]:
- fname = f"screenshot_{time()}.png"
- with open(fname, "wb") as file:
- for chunk in response.iter_content(chunk_size=128):
- file.write(chunk)
- return True, fname
- else:
- return False, response.text
+ link = link_match.group()
+ if Config.GOOGLE_CHROME_BIN is None:
+ await message.err("need to install Google Chrome. Module Stopping")
+ return
+ await message.edit("`Processing ...`")
+ chrome_options = webdriver.ChromeOptions()
+ chrome_options.binary_location = Config.GOOGLE_CHROME_BIN
+ chrome_options.add_argument('--ignore-certificate-errors')
+ chrome_options.add_argument("--test-type")
+ chrome_options.add_argument("--headless")
+ chrome_options.add_argument('--no-sandbox')
+ chrome_options.add_argument('--disable-dev-shm-usage')
+ chrome_options.add_argument("--no-sandbox")
+ chrome_options.add_argument('--disable-gpu')
+ driver = webdriver.Chrome(chrome_options=chrome_options)
+ driver.get(link)
+ height = driver.execute_script(
+ "return Math.max(document.body.scrollHeight, document.body.offsetHeight, "
+ "document.documentElement.clientHeight, document.documentElement.scrollHeight, "
+ "document.documentElement.offsetHeight);")
+ width = driver.execute_script(
+ "return Math.max(document.body.scrollWidth, document.body.offsetWidth, "
+ "document.documentElement.clientWidth, document.documentElement.scrollWidth, "
+ "document.documentElement.offsetWidth);")
+ driver.set_window_size(width + 125, height + 125)
+ wait_for = height / 1000
+ await message.edit(f"`Generating screenshot of the page...`"
+ f"\n`Height of page = {height}px`"
+ f"\n`Width of page = {width}px`"
+ f"\n`Waiting ({int(wait_for)}s) for the page to load.`")
+ await sleep(int(wait_for))
+ im_png = driver.get_screenshot_as_png()
+ driver.close()
+ message_id = message.message_id
+ if message.reply_to_message:
+ message_id = message.reply_to_message.message_id
+ file_path = os.path.join(Config.DOWN_PATH, "webss.png")
+ async with aiofiles.open(file_path, 'wb') as out_file:
+ await out_file.write(im_png)
+ await userge.send_document(chat_id=message.chat.id,
+ document=file_path,
+ caption=link,
+ reply_to_message_id=message_id)
+ os.remove(file_path)
diff --git a/userge/plugins/utils/welcome.py b/userge/plugins/utils/welcome.py
index 573e1ffcb..a11dcd50f 100644
--- a/userge/plugins/utils/welcome.py
+++ b/userge/plugins/utils/welcome.py
@@ -12,6 +12,7 @@
import base64
import asyncio
+import aiofiles
from hachoir.metadata import extractMetadata
from hachoir.parser import createParser
from pyrogram import Message as RawMessage
@@ -206,8 +207,8 @@ async def raw_set(message: Message, name, collection, chats):
"trying to download", userge, message, c_time
)
)
- with open(tmp_path, "rb") as media_file:
- media = base64.b64encode(media_file.read())
+ async with aiofiles.open(tmp_path, "rb") as media_file:
+ media = base64.b64encode(await media_file.read())
file_name = os.path.basename(tmp_path)
os.remove(tmp_path)
@@ -299,8 +300,8 @@ async def raw_say(message: Message, name, collection):
file_name = found['name']
media = found['media']
tmp_media_path = os.path.join(Config.DOWN_PATH, file_name)
- with open(tmp_media_path, "wb") as media_file:
- media_file.write(base64.b64decode(media))
+ async with aiofiles.open(tmp_media_path, "wb") as media_file:
+ await media_file.write(base64.b64decode(media))
file_id, file_ref = await send_proper_type(message, caption, file_type, tmp_media_path)
collection.update_one({'_id': message.chat.id},
{"$set": {'fid': file_id, 'fref': file_ref}},
diff --git a/userge/utils/exceptions.py b/userge/utils/exceptions.py
index 13b9e0b89..d54d94ea9 100644
--- a/userge/utils/exceptions.py
+++ b/userge/utils/exceptions.py
@@ -9,11 +9,7 @@
from asyncio.exceptions import CancelledError
class StopConversation(CancelledError):
- """
- Exception to raise if conversation terminated.
- """
+ """Exception to raise if conversation terminated"""
class ProcessCanceled(Exception):
- """
- Custom Exception to terminate threads.
- """
+ """Custom Exception to terminate threads"""
diff --git a/userge/utils/progress.py b/userge/utils/progress.py
index 6cf28444a..7294531b0 100644
--- a/userge/utils/progress.py
+++ b/userge/utils/progress.py
@@ -20,7 +20,8 @@ async def progress(current: int,
ud_type: str,
client: 'userge.Userge',
message: 'userge.Message',
- start: int) -> None:
+ start: int,
+ file_name: str = '') -> None:
if message.process_is_canceled:
await client.stop_transmission()
now = time.time()
@@ -30,7 +31,7 @@ async def progress(current: int,
speed = current / diff
time_to_completion = time_formatter(int((total - current) / speed))
progress_str = \
- "__{}__\n" + \
+ "__{}__ : `{}`\n" + \
"```[{}{}]```\n" + \
"**Progress** : `{}%`\n" + \
"**Completed** : `{}`\n" + \
@@ -39,6 +40,7 @@ async def progress(current: int,
"**ETA** : `{}`"
progress_str = progress_str.format(
ud_type,
+ file_name,
''.join(["█" for i in range(floor(percentage / 5))]),
''.join(["░" for i in range(20 - floor(percentage / 5))]),
round(percentage, 2),
diff --git a/userge/versions.py b/userge/versions.py
index ddaa7d262..678ecb212 100644
--- a/userge/versions.py
+++ b/userge/versions.py
@@ -14,7 +14,7 @@
__version_mjaor__ = 0
__version_minor__ = 1
__version_micro__ = 4
-__version_beta__ = 4
+__version_beta__ = 5
__version__ = "{}.{}.{}".format(__version_mjaor__,
__version_minor__,