Fixes:
 • Sender Now shows Correct name while downloading replied media.
 • Clean up code for YoutubeDL.
 • Format code according to PEP.

Added:
 • .cancel to cancel a command/media download execution.
 • switch to @cached_property decorator and clean up message.py
 • Parse replied message using custom message class.
 • Rename tools to dev_tools and move loader to it.
 • self-destructing responses.
This commit is contained in:
anonymousx97 2023-07-30 13:00:24 +05:30
parent 2b41731e84
commit 216e0dcfe1
24 changed files with 1179 additions and 926 deletions

View File

@ -1,14 +1,15 @@
from dotenv import load_dotenv import os
from dotenv import load_dotenv
load_dotenv("config.env") load_dotenv("config.env")
from .config import Config from .config import Config
from .core.client import BOT from .core.client import BOT
import os
if not os.environ.get("TERMUX_APK_RELEASE"): if not os.environ.get("TERMUX_APK_RELEASE"):
import uvloop import uvloop
uvloop.install() uvloop.install()
bot = BOT() bot = BOT()

View File

@ -1,6 +1,8 @@
if __name__ == "__main__": if __name__ == "__main__":
import tracemalloc import tracemalloc
tracemalloc.start() tracemalloc.start()
from app import bot from app import bot
bot.run(bot.boot()) bot.run(bot.boot())

View File

@ -11,14 +11,15 @@ class Gallery_DL(ScraperConfig):
def __init__(self, url): def __init__(self, url):
super().__init__() super().__init__()
self.url = url self.url = url
self.set_sauce(url)
async def download_or_extract(self): async def download_or_extract(self):
self.path = "downloads/" + str(time.time()) self.path = "downloads/" + str(time.time())
os.makedirs(self.path) os.makedirs(self.path)
try: try:
async with asyncio.timeout(30): async with asyncio.timeout(30):
await shell.run_shell_cmd(f"gallery-dl -q --range '0-4' -D {self.path} '{self.url}'") await shell.run_shell_cmd(
f"gallery-dl -q --range '0-4' -D {self.path} '{self.url}'"
)
except TimeoutError: except TimeoutError:
pass pass
files = glob.glob(f"{self.path}/*") files = glob.glob(f"{self.path}/*")

View File

@ -9,7 +9,6 @@ from app.core.scraper_config import ScraperConfig
class Reddit(ScraperConfig): class Reddit(ScraperConfig):
def __init__(self, url): def __init__(self, url):
super().__init__() super().__init__()
self.set_sauce(url)
parsed_url = urlparse(url) parsed_url = urlparse(url)
self.url = f"https://www.reddit.com{parsed_url.path}.json?limit=1" self.url = f"https://www.reddit.com{parsed_url.path}.json?limit=1"
@ -17,7 +16,9 @@ class Reddit(ScraperConfig):
headers = { headers = {
"user-agent": "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_8_7 rv:5.0; en-US) AppleWebKit/533.31.5 (KHTML, like Gecko) Version/4.0 Safari/533.31.5" "user-agent": "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_8_7 rv:5.0; en-US) AppleWebKit/533.31.5 (KHTML, like Gecko) Version/4.0 Safari/533.31.5"
} }
response = await aiohttp_tools.get_json(url=self.url, headers=headers, json_=True) response = await aiohttp_tools.get_json(
url=self.url, headers=headers, json_=True
)
if not response: if not response:
return return
@ -26,7 +27,9 @@ class Reddit(ScraperConfig):
except BaseException: except BaseException:
return return
self.caption = f"""__{json_["subreddit_name_prefixed"]}:__\n**{json_["title"]}**""" self.caption = (
f"""__{json_["subreddit_name_prefixed"]}:__\n**{json_["title"]}**"""
)
is_vid, is_gallery = json_.get("is_video"), json_.get("is_gallery") is_vid, is_gallery = json_.get("is_video"), json_.get("is_gallery")
@ -35,16 +38,26 @@ class Reddit(ScraperConfig):
os.makedirs(self.path) os.makedirs(self.path)
self.link = f"{self.path}/v.mp4" self.link = f"{self.path}/v.mp4"
vid_url = json_["secure_media"]["reddit_video"]["hls_url"] vid_url = json_["secure_media"]["reddit_video"]["hls_url"]
await shell.run_shell_cmd(f'ffmpeg -hide_banner -loglevel error -i "{vid_url.strip()}" -c copy {self.link}') await shell.run_shell_cmd(
f'ffmpeg -hide_banner -loglevel error -i "{vid_url.strip()}" -c copy {self.link}'
)
self.thumb = await shell.take_ss(video=self.link, path=self.path) self.thumb = await shell.take_ss(video=self.link, path=self.path)
self.video = self.success = True self.video = self.success = True
elif is_gallery: elif is_gallery:
self.link = [val["s"].get("u", val["s"].get("gif")).replace("preview", "i") for val in json_["media_metadata"].values()] self.link = [
val["s"].get("u", val["s"].get("gif")).replace("preview", "i")
for val in json_["media_metadata"].values()
]
self.group = self.success = True self.group = self.success = True
else: else:
self.link = json_.get("preview", {}).get("reddit_video_preview", {}).get("fallback_url", json_.get("url_overridden_by_dest", "")).strip() self.link = (
json_.get("preview", {})
.get("reddit_video_preview", {})
.get("fallback_url", json_.get("url_overridden_by_dest", ""))
.strip()
)
if not self.link: if not self.link:
return return
if self.link.endswith(".gif"): if self.link.endswith(".gif"):

View File

@ -11,12 +11,15 @@ class Threads(ScraperConfig):
def __init__(self, url): def __init__(self, url):
super().__init__() super().__init__()
self.url = url self.url = url
self.set_sauce(url)
async def download_or_extract(self): async def download_or_extract(self):
shortcode = os.path.basename(urlparse(self.url).path.rstrip("/")) shortcode = os.path.basename(urlparse(self.url).path.rstrip("/"))
response = await (await aiohttp_tools.SESSION.get(f"https://www.threads.net/t/{shortcode}/embed/")).text() response = await (
await aiohttp_tools.SESSION.get(
f"https://www.threads.net/t/{shortcode}/embed/"
)
).text()
soup = BeautifulSoup(response, "html.parser") soup = BeautifulSoup(response, "html.parser")

View File

@ -8,7 +8,6 @@ class Tiktok(ScraperConfig):
def __init__(self, url): def __init__(self, url):
super().__init__() super().__init__()
self.url = url self.url = url
self.set_sauce(url)
async def download_or_extract(self): async def download_or_extract(self):
media = await tiktok_scraper.hybrid_parsing(self.url) media = await tiktok_scraper.hybrid_parsing(self.url)

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,6 @@ class FakeLogger(object):
class YT_DL(ScraperConfig): class YT_DL(ScraperConfig):
def __init__(self, url): def __init__(self, url):
super().__init__() super().__init__()
self.set_sauce(url)
self.url = url self.url = url
self.path = "downloads/" + str(time.time()) self.path = "downloads/" + str(time.time())
self.video_path = self.path + "/v.mp4" self.video_path = self.path + "/v.mp4"
@ -35,30 +34,42 @@ class YT_DL(ScraperConfig):
"quiet": True, "quiet": True,
"logger": FakeLogger(), "logger": FakeLogger(),
"noplaylist": True, "noplaylist": True,
"format": "best[ext=mp4]",
} }
self.set_format()
async def download_or_extract(self): async def download_or_extract(self):
if "youtu" in self.url: if self.check_url():
if "/playlist" in self.url or "/live" in self.url or os.path.basename(self.url).startswith("@"):
return
self._opts["format"] = "bv[ext=mp4][res=480]+ba[ext=m4a]/b[ext=mp4]"
if "/shorts" in self.url:
self._opts["format"] = "bv[ext=mp4][res=720]+ba[ext=m4a]/b[ext=mp4]"
yt_obj = yt_dlp.YoutubeDL(self._opts)
info = yt_obj.extract_info(self.url, download=False)
if not info or info.get("duration", 0) >= 300:
return return
with yt_dlp.YoutubeDL(self._opts) as yt_obj:
info = await asyncio.to_thread(
yt_obj.extract_info, self.url, download=False
)
await asyncio.to_thread(yt_obj.download, self.url) if not info or info.get("duration", 0) >= 300:
return
if "youtu" in self.url: await asyncio.to_thread(yt_obj.download, self.url)
self.caption = f"""__{info.get("channel","")}__:\n**{info.get("title","")}**"""
if "youtu" in self.url:
self.caption = (
f"""__{info.get("channel","")}__:\n**{info.get("title","")}**"""
)
if os.path.isfile(self.video_path): if os.path.isfile(self.video_path):
self.link = self.video_path self.link = self.video_path
self.thumb = await take_ss(self.video_path, path=self.path) self.thumb = await take_ss(self.video_path, path=self.path)
self.video = self.success = True self.video = self.success = True
def check_url(self):
if "youtu" in self.url and (
"/live" in self.url or os.path.basename(self.url).startswith("@")
):
return 1
def set_format(self):
if "/shorts" in self.url:
self._opts["format"] = "bv[ext=mp4][res=720]+ba[ext=m4a]/b[ext=mp4]"
elif "youtu" in self.url:
self._opts["format"] = "bv[ext=mp4][res=480]+ba[ext=m4a]/b[ext=mp4]"
else:
self._opts["format"] = "b[ext=mp4]"

View File

@ -1,14 +1,15 @@
import os
import json import json
import os
class Config: class Config:
API_KEYS = json.loads(os.environ.get("API_KEYS", "[]")) API_KEYS = json.loads(os.environ.get("API_KEYS", "[]"))
BLOCKED_USERS = [] BLOCKED_USERS = []
BLOCKED_USERS_MESSAGE_ID = int(os.environ.get("BLOCKED_USERS_MESSAGE_ID",0)) BLOCKED_USERS_MESSAGE_ID = int(os.environ.get("BLOCKED_USERS_MESSAGE_ID", 0))
CHATS = [] CHATS = []
AUTO_DL_MESSAGE_ID = int(os.environ.get("AUTO_DL_MESSAGE_ID",0)) AUTO_DL_MESSAGE_ID = int(os.environ.get("AUTO_DL_MESSAGE_ID", 0))
CMD_DICT = {} CMD_DICT = {}
@ -17,4 +18,4 @@ class Config:
TRIGGER = os.environ.get("TRIGGER", ".") TRIGGER = os.environ.get("TRIGGER", ".")
USERS = [] USERS = []
USERS_MESSAGE_ID = int(os.environ.get("USERS_MESSAGE_ID",0)) USERS_MESSAGE_ID = int(os.environ.get("USERS_MESSAGE_ID", 0))

View File

@ -4,6 +4,9 @@ import os
import traceback import traceback
from urllib.parse import urlparse from urllib.parse import urlparse
from pyrogram.errors import MediaEmpty, PhotoSaveFileInvalid, WebpageCurlFailed
from pyrogram.types import InputMediaPhoto, InputMediaVideo
from app.api.gallerydl import Gallery_DL from app.api.gallerydl import Gallery_DL
from app.api.instagram import Instagram from app.api.instagram import Instagram
from app.api.reddit import Reddit from app.api.reddit import Reddit
@ -11,8 +14,6 @@ from app.api.threads import Threads
from app.api.tiktok import Tiktok from app.api.tiktok import Tiktok
from app.api.ytdl import YT_DL from app.api.ytdl import YT_DL
from app.core import aiohttp_tools, shell from app.core import aiohttp_tools, shell
from pyrogram.errors import MediaEmpty, PhotoSaveFileInvalid, WebpageCurlFailed
from pyrogram.types import InputMediaPhoto, InputMediaVideo
url_map = { url_map = {
"tiktok.com": Tiktok, "tiktok.com": Tiktok,
@ -29,32 +30,48 @@ url_map = {
class ExtractAndSendMedia: class ExtractAndSendMedia:
def __init__(self, message): def __init__(self, message):
self.exceptions, self.media_objects = [], [] self.exceptions, self.media_objects, self.sender_dict = [], [], {}
self.__client = message._client self.__client = message._client
self.message = message self.message = message
self.doc = "-d" in message.flags self.doc = "-d" in message.flags
self.spoiler = "-s" in message.flags self.spoiler = "-s" in message.flags
self.sender = "" if "-ns" in message.flags else f"\nShared by : {self.extract_sender()}"
self.args_ = { self.args_ = {
"chat_id": self.message.chat.id, "chat_id": self.message.chat.id,
"reply_to_message_id": message.reply_id, "reply_to_message_id": message.reply_id,
} }
def extract_sender(self): def get_sender(self, reply=False):
if "-ns" in self.message.flags:
return ""
text = f"\nShared by : "
author = self.message.author_signature author = self.message.author_signature
sender = user.first_name if (user := self.message.from_user) else "" sender = user.first_name if (user := self.message.from_user) else ""
return author or sender reply_sender = ""
if reply:
reply_msg = self.message.replied
reply_sender = (
reply_user.first_name if (reply_user := reply_msg.from_user) else ""
)
if any((author, sender, reply_sender)):
return text + (author or sender if not reply else reply_sender)
else:
return ""
async def get_media(self): async def get_media(self):
async with asyncio.TaskGroup() as task_group: async with asyncio.TaskGroup() as task_group:
tasks = [] tasks = []
for link in self.message.get_text_list: text_list = self.message.text_list
reply_text_list = self.message.reply_text_list
for link in text_list + reply_text_list:
reply = link in reply_text_list
if match := url_map.get(urlparse(link).netloc): if match := url_map.get(urlparse(link).netloc):
tasks.append(task_group.create_task(match.start(link))) tasks.append(task_group.create_task(match.start(link)))
self.sender_dict[link] = self.get_sender(reply=reply)
else: else:
for key, val in url_map.items(): for key, val in url_map.items():
if key in link: if key in link:
tasks.append(task_group.create_task(val.start(link))) tasks.append(task_group.create_task(val.start(link)))
self.sender_dict[link] = self.get_sender(reply=reply)
self.media_objects = [task.result() for task in tasks if task.result()] self.media_objects = [task.result() for task in tasks if task.result()]
async def send_media(self): async def send_media(self):
@ -62,7 +79,9 @@ class ExtractAndSendMedia:
if "-nc" in self.message.flags: if "-nc" in self.message.flags:
caption = "" caption = ""
else: else:
caption = obj.caption + obj.caption_url + self.sender caption = (
obj.caption + obj.caption_url + self.sender_dict[obj.query_url]
)
try: try:
if self.doc: if self.doc:
await self.send_document(obj.link, caption=caption, path=obj.path) await self.send_document(obj.link, caption=caption, path=obj.path)
@ -70,14 +89,14 @@ class ExtractAndSendMedia:
await self.send_group(obj, caption=caption) await self.send_group(obj, caption=caption)
elif obj.photo: elif obj.photo:
await self.send( await self.send(
media={"photo":obj.link}, media={"photo": obj.link},
method=self.__client.send_photo, method=self.__client.send_photo,
caption=caption, caption=caption,
has_spoiler=self.spoiler, has_spoiler=self.spoiler,
) )
elif obj.video: elif obj.video:
await self.send( await self.send(
media={"video":obj.link}, media={"video": obj.link},
method=self.__client.send_video, method=self.__client.send_video,
thumb=await aiohttp_tools.thumb_dl(obj.thumb), thumb=await aiohttp_tools.thumb_dl(obj.thumb),
caption=caption, caption=caption,
@ -85,14 +104,16 @@ class ExtractAndSendMedia:
) )
elif obj.gif: elif obj.gif:
await self.send( await self.send(
media={"animation":obj.link}, media={"animation": obj.link},
method=self.__client.send_animation, method=self.__client.send_animation,
caption=caption, caption=caption,
has_spoiler=self.spoiler, has_spoiler=self.spoiler,
unsave=True, unsave=True,
) )
except BaseException: except BaseException:
self.exceptions.append("\n".join([obj.caption_url.strip(), traceback.format_exc()])) self.exceptions.append(
"\n".join([obj.caption_url.strip(), traceback.format_exc()])
)
async def send(self, media, method, **kwargs): async def send(self, media, method, **kwargs):
try: try:
@ -103,20 +124,28 @@ class ExtractAndSendMedia:
media[key] = await aiohttp_tools.in_memory_dl(value) media[key] = await aiohttp_tools.in_memory_dl(value)
await method(**media, **self.args_, **kwargs) await method(**media, **self.args_, **kwargs)
except PhotoSaveFileInvalid: except PhotoSaveFileInvalid:
await self.__client.send_document(**self.args_, document=media, caption=caption, force_document=True) await self.__client.send_document(
**self.args_, document=media, caption=caption, force_document=True
)
async def send_document(self, docs, caption, path=""): async def send_document(self, docs, caption, path=""):
if not path: if not path:
docs = await asyncio.gather(*[aiohttp_tools.in_memory_dl(doc) for doc in docs]) docs = await asyncio.gather(
*[aiohttp_tools.in_memory_dl(doc) for doc in docs]
)
else: else:
[os.rename(file_, file_ + ".png") for file_ in glob.glob(f"{path}/*.webp")] [os.rename(file_, file_ + ".png") for file_ in glob.glob(f"{path}/*.webp")]
docs = glob.glob(f"{path}/*") docs = glob.glob(f"{path}/*")
for doc in docs: for doc in docs:
try: try:
await self.__client.send_document(**self.args_, document=doc, caption=caption, force_document=True) await self.__client.send_document(
**self.args_, document=doc, caption=caption, force_document=True
)
except (MediaEmpty, WebpageCurlFailed): except (MediaEmpty, WebpageCurlFailed):
doc = await aiohttp_tools.in_memory_dl(doc) doc = await aiohttp_tools.in_memory_dl(doc)
await self.__client.send_document(**self.args_, document=doc, caption=caption, force_document=True) await self.__client.send_document(
**self.args_, document=doc, caption=caption, force_document=True
)
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
async def send_group(self, media, caption): async def send_group(self, media, caption):
@ -128,7 +157,13 @@ class ExtractAndSendMedia:
if isinstance(data, list): if isinstance(data, list):
await self.__client.send_media_group(**self.args_, media=data) await self.__client.send_media_group(**self.args_, media=data)
else: else:
await self.send(media={"animation": data}, method=self.__client.send_animation, caption=caption, has_spoiler=self.spoiler, unsave=True) await self.send(
media={"animation": data},
method=self.__client.send_animation,
caption=caption,
has_spoiler=self.spoiler,
unsave=True,
)
await asyncio.sleep(1) await asyncio.sleep(1)
async def sort_media_path(self, path, caption): async def sort_media_path(self, path, caption):
@ -136,24 +171,34 @@ class ExtractAndSendMedia:
images, videos, animations = [], [], [] images, videos, animations = [], [], []
for file in glob.glob(f"{path}/*"): for file in glob.glob(f"{path}/*"):
if file.lower().endswith((".png", ".jpg", ".jpeg")): if file.lower().endswith((".png", ".jpg", ".jpeg")):
images.append(InputMediaPhoto(file, caption=caption, has_spoiler=self.spoiler)) images.append(
InputMediaPhoto(file, caption=caption, has_spoiler=self.spoiler)
)
if file.lower().endswith((".mp4", ".mkv", ".webm")): if file.lower().endswith((".mp4", ".mkv", ".webm")):
has_audio = await shell.check_audio(file) has_audio = await shell.check_audio(file)
if not has_audio: if not has_audio:
animations.append(file) animations.append(file)
else: else:
videos.append(InputMediaVideo(file, caption=caption, has_spoiler=self.spoiler)) videos.append(
InputMediaVideo(file, caption=caption, has_spoiler=self.spoiler)
)
return await self.make_chunks(images, videos, animations) return await self.make_chunks(images, videos, animations)
async def sort_media_urls(self, urls, caption): async def sort_media_urls(self, urls, caption):
images, videos, animations = [], [], [] images, videos, animations = [], [], []
downloads = await asyncio.gather(*[aiohttp_tools.in_memory_dl(url) for url in urls]) downloads = await asyncio.gather(
*[aiohttp_tools.in_memory_dl(url) for url in urls]
)
for file_obj in downloads: for file_obj in downloads:
name = file_obj.name.lower() name = file_obj.name.lower()
if name.endswith((".png", ".jpg", ".jpeg")): if name.endswith((".png", ".jpg", ".jpeg")):
images.append(InputMediaPhoto(file_obj, caption=caption, has_spoiler=self.spoiler)) images.append(
InputMediaPhoto(file_obj, caption=caption, has_spoiler=self.spoiler)
)
if name.endswith((".mp4", ".mkv", ".webm")): if name.endswith((".mp4", ".mkv", ".webm")):
videos.append(InputMediaVideo(file_obj, caption=caption, has_spoiler=self.spoiler)) videos.append(
InputMediaVideo(file_obj, caption=caption, has_spoiler=self.spoiler)
)
if name.endswith(".gif"): if name.endswith(".gif"):
animations.append(file_obj) animations.append(file_obj)
return await self.make_chunks(images, videos, animations) return await self.make_chunks(images, videos, animations)

View File

@ -15,9 +15,17 @@ async def session_switch():
await SESSION.close() await SESSION.close()
async def get_json(url: str, headers: dict = None, params: dict = None, json_: bool = False, timeout: int = 10): async def get_json(
url: str,
headers: dict = None,
params: dict = None,
json_: bool = False,
timeout: int = 10,
):
try: try:
async with SESSION.get(url=url, headers=headers, params=params, timeout=timeout) as ses: async with SESSION.get(
url=url, headers=headers, params=params, timeout=timeout
) as ses:
if json_: if json_:
ret_json = await ses.json() ret_json = await ses.json()
else: else:

View File

@ -11,17 +11,15 @@ from pyrogram.enums import ParseMode
from app import Config from app import Config
from app.core import aiohttp_tools from app.core import aiohttp_tools
from app.core.message import Message from app.core.message import Message
class BOT(Client): class BOT(Client):
def __init__(self): def __init__(self):
if string := os.environ.get("STRING_SESSION"): if string := os.environ.get("STRING_SESSION"):
mode_arg = { "session_string": string } mode_arg = {"session_string": string}
else: else:
mode_arg = { "bot_token": os.environ.get("BOT_TOKEN") } mode_arg = {"bot_token": os.environ.get("BOT_TOKEN")}
super().__init__( super().__init__(
name="bot", name="bot",
**mode_arg, **mode_arg,
@ -60,7 +58,11 @@ class BOT(Client):
restart_chat = os.environ.get("RESTART_CHAT") restart_chat = os.environ.get("RESTART_CHAT")
if restart_msg and restart_chat: if restart_msg and restart_chat:
await super().get_chat(int(restart_chat)) await super().get_chat(int(restart_chat))
await super().edit_message_text(chat_id=int(restart_chat), message_id=int(restart_msg), text="#Social-dl\n__Started__") await super().edit_message_text(
chat_id=int(restart_chat),
message_id=int(restart_msg),
text="#Social-dl\n__Started__",
)
os.environ.pop("RESTART_MSG", "") os.environ.pop("RESTART_MSG", "")
os.environ.pop("RESTART_CHAT", "") os.environ.pop("RESTART_CHAT", "")
@ -70,10 +72,17 @@ class BOT(Client):
py_name = name.replace("/", ".") py_name = name.replace("/", ".")
importlib.import_module(py_name) importlib.import_module(py_name)
async def log(self, text, chat=None, func=None, name="log.txt",disable_web_page_preview=True): async def log(
self, text, chat=None, func=None, name="log.txt", disable_web_page_preview=True
):
if chat or func: if chat or func:
text = f"<b>Function:</b> {func}\n<b>Chat:</b> {chat}\n<b>Traceback:</b>\n{text}" text = f"<b>Function:</b> {func}\n<b>Chat:</b> {chat}\n<b>Traceback:</b>\n{text}"
return await self.send_message(chat_id=Config.LOG_CHAT, text=text, name=name, disable_web_page_preview=disable_web_page_preview) return await self.send_message(
chat_id=Config.LOG_CHAT,
text=text,
name=name,
disable_web_page_preview=disable_web_page_preview,
)
async def restart(self): async def restart(self):
await aiohttp_tools.session_switch() await aiohttp_tools.session_switch()
@ -86,16 +95,23 @@ class BOT(Client):
users = Config.USERS_MESSAGE_ID users = Config.USERS_MESSAGE_ID
if chats_id: if chats_id:
Config.CHATS = json.loads((await super().get_messages(Config.LOG_CHAT, chats_id)).text) Config.CHATS = json.loads(
(await super().get_messages(Config.LOG_CHAT, chats_id)).text
)
if blocked_id: if blocked_id:
Config.BLOCKED_USERS = json.loads((await super().get_messages(Config.LOG_CHAT, blocked_id)).text) Config.BLOCKED_USERS = json.loads(
(await super().get_messages(Config.LOG_CHAT, blocked_id)).text
)
if users: if users:
Config.USERS = json.loads((await super().get_messages(Config.LOG_CHAT, users)).text) Config.USERS = json.loads(
(await super().get_messages(Config.LOG_CHAT, users)).text
)
async def send_message(self, chat_id, text, name: str = "output.txt", **kwargs): async def send_message(self, chat_id, text, name: str = "output.txt", **kwargs):
if len(str(text)) < 4096: if len(str(text)) < 4096:
return Message.parse_message((await super().send_message(chat_id=chat_id, text=text, **kwargs))) return Message.parse_message(
(await super().send_message(chat_id=chat_id, text=text, **kwargs))
)
doc = BytesIO(bytes(text, encoding="utf-8")) doc = BytesIO(bytes(text, encoding="utf-8"))
doc.name = name doc.name = name
kwargs.pop("disable_web_page_preview", "") kwargs.pop("disable_web_page_preview", "")

View File

@ -15,7 +15,7 @@ def Dynamic_Chat_Filter(_, __, message):
): ):
return False return False
user = message.from_user user = message.from_user
if user and ( user.id in Config.BLOCKED_USERS or user.is_bot ): if user and (user.id in Config.BLOCKED_USERS or user.is_bot):
return False return False
url_check = check_for_urls(message.text.split()) url_check = check_for_urls(message.text.split())
return bool(url_check) return bool(url_check)

View File

@ -1,58 +1,102 @@
import asyncio
from functools import cached_property
from pyrogram.types import Message as MSG from pyrogram.types import Message as MSG
from app import Config
class Message(MSG): class Message(MSG):
def __init__(self, message): def __init__(self, message):
self.flags = []
self.input, self.flt_input = "", ""
self.replied, self.reply_id = None, None
super().__dict__.update(message.__dict__) super().__dict__.update(message.__dict__)
self.set_reply_properties()
self.flags_n_input()
self.set_flt_input()
@property @cached_property
def get_text_list(self): def text_list(self):
text_list = self.text.split() return self.text.split()
if self.replied and (reply_text := self.replied.text) and "dl" in text_list[0]:
text_list.extend(reply_text.split())
return text_list
def set_reply_properties(self): @cached_property
if replied := self.reply_to_message: def reply_text_list(self):
self.replied = replied reply_text_list = []
self.reply_id = replied.id if (
self.replied
and (reply_text := self.replied.text)
and "dl" in self.text_list[0]
):
reply_text_list = self.replied.text_list
return reply_text_list
def flags_n_input(self): @cached_property
self.flags = [i for i in self.text.split() if i.startswith("-") ] def cmd(self):
split_cmd_str = self.text.split(maxsplit=1) raw_cmd = self.text_list[0]
if len(split_cmd_str) > 1: cmd = raw_cmd.lstrip(Config.TRIGGER)
self.input = split_cmd_str[-1] return cmd if cmd in Config.CMD_DICT else None
def set_flt_input(self): @cached_property
line_split = self.input.splitlines() def flags(self):
split_n_joined =[ return [i for i in self.text_list if i.startswith("-")]
" ".join([word for word in line.split(" ") if word not in self.flags])
for line in line_split @cached_property
def input(self):
if len(self.text_list) > 1:
return self.text.split(maxsplit=1)[-1]
return ""
@cached_property
def flt_input(self):
split_lines = self.input.splitlines()
split_n_joined = [
" ".join([word for word in line.split(" ") if word not in self.flags])
for line in split_lines
] ]
self.flt_input = "\n".join(split_n_joined) return "\n".join(split_n_joined)
async def reply(self, text, **kwargs): @cached_property
return await self._client.send_message(chat_id=self.chat.id, text=text, reply_to_message_id=self.id, **kwargs) def replied(self):
if self.reply_to_message:
return Message.parse_message(self.reply_to_message)
async def edit(self, text, **kwargs): @cached_property
def reply_id(self):
return self.replied.id if self.replied else None
async def reply(self, text, del_in: int = 0, block=True, **kwargs):
task = self._client.send_message(
chat_id=self.chat.id, text=text, reply_to_message_id=self.id, **kwargs
)
if del_in:
await self.async_deleter(task=task, del_in=del_in, block=block)
else:
return await task
async def edit(self, text, del_in: int = 0, block=True, **kwargs):
if len(str(text)) < 4096: if len(str(text)) < 4096:
kwargs.pop("name", "") kwargs.pop("name", "")
await self.edit_text(text, **kwargs) task = self.edit_text(text, **kwargs)
if del_in:
reply = await self.async_deleter(task=task, del_in=del_in, block=block)
else:
reply = await task
else: else:
await super().delete() _, reply = await asyncio.gather(
return await self.reply(text, **kwargs) super().delete(), self.reply(text, **kwargs)
)
return reply
async def delete(self, reply=False): async def delete(self, reply=False):
await super().delete() await super().delete()
if reply and self.replied: if reply and self.replied:
await self.replied.delete() await self.replied.delete()
async def async_deleter(self, del_in, task, block):
if block:
x = await task
await asyncio.sleep(del_in)
await x.delete()
else:
asyncio.create_task(
self.async_deleter(del_in=del_in, task=task, block=True)
)
@classmethod @classmethod
def parse_message(cls, message): def parse_message(cls, message):
ret_obj = cls(message) ret_obj = cls(message)

View File

@ -14,12 +14,14 @@ class ScraperConfig:
self.group = False self.group = False
self.gif = False self.gif = False
def set_sauce(self, url): def set_sauce(self):
self.caption_url = f"\n\n<a href='{url}'>Sauce</a>" self.caption_url = f"\n\n<a href='{self.query_url}'>Sauce</a>"
@classmethod @classmethod
async def start(cls, url): async def start(cls, url):
obj = cls(url=url) obj = cls(url=url)
obj.query_url = url
obj.set_sauce()
await obj.download_or_extract() await obj.download_or_extract()
if obj.success: if obj.success:
return obj return obj

View File

@ -4,18 +4,24 @@ import os
async def take_ss(video: str, path: str): async def take_ss(video: str, path: str):
thumb = f"{path}/i.png" thumb = f"{path}/i.png"
await run_shell_cmd(f'''ffmpeg -hide_banner -loglevel error -ss 0.1 -i "{video}" -vframes 1 "{thumb}"''') await run_shell_cmd(
f'''ffmpeg -hide_banner -loglevel error -ss 0.1 -i "{video}" -vframes 1 "{thumb}"'''
)
if os.path.isfile(thumb): if os.path.isfile(thumb):
return thumb return thumb
async def check_audio(file): async def check_audio(file):
result = await run_shell_cmd(f"ffprobe -v error -show_entries format=nb_streams -of default=noprint_wrappers=1:nokey=1 {file}") result = await run_shell_cmd(
f"ffprobe -v error -show_entries format=nb_streams -of default=noprint_wrappers=1:nokey=1 {file}"
)
return int(result or 0) - 1 return int(result or 0) - 1
async def run_shell_cmd(cmd): async def run_shell_cmd(cmd):
proc = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT) proc = await asyncio.create_subprocess_shell(
cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT
)
stdout, _ = await proc.communicate() stdout, _ = await proc.communicate()
return stdout.decode("utf-8") return stdout.decode("utf-8")
@ -41,7 +47,11 @@ class AsyncShell:
@classmethod @classmethod
async def run_cmd(cls, cmd): async def run_cmd(cls, cmd):
# Create Subprocess and initialise self using cls # Create Subprocess and initialise self using cls
sub_process = cls(process=await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT)) sub_process = cls(
process=await asyncio.create_subprocess_shell(
cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT
)
)
# Start Checking output but don't block code by awaiting it. # Start Checking output but don't block code by awaiting it.
asyncio.create_task(sub_process.get_output()) asyncio.create_task(sub_process.get_output())
# Sleep for a short time to let previous task start # Sleep for a short time to let previous task start

View File

@ -61,8 +61,8 @@ async def add_sudo(bot, message):
config_list=Config.USERS, config_list=Config.USERS,
message_id=Config.USERS_MESSAGE_ID, message_id=Config.USERS_MESSAGE_ID,
): ):
return await message.reply(err) return await message.reply(err, del_in=5)
await message.reply("User Added to Authorised List.") await message.reply("User Added to Authorised List.", del_in=5)
@bot.add_cmd(cmd="delsudo") @bot.add_cmd(cmd="delsudo")
@ -77,8 +77,8 @@ async def add_sudo(bot, message):
config_list=Config.USERS, config_list=Config.USERS,
message_id=Config.USERS_MESSAGE_ID, message_id=Config.USERS_MESSAGE_ID,
): ):
return await message.reply(err) return await message.reply(err, del_in=5)
await message.reply("User Removed from Authorised List.") await message.reply("User Removed from Authorised List.", del_in=5)
@bot.add_cmd(cmd="addchat") @bot.add_cmd(cmd="addchat")
@ -93,8 +93,11 @@ async def add_chat(bot, message):
config_list=Config.CHATS, config_list=Config.CHATS,
message_id=Config.AUTO_DL_MESSAGE_ID, message_id=Config.AUTO_DL_MESSAGE_ID,
): ):
return await message.reply(err) return await message.reply(err, del_in=5)
await message.reply(f"<b>{message.chat.title or message.chat.first_name}</b> Added to Authorised List.") await message.reply(
f"<b>{message.chat.title or message.chat.first_name}</b> Added to Authorised List.",
del_in=5,
)
@bot.add_cmd(cmd="delchat") @bot.add_cmd(cmd="delchat")
@ -109,9 +112,11 @@ async def add_chat(bot, message):
config_list=Config.CHATS, config_list=Config.CHATS,
message_id=Config.AUTO_DL_MESSAGE_ID, message_id=Config.AUTO_DL_MESSAGE_ID,
): ):
return await message.reply(err) return await message.reply(err, del_in=5)
await message.reply(f"<b>{message.chat.title or message.chat.first_name}</b> Added Removed from Authorised List.") await message.reply(
f"<b>{message.chat.title or message.chat.first_name}</b> Added Removed from Authorised List.",
del_in=5,
)
@bot.add_cmd(cmd="block") @bot.add_cmd(cmd="block")
@ -126,8 +131,8 @@ async def add_sudo(bot, message):
config_list=Config.BLOCKED_USERS, config_list=Config.BLOCKED_USERS,
message_id=Config.BLOCKED_USERS_MESSAGE_ID, message_id=Config.BLOCKED_USERS_MESSAGE_ID,
): ):
return await message.reply(err) return await message.reply(err, del_in=5)
await message.reply("User Added to Ban List.") await message.reply("User Added to Ban List.", del_in=5)
@bot.add_cmd(cmd="unblock") @bot.add_cmd(cmd="unblock")
@ -142,8 +147,5 @@ async def add_sudo(bot, message):
config_list=Config.BLOCKED_USERS, config_list=Config.BLOCKED_USERS,
message_id=Config.BLOCKED_USERS_MESSAGE_ID, message_id=Config.BLOCKED_USERS_MESSAGE_ID,
): ):
return await message.reply(err) return await message.reply(err, del_in=5)
await message.reply("User Removed from Ban List.") await message.reply("User Removed from Ban List.", del_in=5)

View File

@ -8,14 +8,23 @@ from app import Config, bot
@bot.add_cmd(cmd="bot") @bot.add_cmd(cmd="bot")
async def info(bot, message): async def info(bot, message):
head = "<b><a href=https://t.me/Social_DL>Social-DL</a> is running.</b>" head = "<b><a href=https://t.me/Social_DL>Social-DL</a> is running.</b>"
chat_count = f"\n<b>Auto-Dl enabled in: <code>{len(Config.CHATS)}</code> chats</b>\n" chat_count = (
f"\n<b>Auto-Dl enabled in: <code>{len(Config.CHATS)}</code> chats</b>\n"
)
supported_sites, photo = await bot.get_messages("Social_DL", [2, 3]) supported_sites, photo = await bot.get_messages("Social_DL", [2, 3])
await photo.copy(message.chat.id, caption="\n".join([head, chat_count, supported_sites.text.html])) await photo.copy(
message.chat.id,
caption="\n".join([head, chat_count, supported_sites.text.html]),
)
@bot.add_cmd(cmd="help") @bot.add_cmd(cmd="help")
async def help(bot, message): async def help(bot, message):
commands = "\n".join([ f"<code>{Config.TRIGGER}{i}</code>" for i in Config.CMD_DICT.keys()]) commands = "\n".join(
await message.reply(f"<b>Available Commands:</b>\n\n{commands}") [f"<code>{Config.TRIGGER}{i}</code>" for i in Config.CMD_DICT.keys()]
)
await message.reply(f"<b>Available Commands:</b>\n\n{commands}", del_in=30)
@bot.add_cmd(cmd="restart") @bot.add_cmd(cmd="restart")
async def restart(bot, message): async def restart(bot, message):
@ -29,4 +38,4 @@ async def restart(bot, message):
@bot.add_cmd(cmd="update") @bot.add_cmd(cmd="update")
async def chat_update(bot, message): async def chat_update(bot, message):
await bot.set_filter_list() await bot.set_filter_list()
await message.reply("Filters Refreshed") await message.reply("Filters Refreshed", del_in=10)

109
app/plugins/dev_tools.py Normal file
View File

@ -0,0 +1,109 @@
import asyncio
import importlib
import sys
import traceback
from io import StringIO
from pyrogram.enums import ParseMode
from app import Config
from app.core import shell
from app.core import aiohttp_tools as aio # isort:skip
# Run shell commands
async def run_cmd(bot, message):
cmd = message.input.strip()
status_ = await message.reply("executing...")
proc_stdout = await shell.run_shell_cmd(cmd)
output = f"`${cmd}`\n\n`{proc_stdout}`"
return await status_.edit(output, name="sh.txt", disable_web_page_preview=True)
# Shell but Live Output
async def live_shell(bot, message):
cmd = message.input.strip()
sub_process = await shell.AsyncShell.run_cmd(cmd)
reply = await message.reply("`getting live output....`")
output = ""
sleep_for = 1
while sub_process.is_not_completed:
# Edit message only when there's new output.
if output != sub_process.full_std:
output = sub_process.full_std
if len(output) <= 4096:
await reply.edit(
f"`{output}`",
disable_web_page_preview=True,
parse_mode=ParseMode.MARKDOWN,
)
# Reset sleep duration
if sleep_for >= 5:
sleep_for = 1
# Sleep to Unblock running loop and let output reader read new
# output.
await asyncio.sleep(sleep_for)
sleep_for += 1
# If the subprocess is finished edit the message with cmd and full
# output
return await reply.edit(
f"`$ {cmd}\n\n``{sub_process.full_std}`",
name="shell.txt",
disable_web_page_preview=True,
)
# Run Python code
async def executor(bot, message):
code = message.flt_input.strip()
if not code:
return await message.reply("exec Jo mama?")
reply = await message.reply("executing")
sys.stdout = codeOut = StringIO()
sys.stderr = codeErr = StringIO()
# Indent code as per proper python syntax
formatted_code = "\n ".join(code.splitlines())
try:
# Create and initialise the function
exec(f"async def _exec(bot, message):\n {formatted_code}")
func_out = await locals()["_exec"](bot, message)
except BaseException:
func_out = str(traceback.format_exc())
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
output = f"`{codeOut.getvalue().strip() or codeErr.getvalue().strip() or func_out}`"
if "-s" not in message.flags:
output = f"> `{code}`\n\n>> {output}"
return await reply.edit(
output,
name="exec.txt",
disable_web_page_preview=True,
parse_mode=ParseMode.MARKDOWN,
)
async def loader(bot, message):
if (
not message.replied
or not message.replied.document
or not message.replied.document.file_name.endswith(".py")
):
return await message.reply("reply to a plugin.")
reply = await message.reply("Loading....")
file_name = message.replied.document.file_name.rstrip(".py")
reload = sys.modules.pop(f"app.temp.{file_name}", None)
status = "Reloaded" if reload else "Loaded"
await message.replied.download("app/temp/")
try:
importlib.import_module(f"app.temp.{file_name}")
except BaseException:
return await reply.edit(str(traceback.format_exc()))
await reply.edit(f"{status} {file_name}.py.")
if Config.DEV_MODE:
Config.CMD_DICT["sh"] = run_cmd
Config.CMD_DICT["shell"] = live_shell
Config.CMD_DICT["exec"] = executor
Config.CMD_DICT["load"] = loader

View File

@ -1,24 +0,0 @@
import importlib
import sys
import traceback
from app import bot
@bot.add_cmd(cmd="load")
async def loader(bot, message):
if (
not message.replied
or not message.replied.document
or not message.replied.document.file_name.endswith(".py")
):
return await message.reply("reply to a plugin.")
reply = await message.reply("Loading....")
file_name = message.replied.document.file_name.rstrip(".py")
reload = sys.modules.pop(f"app.temp.{file_name}", None)
status = "Reloaded" if reload else "Loaded"
plugin = await message.replied.download("app/temp/")
try:
importlib.import_module(f"app.temp.{file_name}")
except BaseException:
return await reply.edit(str(traceback.format_exc()))
await reply.edit(f"{status} {file_name}.py.")

View File

@ -5,11 +5,19 @@ from time import time
from urllib.parse import urlparse from urllib.parse import urlparse
import yt_dlp import yt_dlp
from app import bot from app import bot
from app.api.ytdl import FakeLogger from app.api.ytdl import FakeLogger
from app.core.aiohttp_tools import in_memory_dl from app.core.aiohttp_tools import in_memory_dl
domains = ["www.youtube.com", "youtube.com", "m.youtube.com", "youtu.be", "www.youtube-nocookie.com", "music.youtube.com"] domains = [
"www.youtube.com",
"youtube.com",
"m.youtube.com",
"youtu.be",
"www.youtube-nocookie.com",
"music.youtube.com",
]
@bot.add_cmd(cmd="song") @bot.add_cmd(cmd="song")
@ -36,7 +44,11 @@ async def song_dl(bot, message):
"logger": FakeLogger(), "logger": FakeLogger(),
"outtmpl": dl_path + "%(title)s.%(ext)s", "outtmpl": dl_path + "%(title)s.%(ext)s",
"format": "bestaudio", "format": "bestaudio",
"postprocessors": [{"key": "FFmpegExtractAudio", "preferredcodec": aformat}, {"key": "FFmpegMetadata"}, {"key": "EmbedThumbnail"}], "postprocessors": [
{"key": "FFmpegExtractAudio", "preferredcodec": aformat},
{"key": "FFmpegMetadata"},
{"key": "EmbedThumbnail"},
],
} }
ytdl = yt_dlp.YoutubeDL(yt_opts) ytdl = yt_dlp.YoutubeDL(yt_opts)
yt_info = await asyncio.to_thread(ytdl.extract_info, query_or_search) yt_info = await asyncio.to_thread(ytdl.extract_info, query_or_search)
@ -51,6 +63,11 @@ async def song_dl(bot, message):
await response.edit("Uploading....") await response.edit("Uploading....")
for audio_file in down_path: for audio_file in down_path:
if audio_file.endswith((".opus", ".mp3")): if audio_file.endswith((".opus", ".mp3")):
await message.reply_audio(audio=audio_file, duration=int(duration), performer=str(artist), thumb=thumb) await message.reply_audio(
audio=audio_file,
duration=int(duration),
performer=str(artist),
thumb=thumb,
)
await response.delete() await response.delete()
shutil.rmtree(dl_path, ignore_errors=True) shutil.rmtree(dl_path, ignore_errors=True)

View File

@ -23,7 +23,9 @@ async def purge_(bot, message: Message):
start_message = reply.id start_message = reply.id
end_message = message.id end_message = message.id
messages = [end_message] + [i for i in range(int(start_message), int(end_message))] messages = [end_message] + [i for i in range(int(start_message), int(end_message))]
await bot.delete_messages(chat_id=message.chat.id, message_ids=messages, revoke=True) await bot.delete_messages(
chat_id=message.chat.id, message_ids=messages, revoke=True
)
@bot.add_cmd(cmd="ids") @bot.add_cmd(cmd="ids")
@ -70,4 +72,9 @@ async def leave_chat(bot, message):
@bot.add_cmd(cmd="reply") @bot.add_cmd(cmd="reply")
async def reply(bot, message): async def reply(bot, message):
text = message.input text = message.input
await bot.send_message(chat_id=message.chat.id, text=text, reply_to_message_id=message.reply_id, disable_web_page_preview=True) await bot.send_message(
chat_id=message.chat.id,
text=text,
reply_to_message_id=message.reply_id,
disable_web_page_preview=True,
)

View File

@ -1,76 +1,19 @@
import asyncio from app import bot
import sys from app.social_dl import current_tasks
import traceback
from io import StringIO
from pyrogram.enums import ParseMode
from app import Config
from app.core import shell
from app.core import aiohttp_tools as aio # isort:skip
# Run shell commands
async def run_cmd(bot, message):
cmd = message.input.strip()
status_ = await message.reply("executing...")
proc_stdout = await shell.run_shell_cmd(cmd)
output = f"`${cmd}`\n\n`{proc_stdout}`"
return await status_.edit(output, name="sh.txt", disable_web_page_preview=True)
# Shell but Live Output @bot.add_cmd(cmd="cancel")
async def cancel_task(bot, message):
task_id = message.reply_id
async def live_shell(bot, message): if not task_id:
cmd = message.input.strip() return await message.reply("Reply To a Command or Bot's Response Message.")
sub_process = await shell.AsyncShell.run_cmd(cmd) task = current_tasks.get(task_id)
reply = await message.reply("`getting live output....`") if not task:
output = "" return await message.reply("Task not in Currently Running Tasks.")
sleep_for = 1 reply = await message.reply("Cancelling....")
while sub_process.is_not_completed: cancelled = task.cancel()
# Edit message only when there's new output. if cancelled:
if output != sub_process.full_std: response = "Task Cancelled Successfully."
output = sub_process.full_std else:
if len(output) <= 4096: response = "Task not Running.\nIt either is Finished or has Errored."
await reply.edit(f"`{output}`", disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN) await reply.edit(response)
# Reset sleep duration
if sleep_for >= 5:
sleep_for = 1
# Sleep to Unblock running loop and let output reader read new
# output.
await asyncio.sleep(sleep_for)
sleep_for += 1
# If the subprocess is finished edit the message with cmd and full
# output
return await reply.edit(f"`$ {cmd}\n\n``{sub_process.full_std}`", name="shell.txt", disable_web_page_preview=True)
# Run Python code
async def executor_(bot, message):
code = message.flt_input.strip()
if not code:
return await message.reply("exec Jo mama?")
reply = await message.reply("executing")
sys.stdout = codeOut = StringIO()
sys.stderr = codeErr = StringIO()
# Indent code as per proper python syntax
formatted_code = "\n ".join(code.splitlines())
try:
# Create and initialise the function
exec(f"async def _exec(bot, message):\n {formatted_code}")
func_out = await locals().get("_exec")(bot, message)
except BaseException:
func_out = str(traceback.format_exc())
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
output = f"`{codeOut.getvalue().strip() or codeErr.getvalue().strip() or func_out}`"
if "-s" not in message.flags:
output = f"> `{code}`\n\n>> {output}"
return await reply.edit(output, name="exec.txt", disable_web_page_preview=True,parse_mode=ParseMode.MARKDOWN)
if Config.DEV_MODE:
Config.CMD_DICT["sh"] = run_cmd
Config.CMD_DICT["shell"] = live_shell
Config.CMD_DICT["exec"] = executor_

View File

@ -1,39 +1,73 @@
import asyncio
import traceback import traceback
from app import Config, bot from app import Config, bot
from app.core import filters from app.core import filters
from app.core.MediaHandler import ExtractAndSendMedia from app.core.MediaHandler import ExtractAndSendMedia
from app.core.message import Message from app.core.message import Message
current_tasks = {}
@bot.add_cmd(cmd="dl") @bot.add_cmd(cmd="dl")
async def dl(bot, message): async def dl(bot, message):
reply = await bot.send_message(chat_id=message.chat.id, text="`trying to download...`") reply = await bot.send_message(
media = await ExtractAndSendMedia.process(message) chat_id=message.chat.id, text="`trying to download...`"
)
task = asyncio.Task(ExtractAndSendMedia.process(message))
current_tasks[reply.id] = task
media = await task
if media.exceptions: if media.exceptions:
exceptions = "\n".join(media.exceptions) exceptions = "\n".join(media.exceptions)
await bot.log(text=exceptions, func="DL", chat=message.chat.title or message.chat.first_name, name="traceback.txt") await bot.log(
text=exceptions,
func="DL",
chat=message.chat.title or message.chat.first_name,
name="traceback.txt",
)
current_tasks.pop(reply.id)
return await reply.edit(f"Media Download Failed.") return await reply.edit(f"Media Download Failed.")
if media.media_objects: if media.media_objects:
await message.delete() await message.delete()
await reply.delete() await reply.delete()
current_tasks.pop(reply.id)
@bot.on_message(filters.user_filter) @bot.on_message(filters.user_filter)
@bot.on_edited_message(filters.user_filter) @bot.on_edited_message(filters.user_filter)
async def cmd_dispatcher(bot, message): async def cmd_dispatcher(bot, message):
func = Config.CMD_DICT[message.text.split(maxsplit=1)[0].lstrip(Config.TRIGGER)]
parsed_message = Message.parse_message(message) parsed_message = Message.parse_message(message)
func = Config.CMD_DICT[parsed_message.cmd]
try: try:
await func(bot, parsed_message) task = asyncio.Task(func(bot, parsed_message))
current_tasks[message.id] = task
await task
except asyncio.exceptions.CancelledError:
pass
except BaseException: except BaseException:
await bot.log(text=str(traceback.format_exc()), chat=message.chat.title or message.chat.first_name, func=func.__name__, name="traceback.txt") await bot.log(
text=str(traceback.format_exc()),
chat=message.chat.title or message.chat.first_name,
func=func.__name__,
name="traceback.txt",
)
current_tasks.pop(message.id)
@bot.on_message(filters.chat_filter) @bot.on_message(filters.chat_filter)
async def dl_dispatcher(bot, message): async def dl_dispatcher(bot, message):
func = Config.CMD_DICT["dl"]
parsed_message = Message.parse_message(message) parsed_message = Message.parse_message(message)
try: try:
await func(bot, parsed_message) task = asyncio.Task(dl(bot, parsed_message))
current_tasks[message.id] = task
await task
except asyncio.exceptions.CancelledError:
pass
except BaseException: except BaseException:
await bot.log(text=str(traceback.format_exc()), chat=message.chat.title or message.chat.first_name, func=func.__name__, name="traceback.txt") await bot.log(
text=str(traceback.format_exc()),
chat=message.chat.title or message.chat.first_name,
func=dl.__name__,
name="traceback.txt",
)
current_tasks.pop(message.id)