From b8781c87853d3246bcd7fa5d3c67e18482be7abb Mon Sep 17 00:00:00 2001 From: Leorio Paradinight <62891774+code-rgb@users.noreply.github.com> Date: Mon, 8 Feb 2021 22:19:48 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20iYTDL=20=20v2.5=20(#134)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Improvements * added regex for faster match * support for bot mode * code cleanup * Faster (switched to pyrogram cuz now it DC id bug fixed) * Video will now output as mp4 (streamable on TG) * Improved thumb for videos * added [Best Audio Option] šŸ˜œ 320 kbps # Upstreams # fixes * kang.py * deepsource fixes --- requirements.txt | 1 - userge/core/ext/raw_client.py | 117 +++++----- userge/plugins/admin/gadmin.py | 4 +- userge/plugins/bot/opinion.py | 30 +-- userge/plugins/bot/utube_inline.py | 331 ++++++++++++++--------------- userge/plugins/fun/kang.py | 6 +- userge/plugins/fun/nsfw.py | 88 +++----- userge/plugins/fun/quote.py | 5 +- userge/plugins/help.py | 93 ++------ userge/plugins/misc/upload.py | 85 ++++---- userge/plugins/tools/json.py | 4 +- userge/plugins/utils/currency.py | 4 +- userge/plugins/utils/translate.py | 4 +- userge/utils/__init__.py | 6 +- userge/utils/aiohttp_helper.py | 50 ++--- userge/utils/botapi/XParser.py | 90 -------- userge/utils/botapi/__init__.py | 2 - userge/utils/botapi/iprogress.py | 87 -------- userge/utils/botapi/rawbotapi.py | 279 ------------------------ userge/utils/progress.py | 32 ++- 20 files changed, 398 insertions(+), 920 deletions(-) delete mode 100644 userge/utils/botapi/XParser.py delete mode 100644 userge/utils/botapi/__init__.py delete mode 100644 userge/utils/botapi/iprogress.py delete mode 100644 userge/utils/botapi/rawbotapi.py diff --git a/requirements.txt b/requirements.txt index 16509ef72..e9e670fcf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,6 @@ beautifulsoup4>=4.9.1 covid>=2.4.0 cowpy>=1.1.0 dnspython>=2.0.0 -emoji>=0.6.0 gitpython>=3.1.11 google-api-python-client>=1.12.8 google-auth-httplib2>=0.0.4 diff --git a/userge/core/ext/raw_client.py b/userge/core/ext/raw_client.py index 494c9d86e..b1482fe48 100644 --- a/userge/core/ext/raw_client.py +++ b/userge/core/ext/raw_client.py @@ -11,8 +11,9 @@ __all__ = ['RawClient'] import asyncio -import time -from typing import Optional, Dict +from math import floor +from typing import Optional, Dict, List +from time import time, perf_counter, sleep import pyrogram.raw.functions as funcs import pyrogram.raw.types as types @@ -29,11 +30,8 @@ class RawClient(Client): """ userge raw client """ DUAL_MODE = False - LAST_OUTGOING_TIME = time.time() - + LAST_OUTGOING_TIME = time() REQ_LOGS: Dict[int, 'ChatReq'] = {} - DELAY_BET_MSG_REQ = 1 - MSG_REQ_PER_MIN = 20 REQ_LOCK = asyncio.Lock() def __init__(self, bot: Optional['userge.core.client.UsergeBot'] = None, **kwargs) -> None: @@ -46,69 +44,92 @@ async def send(self, data: TLObject, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT, sleep_threshold: float = None): key = 0 if isinstance(data, (funcs.messages.SendMessage, + funcs.messages.SendMedia, + funcs.messages.SendMultiMedia, funcs.messages.EditMessage, funcs.messages.ForwardMessages)): if isinstance(data, funcs.messages.ForwardMessages): tmp = data.to_peer else: tmp = data.peer - if isinstance(tmp, (types.InputPeerChannel, types.InputPeerChannelFromMessage)): - key = int(tmp.channel_id) - elif isinstance(tmp, types.InputPeerChat): - key = int(tmp.chat_id) - elif isinstance(tmp, (types.InputPeerUser, types.InputPeerUserFromMessage)): - key = int(tmp.user_id) + if isinstance(data, funcs.messages.SendMedia) and isinstance( + data.media, (types.InputMediaUploadedDocument, + types.InputMediaUploadedPhoto)): + tmp = None + if tmp: + if isinstance(tmp, (types.InputPeerChannel, types.InputPeerChannelFromMessage)): + key = int(tmp.channel_id) + elif isinstance(tmp, types.InputPeerChat): + key = int(tmp.chat_id) + elif isinstance(tmp, (types.InputPeerUser, types.InputPeerUserFromMessage)): + key = int(tmp.user_id) elif isinstance(data, funcs.channels.DeleteMessages): if isinstance(data.channel, (types.InputChannel, types.InputChannelFromMessage)): key = int(data.channel.channel_id) if key: - async def slp(to_sl: float) -> None: - if to_sl > 0.1: - if to_sl > 1: - _LOG.info(_LOG_STR, to_sl, key) - else: - _LOG.debug(_LOG_STR, to_sl, key) - await asyncio.sleep(to_sl) async with self.REQ_LOCK: - if key in self.REQ_LOGS: - chat_req = self.REQ_LOGS[key] - else: - chat_req = self.REQ_LOGS[key] = ChatReq() - diff = chat_req.small_diff - if 0 < diff < self.DELAY_BET_MSG_REQ: - await slp(1 - diff) - diff = chat_req.big_diff - if diff >= 60: - chat_req.reset() - elif chat_req.count > self.MSG_REQ_PER_MIN: - await slp(60 - diff) - chat_req.reset() - else: - chat_req.update() + try: + req = self.REQ_LOGS[key] + except KeyError: + req = self.REQ_LOGS[key] = ChatReq() + async with req.lock: + now = perf_counter() + req.update(now - 60) + if req.has: + to_sl = 0.0 + diff = now - req.last + if 0 < diff < 1: + to_sl = 1 - diff + diff = now - req.first + if req.count > 18: + to_sl = max(to_sl, 60 - diff) + if to_sl > 0: + if to_sl > 1: + _LOG.info(_LOG_STR, to_sl, key) + else: + _LOG.debug(_LOG_STR, to_sl, key) + await asyncio.sleep(to_sl) + now += to_sl + count = 0 + counter = floor(now - 1) + for r in self.REQ_LOGS.values(): + if r.has and r.last > counter: + count += 1 + if count > 25: + _LOG.info(_LOG_STR, 1, key) + sleep(1) + now += 1 + req.add(now) return await super().send(data, retries, timeout, sleep_threshold) class ChatReq: def __init__(self) -> None: - self._first = self._last = time.time() - self._count = 0 + self._lock = asyncio.Lock() + self._logs: List[float] = [] + + @property + def lock(self): + return self._lock + + @property + def has(self) -> bool: + return len(self._logs) != 0 @property - def small_diff(self) -> float: - return time.time() - self._last + def first(self) -> float: + return self._logs[0] @property - def big_diff(self) -> float: - return time.time() - self._first + def last(self) -> Optional[float]: + return self._logs[-1] @property - def count(self) -> float: - return self._count + def count(self) -> int: + return len(self._logs) - def reset(self) -> None: - self._first = self._last = time.time() - self._count = 1 + def add(self, log: float) -> None: + self._logs.append(log) - def update(self) -> None: - self._last = time.time() - self._count += 1 + def update(self, t: float) -> None: + self._logs = [i for i in self._logs if i > t] \ No newline at end of file diff --git a/userge/plugins/admin/gadmin.py b/userge/plugins/admin/gadmin.py index 4e9d069b6..883b2d3c7 100644 --- a/userge/plugins/admin/gadmin.py +++ b/userge/plugins/admin/gadmin.py @@ -4,7 +4,6 @@ import os import time -from emoji import get_emoji_regexp from pyrogram.errors import ( FloodWait, PeerIdInvalid, @@ -15,6 +14,7 @@ from pyrogram.types import ChatPermissions from userge import Message, userge +from userge.utils.functions import get_emoji_regex CHANNEL = userge.getCLogger(__name__) @@ -47,7 +47,7 @@ async def promote_usr(message: Message): ) return if custom_rank: - custom_rank = get_emoji_regexp().sub("", custom_rank) + custom_rank = get_emoji_regex().sub("", custom_rank) if len(custom_rank) > 15: custom_rank = custom_rank[:15] try: diff --git a/userge/plugins/bot/opinion.py b/userge/plugins/bot/opinion.py index fe07d814b..06f1a93c1 100644 --- a/userge/plugins/bot/opinion.py +++ b/userge/plugins/bot/opinion.py @@ -2,14 +2,15 @@ # All rights reserved. +import asyncio import os import ujson from pyrogram import filters +from pyrogram.errors import BadRequest, FloodWait from pyrogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from userge import Config, Message, userge -from userge.utils import xbot if not os.path.exists("userge/xcache"): os.mkdir("userge/xcache") @@ -84,10 +85,8 @@ async def choice_cb(_, c_q: CallbackQuery): data[str(opinion_id)] = view_data with open(PATH, "w") as outfile: ujson.dump(data, outfile) - agree_data += f" {view_data[1]['agree']}" disagree_data += f" {view_data[1]['disagree']}" - opinion_data = [ [ InlineKeyboardButton(agree_data, callback_data=f"op_y_{opinion_id}"), @@ -95,18 +94,14 @@ async def choice_cb(_, c_q: CallbackQuery): ], [InlineKeyboardButton("šŸ“Š Stats", callback_data=f"opresult_{opinion_id}")], ] - - await xbot.edit_inline_reply_markup( - c_q.inline_message_id, reply_markup=InlineKeyboardMarkup(opinion_data) - ) - - # await userge.bot.edit_inline_reply_markup( - # c_q.inline_message_id, reply_markup=InlineKeyboardMarkup(opinion_data) - # ) - # except FloodWait as e: - # await asyncio.sleep(e.x) - # except BadRequest: - # return + try: + await c_q.edit_message_reply_markup( + reply_markup=InlineKeyboardMarkup(opinion_data) + ) + except FloodWait as e: + await asyncio.sleep(e.x) + except BadRequest: + return @userge.bot.on_callback_query(filters.regex(pattern=r"^opresult_(\d+)$")) async def choice_result_cb(_, c_q: CallbackQuery): @@ -124,10 +119,7 @@ async def choice_result_cb(_, c_q: CallbackQuery): msg += f"ā€¢ šŸ‘¤ `{total} People voted`\n\n" msg += f"ā€¢ šŸ‘ `{agreed}% People Agreed`\n\n" msg += f"ā€¢ šŸ‘Ž `{disagreed}% People Disagreed`\n\n" - - await xbot.edit_inline_text(c_q.inline_message_id, msg) - - # await userge.bot.edit_inline_text(c_q.inline_message_id, msg) + await c_q.edit_message_text(msg) else: a = await userge.get_me() if a.username: diff --git a/userge/plugins/bot/utube_inline.py b/userge/plugins/bot/utube_inline.py index 29e4fb0ca..c0e381698 100644 --- a/userge/plugins/bot/utube_inline.py +++ b/userge/plugins/bot/utube_inline.py @@ -1,15 +1,29 @@ +""" Download Youtube Video/ Audio in a User friendly interface """ +# -------------------------- # +# Modded ytdl by code-rgb +# -------------------------- # + import glob import os +from collections import defaultdict from pathlib import Path +from re import search from time import time -from urllib.parse import parse_qs, urlparse import ujson import youtube_dl from pyrogram import filters -from pyrogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup +from pyrogram.types import ( + CallbackQuery, + InlineKeyboardButton, + InlineKeyboardMarkup, + InputMediaAudio, + InputMediaPhoto, + InputMediaVideo, +) from wget import download from youtube_dl.utils import DownloadError +from youtubesearchpython import VideosSearch from userge import Config, Message, pool, userge from userge.utils import ( @@ -18,9 +32,8 @@ get_response, humanbytes, post_to_telegraph, + rand_key, sublists, - xbot, - xmedia, ) from ..misc.upload import upload @@ -28,15 +41,17 @@ LOGGER = userge.getLogger(__name__) CHANNEL = userge.getCLogger(__name__) BASE_YT_URL = "https://www.youtube.com/watch?v=" +YOUTUBE_REGEX = r"(?:(?:https?:)?\/\/)?(?:(?:www|m)\.)?(?:(?:youtube\.com|youtu.be))(?:\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(?:\S+)?" PATH = "./userge/xcache/ytsearch.json" class YT_Search_X: def __init__(self): if not os.path.exists(PATH): - d = {} - ujson.dump(d, open(PATH, "w")) - self.db = ujson.load(open(PATH)) + with open(PATH, "w") as f_x: + ujson.dump({}, f_x) + with open(PATH) as yt_db: + self.db = ujson.load(yt_db) def store_(self, rnd_id: str, results: dict): self.db[rnd_id] = results @@ -58,7 +73,6 @@ async def get_ytthumb(videoid: str): "mqdefault.jpg", "default.jpg", # Worst quality ] - thumb_link = "https://i.imgur.com/4LwPLai.png" for qualiy in thumb_quality: link = f"https://i.ytimg.com/vi/{videoid}/{qualiy}" @@ -85,16 +99,61 @@ async def iytdl_inline(message: Message): input_url = reply.text elif reply.caption: input_url = reply.caption - if not input_url: return await message.err("Input or reply to a valid youtube URL", del_in=5) await message.edit(f"šŸ”Ž Searching Youtube for: '{input_url}'") - bot = await userge.bot.get_me() - x = await userge.get_inline_bot_results(bot.username, f"ytdl {input_url.strip()}") - await message.delete() - await userge.send_inline_bot_result( - chat_id=message.chat.id, query_id=x.query_id, result_id=x.results[0].id - ) + input_url = input_url.strip() + if message.client.is_bot: + link = get_yt_video_id(input_url) + if link is None: + search_ = VideosSearch(input_url, limit=15) + resp = (search_.result()).get("result") + if len(resp) == 0: + await message.err(f'No Results found for "{input_url}"', del_in=7) + return + outdata = await result_formatter(resp) + key_ = rand_key() + ytsearch_data.store_(key_, outdata) + buttons = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=f"1 / {len(outdata)}", + callback_data=f"ytdl_next_{key_}_1", + ) + ], + [ + InlineKeyboardButton( + text="šŸ“œ List all", + callback_data=f"ytdl_listall_{key_}_1", + ), + InlineKeyboardButton( + text="ā¬‡ļø Download", + callback_data=f'ytdl_download_{outdata[1]["video_id"]}_0', + ), + ], + ] + ) + caption = outdata[1]["message"] + photo = outdata[1]["thumb"] + else: + caption, buttons = await download_button(link, body=True) + photo = await get_ytthumb(link) + + await userge.bot.send_photo( + message.chat.id, + photo=photo, + caption=caption, + reply_markup=buttons, + ) + await message.delete() + else: + bot = await userge.bot.get_me() + x = await userge.get_inline_bot_results(bot.username, f"ytdl {input_url}") + await message.delete() + await userge.send_inline_bot_result( + chat_id=message.chat.id, query_id=x.query_id, result_id=x.results[0].id + ) if userge.has_bot: @@ -110,26 +169,27 @@ async def ytdl_download_callback(c_q: CallbackQuery): choice_id = int(choice_id) if choice_id == 0: await c_q.answer("šŸ”„ Processing...", show_alert=False) - await xbot.edit_inline_reply_markup( - c_q.inline_message_id, reply_markup=(await download_button(yt_code)) + await c_q.edit_message_reply_markup( + reply_markup=(await download_button(yt_code)) ) return else: choice_id = None - startTime = time() downtype = c_q.matches[0].group(3) media_type = "Video" if downtype == "v" else "Audio" callback_continue = f"Downloading {media_type} Please Wait..." - callback_continue += f"\n\nFormat Code : {choice_id or 'bestaudio/best'}" + frmt_text = choice_id or ( + "bestaudio/best [mp4]" if downtype == "v" else "320 Kbps" + ) + callback_continue += f"\n\nFormat Code : {frmt_text}" await c_q.answer(callback_continue, show_alert=True) upload_msg = await userge.send_message(Config.LOG_CHANNEL_ID, "Uploading...") yt_url = BASE_YT_URL + yt_code - await xbot.edit_inline_caption( - c_q.inline_message_id, - caption=( + await c_q.edit_message_text( + text=( f"**ā¬‡ļø Downloading {media_type} ...**" - f"\n\nšŸ”— [Link]({yt_url})\nšŸ†” Format Code : {choice_id or 'bestaudio/best'}" + f"\n\nšŸ”— [Link]({yt_url})\nšŸ†” Format Code : {frmt_text}" ), ) if downtype == "v": @@ -139,40 +199,42 @@ async def ytdl_download_callback(c_q: CallbackQuery): if retcode != 0: return await upload_msg.edit(str(retcode)) _fpath = "" + thumb_pic = None for _path in glob.glob(os.path.join(Config.DOWN_PATH, str(startTime), "*")): - if not _path.lower().endswith((".jpg", ".png", ".webp")): + if _path.lower().endswith((".jpg", ".png", ".webp")): + thumb_pic = _path + else: _fpath = _path if not _fpath: await upload_msg.err("nothing found !") return - thumb_ = str(download(await get_ytthumb(yt_code))) if downtype == "v" else None + if not thumb_pic and downtype == "v": + thumb_pic = str(download(await get_ytthumb(yt_code))) uploaded_media = await upload( upload_msg, - Path(_fpath), - logvid=False, - custom_thumb=thumb_, - inline_id=c_q.inline_message_id, + path=Path(_fpath), + callback=c_q, + custom_thumb=thumb_pic, + log=False, ) refresh_vid = await userge.bot.get_messages( Config.LOG_CHANNEL_ID, uploaded_media.message_id ) f_id = get_file_id(refresh_vid) if downtype == "v": - await xbot.edit_inline_media( - c_q.inline_message_id, + await c_q.edit_message_media( media=( - await xmedia.InputMediaVideo( - file_id=f_id, + InputMediaVideo( + media=f_id, caption=f"šŸ“¹ [{uploaded_media.caption}]({yt_url})", ) ), ) else: # Audio - await xbot.edit_inline_media( - c_q.inline_message_id, + await c_q.edit_message_media( media=( - await xmedia.InputMediaAudio( - file_id=f_id, + InputMediaAudio( + media=f_id, caption=f"šŸŽµ [{uploaded_media.caption}]({yt_url})", ) ), @@ -201,11 +263,10 @@ async def ytdl_callback(c_q: CallbackQuery): del_back = index == 1 await c_q.answer() back_vid = search_data.get(str(index)) - await xbot.edit_inline_media( - c_q.inline_message_id, + await c_q.edit_message_media( media=( - await xmedia.InputMediaPhoto( - file_id=back_vid.get("thumb"), + InputMediaPhoto( + media=back_vid.get("thumb"), caption=back_vid.get("message"), ) ), @@ -223,11 +284,10 @@ async def ytdl_callback(c_q: CallbackQuery): return await c_q.answer("That's All Folks !", show_alert=True) await c_q.answer() front_vid = search_data.get(str(index)) - await xbot.edit_inline_media( - c_q.inline_message_id, + await c_q.edit_message_media( media=( - await xmedia.InputMediaPhoto( - file_id=front_vid.get("thumb"), + InputMediaPhoto( + media=front_vid.get("thumb"), caption=front_vid.get("message"), ) ), @@ -238,7 +298,6 @@ async def ytdl_callback(c_q: CallbackQuery): total=total, ), ) - elif choosen_btn == "listall": await c_q.answer("View Changed to: šŸ“œ List", show_alert=False) list_res = "" @@ -248,11 +307,10 @@ async def ytdl_callback(c_q: CallbackQuery): a_title=f"Showing {total} youtube video results for the given query ...", content=list_res, ) - await xbot.edit_inline_media( - c_q.inline_message_id, + await c_q.edit_message_media( media=( - await xmedia.InputMediaPhoto( - file_id=search_data.get("1").get("thumb"), + InputMediaPhoto( + media=search_data.get("1").get("thumb"), # caption=f"[Click to view]({})", ) ), @@ -273,16 +331,14 @@ async def ytdl_callback(c_q: CallbackQuery): ] ), ) - else: # Detailed index = 1 await c_q.answer("View Changed to: šŸ“° Detailed", show_alert=False) first = search_data.get(str(index)) - await xbot.edit_inline_media( - c_q.inline_message_id, + await c_q.edit_message_media( media=( - await xmedia.InputMediaPhoto( - file_id=first.get("thumb"), + InputMediaPhoto( + media=first.get("thumb"), caption=first.get("message"), ) ), @@ -306,7 +362,7 @@ def _tubeDl(url: str, starttime, uid=None): Config.DOWN_PATH, str(starttime), "%(title)s-%(format)s.%(ext)s" ), "logger": LOGGER, - "format": "{}+bestaudio/best".format(uid or "bestvideo"), + "format": f"{uid or 'bestvideo[ext=mp4]'}+bestaudio[ext=m4a]/best[ext=mp4]", "writethumbnail": True, "prefer_ffmpeg": True, "postprocessors": [ @@ -339,7 +395,7 @@ def _mp3Dl(url: str, starttime, uid): { "key": "FFmpegExtractAudio", "preferredcodec": "mp3", - "preferredquality": str(uid), + "preferredquality": uid or "320", }, {"key": "EmbedThumbnail"}, # ERROR: Conversion failed! {"key": "FFmpegMetadata"}, @@ -356,39 +412,12 @@ def _mp3Dl(url: str, starttime, uid): return dloader -# initial version: http://stackoverflow.com/a/7936523/617185 \ -# by Mikhail Kashkin (http://stackoverflow.com/users/85739/mikhail-kashkin) -# -# Returns Video_ID extracting from the given url of Youtube -# Examples of URLs: -# Valid: -# 'http://youtu.be/_lOT2p_FCvA', -# 'www.youtube.com/watch?v=_lOT2p_FCvA&feature=feedu', -# 'http://www.youtube.com/embed/_lOT2p_FCvA', -# 'http://www.youtube.com/v/_lOT2p_FCvA?version=3&hl=en_US', -# 'https://www.youtube.com/watch?v=rTHlyTphWP0&index=6&list=PLjeDyYvG6-40qawYNR4juzvSOg-ezZ2a6', -# 'youtube.com/watch?v=_lOT2p_FCvA', -# -# Invalid: -# 'youtu.be/watch?v=_lOT2p_FCvA' - - def get_yt_video_id(url: str): - if url.startswith(("youtu", "www")): - url = "http://" + url - yt_link = None - try: - query = urlparse(url) - if "youtube" in query.hostname: - if query.path == "/watch": - yt_link = parse_qs(query.query)["v"][0] - if query.path.startswith(("/embed/", "/v/")): - yt_link = query.path.split("/")[2] - elif "youtu.be" in query.hostname: - yt_link = query.path[1:] - except TypeError: - pass - return yt_link + # https://regex101.com/r/boXuXb/1 + match = search(YOUTUBE_REGEX, url) + if match: + return match.group(1) + return async def result_formatter(results: list): @@ -409,12 +438,14 @@ async def result_formatter(results: list): if upld: out += "āÆ Uploader: " out += f'{upld.get("name")}' + v_deo_id = r.get("id") output[index] = dict( message=out, thumb=thumb, - video_id=r.get("id"), - list_view=f'{index}. {r.get("accessibility").get("title")}

', + video_id=v_deo_id, + list_view=f'{index}. {r.get("accessibility").get("title")}
', ) + return output @@ -450,93 +481,61 @@ def yt_search_btns( @pool.run_in_thread def download_button(vid: str, body: bool = False): - x = youtube_dl.YoutubeDL({"no-playlist": True}).extract_info( + vid_data = youtube_dl.YoutubeDL({"no-playlist": True}).extract_info( BASE_YT_URL + vid, download=False ) - ### - ( - format_144, - format_240, - format_360, - format_720, - format_1080, - format_1440, - format_2160, - ) = [0 for _ in range(7)] - btn = [ + buttons = [ [ InlineKeyboardButton( - "ā­ļø BEST (Video + Audio)", callback_data=f"ytdl_download_{vid}_best_v" - ) + "ā­ļø BEST VIDEO", callback_data=f"ytdl_download_{vid}_best_v" + ), + InlineKeyboardButton( + "ā­ļø BEST AUDIO", callback_data=f"ytdl_download_{vid}_best_a" + ), ] ] - audio, format_data = {}, {} - ### - for video in x["formats"]: - if video.get("ext") == "mp4": - f_note = video.get("format_note") - fr_id = int(video.get("format_id")) - if f_note in ("2160p", "2160p60") and fr_id > format_2160: - format_2160 = fr_id - if f_note in ("1440p", "1440p60") and fr_id > format_1440: - format_1440 = fr_id - if f_note in ("1080p", "1080p60") and fr_id > format_1080: - format_1080 = fr_id - if f_note in ("720p", "720p60") and fr_id > format_720: - format_720 = fr_id - if f_note in ("360p", "360p60") and fr_id > format_360: - format_360 = fr_id - if f_note in ("240p", "240p60") and fr_id > format_240: - format_240 = fr_id - if f_note in ("144p", "144p60") and fr_id > format_144: - format_144 = fr_id - format_data[ - fr_id - ] = f'šŸ“¹ {f_note} ({humanbytes(video.get("filesize")) or "N/A"})' - + # ------------------------------------------------ # + qual_dict = defaultdict(lambda: defaultdict(int)) + qual_list = ["144p", "360p", "720p", "1080p", "1440p"] + audio_dict = {} + # ------------------------------------------------ # + for video in vid_data["formats"]: + fr_note = video.get("format_note") + fr_id = int(video.get("format_id")) + fr_size = video.get("filesize") + for frmt_ in qual_list: + if fr_note in (frmt_, frmt_ + "60"): + qual_dict[frmt_][fr_id] = fr_size if video.get("acodec") != "none": - bitrrate = video.get("abr") - if bitrrate is not None: - audio[ - int(bitrrate) - ] = f'šŸŽµ {bitrrate}Kbps ({humanbytes(video.get("filesize")) or "N/A"})' - - btn += sublists( - [ - InlineKeyboardButton( - format_data.get(qual_), callback_data=f"ytdl_download_{vid}_{qual_}_v" + bitrrate = int(video.get("abr", 0)) + if bitrrate != 0: + audio_dict[ + bitrrate + ] = f"šŸŽµ {bitrrate}Kbps ({humanbytes(fr_size) or 'N/A'})" + + video_btns = [] + for frmt in qual_list: + frmt_dict = qual_dict[frmt] + if len(frmt_dict) != 0: + frmt_id = sorted(list(frmt_dict))[-1] + frmt_size = humanbytes(frmt_dict.get(frmt_id)) or "N/A" + video_btns.append( + InlineKeyboardButton( + f"šŸ“¹ {frmt} ({frmt_size})", + callback_data=f"ytdl_download_{vid}_{frmt_id}_v", + ) ) - for qual_ in [ - format_144, - format_240, - format_360, - format_720, - format_1080, - format_1440, - format_2160, - ] - if qual_ != 0 - ], - width=2, - ) - btn += sublists( + buttons += sublists(video_btns, width=2) + buttons += sublists( [ InlineKeyboardButton( - audio.get(key_), callback_data=f"ytdl_download_{vid}_{key_}_a" + audio_dict.get(key_), callback_data=f"ytdl_download_{vid}_{key_}_a" ) - for key_ in sorted(audio.keys()) + for key_ in sorted(audio_dict.keys()) ], width=2, ) if body: - vid_body = f"[{x.get('title')}]({x.get('webpage_url')})" - - # ERROR Media Caption Too Long - # {x.get("description")} - # āÆ Duration: {x.get('duration')} - # āÆ Views: {x.get('view_count')} - # āÆ Upload date: {x.get('upload_date')} - # āÆ Uploader: [{x.get('uploader')}]({x.get('uploader_url')}) - - return vid_body, InlineKeyboardMarkup(btn) - return InlineKeyboardMarkup(btn) + vid_body = f"[{vid_data.get('title')}]({vid_data.get('webpage_url')})" + return vid_body, InlineKeyboardMarkup(buttons) + return InlineKeyboardMarkup(buttons) diff --git a/userge/plugins/fun/kang.py b/userge/plugins/fun/kang.py index 3c602318d..372b1ecac 100644 --- a/userge/plugins/fun/kang.py +++ b/userge/plugins/fun/kang.py @@ -12,9 +12,9 @@ import os import random -import emoji from bs4 import BeautifulSoup as bs from PIL import Image +from pyrogram import emoji from pyrogram.errors import StickersetInvalid, YouBlockedUser from pyrogram.raw.functions.messages import GetStickerSet from pyrogram.raw.types import InputStickerSetShortName @@ -84,7 +84,9 @@ async def kang_(message: Message): else: emoji_ = args[0] - if emoji_ and emoji_ not in emoji.UNICODE_EMOJI: + if emoji_ and emoji_ not in ( + getattr(emoji, _) for _ in dir(emoji) if not _.startswith("_") + ): emoji_ = None if not emoji_: emoji_ = "šŸ¤”" diff --git a/userge/plugins/fun/nsfw.py b/userge/plugins/fun/nsfw.py index ab83bee10..f52b423e0 100644 --- a/userge/plugins/fun/nsfw.py +++ b/userge/plugins/fun/nsfw.py @@ -1,8 +1,14 @@ from pyrogram import filters -from pyrogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup +from pyrogram.errors import MessageNotModified +from pyrogram.types import ( + CallbackQuery, + InlineKeyboardButton, + InlineKeyboardMarkup, + InputMediaPhoto, +) from userge import Config, userge -from userge.utils import get_file_id, xbot, xmedia +from userge.utils import get_file_id async def age_verification(msg): @@ -30,7 +36,6 @@ async def age_verification_true(_, c_q: CallbackQuery): await c_q.answer("Yes I'm 18+", show_alert=False) msg = await userge.bot.get_messages("useless_x", 19) f_id = get_file_id(msg) - buttons = [ [ InlineKeyboardButton( @@ -39,30 +44,16 @@ async def age_verification_true(_, c_q: CallbackQuery): ) ] ] - await xbot.edit_inline_media( - c_q.inline_message_id, - media=( - await xmedia.InputMediaPhoto( - file_id=f_id, + try: + await c_q.edit_message_media( + media=InputMediaPhoto( + media=f_id, caption="Set ALLOW_NSFW = True in Heroku Vars to access this plugin", - ) - ), - reply_markup=InlineKeyboardMarkup(buttons), - ) - # """ - # try: - - # await c_q.edit_message_media( - # media=InputMediaPhoto( - # media=f_id, - # caption="Set ALLOW_NSFW = True in Heroku Vars to access this plugin", - # ), - # reply_markup=InlineKeyboardMarkup(buttons), - # ) - - # except MessageNotModified: - # pass - # """ + ), + reply_markup=InlineKeyboardMarkup(buttons), + ) + except MessageNotModified: + pass @userge.bot.on_callback_query(filters.regex(pattern=r"^age_verification_false")) async def age_verification_false(_, c_q: CallbackQuery): @@ -76,7 +67,6 @@ async def age_verification_false(_, c_q: CallbackQuery): msg = await userge.bot.get_messages("useless_x", 20) f_id = get_file_id(msg) img_text = "GO AWAY KID !" - buttons = [ [ InlineKeyboardButton( @@ -85,21 +75,13 @@ async def age_verification_false(_, c_q: CallbackQuery): ) ] ] - await xbot.edit_inline_media( - c_q.inline_message_id, - media=(await xmedia.InputMediaPhoto(file_id=f_id, caption=img_text)), - reply_markup=InlineKeyboardMarkup(buttons), - ) - - # """ - # try: - # await c_q.edit_message_media( - # media=InputMediaPhoto(media=f_id, caption=img_text), - # reply_markup=InlineKeyboardMarkup(buttons), - # ) - # except MessageNotModified: - # return - # """ + try: + await c_q.edit_message_media( + media=InputMediaPhoto(media=f_id, caption=img_text), + reply_markup=InlineKeyboardMarkup(buttons), + ) + except MessageNotModified: + return @userge.bot.on_callback_query(filters.regex(pattern=r"^chg_of_decision_")) async def chg_of_decision_(_, c_q: CallbackQuery): @@ -113,7 +95,6 @@ async def chg_of_decision_(_, c_q: CallbackQuery): msg = await userge.bot.get_messages("useless_x", 21) f_id = get_file_id(msg) img_text = "ARE YOU OLD ENOUGH FOR THIS ?" - buttons = [ [ InlineKeyboardButton( @@ -124,17 +105,10 @@ async def chg_of_decision_(_, c_q: CallbackQuery): ), ] ] - await xbot.edit_inline_media( - c_q.inline_message_id, - media=(await xmedia.InputMediaPhoto(file_id=f_id, caption=img_text)), - reply_markup=InlineKeyboardMarkup(buttons), - ) - # """ - # try: - # await c_q.edit_message_media( - # media=InputMediaPhoto(media=f_id, caption=img_text), - # reply_markup=InlineKeyboardMarkup(buttons), - # ) - # except MessageNotModified: - # pass - # """ + try: + await c_q.edit_message_media( + media=InputMediaPhoto(media=f_id, caption=img_text), + reply_markup=InlineKeyboardMarkup(buttons), + ) + except MessageNotModified: + pass diff --git a/userge/plugins/fun/quote.py b/userge/plugins/fun/quote.py index 6a30d4c2b..05f6d9628 100644 --- a/userge/plugins/fun/quote.py +++ b/userge/plugins/fun/quote.py @@ -46,7 +46,10 @@ async def quotecmd(message: Message): await message.edit(message.input_str) else: args = message.input_str - quote_list.append(message.message_id) if self_mid else await message.delete() + if self_mid: + quote_list.append(message.message_id) + else: + await message.delete() if not args and len(quote_list) == 0: await message.err("Reply to a message or provide an input to quote !", del_in=5) return diff --git a/userge/plugins/help.py b/userge/plugins/help.py index 046fbd29b..31443b079 100644 --- a/userge/plugins/help.py +++ b/userge/plugins/help.py @@ -24,9 +24,10 @@ from youtubesearchpython import VideosSearch from userge import Config, Message, get_collection, userge +from userge.core.ext import RawClient from userge.utils import get_file_id, get_response from userge.utils import parse_buttons as pb -from userge.utils import rand_key, xbot +from userge.utils import rand_key from .bot.alive import Bot_Alive from .bot.gogo import Anime @@ -198,13 +199,9 @@ async def callback_next_prev(callback_query: CallbackQuery): ) elif len(pos_list) == 3: _, buttons = plugin_data(cur_pos, p_num) - await xbot.edit_inline_reply_markup( - callback_query.inline_message_id, - reply_markup=InlineKeyboardMarkup(buttons), + await callback_query.edit_message_reply_markup( + reply_markup=InlineKeyboardMarkup(buttons) ) - # await callback_query.edit_message_reply_markup( - # reply_markup=InlineKeyboardMarkup(buttons) - # ) @userge.bot.on_callback_query(filters.regex(pattern=r"back\((.+)\)")) @check_owner @@ -221,17 +218,10 @@ async def callback_back(callback_query: CallbackQuery): text, buttons = category_data(cur_pos) elif len(pos_list) == 4: text, buttons = plugin_data(cur_pos) - - await xbot.edit_inline_text( - callback_query.inline_message_id, - text=text, - reply_markup=InlineKeyboardMarkup(buttons), + await callback_query.edit_message_text( + text, reply_markup=InlineKeyboardMarkup(buttons) ) - # await callback_query.edit_message_text( - # text, reply_markup=InlineKeyboardMarkup(buttons) - # ) - @userge.bot.on_callback_query(filters.regex(pattern=r"enter\((.+)\)")) @check_owner async def callback_enter(callback_query: CallbackQuery): @@ -243,17 +233,10 @@ async def callback_enter(callback_query: CallbackQuery): text, buttons = plugin_data(cur_pos) elif len(pos_list) == 4: text, buttons = filter_data(cur_pos) - - await xbot.edit_inline_text( - callback_query.inline_message_id, - text=text, - reply_markup=InlineKeyboardMarkup(buttons), + await callback_query.edit_message_text( + text, reply_markup=InlineKeyboardMarkup(buttons) ) - # await callback_query.edit_message_text( - # text, reply_markup=InlineKeyboardMarkup(buttons) - # ) - @userge.bot.on_callback_query( filters.regex(pattern=r"((?:un)?load|(?:en|dis)able)\((.+)\)") ) @@ -273,52 +256,38 @@ async def callback_manage(callback_query: CallbackQuery): plg = userge.manager.plugins[pos_list[-1]] await getattr(plg, task)() text, buttons = plugin_data(cur_pos) - await xbot.edit_inline_text( - callback_query.inline_message_id, - text=text, - reply_markup=InlineKeyboardMarkup(buttons), + await callback_query.edit_message_text( + text, reply_markup=InlineKeyboardMarkup(buttons) ) - # await callback_query.edit_message_text( - # text, reply_markup=InlineKeyboardMarkup(buttons) - # ) @userge.bot.on_callback_query(filters.regex(pattern=r"^mm$")) @check_owner async def callback_mm(callback_query: CallbackQuery): - - await xbot.edit_inline_text( - callback_query.inline_message_id, - text=" š”š’š„š‘š†š„-š— š— š—”š—œš—” š— š—˜š—”š—Ø ", + await callback_query.edit_message_text( + " š”š’š„š‘š†š„-š— š— š—”š—œš—” š— š—˜š—”š—Ø ", reply_markup=InlineKeyboardMarkup(main_menu_buttons()), ) - # await callback_query.edit_message_text( - # " š”š’š„š‘š†š„-š— š— š—”š—œš—” š— š—˜š—”š—Ø ", - # reply_markup=InlineKeyboardMarkup(main_menu_buttons()), - # ) - @userge.bot.on_callback_query(filters.regex(pattern=r"^chgclnt$")) @check_owner async def callback_chgclnt(callback_query: CallbackQuery): + if not RawClient.DUAL_MODE: + return await callback_query.answer( + "you using [BOT MODE], can't change client.", show_alert=True + ) if Config.USE_USER_FOR_CLIENT_CHECKS: Config.USE_USER_FOR_CLIENT_CHECKS = False - else: + elif RawClient.DUAL_MODE: Config.USE_USER_FOR_CLIENT_CHECKS = True await SAVED_SETTINGS.update_one( {"_id": "CURRENT_CLIENT"}, {"$set": {"is_user": Config.USE_USER_FOR_CLIENT_CHECKS}}, upsert=True, ) - - await xbot.edit_inline_reply_markup( - callback_query.inline_message_id, - reply_markup=InlineKeyboardMarkup(main_menu_buttons()), + await callback_query.edit_message_reply_markup( + reply_markup=InlineKeyboardMarkup(main_menu_buttons()) ) - # await callback_query.edit_message_reply_markup( - # reply_markup=InlineKeyboardMarkup(main_menu_buttons()) - # ) - @userge.bot.on_callback_query(filters.regex(pattern=r"refresh\((.+)\)")) @check_owner async def callback_exit(callback_query: CallbackQuery): @@ -328,21 +297,9 @@ async def callback_exit(callback_query: CallbackQuery): text, buttons = filter_data(cur_pos) else: text, buttons = plugin_data(cur_pos) - - response = await xbot.edit_inline_text( - callback_query.inline_message_id, - text=text, - reply_markup=InlineKeyboardMarkup(buttons), + await callback_query.edit_message_text( + text, reply_markup=InlineKeyboardMarkup(buttons) ) - errors = response.get("description", None) - if errors: - if "not modified:" in errors: - raise MessageNotModified - if "MESSAGE_ID_INVALID" in errors: - raise MessageIdInvalid - # await callback_query.edit_message_text( - # text, reply_markup=InlineKeyboardMarkup(buttons) - # ) def is_filter(name: str) -> bool: split_ = name.split(".") @@ -399,10 +356,7 @@ def default_buttons(cur_pos: str): ) ) if len(cur_pos.split("|")) > 2: - tmp_btns.append( - InlineKeyboardButton("šŸ–„ Main Menu", callback_data="mm") - # .encode() - ) + tmp_btns.append(InlineKeyboardButton("šŸ–„ Main Menu", callback_data="mm")) tmp_btns.append( InlineKeyboardButton( "šŸ”„ Refresh", callback_data=f"refresh({cur_pos})".encode() @@ -413,8 +367,7 @@ def default_buttons(cur_pos: str): tmp_btns.append( InlineKeyboardButton( f"šŸ”© Client for Checks and Sudos : {cur_clnt}", - callback_data="chgclnt" - # .encode() + callback_data="chgclnt", ) ) return [tmp_btns] diff --git a/userge/plugins/misc/upload.py b/userge/plugins/misc/upload.py index f323d27de..0189afcdf 100644 --- a/userge/plugins/misc/upload.py +++ b/userge/plugins/misc/upload.py @@ -1,6 +1,5 @@ """ upload , rename and convert telegram files """ - import io import os import re @@ -12,18 +11,18 @@ from hachoir.metadata import extractMetadata from hachoir.parser import createParser from PIL import Image -from pyrogram.errors.exceptions import FloodWait +from pyrogram.errors import FloodWait +from pyrogram.types import CallbackQuery from userge import Config, Message, userge from userge.plugins.misc.download import tg_download, url_download from userge.utils import humanbytes, progress, take_screen_shot -from userge.utils.botapi import inline_progress from userge.utils.exceptions import ProcessCanceled LOGGER = userge.getLogger(__name__) CHANNEL = userge.getCLogger(__name__) -LOGO_PATH = "resources/userge.png" +LOGO_PATH = "resources/logo_x.png" @userge.on_cmd( @@ -159,12 +158,12 @@ def explorer(_path: Path) -> None: async def upload( message: Message, path: Path, + callback: CallbackQuery = None, del_path: bool = False, extra: str = "", with_thumb: bool = True, - logvid: bool = True, - custom_thumb: str = None, - inline_id: str = None, + custom_thumb: str = "", + log: bool = True, ): if "wt" in message.flags: with_thumb = False @@ -172,13 +171,13 @@ async def upload( "d" not in message.flags ): return await vid_upload( - message, path, del_path, extra, with_thumb, logvid, custom_thumb, inline_id + message, path, callback, del_path, extra, with_thumb, custom_thumb, log ) elif path.name.lower().endswith((".mp3", ".flac", ".wav", ".m4a")) and ( "d" not in message.flags ): return await audio_upload( - message, path, del_path, extra, with_thumb, logvid, inline_id + message, path, callback, del_path, extra, with_thumb, log ) elif path.name.lower().endswith((".jpg", ".jpeg", ".png", ".bmp")) and ( "d" not in message.flags @@ -230,15 +229,23 @@ async def doc_upload( async def vid_upload( message: Message, path, + callback: CallbackQuery = None, del_path: bool = False, extra: str = "", with_thumb: bool = True, - logvid: bool = True, - custom_thumb: str = None, - inline_id: str = None, + custom_thumb: str = "", + log: bool = True, ): str_path = str(path) - thumb = (custom_thumb or await get_thumb(str_path)) if with_thumb else None + thumb = None + if with_thumb: + if custom_thumb: + try: + thumb = await check_thumb(custom_thumb) + except Exception as e_r: + await CHANNEL.log(str(e_r)) + if not thumb: + thumb = await get_thumb(str_path) duration = 0 metadata = extractMetadata(createParser(str_path)) if metadata and metadata.has("duration"): @@ -257,16 +264,6 @@ async def vid_upload( if t_m and t_m.has("height"): height = t_m.get("height") try: - if logvid: - progress_args = (message, f"uploading {extra}", str_path) - else: - progress_args = ( - message, - inline_id, - f"uploading {extra}", - str_path, - "caption", - ) msg = await message.client.send_video( chat_id=message.chat.id, video=str_path, @@ -277,8 +274,8 @@ async def vid_upload( caption=path.name, parse_mode="html", disable_notification=True, - progress=progress if logvid else inline_progress, - progress_args=progress_args, + progress=progress, + progress_args=(message, f"uploading {extra}", str_path, callback), ) except ValueError as e_e: await sent.edit(f"Skipping `{str_path}` due to {e_e}") @@ -288,21 +285,30 @@ async def vid_upload( else: await sent.delete() await remove_thumb(thumb) - if logvid: + if log: await finalize(message, msg, start_t) if os.path.exists(str_path) and del_path: os.remove(str_path) - return msg + return msg + + +async def check_thumb(thumb_path: str): + f_path = os.path.splitext(thumb_path) + if f_path[1] != ".jpg": + new_thumb_path = f"{f_path[0]}.jpg" + Image.open(thumb_path).convert("RGB").save(new_thumb_path, "JPEG") + os.remove(thumb_path) + return thumb_path async def audio_upload( message: Message, path, + callback: CallbackQuery = None, del_path: bool = False, extra: str = "", with_thumb: bool = True, - logvid: bool = True, - inline_id: str = None, + log: bool = True, ): title = None artist = None @@ -336,16 +342,6 @@ async def audio_upload( start_t = datetime.now() await message.client.send_chat_action(message.chat.id, "upload_audio") try: - if logvid: - progress_args = (message, f"uploading {extra}", str_path) - else: - progress_args = ( - message, - inline_id, - f"uploading {extra}", - str_path, - "caption", - ) msg = await message.client.send_audio( chat_id=message.chat.id, audio=str_path, @@ -356,8 +352,8 @@ async def audio_upload( duration=duration, parse_mode="html", disable_notification=True, - progress=progress if logvid else inline_progress, - progress_args=progress_args, + progress=progress, + progress_args=(message, f"uploading {extra}", str_path, callback), ) except ValueError as e_e: await sent.edit(f"Skipping `{str_path}` due to {e_e}") @@ -366,13 +362,12 @@ async def audio_upload( raise u_e else: await sent.delete() - if logvid: + if log: await finalize(message, msg, start_t) if os.path.exists(str_path) and del_path: os.remove(str_path) - finally: - if os.path.lexists("album_cover.jpg"): - os.remove("album_cover.jpg") + if os.path.lexists("album_cover.jpg"): + os.remove("album_cover.jpg") return msg diff --git a/userge/plugins/tools/json.py b/userge/plugins/tools/json.py index 13732b4ce..5b95c04da 100644 --- a/userge/plugins/tools/json.py +++ b/userge/plugins/tools/json.py @@ -69,7 +69,7 @@ def dump(self, data, stream=None, **kw): return stream.getvalue() -def yamlify(input): +def yamlify(input_): yaml = MyYAML() yaml.indent(mapping=2, sequence=4, offset=2) - return f"
{yaml.dump(input)}
" + return f"
{yaml.dump(input_)}
" diff --git a/userge/plugins/utils/currency.py b/userge/plugins/utils/currency.py index 5c8390386..869891853 100644 --- a/userge/plugins/utils/currency.py +++ b/userge/plugins/utils/currency.py @@ -9,9 +9,9 @@ import json import aiohttp -from emoji import get_emoji_regexp from userge import Config, Message, userge +from userge.utils.functions import get_emoji_regex CHANNEL = userge.getCLogger(__name__) LOG = userge.getLogger(__name__) @@ -40,7 +40,7 @@ async def cur_conv(message: Message): ) return - filterinput = get_emoji_regexp().sub("", message.input_str) + filterinput = get_emoji_regex().sub("", message.input_str) curcon = filterinput.upper().split() if len(curcon) == 3: diff --git a/userge/plugins/utils/translate.py b/userge/plugins/utils/translate.py index 70d889d06..adb8ff881 100644 --- a/userge/plugins/utils/translate.py +++ b/userge/plugins/utils/translate.py @@ -9,10 +9,10 @@ import time from json import dumps -from emoji import get_emoji_regexp from googletrans import LANGUAGES, Translator from userge import Config, Message, pool, userge +from userge.utils.functions import get_emoji_regex @userge.on_cmd( @@ -51,7 +51,7 @@ async def translateme(message: Message): src, dest = "auto", list(flags)[0] else: src, dest = "auto", Config.LANG - text = get_emoji_regexp().sub("", text) + text = get_emoji_regex().sub("", text) await message.edit("`Translating ...`") try: reply_text = await _translate_this(text, dest, src) diff --git a/userge/utils/__init__.py b/userge/utils/__init__.py index 463127e79..c72e9e86e 100644 --- a/userge/utils/__init__.py +++ b/userge/utils/__init__.py @@ -1,6 +1,4 @@ from .aiohttp_helper import get_response -from .botapi import XMediaTypes as xmedia -from .botapi import xbot from .functions import ( check_owner, cleanhtml, @@ -13,8 +11,8 @@ rand_key, thumb_from_audio, ) -from .progress import progress # noqa -from .sys_tools import SafeDict, get_import_path, secure_text, terminate # noqa +from .progress import progress +from .sys_tools import SafeDict, get_import_path, secure_text, terminate from .tools import ( get_file_id, humanbytes, diff --git a/userge/utils/aiohttp_helper.py b/userge/utils/aiohttp_helper.py index 326e4221c..09f826bcb 100644 --- a/userge/utils/aiohttp_helper.py +++ b/userge/utils/aiohttp_helper.py @@ -1,40 +1,42 @@ -from aiohttp import ClientTimeout - -from .botapi.rawbotapi import xbot +from aiohttp import ClientSession, ClientTimeout class get_response: @staticmethod # Can be used without initialising async def json(link: str, params: dict = None): - async with xbot.session.get( - link, params=params, timeout=ClientTimeout(total=30) - ) as resp: - if resp.status != 200: - raise ValueError - # Raises an AssertionError if status != 200 - return await resp.json() + async with ClientSession() as session: + async with session.get( + link, params=params, timeout=ClientTimeout(total=30) + ) as resp: + if resp.status != 200: + raise ValueError + # Raises an AssertionError if status != 200 + return await resp.json() @staticmethod async def text(link: str, params: dict = None): - async with xbot.session.get( - link, params=params, timeout=ClientTimeout(total=30) - ) as resp: - if resp.status != 200: - raise ValueError - return await resp.text() + async with ClientSession() as session: + async with session.get( + link, params=params, timeout=ClientTimeout(total=30) + ) as resp: + if resp.status != 200: + raise ValueError + return await resp.text() @staticmethod async def read(link: str, params: dict = None): - async with xbot.session.get( - link, params=params, timeout=ClientTimeout(total=30) - ) as resp: - if resp.status != 200: - raise ValueError - return await resp.read() + async with ClientSession() as session: + async with session.get( + link, params=params, timeout=ClientTimeout(total=30) + ) as resp: + if resp.status != 200: + raise ValueError + return await resp.read() # Just returns the Header @staticmethod async def status(link: str, wait: int = 5): - async with xbot.session.get(link, timeout=ClientTimeout(total=wait)) as resp: - return resp.status + async with ClientSession() as session: + async with session.get(link, timeout=ClientTimeout(total=wait)) as resp: + return resp.status diff --git a/userge/utils/botapi/XParser.py b/userge/utils/botapi/XParser.py deleted file mode 100644 index 85e7c220d..000000000 --- a/userge/utils/botapi/XParser.py +++ /dev/null @@ -1,90 +0,0 @@ -from enum import Enum, auto - -from bs4 import BeautifulSoup as soup -from pyrogram import raw, types -from pyrogram.parser.parser import Parser -from pyrogram.raw.functions.users import GetUsers -from pyrogram.types.messages_and_media.message_entity import MessageEntity - -from userge.core.ext.raw_client import RawClient as userge - - -class AutoName(Enum): - def _generate_next_value_(self, *args): - return self.lower() - - -class MessageEntityType(AutoName): - MENTION = auto() - HASHTAG = auto() - CASHTAG = auto() - BOT_COMMAND = auto() - URL = auto() - EMAIL = auto() - PHONE_NUMBER = auto() - BOLD = auto() - ITALIC = auto() - UNDERLINE = auto() - STRIKETHROUGH = auto() - CODE = auto() - PRE = auto() - TEXT_LINK = auto() - TEXT_MENTION = auto() - BLOCKQUOTE = auto() - - -RAW_ENTITIES_TO_TYPE = { - raw.types.MessageEntityMention: MessageEntityType.MENTION, - raw.types.MessageEntityHashtag: MessageEntityType.HASHTAG, - raw.types.MessageEntityCashtag: MessageEntityType.CASHTAG, - raw.types.MessageEntityBotCommand: MessageEntityType.BOT_COMMAND, - raw.types.MessageEntityUrl: MessageEntityType.URL, - raw.types.MessageEntityEmail: MessageEntityType.EMAIL, - raw.types.MessageEntityBold: MessageEntityType.BOLD, - raw.types.MessageEntityItalic: MessageEntityType.ITALIC, - raw.types.MessageEntityCode: MessageEntityType.CODE, - raw.types.MessageEntityPre: MessageEntityType.PRE, - raw.types.MessageEntityUnderline: MessageEntityType.UNDERLINE, - raw.types.MessageEntityStrike: MessageEntityType.STRIKETHROUGH, - raw.types.MessageEntityBlockquote: MessageEntityType.BLOCKQUOTE, - raw.types.MessageEntityTextUrl: MessageEntityType.TEXT_LINK, - raw.types.MessageEntityMentionName: MessageEntityType.TEXT_MENTION, - raw.types.MessageEntityPhone: MessageEntityType.PHONE_NUMBER, - raw.types.InputMessageEntityMentionName: MessageEntityType.TEXT_MENTION, # <- HACKS -} - - -async def e_gen(entity, client): - entity_type = RAW_ENTITIES_TO_TYPE.get(entity.__class__) - if entity_type is None: - return None - - # language=getattr(entity, "language", None), - return MessageEntity( - type=entity_type.value, - offset=entity.offset, - length=entity.length, - url=getattr(entity, "url", None), - user=(await get_user(entity)), - client=client, - ) - - -async def get_user(entity): - user_id = getattr(getattr(entity, "user_id", None), "user_id", None) - if not user_id: - return - k = await userge.send(GetUsers(id=[await userge.resolve_peer(user_id)])) - return types.User._parse(userge, k[0]) - - -async def mixed_to_html(text: str): - pyro_entity = types.List() - x = Parser(userge) - y = await x.parse(text, mode="combined") - for i in y["entities"]: - ent = await e_gen(i, userge) - if ent: - pyro_entity.append(ent) - out = x.unparse(y["message"], pyro_entity, is_html=True) - return str(soup(out, "html.parser")) diff --git a/userge/utils/botapi/__init__.py b/userge/utils/botapi/__init__.py deleted file mode 100644 index 7af1a6d7d..000000000 --- a/userge/utils/botapi/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .iprogress import inline_progress -from .rawbotapi import XMediaTypes, xbot diff --git a/userge/utils/botapi/iprogress.py b/userge/utils/botapi/iprogress.py deleted file mode 100644 index 6b547e321..000000000 --- a/userge/utils/botapi/iprogress.py +++ /dev/null @@ -1,87 +0,0 @@ -import time -from math import floor -from typing import Dict, Tuple - -import userge -from userge.utils.tools import humanbytes, time_formatter - -from .rawbotapi import xbot - -_TASKS: Dict[str, Tuple[int, int]] = {} - - -async def inline_progress( - current: int, - total: int, - message: "userge.Message", - inline_id: str, - ud_type: str, - file_name: str = "", - edit_type: str = "text", - delay: int = userge.Config.EDIT_SLEEP_TIMEOUT, -) -> None: - """ progress function """ - if message.process_is_canceled: - await message.client.stop_transmission() - task_id = f"{message.chat.id}.{message.message_id}" - if current == total: - if task_id not in _TASKS: - return - del _TASKS[task_id] - if edit_type == "text": - - await xbot.edit_inline_text( - inline_id, text="Uploading to telegram..." - ) - - else: - - await xbot.edit_inline_caption( - inline_id, caption="Uploading to telegram ..." - ) - - now = time.time() - if task_id not in _TASKS: - _TASKS[task_id] = (now, now) - start, last = _TASKS[task_id] - elapsed_time = now - start - if (now - last) >= delay: - _TASKS[task_id] = (start, now) - percentage = current * 100 / total - speed = current / elapsed_time - time_to_completion = time_formatter(int((total - current) / speed)) - progress_str = ( - "__{}__ : `{}`\n" - + "```[{}{}]```\n" - + "**Progress** : `{}%`\n" - + "**Completed** : `{}`\n" - + "**Total** : `{}`\n" - + "**Speed** : `{}/s`\n" - + "**ETA** : `{}`" - ) - progress_str = progress_str.format( - ud_type, - file_name, - "".join( - ( - userge.Config.FINISHED_PROGRESS_STR - for i in range(floor(percentage / 5)) - ) - ), - "".join( - ( - userge.Config.UNFINISHED_PROGRESS_STR - for i in range(20 - floor(percentage / 5)) - ) - ), - round(percentage, 2), - humanbytes(current), - humanbytes(total), - humanbytes(speed), - time_to_completion or "0 s", - ) - - if edit_type == "text": - await xbot.edit_inline_text(inline_id, text=progress_str) - else: - await xbot.edit_inline_caption(inline_id, caption=progress_str) diff --git a/userge/utils/botapi/rawbotapi.py b/userge/utils/botapi/rawbotapi.py deleted file mode 100644 index b28ee0744..000000000 --- a/userge/utils/botapi/rawbotapi.py +++ /dev/null @@ -1,279 +0,0 @@ -import asyncio -from typing import Optional - -import aiohttp -import ujson -from pyrogram.types import InlineKeyboardMarkup - -from userge.config import Config - -from .XParser import mixed_to_html - - -class XBot: - def __init__(self): - token = getattr(Config, "BOT_TOKEN", None) - if not token: - return - self.api = "https://api.telegram.org/bot" + token - self._session: Optional[aiohttp.ClientSession] = None - - @staticmethod - def get_new_session() -> aiohttp.ClientSession: - return aiohttp.ClientSession( - json_serialize=ujson.dumps, timeout=aiohttp.ClientTimeout(total=300) - ) - - @property - def session(self) -> Optional[aiohttp.ClientSession]: - if self._session is None or self._session.closed: - self._session = self.get_new_session() - return self._session - - async def post_(self, method: str, params: dict): - session = self.session - link = f"{self.api}/{method}" - - timeout = aiohttp.ClientTimeout(total=30) - - try: - async with session.get(link, params=params, timeout=timeout) as resp: - data = await resp.json() - except aiohttp.ClientError as ex: - await session.close() - print(ex) - return - except asyncio.TimeoutError: - return - return data - - async def edit_inline_text( - self, - inline_message_id: str, - text: str, - reply_markup: InlineKeyboardMarkup = None, - parse_mode: str = "mixed", - disable_web_page_preview: bool = False, - ): - params = { - "inline_message_id": inline_message_id, - "text": await mixed_to_html(text) - if parse_mode.lower() == "mixed" - else text, - } - if reply_markup: # :: Optional :: - params["reply_markup"] = XBot.InlineKeyboard(reply_markup) - if disable_web_page_preview: - params["disable_web_page_preview"] = "True" - if parse_mode.lower() in ("md", "markdown"): - params["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - params["parse_mode"] = "HTML" - return await self.post_("editMessageText", params) - - async def edit_inline_caption( - self, - inline_message_id: str, - caption: str, - reply_markup: InlineKeyboardMarkup = None, - parse_mode: str = "mixed", - ): - params = { - "inline_message_id": inline_message_id, - "caption": await mixed_to_html(caption) - if parse_mode.lower() == "mixed" - else caption, - } - if reply_markup: # :: Optional :: - params["reply_markup"] = XBot.InlineKeyboard(reply_markup) - if parse_mode.lower() in ("md", "markdown"): - params["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - params["parse_mode"] = "HTML" - return await self.post_("editMessageCaption", params) - - async def edit_inline_media( - self, - inline_message_id: str, - media: str, - reply_markup: InlineKeyboardMarkup = None, - ): - params = {"inline_message_id": inline_message_id, "media": media} - if reply_markup: # :: Optional :: - params["reply_markup"] = XBot.InlineKeyboard(reply_markup) - return await self.post_("editMessageMedia", params) - - async def edit_inline_reply_markup( - self, - inline_message_id: str, - reply_markup: InlineKeyboardMarkup = None, - ): - params = { - "inline_message_id": inline_message_id, - } - if reply_markup: # :: Optional :: - params["reply_markup"] = XBot.InlineKeyboard(reply_markup) - return await self.post_("editMessageReplyMarkup", params) - - @staticmethod - def InlineKeyboard(mkrp): - if isinstance(mkrp, InlineKeyboardMarkup): - btn = str(mkrp) - elif isinstance(mkrp, list): - btn = str(InlineKeyboardMarkup(mkrp)) - else: - return None - buttons = ujson.loads(btn)["inline_keyboard"] - return ujson.dumps({"inline_keyboard": XBot.clean_markup(buttons)}) - - @staticmethod - def clean_markup(btn_array: list): - a = [] - b = [] - for rows in btn_array: - for cell in rows: - b.append({key: val for key, val in cell.items() if key != "_"}) - a.append(b) - b = [] - return a - - -class XMediaTypes: - @staticmethod - async def InputMediaPhoto( - file_id: str, caption: str = None, parse_mode: str = "mixed" - ): - media = {"type": "photo", "media": file_id} - if caption: - if parse_mode.lower() == "mixed": - caption = await mixed_to_html(caption) - media["caption"] = caption - if parse_mode.lower() in ("md", "markdown"): - media["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - media["parse_mode"] = "HTML" - return ujson.dumps(media) - - @staticmethod - async def InputMediaAnimation( - file_id: str, - thumb: str = None, - caption: str = None, - parse_mode: str = "mixed", - width: int = None, - height: int = None, - duration: int = None, - ): - media = {"type": "animation", "media": file_id} - if caption: - if parse_mode.lower() == "mixed": - caption = await mixed_to_html(caption) - media["caption"] = caption - if thumb: - media["thumb"] = thumb - if width: - media["width"] = width - if height: - media["height"] = height - if duration: - media["duration"] = duration - if parse_mode.lower() in ("md", "markdown"): - media["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - media["parse_mode"] = "HTML" - return ujson.dumps(media) - - @staticmethod - async def InputMediaDocument( - file_id: str, - thumb: str = None, - caption: str = None, - parse_mode: str = "mixed", - disable_content_type_detection: bool = "None", - ): - media = {"type": "document", "media": file_id} - if caption: - if parse_mode.lower() == "mixed": - caption = await mixed_to_html(caption) - media["caption"] = caption - if thumb: - media["thumb"] = thumb - if isinstance(disable_content_type_detection, bool): - media["disable_content_type_detection"] = disable_content_type_detection - if parse_mode.lower() in ("md", "markdown"): - media["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - media["parse_mode"] = "HTML" - return ujson.dumps(media) - - @staticmethod - async def InputMediaAudio( - file_id: str, - thumb: str = None, - caption: str = None, - parse_mode: str = "mixed", - performer: str = None, - title: str = None, - duration: int = None, - ): - media = {"type": "audio", "media": file_id} - if caption: - if parse_mode.lower() == "mixed": - caption = await mixed_to_html(caption) - media["caption"] = caption - if thumb: - media["thumb"] = thumb - if performer: - media["performer"] = performer - if duration: - media["duration"] = duration - if title: - media["title"] = title - if parse_mode.lower() in ("md", "markdown"): - media["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - media["parse_mode"] = "HTML" - - return ujson.dumps(media) - - @staticmethod - async def InputMediaVideo( - file_id: str, - thumb: str = None, - caption: str = None, - parse_mode: str = "mixed", - width: int = None, - height: int = None, - duration: int = None, - supports_streaming: bool = True, - ): - media = { - "type": "video", - "media": file_id, - "supports_streaming": True, - } - if not supports_streaming: - media["supports_streaming"] = False - if caption: - if parse_mode.lower() == "mixed": - caption = await mixed_to_html(caption) - media["caption"] = caption - if thumb: - media["thumb"] = thumb - if width: - media["width"] = width - if height: - media["height"] = height - if duration: - media["duration"] = duration - - if parse_mode.lower() in ("md", "markdown"): - media["parse_mode"] = "Markdown" - elif parse_mode.lower() in ("html", "mixed"): - media["parse_mode"] = "HTML" - - return ujson.dumps(media) - - -# bot api class -xbot = XBot() diff --git a/userge/utils/progress.py b/userge/utils/progress.py index 7f4980904..8f5de41ee 100644 --- a/userge/utils/progress.py +++ b/userge/utils/progress.py @@ -1,18 +1,10 @@ -# pylint: disable=missing-module-docstring -# -# 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 asyncio import time from math import floor from typing import Dict, Tuple -from pyrogram.errors.exceptions import FloodWait +from pyrogram.errors import FloodWait +from pyrogram.types import CallbackQuery import userge @@ -27,6 +19,7 @@ async def progress( message: "userge.Message", ud_type: str, file_name: str = "", + c_q: CallbackQuery = None, delay: int = userge.Config.EDIT_SLEEP_TIMEOUT, ) -> None: """ progress function """ @@ -38,9 +31,12 @@ async def progress( return del _TASKS[task_id] try: - await message.try_to_edit("`finalizing process ...`") + if c_q: + await c_q.edit_message_text("`finalizing process ...`") + else: + await message.try_to_edit("`finalizing process ...`") except FloodWait as f_e: - time.sleep(f_e.x) + await asyncio.sleep(f_e.x) return now = time.time() if task_id not in _TASKS: @@ -80,10 +76,12 @@ async def progress( humanbytes(current), humanbytes(total), humanbytes(speed), - time_to_completion or "0 s", + time_to_completion if time_to_completion else "0 s", ) - try: - await message.try_to_edit(progress_str) + if c_q: + await c_q.edit_message_text(progress_str) + else: + await message.try_to_edit(progress_str) except FloodWait as f_e: - time.sleep(f_e.x) + await asyncio.sleep(f_e.x)