Fixes:
 • Fixed instagram set sauce bug.
 • Fixed Tasks getting overwritten bug.
 • Fixed Get_output() wasn't being cancelled on cmd cancellation.

Add/Misc:
 • Add Task IDs in Custom message object.
 • Clean up/Improve logic for .shell .
This commit is contained in:
anonymousx97 2023-08-03 09:30:19 +05:30
parent 1f11bc8405
commit ae04775a3c
8 changed files with 260 additions and 134 deletions

View File

@ -6,7 +6,6 @@ load_dotenv("config.env")
from .config import Config from .config import Config
from .core.client import BOT from .core.client import BOT
if not os.environ.get("TERMUX_APK_RELEASE"): if not os.environ.get("TERMUX_APK_RELEASE"):
import uvloop import uvloop

View File

@ -5,16 +5,14 @@ from app import Config
from app.core import aiohttp_tools from app.core import aiohttp_tools
from app.core.scraper_config import ScraperConfig from app.core.scraper_config import ScraperConfig
API_KEYS = { "KEYS": Config.API_KEYS , "counter": 0 } API_KEYS = {"KEYS": Config.API_KEYS, "counter": 0}
class Instagram(ScraperConfig): class Instagram(ScraperConfig):
def __init__(self, url): def __init__(self, url):
super().__init__() super().__init__()
shortcode = os.path.basename(urlparse(url).path.rstrip("/")) shortcode = os.path.basename(urlparse(url).path.rstrip("/"))
self.url = ( self.url = f"https://www.instagram.com/graphql/query?query_hash=2b0673e0dc4580674a88d426fe00ea90&variables=%7B%22shortcode%22%3A%22{shortcode}%22%7D"
f"https://www.instagram.com/graphql/query?query_hash=2b0673e0dc4580674a88d426fe00ea90&variables=%7B%22shortcode%22%3A%22{shortcode}%22%7D"
)
self.set_sauce(url)
async def download_or_extract(self): async def download_or_extract(self):
for func in [self.no_api_dl, self.api_dl]: for func in [self.no_api_dl, self.api_dl]:
@ -24,17 +22,31 @@ class Instagram(ScraperConfig):
async def no_api_dl(self): async def no_api_dl(self):
response = await aiohttp_tools.get_json(url=self.url) response = await aiohttp_tools.get_json(url=self.url)
if not response or "data" not in response or not response["data"]["shortcode_media"]: if (
not response
or "data" not in response
or not response["data"]["shortcode_media"]
):
return return
return await self.parse_ghraphql(response["data"]["shortcode_media"]) return await self.parse_ghraphql(response["data"]["shortcode_media"])
async def api_dl(self): async def api_dl(self):
if not Config.API_KEYS: if not Config.API_KEYS:
return return
param = {"api_key": await self.get_key(), "url": self.url, "proxy": "residential", "js": False} param = {
response = await aiohttp_tools.get_json(url="https://api.webscraping.ai/html", timeout=30, params=param) "api_key": await self.get_key(),
if not response or "data" not in response or not response["data"]["shortcode_media"]: "url": self.url,
"proxy": "residential",
"js": False,
}
response = await aiohttp_tools.get_json(
url="https://api.webscraping.ai/html", timeout=30, params=param
)
if (
not response
or "data" not in response
or not response["data"]["shortcode_media"]
):
return return
self.caption = ".." self.caption = ".."
return await self.parse_ghraphql(response["data"]["shortcode_media"]) return await self.parse_ghraphql(response["data"]["shortcode_media"])
@ -44,7 +56,10 @@ class Instagram(ScraperConfig):
if not type_check: if not type_check:
return return
elif type_check == "GraphSidecar": elif type_check == "GraphSidecar":
self.link = [i["node"].get("video_url") or i["node"].get("display_url") for i in json_["edge_sidecar_to_children"]["edges"]] self.link = [
i["node"].get("video_url") or i["node"].get("display_url")
for i in json_["edge_sidecar_to_children"]["edges"]
]
self.group = True self.group = True
else: else:
if link := json_.get("video_url"): if link := json_.get("video_url"):
@ -64,4 +79,4 @@ class Instagram(ScraperConfig):
count = 0 count = 0
ret_key = keys[count] ret_key = keys[count]
API_KEYS["counter"] = count API_KEYS["counter"] = count
return ret_key return ret_key

View File

@ -56,7 +56,10 @@ class Scraper:
if self.config["Scraper"]["Use_different_protocols"] == "False": if self.config["Scraper"]["Use_different_protocols"] == "False":
self.proxies = {"all": self.config["Scraper"]["All"]} self.proxies = {"all": self.config["Scraper"]["All"]}
else: else:
self.proxies = {"http": self.config["Scraper"]["Http_proxy"], "https": self.config["Scraper"]["Https_proxy"]} self.proxies = {
"http": self.config["Scraper"]["Http_proxy"],
"https": self.config["Scraper"]["Https_proxy"],
}
else: else:
self.proxies = None self.proxies = None
# 配置文件不存在则不使用代理/If the configuration file does not exist, do not use # 配置文件不存在则不使用代理/If the configuration file does not exist, do not use
@ -75,7 +78,10 @@ class Scraper:
try: try:
# 从输入文字中提取索引链接存入列表/Extract index links from input text and store in # 从输入文字中提取索引链接存入列表/Extract index links from input text and store in
# list # list
url = re.findall("http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+", text) url = re.findall(
"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",
text,
)
# 判断是否有链接/Check if there is a link # 判断是否有链接/Check if there is a link
if len(url) > 0: if len(url) > 0:
return url[0] return url[0]
@ -88,7 +94,9 @@ class Scraper:
@staticmethod @staticmethod
def generate_x_bogus_url(url: str, headers: dict) -> str: def generate_x_bogus_url(url: str, headers: dict) -> str:
query = urllib.parse.urlparse(url).query query = urllib.parse.urlparse(url).query
xbogus = execjs.compile(open("./X-Bogus.js").read()).call("sign", query, headers["User-Agent"]) xbogus = execjs.compile(open("./X-Bogus.js").read()).call(
"sign", query, headers["User-Agent"]
)
new_url = url + "&X-Bogus=" + xbogus new_url = url + "&X-Bogus=" + xbogus
return new_url return new_url
@ -127,7 +135,13 @@ class Scraper:
print("正在通过抖音分享链接获取原始链接...") print("正在通过抖音分享链接获取原始链接...")
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(url, headers=self.headers, proxy=self.proxies, allow_redirects=False, timeout=10) as response: async with session.get(
url,
headers=self.headers,
proxy=self.proxies,
allow_redirects=False,
timeout=10,
) as response:
if response.status == 302: if response.status == 302:
url = ( url = (
response.headers["Location"].split("?")[0] response.headers["Location"].split("?")[0]
@ -165,7 +179,13 @@ class Scraper:
print("正在通过TikTok分享链接获取原始链接...") print("正在通过TikTok分享链接获取原始链接...")
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(url, headers=self.headers, proxy=self.proxies, allow_redirects=False, timeout=10) as response: async with session.get(
url,
headers=self.headers,
proxy=self.proxies,
allow_redirects=False,
timeout=10,
) as response:
if response.status == 301: if response.status == 301:
url = ( url = (
response.headers["Location"].split("?")[0] response.headers["Location"].split("?")[0]
@ -209,7 +229,9 @@ class Scraper:
""" """
# 调用JavaScript函数 # 调用JavaScript函数
query = urllib.parse.urlparse(url).query query = urllib.parse.urlparse(url).query
xbogus = execjs.compile(open("./X-Bogus.js").read()).call("sign", query, self.headers["User-Agent"]) xbogus = execjs.compile(open("./X-Bogus.js").read()).call(
"sign", query, self.headers["User-Agent"]
)
if not quiet_mode: if not quiet_mode:
print("生成的X-Bogus签名为: {}".format(xbogus)) print("生成的X-Bogus签名为: {}".format(xbogus))
new_url = url + "&X-Bogus=" + xbogus new_url = url + "&X-Bogus=" + xbogus
@ -275,7 +297,12 @@ class Scraper:
if not quiet_mode: if not quiet_mode:
print("正在获取视频数据API: {}".format(api_url)) print("正在获取视频数据API: {}".format(api_url))
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=self.douyin_api_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url,
headers=self.douyin_api_headers,
proxy=self.proxies,
timeout=10,
) as response:
response = await response.json() response = await response.json()
# 获取视频数据/Get video data # 获取视频数据/Get video data
video_data = response["aweme_detail"] video_data = response["aweme_detail"]
@ -297,12 +324,19 @@ class Scraper:
print("正在获取抖音视频数据...") print("正在获取抖音视频数据...")
try: try:
# 构造访问链接/Construct the access link # 构造访问链接/Construct the access link
api_url = f"https://live.douyin.com/webcast/web/enter/?aid=6383&web_rid={web_rid}" api_url = (
f"https://live.douyin.com/webcast/web/enter/?aid=6383&web_rid={web_rid}"
)
# 访问API/Access API # 访问API/Access API
if not quiet_mode: if not quiet_mode:
print("正在获取视频数据API: {}".format(api_url)) print("正在获取视频数据API: {}".format(api_url))
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=self.douyin_api_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url,
headers=self.douyin_api_headers,
proxy=self.proxies,
timeout=10,
) as response:
response = await response.json() response = await response.json()
# 获取视频数据/Get video data # 获取视频数据/Get video data
video_data = response["data"] video_data = response["data"]
@ -319,12 +353,16 @@ class Scraper:
# 获取单个抖音视频数据/Get single Douyin video data # 获取单个抖音视频数据/Get single Douyin video data
@retry(stop=stop_after_attempt(4), wait=wait_fixed(7)) @retry(stop=stop_after_attempt(4), wait=wait_fixed(7))
async def get_douyin_user_profile_videos(self, profile_url: str, tikhub_token: str) -> Union[dict, None]: async def get_douyin_user_profile_videos(
self, profile_url: str, tikhub_token: str
) -> Union[dict, None]:
try: try:
api_url = f"https://api.tikhub.io/douyin_profile_videos/?douyin_profile_url={profile_url}&cursor=0&count=20" api_url = f"https://api.tikhub.io/douyin_profile_videos/?douyin_profile_url={profile_url}&cursor=0&count=20"
_headers = {"Authorization": f"Bearer {tikhub_token}"} _headers = {"Authorization": f"Bearer {tikhub_token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url, headers=_headers, proxy=self.proxies, timeout=10
) as response:
response = await response.json() response = await response.json()
return response return response
except Exception as e: except Exception as e:
@ -335,12 +373,16 @@ class Scraper:
# 获取抖音主页点赞视频数据/Get Douyin profile like video data # 获取抖音主页点赞视频数据/Get Douyin profile like video data
@retry(stop=stop_after_attempt(4), wait=wait_fixed(7)) @retry(stop=stop_after_attempt(4), wait=wait_fixed(7))
async def get_douyin_profile_liked_data(self, profile_url: str, tikhub_token: str) -> Union[dict, None]: async def get_douyin_profile_liked_data(
self, profile_url: str, tikhub_token: str
) -> Union[dict, None]:
try: try:
api_url = f"https://api.tikhub.io/douyin_profile_liked_videos/?douyin_profile_url={profile_url}&cursor=0&count=20" api_url = f"https://api.tikhub.io/douyin_profile_liked_videos/?douyin_profile_url={profile_url}&cursor=0&count=20"
_headers = {"Authorization": f"Bearer {tikhub_token}"} _headers = {"Authorization": f"Bearer {tikhub_token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url, headers=_headers, proxy=self.proxies, timeout=10
) as response:
response = await response.json() response = await response.json()
return response return response
except Exception as e: except Exception as e:
@ -351,12 +393,16 @@ class Scraper:
# 获取抖音视频评论数据/Get Douyin video comment data # 获取抖音视频评论数据/Get Douyin video comment data
@retry(stop=stop_after_attempt(4), wait=wait_fixed(7)) @retry(stop=stop_after_attempt(4), wait=wait_fixed(7))
async def get_douyin_video_comments(self, video_url: str, tikhub_token: str) -> Union[dict, None]: async def get_douyin_video_comments(
self, video_url: str, tikhub_token: str
) -> Union[dict, None]:
try: try:
api_url = f"https://api.tikhub.io/douyin_video_comments/?douyin_video_url={video_url}&cursor=0&count=20" api_url = f"https://api.tikhub.io/douyin_video_comments/?douyin_video_url={video_url}&cursor=0&count=20"
_headers = {"Authorization": f"Bearer {tikhub_token}"} _headers = {"Authorization": f"Bearer {tikhub_token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url, headers=_headers, proxy=self.proxies, timeout=10
) as response:
response = await response.json() response = await response.json()
return response return response
except Exception as e: except Exception as e:
@ -406,7 +452,12 @@ class Scraper:
if not quiet_mode: if not quiet_mode:
print("正在获取视频数据API: {}".format(api_url)) print("正在获取视频数据API: {}".format(api_url))
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=self.tiktok_api_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url,
headers=self.tiktok_api_headers,
proxy=self.proxies,
timeout=10,
) as response:
response = await response.json() response = await response.json()
video_data = response["aweme_list"][0] video_data = response["aweme_list"][0]
if not quiet_mode: if not quiet_mode:
@ -419,12 +470,16 @@ class Scraper:
raise e raise e
@retry(stop=stop_after_attempt(4), wait=wait_fixed(7)) @retry(stop=stop_after_attempt(4), wait=wait_fixed(7))
async def get_tiktok_user_profile_videos(self, tiktok_video_url: str, tikhub_token: str) -> Union[dict, None]: async def get_tiktok_user_profile_videos(
self, tiktok_video_url: str, tikhub_token: str
) -> Union[dict, None]:
try: try:
api_url = f"https://api.tikhub.io/tiktok_profile_videos/?tiktok_video_url={tiktok_video_url}&cursor=0&count=20" api_url = f"https://api.tikhub.io/tiktok_profile_videos/?tiktok_video_url={tiktok_video_url}&cursor=0&count=20"
_headers = {"Authorization": f"Bearer {tikhub_token}"} _headers = {"Authorization": f"Bearer {tikhub_token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url, headers=_headers, proxy=self.proxies, timeout=10
) as response:
response = await response.json() response = await response.json()
return response return response
except Exception as e: except Exception as e:
@ -434,12 +489,16 @@ class Scraper:
raise e raise e
@retry(stop=stop_after_attempt(4), wait=wait_fixed(7)) @retry(stop=stop_after_attempt(4), wait=wait_fixed(7))
async def get_tiktok_user_profile_liked_videos(self, tiktok_video_url: str, tikhub_token: str) -> Union[dict, None]: async def get_tiktok_user_profile_liked_videos(
self, tiktok_video_url: str, tikhub_token: str
) -> Union[dict, None]:
try: try:
api_url = f"https://api.tikhub.io/tiktok_profile_liked_videos/?tiktok_video_url={tiktok_video_url}&cursor=0&count=20" api_url = f"https://api.tikhub.io/tiktok_profile_liked_videos/?tiktok_video_url={tiktok_video_url}&cursor=0&count=20"
_headers = {"Authorization": f"Bearer {tikhub_token}"} _headers = {"Authorization": f"Bearer {tikhub_token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=_headers, proxy=self.proxies, timeout=10) as response: async with session.get(
api_url, headers=_headers, proxy=self.proxies, timeout=10
) as response:
response = await response.json() response = await response.json()
return response return response
except Exception as e: except Exception as e:
@ -458,13 +517,21 @@ class Scraper:
print("当前链接平台为:{}".format(url_platform)) print("当前链接平台为:{}".format(url_platform))
# 获取视频ID/Get video ID # 获取视频ID/Get video ID
print("正在获取视频ID...") print("正在获取视频ID...")
video_id = await self.get_douyin_video_id(video_url) if url_platform == "douyin" else await self.get_tiktok_video_id(video_url) video_id = (
await self.get_douyin_video_id(video_url)
if url_platform == "douyin"
else await self.get_tiktok_video_id(video_url)
)
if video_id: if video_id:
if not quiet_mode: if not quiet_mode:
print("获取视频ID成功,视频ID为:{}".format(video_id)) print("获取视频ID成功,视频ID为:{}".format(video_id))
# 获取视频数据/Get video data # 获取视频数据/Get video data
print("正在获取视频数据...") print("正在获取视频数据...")
data = await self.get_douyin_video_data(video_id) if url_platform == "douyin" else await self.get_tiktok_video_data(video_id) data = (
await self.get_douyin_video_data(video_id)
if url_platform == "douyin"
else await self.get_tiktok_video_data(video_id)
)
if data: if data:
if not quiet_mode: if not quiet_mode:
print("获取视频数据成功,正在判断数据类型...") print("获取视频数据成功,正在判断数据类型...")
@ -571,7 +638,10 @@ class Scraper:
no_watermark_image_list.append(i["url_list"][0]) no_watermark_image_list.append(i["url_list"][0])
watermark_image_list.append(i["download_url_list"][0]) watermark_image_list.append(i["download_url_list"][0])
api_data = { api_data = {
"image_data": {"no_watermark_image_list": no_watermark_image_list, "watermark_image_list": watermark_image_list} "image_data": {
"no_watermark_image_list": no_watermark_image_list,
"watermark_image_list": watermark_image_list,
}
} }
# TikTok数据处理/TikTok data processing # TikTok数据处理/TikTok data processing
elif url_platform == "tiktok": elif url_platform == "tiktok":
@ -585,8 +655,12 @@ class Scraper:
"video_data": { "video_data": {
"wm_video_url": wm_video, "wm_video_url": wm_video,
"wm_video_url_HQ": wm_video, "wm_video_url_HQ": wm_video,
"nwm_video_url": data["video"]["play_addr"]["url_list"][0], "nwm_video_url": data["video"]["play_addr"][
"nwm_video_url_HQ": data["video"]["bit_rate"][0]["play_addr"]["url_list"][0], "url_list"
][0],
"nwm_video_url_HQ": data["video"]["bit_rate"][0][
"play_addr"
]["url_list"][0],
} }
} }
# TikTok图片数据处理/TikTok image data processing # TikTok图片数据处理/TikTok image data processing
@ -598,25 +672,38 @@ class Scraper:
# 有水印图片列表/With watermark image list # 有水印图片列表/With watermark image list
watermark_image_list = [] watermark_image_list = []
for i in data["image_post_info"]["images"]: for i in data["image_post_info"]["images"]:
no_watermark_image_list.append(i["display_image"]["url_list"][0]) no_watermark_image_list.append(
watermark_image_list.append(i["owner_watermark_image"]["url_list"][0]) i["display_image"]["url_list"][0]
)
watermark_image_list.append(
i["owner_watermark_image"]["url_list"][0]
)
api_data = { api_data = {
"image_data": {"no_watermark_image_list": no_watermark_image_list, "watermark_image_list": watermark_image_list} "image_data": {
"no_watermark_image_list": no_watermark_image_list,
"watermark_image_list": watermark_image_list,
}
} }
# 更新数据/Update data # 更新数据/Update data
result_data.update(api_data) result_data.update(api_data)
# print("数据处理完成,最终数据: \n{}".format(result_data)) # print("数据处理完成,最终数据: \n{}".format(result_data))
# 返回数据/Return data # 返回数据/Return data
return result_data return result_data
except Exception as e: except Exception:
if not quiet_mode: if not quiet_mode:
traceback.print_exc() traceback.print_exc()
print("数据处理失败!") print("数据处理失败!")
return {"status": "failed", "message": "数据处理失败!/Data processing failed!"} return {
"status": "failed",
"message": "数据处理失败!/Data processing failed!",
}
else: else:
if not quiet_mode: if not quiet_mode:
print("[抖音|TikTok方法]返回数据为空,无法处理!") print("[抖音|TikTok方法]返回数据为空,无法处理!")
return {"status": "failed", "message": "返回数据为空,无法处理!/Return data is empty and cannot be processed!"} return {
"status": "failed",
"message": "返回数据为空,无法处理!/Return data is empty and cannot be processed!",
}
else: else:
if not quiet_mode: if not quiet_mode:
print("获取视频ID失败") print("获取视频ID失败")
@ -633,12 +720,24 @@ class Scraper:
"platform": data.get("platform"), "platform": data.get("platform"),
"type": data.get("type"), "type": data.get("type"),
"desc": data.get("desc"), "desc": data.get("desc"),
"wm_video_url": data["video_data"]["wm_video_url"] if data["type"] == "video" else None, "wm_video_url": data["video_data"]["wm_video_url"]
"wm_video_url_HQ": data["video_data"]["wm_video_url_HQ"] if data["type"] == "video" else None, if data["type"] == "video"
"nwm_video_url": data["video_data"]["nwm_video_url"] if data["type"] == "video" else None, else None,
"nwm_video_url_HQ": data["video_data"]["nwm_video_url_HQ"] if data["type"] == "video" else None, "wm_video_url_HQ": data["video_data"]["wm_video_url_HQ"]
"no_watermark_image_list": data["image_data"]["no_watermark_image_list"] if data["type"] == "image" else None, if data["type"] == "video"
"watermark_image_list": data["image_data"]["watermark_image_list"] if data["type"] == "image" else None, else None,
"nwm_video_url": data["video_data"]["nwm_video_url"]
if data["type"] == "video"
else None,
"nwm_video_url_HQ": data["video_data"]["nwm_video_url_HQ"]
if data["type"] == "video"
else None,
"no_watermark_image_list": data["image_data"]["no_watermark_image_list"]
if data["type"] == "image"
else None,
"watermark_image_list": data["image_data"]["watermark_image_list"]
if data["type"] == "image"
else None,
} }
return result return result
else: else:
@ -679,4 +778,4 @@ if __name__ == "__main__":
# api.generate_x_bogus(params) # api.generate_x_bogus(params)
douyin_url = "https://v.douyin.com/rLyrQxA/6.66" douyin_url = "https://v.douyin.com/rLyrQxA/6.66"
tiktok_url = "https://vt.tiktok.com/ZSRwWXtdr/" tiktok_url = "https://vt.tiktok.com/ZSRwWXtdr/"
asyncio.run(async_test(_douyin_url=douyin_url, _tiktok_url=tiktok_url)) asyncio.run(async_test(_douyin_url=douyin_url, _tiktok_url=tiktok_url))

View File

@ -12,8 +12,42 @@ class Message(MSG):
super().__dict__.update(message.__dict__) super().__dict__.update(message.__dict__)
@cached_property @cached_property
def text_list(self): def cmd(self):
return self.text.split() raw_cmd = self.text_list[0]
cmd = raw_cmd.lstrip(Config.TRIGGER)
return cmd if cmd in Config.CMD_DICT else None
@cached_property
def flags(self):
return [i for i in self.text_list if i.startswith("-")]
@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
]
return "\n".join(split_n_joined)
@cached_property
def input(self):
if len(self.text_list) > 1:
return self.text.split(maxsplit=1)[-1]
return ""
@cached_property
def replied(self):
if self.reply_to_message:
return Message.parse_message(self.reply_to_message)
@cached_property
def reply_id(self):
return self.replied.id if self.replied else None
@cached_property
def replied_task_id(self):
return self.replied.task_id if self.replied else None
@cached_property @cached_property
def reply_text_list(self): def reply_text_list(self):
@ -27,47 +61,30 @@ class Message(MSG):
return reply_text_list return reply_text_list
@cached_property @cached_property
def cmd(self): def task_id(self):
raw_cmd = self.text_list[0] return f"{self.chat.id}-{self.id}"
cmd = raw_cmd.lstrip(Config.TRIGGER)
return cmd if cmd in Config.CMD_DICT else None
@cached_property @cached_property
def flags(self): def text_list(self):
return [i for i in self.text_list if i.startswith("-")] return self.text.split()
@cached_property async def async_deleter(self, del_in, task, block):
def input(self): if block:
if len(self.text_list) > 1: x = await task
return self.text.split(maxsplit=1)[-1] await asyncio.sleep(del_in)
return "" await x.delete()
@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
]
return "\n".join(split_n_joined)
@cached_property
def replied(self):
if self.reply_to_message:
return Message.parse_message(self.reply_to_message)
@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: else:
return await task asyncio.create_task(
self.async_deleter(del_in=del_in, task=task, block=True)
)
async def delete(self, reply=False):
try:
await super().delete()
if reply and self.replied:
await self.replied.delete()
except MessageDeleteForbidden:
pass
async def edit(self, text, del_in: int = 0, block=True, **kwargs): async def edit(self, text, del_in: int = 0, block=True, **kwargs):
if len(str(text)) < 4096: if len(str(text)) < 4096:
@ -83,23 +100,14 @@ class Message(MSG):
) )
return reply return reply
async def delete(self, reply=False): async def reply(self, text, del_in: int = 0, block=True, **kwargs):
try: task = self._client.send_message(
await super().delete() chat_id=self.chat.id, text=text, reply_to_message_id=self.id, **kwargs
if reply and self.replied: )
await self.replied.delete() if del_in:
except MessageDeleteForbidden: await self.async_deleter(task=task, del_in=del_in, block=block)
pass
async def async_deleter(self, del_in, task, block):
if block:
x = await task
await asyncio.sleep(del_in)
await x.delete()
else: else:
asyncio.create_task( return await task
self.async_deleter(del_in=del_in, task=task, block=True)
)
@classmethod @classmethod
def parse_message(cls, message): def parse_message(cls, message):

View File

@ -27,7 +27,6 @@ async def run_shell_cmd(cmd):
class AsyncShell: class AsyncShell:
def __init__(self, process): def __init__(self, process):
self.process = process self.process = process
self.full_std = "" self.full_std = ""
@ -46,6 +45,11 @@ class AsyncShell:
while not self.is_done: while not self.is_done:
yield self.full_std yield self.full_std
def cancel(self):
if not self.is_done:
self.process.kill()
self._task.cancel()
@classmethod @classmethod
async def run_cmd(cls, cmd, name="shell"): async def run_cmd(cls, cmd, name="shell"):
sub_process = cls( sub_process = cls(
@ -53,6 +57,8 @@ class AsyncShell:
cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT
) )
) )
asyncio.create_task(sub_process.read_output()) sub_process._task = asyncio.create_task(
sub_process.read_output(), name="AsyncShell"
)
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
return sub_process return sub_process

View File

@ -17,9 +17,7 @@ async def run_cmd(bot, message):
cmd = message.input.strip() cmd = message.input.strip()
reply = await message.reply("executing...") reply = await message.reply("executing...")
try: try:
proc_stdout = await asyncio.Task( proc_stdout = await asyncio.Task(shell.run_shell_cmd(cmd), name=reply.task_id)
shell.run_shell_cmd(cmd), name=f"{message.chat.id}-{reply.id}"
)
except asyncio.exceptions.CancelledError: except asyncio.exceptions.CancelledError:
return await reply.edit("`Cancelled...`") return await reply.edit("`Cancelled...`")
output = f"`${cmd}`\n\n`{proc_stdout}`" output = f"`${cmd}`\n\n`{proc_stdout}`"
@ -28,12 +26,12 @@ async def run_cmd(bot, message):
# Shell but Live Output # Shell but Live Output
async def live_shell(bot, message): async def live_shell(bot, message):
cmd = message.input.strip()
reply = await message.reply("`getting live output....`")
sub_process = await shell.AsyncShell.run_cmd(cmd)
sleep_for = 1
output = ""
try: try:
cmd = message.input.strip()
reply = await message.reply("`getting live output....`")
sub_process = await shell.AsyncShell.run_cmd(cmd)
sleep_for = 1
output = ""
async for stdout in sub_process.get_output(): async for stdout in sub_process.get_output():
if output != stdout: if output != stdout:
if len(stdout) <= 4096: if len(stdout) <= 4096:
@ -43,11 +41,9 @@ async def live_shell(bot, message):
parse_mode=ParseMode.MARKDOWN, parse_mode=ParseMode.MARKDOWN,
) )
output = stdout output = stdout
if sleep_for >= 5: if sleep_for >= 6:
sleep_for = 1 sleep_for = 1
await asyncio.Task( await asyncio.Task(asyncio.sleep(sleep_for), name=reply.task_id)
asyncio.sleep(sleep_for), name=f"{message.chat.id}-{reply.id}"
)
sleep_for += 1 sleep_for += 1
return await reply.edit( return await reply.edit(
f"`$ {cmd}\n\n``{sub_process.full_std}`", f"`$ {cmd}\n\n``{sub_process.full_std}`",
@ -55,7 +51,8 @@ async def live_shell(bot, message):
disable_web_page_preview=True, disable_web_page_preview=True,
) )
except asyncio.exceptions.CancelledError: except asyncio.exceptions.CancelledError:
return await reply.edit("`Cancelled...`") sub_process.cancel()
return await reply.edit(f"`Cancelled....`")
# Run Python code # Run Python code
@ -74,7 +71,7 @@ async def executor(bot, message):
# Create and initialise the function # Create and initialise the function
exec(f"async def _exec(bot, message):\n {formatted_code}") exec(f"async def _exec(bot, message):\n {formatted_code}")
func_out = await asyncio.Task( func_out = await asyncio.Task(
locals()["_exec"](bot, message), name=f"{message.chat.id}-{reply.id}" locals()["_exec"](bot, message), name=reply.task_id
) )
except asyncio.exceptions.CancelledError: except asyncio.exceptions.CancelledError:
return await reply.edit("`Cancelled....`") return await reply.edit("`Cancelled....`")
@ -82,9 +79,11 @@ async def executor(bot, message):
func_out = str(traceback.format_exc()) func_out = str(traceback.format_exc())
sys.stdout = sys.__stdout__ sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__ sys.stderr = sys.__stderr__
output = f"`{codeOut.getvalue().strip() or codeErr.getvalue().strip() or func_out}`" output = codeErr.getvalue().strip() or codeOut.getvalue().strip()
if func_out is not None:
output = "\n\n".join([output, str(func_out)]).strip()
if "-s" not in message.flags: if "-s" not in message.flags:
output = f"> `{code}`\n\n>> {output}" output = f"> `{code}`\n\n>> `{output}`"
return await reply.edit( return await reply.edit(
output, output,
name="exec.txt", name="exec.txt",

View File

@ -5,13 +5,13 @@ from app import bot
@bot.add_cmd(cmd=["cancel", "c"]) @bot.add_cmd(cmd=["cancel", "c"])
async def cancel_task(bot, message): async def cancel_task(bot, message):
task_id = message.reply_id task_id = message.replied_task_id
if not task_id: if not task_id:
return await message.reply( return await message.reply(
"Reply To a Command or Bot's Response Message.", del_in=8 "Reply To a Command or Bot's Response Message.", del_in=8
) )
all_tasks = asyncio.all_tasks() all_tasks = asyncio.all_tasks()
tasks = [x for x in all_tasks if x.get_name() == f"{message.chat.id}-{task_id}"] tasks = [x for x in all_tasks if x.get_name() == task_id]
if not tasks: if not tasks:
return await message.reply("Task not in Currently Running Tasks.", del_in=8) return await message.reply("Task not in Currently Running Tasks.", del_in=8)
response = "" response = ""

View File

@ -13,7 +13,7 @@ async def dl(bot, message):
chat_id=message.chat.id, text="`trying to download...`" chat_id=message.chat.id, text="`trying to download...`"
) )
coro = ExtractAndSendMedia.process(message) coro = ExtractAndSendMedia.process(message)
task = asyncio.Task(coro, name=f"{message.chat.id}-{message.id}") task = asyncio.Task(coro, name=message.task_id)
media = await task media = await task
if media.exceptions: if media.exceptions:
exceptions = "\n".join(media.exceptions) exceptions = "\n".join(media.exceptions)
@ -32,11 +32,11 @@ async def dl(bot, message):
@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):
parsed_message = Message.parse_message(message) message = Message.parse_message(message)
func = Config.CMD_DICT[parsed_message.cmd] func = Config.CMD_DICT[message.cmd]
coro = func(bot, parsed_message) coro = func(bot, message)
try: try:
task = asyncio.Task(coro, name=f"{message.chat.id}-{message.id}") task = asyncio.Task(coro, name=message.task_id)
await task await task
except asyncio.exceptions.CancelledError: except asyncio.exceptions.CancelledError:
await bot.log(text=f"<b>#Cancelled</b>:\n<code>{message.text}</code>") await bot.log(text=f"<b>#Cancelled</b>:\n<code>{message.text}</code>")
@ -51,10 +51,10 @@ async def cmd_dispatcher(bot, message):
@bot.on_message(filters.chat_filter) @bot.on_message(filters.chat_filter)
async def dl_dispatcher(bot, message): async def dl_dispatcher(bot, message):
parsed_message = Message.parse_message(message) message = Message.parse_message(message)
coro = dl(bot, parsed_message) coro = dl(bot, message)
try: try:
task = asyncio.Task(coro, name=f"{message.chat.id}-{message.id}") task = asyncio.Task(coro, name=message.task_id)
await task await task
except asyncio.exceptions.CancelledError: except asyncio.exceptions.CancelledError:
await bot.log(text=f"<b>#Cancelled</b>:\n<code>{message.text}</code>") await bot.log(text=f"<b>#Cancelled</b>:\n<code>{message.text}</code>")