diff --git a/resources/config.conf b/.apt/usr/bin/config/config.conf similarity index 100% rename from resources/config.conf rename to .apt/usr/bin/config/config.conf diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile new file mode 100644 index 000000000..d33f73466 --- /dev/null +++ b/.gitpod.Dockerfile @@ -0,0 +1,15 @@ + +FROM gitpod/workspace-full + +RUN sudo apt-get update \ + && sudo apt-get install -y --no-install-recommends \ + tree \ + wget2 \ + pv \ + p7zip-full \ + mediainfo \ + neofetch \ + ffmpeg \ + && sudo rm -rf /var/lib/apt/lists/* + +RUN curl https://cli-assets.heroku.com/install.sh | sh diff --git a/.gitpod.yml b/.gitpod.yml index 905e366d0..1591de877 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,5 +1,5 @@ -#image: - #file: .gitpod.Dockerfile +image: + file: .gitpod.Dockerfile tasks: # Install dependencies first. @@ -9,6 +9,5 @@ tasks: if [[ -f config.env ]]; then bash run else - echo "Please copy the config.env.sample file and edit it to continue." + echo "Please edit the config.env.sample and rename it to 'config.env'. Then to run do-> bash run" fi - diff --git a/Dockerfile b/Dockerfile index b09a2d607..130ead4b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,8 @@ RUN apt -qq install -y --no-install-recommends \ wget \ ffmpeg \ jq \ - mediainfo + mediainfo \ + neofetch # install chrome RUN mkdir -p /tmp/ && \ diff --git a/README.md b/README.md index e3e169073..72e04605f 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,10 @@

Owner: ๐š‚๐šข๐š—๐š๐šŠ๐šก โ–‘ ฮฃrrโ™ขr

- -
- -

- Userge-x -
-
+ Userge-x +
+

-

USERGE-X

Pluggable Telegram UserBot
@@ -30,68 +25,55 @@ [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/code-rgb/userge-x)
- **USERGE-X** is a Powerful , _Pluggable_ Telegram UserBot written in _Python_ using [Pyrogram](https://github.com/pyrogram/pyrogram). +**USERGE-X** is a Powerful , _Pluggable_ Telegram UserBot written in _Python_ using [Pyrogram](https://github.com/pyrogram/pyrogram).
- -[![Telegram](https://img.shields.io/badge/Support%20Group-USERGE--X-blue?&logo=telegram&style=social)](https://telegram.dog/x_xtests) +

+

## Disclaimer - - - ``` - +``` /** - โš ๏ธKang at your own riskโš ๏ธ - Your Telegram account may get banned. - I am not responsible for any improper use of this bot - This bot is intended for the purpose of having fun with memes, - as well as efficiently managing groups. - It can help you with managing yourself as well. - You ended up spamming groups, getting reported left and right, - and then you ended up in a Final Battle with Telegram - and at the end the Telegram Team - deleted your account? - And after that, you pointed your fingers at us - for getting your account deleted? - We will be rolling on the floor laughing at you. - Yes! you heard it right. + โš ๏ธKang at your own riskโš ๏ธ + Your Telegram account may get banned. + I am not responsible for any improper use of this bot + This bot is intended for the purpose of having fun with memes, + as well as efficiently managing groups. + It can help you with managing yourself as well. + You ended up spamming groups, getting reported left and right, + and then you ended up in a Final Battle with Telegram + and at the end the Telegram Team + deleted your account? + And after that, you pointed your fingers at us + for getting your account deleted? + We will be rolling on the floor laughing at you. + Yes! you heard it right. /** ``` - - ## Requirements - * Python 3.8 or Higher * Telegram [API Keys](https://my.telegram.org/apps) * Google Drive [API Keys](https://console.developers.google.com/) * MongoDB [Database URL](https://cloud.mongodb.com/) - - ## How To Deploy * With Heroku: -

-Press to Takeoff

+ Press to Takeoff +


- > **NOTE** : your can fill other vars as your need and they are optional. (settings -> reveal config vars) - * First click The Button Above. - * Fill `API_ID`, `API_HASH`, `DATABASE_URL` and `LOG_CHANNEL_ID` and `HEROKU_APP_NAME` (**required**) - * Then fill Dual Mode vars : `OWNER_ID`, `BOT_TOKEN` and `HU_STRING_SESSION` - * Then fill [other **non-required** vars](https://telegra.ph/Heroku-Vars-for-USERGE-X-08-25) later - * Finally **hit deploy** button - - +> **NOTE** : your can fill other vars as your need and they are optional. (settings -> reveal config vars) +* First click The Button Above. +* Fill `API_ID`, `API_HASH`, `DATABASE_URL`, `LOG_CHANNEL_ID`, `HEROKU_APP_NAME` and `HEROKU_API_KEY` (**required**) +* Then fill Dual Mode vars : `OWNER_ID`, `BOT_TOKEN` and `HU_STRING_SESSION` +* Then fill [other **non-required** vars](https://telegra.ph/Heroku-Vars-for-USERGE-X-08-25) later +* Finally **hit deploy** button ## String Session -**VAR :** `HU_STRING_SESSION` - -### HEROKU -- [open your app](https://dashboard.heroku.com/apps/) then go to **more** -> **run console** and paste the command below and click **run**. - > command: `bash genStr` -### REPL -- [**Generate on REPL**](https://stringsessiongen.leorio.repl.run/) - -## Read more +**VAR ->** `HU_STRING_SESSION` +#### By HEROKU +- [open your app](https://dashboard.heroku.com/apps/) then go to **more** -> **run console** and type `bash genStr` and click **run**. +#### On REPL +- [Generate on REPL](https://repl.it/@Leorio/stringsessiongen#main.py) +### Read more
Details and Guides @@ -119,11 +101,11 @@ # get string session and add it to config.env bash genStr - # finally run the Userge ;) + # finally run the USERGE-X ;) bash run ``` - +

Guide to Upstream Forked Repo

Upstream Forked Repo
@@ -182,15 +164,10 @@ async def test_filter(message: Message):
- ### Project Credits - * [Pyrogram Assistant](https://github.com/pyrogram/assistant) * [PyroGramBot](https://github.com/SpEcHiDe/PyroGramBot) * [PaperPlane](https://github.com/RaphielGang/Telegram-Paperplane) * [Uniborg](https://github.com/SpEcHiDe/UniBorg) - - ### Copyright & License - -[**GNU General Public License v3.0**](https://github.com/code-rgb/USERGE-X/blob/alpha/LICENSE) +[**GNU General Public License v3.0**](https://github.com/code-rgb/USERGE-X/blob/alpha/LICENSE) \ No newline at end of file diff --git a/config.env.sample b/config.env.sample index 210a9db61..aafb9b272 100644 --- a/config.env.sample +++ b/config.env.sample @@ -21,8 +21,9 @@ LOG_CHANNEL_ID="" # USERGE-X MODE -# USERGE-X Utilizes Both [ USER and BOT ] MODE so its a [ DUAL MODE ] userbot -# see below for more info +# Fills Vars for the mode you [ USER ], [ BOT ] +# or [ DUAL MODE ] ( USER + BOT ) +# See USERGE-X MODES For More Info # ----------- OPTIONAL ----------- # @@ -133,11 +134,8 @@ DEEP_AI="" ALIVE_MEDIA="" -# your instagram username +# your instagram username and password INSTA_ID="" - - -# your instagram password INSTA_PASS="" @@ -148,6 +146,11 @@ IMGFLIP_ID="" IMGFLIP_PASS="" +# LastFM username and api key +LASTFM_USERNAME = "" +LASTFM_API_KEY = "" + + # ----------- Only If Using Heroku ----------- # @@ -159,14 +162,15 @@ HEROKU_API_KEY="" HEROKU_APP_NAME="" -# ----------- USERGE-X DUAL MODE ----------- # -# Both BOT and USER Sessions are Required - +# ----------- USERGE-X MODES ----------- # +# Both BOT and USER Sessions are Required for DUAL MODE +# USER MODE # get this using [ 'https://GenUserGeString.usergeuserbot.repl.run' or `bash genStr` ] HU_STRING_SESSION="" +# BOT MODE # get this from https://t.me/botfather Your USERGE-X Bot BOT_TOKEN="" OWNER_ID="" # your user_id \ No newline at end of file diff --git a/tools/genStrSession.py b/tools/genStrSession.py index 9a0c1063c..61fc4f2e7 100644 --- a/tools/genStrSession.py +++ b/tools/genStrSession.py @@ -26,7 +26,7 @@ async def genStrSession() -> None: # pylint: disable=missing-function-docstring ) as userge: print("\nprocessing...") await userge.send_message( - "me", f"#USERGE #HU_STRING_SESSION\n\n```{await userge.export_session_string()}```") + "me", f"#USERGE-X #HU_STRING_SESSION\n\n```{await userge.export_session_string()}```") print("Done !, session string has been sent to saved messages!") if __name__ == "__main__": diff --git a/userge/config.py b/userge/config.py index 5e1805f48..66828e451 100644 --- a/userge/config.py +++ b/userge/config.py @@ -32,7 +32,7 @@ class Config: WORKERS = min(32, int(os.environ.get("WORKERS")) or os.cpu_count() + 4) BOT_TOKEN = os.environ.get("BOT_TOKEN", None) HU_STRING_SESSION = os.environ.get("HU_STRING_SESSION", None) - OWNER_ID = int(os.environ.get("OWNER_ID", 0)) + OWNER_ID = tuple(filter(lambda x: x, map(int, os.environ.get("OWNER_ID", "0").split()))) LOG_CHANNEL_ID = int(os.environ.get("LOG_CHANNEL_ID")) DB_URI = os.environ.get("DATABASE_URL") LANG = os.environ.get("PREFERRED_LANGUAGE") diff --git a/userge/core/client.py b/userge/core/client.py index ab6832823..668c10c76 100644 --- a/userge/core/client.py +++ b/userge/core/client.py @@ -192,12 +192,13 @@ async def _shutdown(sig: signal.Signals) -> None: running_tasks.append(self.loop.create_task(task())) logbot.edit_last_msg("USERGE-X has Started Successfully !") logbot.end() + mode = "[DUAL]" if RawClient.DUAL_MODE else "[BOT]" if Config.BOT_TOKEN else "[USER]" try: if coro: - _LOG.info(_LOG_STR, "Running Coroutine") + _LOG.info(_LOG_STR, f"Running Coroutine - {mode}") self.loop.run_until_complete(coro) else: - _LOG.info(_LOG_STR, "Idling USERGE-X") + _LOG.info(_LOG_STR, f"Idling USERGE-X - {mode}") idle() self.loop.run_until_complete(_finalize()) except (asyncio.exceptions.CancelledError, RuntimeError): diff --git a/userge/core/ext/pool.py b/userge/core/ext/pool.py index bbb10a8f4..1abfb2757 100644 --- a/userge/core/ext/pool.py +++ b/userge/core/ext/pool.py @@ -65,6 +65,9 @@ async def _stop(): for _ in range(_WORKERS): _ASYNC_QUEUE.put_nowait(None) for task in _TASKS: - await task + try: + await asyncio.wait_for(task, timeout=0.3) + except asyncio.TimeoutError: + task.cancel() _TASKS.clear() _LOG.info(_LOG_STR, f"Stopped Pool : {_WORKERS} Workers") diff --git a/userge/core/types/new/conversation.py b/userge/core/types/new/conversation.py index 0c77345fd..0378b076d 100644 --- a/userge/core/types/new/conversation.py +++ b/userge/core/types/new/conversation.py @@ -92,17 +92,22 @@ async def mark_read(self, message: Optional[RawMessage] = None) -> bool: return bool( await self._client.send_read_acknowledge(chat_id=self._chat_id, message=message)) - async def send_message(self, text: str) -> RawMessage: + async def send_message(self, + text: str, + parse_mode: Union[str, object] = object) -> RawMessage: """\nSend text messages to the conversation. Parameters: text (``str``): Text of the message to be sent. + parse_mode (``str | object``): + parser to be used to parse text entities. Returns: :obj:`Message`: On success, the sent text message is returned. """ - return await self._client.send_message(chat_id=self._chat_id, text=text) + return await self._client.send_message(chat_id=self._chat_id, + text=text, parse_mode=parse_mode) async def send_document(self, document: str) -> Optional[RawMessage]: """\nSend documents to the conversation. @@ -184,4 +189,4 @@ async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: error = f"ended conversation with {self._chat_id}, message limit reached!" if error: _LOG.error(_LOG_STR, error) - raise StopConversation(error) + raise StopConversation(error) \ No newline at end of file diff --git a/userge/core/types/raw/command.py b/userge/core/types/raw/command.py index dd0e981c0..a7f73c2a6 100644 --- a/userge/core/types/raw/command.py +++ b/userge/core/types/raw/command.py @@ -64,7 +64,7 @@ def parse(cls, command: str, # pylint: disable=arguments-differ and not m.outgoing and trigger and m.from_user and m.text - and ((m.from_user.id == Config.OWNER_ID) + and ((m.from_user.id in Config.OWNER_ID) or (Config.SUDO_ENABLED and (m.from_user.id in Config.SUDO_USERS) and (cname.lstrip(trigger) in Config.ALLOWED_COMMANDS))) and m.text.startswith(Config.SUDO_TRIGGER)) diff --git a/userge/plugins/admin/gadmin.py b/userge/plugins/admin/gadmin.py index a6f91d2f5..e0a6ab5d7 100644 --- a/userge/plugins/admin/gadmin.py +++ b/userge/plugins/admin/gadmin.py @@ -1,12 +1,5 @@ """ manage your group """ -# 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 os @@ -70,14 +63,15 @@ async def promote_usr(message: Message): can_invite_users=True, can_pin_messages=True, ) - await asyncio.sleep(2) - await message.client.set_administrator_title(chat_id, user_id, custom_rank) + if custom_rank: + await asyncio.sleep(2) + await message.client.set_administrator_title(chat_id, user_id, custom_rank) await message.edit("`๐Ÿ‘‘ Promoted Successfully..`", del_in=5) await CHANNEL.log( "#PROMOTE\n\n" f"USER: [{get_mem.user.first_name}](tg://user?id={get_mem.user.id}) " f"(`{get_mem.user.id}`)\n" - f"CUSTOM TITLE: `{custom_rank}`\n" + f"CUSTOM TITLE: `{custom_rank or None}`\n" f"CHAT: `{message.chat.title}` (`{chat_id}`)" ) except UsernameInvalid: @@ -457,16 +451,14 @@ async def zombie_clean(message: Message): ) flags = message.flags rm_delaccs = "-c" in flags - del_stats = ( - r"`Zero zombie accounts found in this chat... WOOHOO group is clean.. \^o^/`" - ) - del_users = 0 + can_clean = check_user.status in ("administrator", "creator") if rm_delaccs: - can_clean = check_user.status in ("administrator", "creator") + del_users = 0 + del_admins = 0 + del_total = 0 + del_stats = r"`Zero zombie accounts found in this chat... WOOHOO group is clean.. \^o^/`" if can_clean: await message.edit("`Hang on!! cleaning zombie accounts from this chat..`") - del_admins = 0 - del_total = 0 async for member in message.client.iter_chat_members(chat_id): if member.user.is_deleted: try: @@ -500,6 +492,8 @@ async def zombie_clean(message: Message): r"`i don't have proper permission to do that! (* ๏ฟฃ๏ธฟ๏ฟฃ)`", del_in=5 ) else: + del_users = 0 + del_stats = r"`Zero zombie accounts found in this chat... WOOHOO group is clean.. \^o^/`" await message.edit("`๐Ÿ”Ž Searching for zombie accounts in this chat..`") async for member in message.client.iter_chat_members(chat_id): if member.user.is_deleted: diff --git a/userge/plugins/admin/privacy.py b/userge/plugins/admin/privacy.py index d63075a14..af1d1ffd7 100644 --- a/userge/plugins/admin/privacy.py +++ b/userge/plugins/admin/privacy.py @@ -30,7 +30,7 @@ async def block_user(message: Message): return user_id = reply.from_user.id if reply else message.input_str bot_id = (await userge.bot.get_me()).id - if user_id in [bot_id, Config.OWNER_ID]: + if user_id == bot_id or user_id in Config.OWNER_ID: await message.edit("Are you serious bruh? :/") await asyncio.sleep(2) await message.edit("Do you want me to block myself? :|", del_in=5) @@ -62,7 +62,7 @@ async def unblock_user(message: Message): await message.err("Reply to a user or give ID to unblock him/her!", del_in=5) return user_id = reply.from_user.id if reply else message.input_str - if user_id == Config.OWNER_ID: + if user_id in Config.OWNER_ID: await message.edit("Are you serious bruh? :/") await asyncio.sleep(2) await message.edit("How am i even supposed to unblock myself? :|", del_in=5) diff --git a/userge/plugins/bot/bot_forwards.py b/userge/plugins/bot/bot_forwards.py index cdd7a4bef..f7c873bc8 100644 --- a/userge/plugins/bot/bot_forwards.py +++ b/userge/plugins/bot/bot_forwards.py @@ -56,7 +56,7 @@ async def bot_fwd_(message: Message): @userge.bot.on_message( allowForwardFilter - & ~filters.user(Config.OWNER_ID) + & ~filters.user(list(Config.OWNER_ID)) & filters.private & filters.incoming & ~filters.command("start") @@ -68,7 +68,7 @@ async def forward_bot(_, message: Message): msg_id = message.message_id try: msg_owner = await userge.bot.forward_messages( - Config.OWNER_ID, message.chat.id, msg_id + Config.OWNER_ID[0], message.chat.id, msg_id ) except MessageIdInvalid: return @@ -77,7 +77,7 @@ async def forward_bot(_, message: Message): @userge.bot.on_message( allowForwardFilter - & filters.user(Config.OWNER_ID) + & filters.user(list(Config.OWNER_ID)) & filters.private & filters.reply & ~filters.regex( @@ -88,34 +88,39 @@ async def forward_reply(_, message: Message): replied = message.reply_to_message to_user = replied.forward_from msg_id = message.message_id + to_copy = False if message.poll else True if not to_user: - if replied.forward_sender_name: - try: - data = json.load(open(PATH)) - user_id = data[0][str(replied.message_id)] - await userge.bot.forward_messages( - user_id, message.chat.id, msg_id, as_copy=True - ) - except BadRequest: - return - except: - await userge.bot.send_message( - message.chat.id, - "`You can't reply to old messages with if user's" - "forward privacy is enabled`", - del_in=10, - ) - return - else: + if not replied.forward_sender_name: + return + try: + data = json.load(open(PATH)) + user_id = data[0][str(replied.message_id)] + + await userge.bot.forward_messages( + user_id, message.chat.id, msg_id, as_copy=to_copy + ) + except BadRequest: + return + except: + await userge.bot.send_message( + message.chat.id, + "`You can't reply to old messages with if user's" + "forward privacy is enabled`", + del_in=5, + ) return else: - to_id = to_user.id - await userge.bot.forward_messages(to_id, message.chat.id, msg_id) + # Incase message is your own forward + if to_user.id in Config.OWNER_ID: + return + await userge.bot.forward_messages( + to_user.id, message.chat.id, msg_id, as_copy=to_copy + ) # Based - https://github.com/UsergeTeam/Userge/.../gban.py @userge.bot.on_message( - filters.user(Config.OWNER_ID) + filters.user(list(Config.OWNER_ID)) & filters.private & filters.incoming & filters.regex(pattern=r"^\/ban(?: )(.+)") @@ -135,7 +140,7 @@ async def bot_ban_(_, message: Message): get_mem = await userge.bot.get_users(user_id) firstname = get_mem.first_name user_id = get_mem.id - if user_id == Config.OWNER_ID: + if user_id in Config.OWNER_ID: await start_ban.edit(r"I Can't Ban You My Master") return if user_id in Config.SUDO_USERS: @@ -172,7 +177,7 @@ async def bot_ban_(_, message: Message): @userge.bot.on_message( allowForwardFilter - & filters.user(Config.OWNER_ID) + & filters.user(list(Config.OWNER_ID)) & filters.private & filters.command("broadcast") ) @@ -185,6 +190,9 @@ async def broadcast_(_, message: Message): return br_cast = await message.reply_text("`Broadcasting ...`", quote=True) b_msg = replied.message_id + blocked_users = [] + count = 0 + to_copy = False if replied.poll else True async for c in BOT_START.find(): try: b_id = c["user_id"] @@ -192,14 +200,55 @@ async def broadcast_(_, message: Message): b_id, "๐Ÿ”Š You received a **new** Broadcast." ) await userge.bot.forward_messages( - b_id, message.chat.id, b_msg, as_copy=True + b_id, message.chat.id, b_msg, as_copy=to_copy ) except FloodWait as e: await asyncio.sleep(e.x) except BadRequest: - await asyncio.gather(BOT_START.delete_one({"user_id": b_id})) - b_info = "๐Ÿ”Š **Successfully Broadcasted This Message**" + blocked_users.append( + b_id + ) # Collect the user id and removing them later + else: + count += 1 + + b_info = f"๐Ÿ”Š **Successfully Broadcasted This Message to** `{count} users`" + if len(blocked_users) != 0: + b_info += f"\n\n๐Ÿ˜• {len(blocked_users)} users blocked your bot recently" await br_cast.edit(b_info) + if blocked_users: + for buser in blocked_users: + await BOT_START.find_one_and_delete({"user_id": buser}) + + @userge.bot.on_message( + filters.user(list(Config.OWNER_ID)) + & filters.private + & filters.reply + & filters.command("uinfo") + ) + async def uinfo_(_, message: Message): + replied = message.reply_to_message + if not replied: + await userge.bot.send_message( + message.chat.id, "Reply to a message to see user info" + ) + return + fwd = replied.forward_from + info_msg = await message.reply("`๐Ÿ”Ž Searching for user in database ...`") + usr = None + if replied.forward_sender_name: + try: + data = json.load(open(PATH)) + user_id = data[0].get(str(replied.message_id), None) + usr = (await userge.bot.get_users(user_id)).mention + except (BadRequest, FileNotFoundError): + user_id = None + elif fwd: + usr = fwd.mention + user_id = fwd.id + + if not (user_id and usr): + return await message.err("Not Found", del_in=3) + await info_msg.edit(f"User Info\n\n__ID__ `{user_id}`\n๐Ÿ‘ค: {usr}") async def dumper(a, b, update): @@ -212,7 +261,7 @@ async def dumper(a, b, update): json.dump(data, open(PATH, "w")) # Dump -def extract_content(msg): # Modified a bound method +def extract_content(msg: Message): # Modified a bound method id_reason = msg.matches[0].group(1) replied = msg.reply_to_message if replied: @@ -332,10 +381,14 @@ async def bf_help(message: Message): /ban [reply to forwarded message with reason] /ban [user_id/user_name] reason -โ€ข `/broadcast` - Send a Broadcast Message to Users in your `{cmd_}startlist` +โ€ข `/broadcast` - Send a Broadcast Message to Users in your `{cmd_}bot_users` e.g- /broadcast [reply to a message] +โ€ข `/uinfo` - Get user Info + e.g- + /uinfo [reply to forwarded message] + can work outside bot pm โ€ข `{cmd_}bblist` - BotBanList (Users Banned from your Bot's PM) e.g- @@ -346,4 +399,4 @@ async def bf_help(message: Message): {cmd_}unbban [user_id/user_name] Hint: Check bblist for banned users. """ - await userge.send_message(message.chat.id, bot_forwards_help, del_in=60) + await message.edit(bot_forwards_help, del_in=60) diff --git a/userge/plugins/bot/bot_pm.py b/userge/plugins/bot/bot_pm.py index 5b560639a..0e9392298 100644 --- a/userge/plugins/bot/bot_pm.py +++ b/userge/plugins/bot/bot_pm.py @@ -55,7 +55,7 @@ async def start_bot(_, message: Message): hello += "\nNOTE: " hello += "**Bot Forwarding is** : โ˜‘๏ธ `Enabled`\n" hello += "All your messages here will be forwared to my **MASTER**" - if u_id != Config.OWNER_ID: + if u_id not in Config.OWNER_ID: found = await BOT_START.find_one({"user_id": u_id}) if not found: today = date.today() @@ -153,7 +153,7 @@ async def _send_botstart( @userge.bot.on_callback_query(filters.regex(pattern=r"^add_to_grp$")) async def add_to_grp(_, callback_query: CallbackQuery): u_id = callback_query.from_user.id - if u_id == Config.OWNER_ID: + if u_id in Config.OWNER_ID: botname = (await userge.bot.get_me()).username msg = "**๐Ÿค– Add Your Bot to Group** \n\n Note: Admin Privilege Required !" add_bot = f"http://t.me/{botname}?startgroup=start" diff --git a/userge/plugins/bot/gapps.py b/userge/plugins/bot/gapps.py index c8c559ea6..23d8c6b38 100644 --- a/userge/plugins/bot/gapps.py +++ b/userge/plugins/bot/gapps.py @@ -32,7 +32,7 @@ async def gapps_inline(message: Message): @userge.bot.on_callback_query(filters.regex(pattern=r"^open_gapps$")) async def open_cb(_, callback_query: CallbackQuery): u_id = callback_query.from_user.id - if u_id == Config.OWNER_ID or u_id in Config.SUDO_USERS: + if u_id in Config.OWNER_ID or u_id in Config.SUDO_USERS: gapps_link = [] r = requests.get( "https://raw.githubusercontent.com/Pharuxtan/OpenGappsFetcher/master/gapps.json" @@ -84,7 +84,7 @@ async def open_cb(_, callback_query: CallbackQuery): @userge.bot.on_callback_query(filters.regex(pattern=r"^flame_gapps$")) async def flame_cb(_, callback_query: CallbackQuery): u_id = callback_query.from_user.id - if u_id == Config.OWNER_ID or u_id in Config.SUDO_USERS: + if u_id in Config.OWNER_ID or u_id in Config.SUDO_USERS: link = "https://sourceforge.net/projects/flamegapps/files/arm64/android-10/" url = get(link) if url.status_code == 404: @@ -119,7 +119,7 @@ async def flame_cb(_, callback_query: CallbackQuery): @userge.bot.on_callback_query(filters.regex(pattern=r"^nik_gapps$")) async def nik_cb(_, callback_query: CallbackQuery): u_id = callback_query.from_user.id - if u_id == Config.OWNER_ID or u_id in Config.SUDO_USERS: + if u_id in Config.OWNER_ID or u_id in Config.SUDO_USERS: link = ( "https://sourceforge.net/projects/nikgapps/files/Releases/NikGapps-Q/" ) @@ -149,7 +149,7 @@ async def nik_cb(_, callback_query: CallbackQuery): @userge.bot.on_callback_query(filters.regex(pattern=r"^back_gapps$")) async def back_cb(_, callback_query: CallbackQuery): u_id = callback_query.from_user.id - if u_id == Config.OWNER_ID or u_id in Config.SUDO_USERS: + if u_id in Config.OWNER_ID or u_id in Config.SUDO_USERS: buttons = [ [ diff --git a/userge/plugins/bot/opinion.py b/userge/plugins/bot/opinion.py index fca17064d..cc57c0abe 100644 --- a/userge/plugins/bot/opinion.py +++ b/userge/plugins/bot/opinion.py @@ -105,7 +105,7 @@ async def choice_cb(_, c_q: CallbackQuery): async def choice_result_cb(_, c_q: CallbackQuery): u_id = c_q.from_user.id opinion_id = c_q.matches[0].group(1) - if u_id == Config.OWNER_ID: + if u_id in Config.OWNER_ID: data = json.load(open(PATH)) view_data = data[str(opinion_id)] total = len(view_data[0]) diff --git a/userge/plugins/bot/secret.py b/userge/plugins/bot/secret.py index a61f23b49..3d5a4fba0 100644 --- a/userge/plugins/bot/secret.py +++ b/userge/plugins/bot/secret.py @@ -26,7 +26,7 @@ async def alive_callback(_, c_q: CallbackQuery): receiver = data["user_id"] msg += data["msg"] u_id = c_q.from_user.id - if u_id in [Config.OWNER_ID, receiver]: + if u_id in Config.OWNER_ID or u_id == receiver: await c_q.answer(msg, show_alert=True) else: await c_q.answer("This Message is Confidential", show_alert=True) diff --git a/userge/plugins/bot/spoiler.py b/userge/plugins/bot/spoiler.py index 290b1bbf0..714aeb0c1 100644 --- a/userge/plugins/bot/spoiler.py +++ b/userge/plugins/bot/spoiler.py @@ -28,7 +28,7 @@ def __init__(self): self.db = json.load(open(PATH)) def stats_(self, rnd_id: str, user_id: int, user_name: str): - if user_id != Config.OWNER_ID and user_id not in self.db[rnd_id]["stats"]: + if user_id not in Config.OWNER_ID and user_id not in self.db[rnd_id]["stats"]: self.db[rnd_id]["stats"][user_id] = user_name self.save() @@ -92,67 +92,66 @@ async def spoiler_alert_(message: Message): await message.edit(text_, reply_markup=buttons, disable_web_page_preview=True) -@userge.bot.on_message( - filters.private - & ( - filters.regex(pattern=r"^/start spoiler_([\S]+)") - | filters.regex(pattern=r"^/spoiler_([\S]+)") +if userge.has_bot: + + @userge.bot.on_message( + filters.private + & ( + filters.regex(pattern=r"^/start spoiler_([\S]+)") + | filters.regex(pattern=r"^/spoiler_([\S]+)") + ) ) -) -async def spoiler_get(_, message: Message): - u_user = message.from_user - if u_user.id != Config.OWNER_ID and u_user.id not in Config.SUDO_USERS: - found = await BOT_BAN.find_one({"user_id": u_user.id}) - if found: - return - spoiler_key = message.matches[0].group(1) - if os.path.exists(PATH): - view_data = SPOILER_DB.db - mid = view_data.get(spoiler_key, None) - if mid: - try: - await CHANNEL.forward_stored( - client=userge.bot, - message_id=mid["msg_id"], - user_id=u_user.id, - chat_id=message.chat.id, - reply_to_message_id=message.message_id, + async def spoiler_get(_, message: Message): + u_user = message.from_user + if u_user.id not in Config.OWNER_ID and u_user.id not in Config.SUDO_USERS: + found = await BOT_BAN.find_one({"user_id": u_user.id}) + if found: + return + spoiler_key = message.matches[0].group(1) + if os.path.exists(PATH): + view_data = SPOILER_DB.db + mid = view_data.get(spoiler_key, None) + if mid: + try: + await CHANNEL.forward_stored( + client=userge.bot, + message_id=mid["msg_id"], + user_id=u_user.id, + chat_id=message.chat.id, + reply_to_message_id=message.message_id, + ) + except UserIsBlocked: + pass + else: + try: + await message.reply("Sorry ๐Ÿฅบ , The Spoiler has now been expired !") + except UserIsBlocked: + pass + + if u_user.id not in Config.OWNER_ID and u_user.id not in Config.SUDO_USERS: + SPOILER_DB.stats_(spoiler_key, u_user.id, u_user.first_name) + user_list = await BOT_START.find_one({"user_id": u_user.id}) + if not user_list: + today = datetime.date.today() + d2 = today.strftime("%B %d, %Y") + start_date = d2.replace(",", "") + BOT_START.insert_one( + { + "firstname": u_user.first_name, + "user_id": u_user.id, + "date": start_date, + } ) - except UserIsBlocked: - pass - else: - try: - await message.reply("Sorry ๐Ÿฅบ , The Spoiler has now been expired !") - except UserIsBlocked: - pass - - if u_user.id != Config.OWNER_ID and u_user.id not in Config.SUDO_USERS: - SPOILER_DB.stats_(spoiler_key, u_user.id, u_user.first_name) - user_list = await BOT_START.find_one({"user_id": u_user.id}) - if not user_list: - today = datetime.date.today() - d2 = today.strftime("%B %d, %Y") - start_date = d2.replace(",", "") - BOT_START.insert_one( - { - "firstname": u_user.first_name, - "user_id": u_user.id, - "date": start_date, - } - ) - log_msg = ( - f"A New User Started your Bot \n\nโ€ข ID: `{u_user.id}`\n ๐Ÿ‘ค : " - ) - log_msg += f"@{u_user.username}" if u_user.username else u_user.first_name - await CHANNEL.log(log_msg) - - -if userge.has_bot: + log_msg = f"A New User Started your Bot \n\nโ€ข ID: `{u_user.id}`\n ๐Ÿ‘ค : " + log_msg += ( + f"@{u_user.username}" if u_user.username else u_user.first_name + ) + await CHANNEL.log(log_msg) @userge.bot.on_callback_query(filters.regex(pattern=r"^getl([\S]+)$")) async def get_spoiler_link(_, c_q: CallbackQuery): u_id = c_q.from_user.id - if u_id != Config.OWNER_ID and u_id not in Config.SUDO_USERS: + if u_id not in Config.OWNER_ID and u_id not in Config.SUDO_USERS: return await c_q.answer( "Given That It's A Stupid-Ass Decision, I've Elected To Ignore It.", show_alert=True, @@ -179,7 +178,7 @@ async def get_spoiler_link(_, c_q: CallbackQuery): async def nobtnspoiler_(_, c_q: CallbackQuery): u_id = c_q.from_user.id u_name = c_q.from_user.first_name - if u_id != Config.OWNER_ID and u_id not in Config.SUDO_USERS: + if u_id not in Config.OWNER_ID and u_id not in Config.SUDO_USERS: return await c_q.answer( "Given That It's A Stupid-Ass Decision, I've Elected To Ignore It.", show_alert=True, diff --git a/userge/plugins/bot/utube_inline.py b/userge/plugins/bot/utube_inline.py index bc333c872..42a353497 100644 --- a/userge/plugins/bot/utube_inline.py +++ b/userge/plugins/bot/utube_inline.py @@ -7,14 +7,20 @@ import requests import youtube_dl from pyrogram import filters +from pyrogram.errors import MessageIdInvalid +from pyrogram.raw.types import UpdateNewChannelMessage, UpdateNewMessage from pyrogram.types import CallbackQuery, InlineKeyboardButton, InputMediaVideo +from wget import download +from youtube_dl.utils import DownloadError -from userge import Config, pool, userge +from userge import Config, Message, pool, userge from userge.utils import get_file_id_and_ref from ..misc.upload import upload LOGGER = userge.getLogger(__name__) +CHANNEL = userge.getCLogger(__name__) +STORE_DATA = {} def get_ytthumb(videoid): @@ -35,12 +41,12 @@ def get_ytthumb(videoid): return thumb_link -def ytdl_btn_generator(array, code): +def ytdl_btn_generator(array, code, i_q_id): btn = [] b = [] for i in array: name = f"{i.get('format_note', None)} ({i.get('ext', None)})" - call_back = f"ytdl{code}|{i.get('format_id', '')}" + call_back = f"ytdl{code}|{i.get('format_id', '')}|{i_q_id}" b.append(InlineKeyboardButton(name, callback_data=call_back)) if len(b) == 3: # no. of columns btn.append(b) @@ -60,25 +66,82 @@ def date_formatter(date_): return str(x.strftime("%d-%b-%Y")) +@userge.on_cmd( + "iytdl", + about={ + "header": "ytdl with inline buttons", + "usage": "{tr}iytdl [URL] or [Reply to URL]", + }, +) +async def iytdl_inline(message: Message): + reply = message.reply_to_message + input_url = None + if message.input_str or (reply and message.input_str): + input_url = message.input_str + elif reply and not message.input_str: + if reply.text: + 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) + + bot = await userge.bot.get_me() + x = await userge.get_inline_bot_results(bot.username, f"ytdl {input_url}") + y = await userge.send_inline_bot_result( + chat_id=message.chat.id, query_id=x.query_id, result_id=x.results[0].id + ) + for i in y.updates: + if isinstance(i, UpdateNewMessage) or isinstance(i, UpdateNewChannelMessage): + datax = ( + ( + (i["message"].reply_markup.rows[0].buttons[0].data).decode("utf-8") + ).split("|") + )[2] + break + await message.delete() + STORE_DATA[datax] = {"chat_id": message.chat.id, "msg_id": y.updates[0].id} + + if userge.has_bot: - @userge.bot.on_callback_query(filters.regex(pattern=r"^ytdl(\S+)\|(\d+)$")) + @userge.bot.on_callback_query(filters.regex(pattern=r"^ytdl(\S+)\|(\d+)\|(\d+)$")) async def ytdl_callback(_, c_q: CallbackQuery): + await CHANNEL.log(str(c_q)) startTime = time() + inline_mode = True u_id = c_q.from_user.id - if u_id != Config.OWNER_ID and u_id not in Config.SUDO_USERS: + if u_id not in Config.OWNER_ID and u_id not in Config.SUDO_USERS: return await c_q.answer("๐˜ฟ๐™š๐™ฅ๐™ก๐™ค๐™ฎ ๐™ฎ๐™ค๐™ช๐™ง ๐™ค๐™ฌ๐™ฃ ๐™๐™Ž๐™€๐™๐™‚๐™€-๐™“", show_alert=True) choice_id = c_q.matches[0].group(2) + i_q_id = c_q.matches[0].group(3) callback_continue = "Downloading Video Please Wait..." callback_continue += f"\n\nFormat Code : {choice_id}" await c_q.answer(callback_continue, show_alert=True) upload_msg = await userge.send_message(Config.LOG_CHANNEL_ID, "Uploading...") yt_code = c_q.matches[0].group(1) yt_url = f"https://www.youtube.com/watch?v={yt_code}" - await c_q.edit_message_caption( - caption=f"Video is now Downloading, for progress see [LOG CHANNEL]({upload_msg.link})\n\n๐Ÿ”— [Link]({yt_url})\n๐Ÿ†” Format Code : {choice_id}", - reply_markup=None, - ) + try: + await c_q.edit_message_caption( + caption=( + f"Video is now being โฌ‡๏ธ Downloaded, for progress see:\nLog Channel: [click here]({upload_msg.link})" + f"\n\n๐Ÿ”— [Link]({yt_url})\n๐Ÿ†” Format Code : {choice_id}" + ), + reply_markup=None, + ) + except MessageIdInvalid: + inline_mode = False + todelete = STORE_DATA.get(i_q_id, None) + if todelete: + bad_msg = await userge.get_messages( + todelete["chat_id"], todelete["msg_id"] + ) + await bad_msg.delete() + upload_msg = await userge.send_message( + todelete["chat_id"], "Uploading ..." + ) + retcode = await _tubeDl(yt_url, startTime, choice_id) if retcode == 0: _fpath = "" @@ -91,44 +154,53 @@ async def ytdl_callback(_, c_q: CallbackQuery): uploaded_vid = await upload(upload_msg, Path(_fpath)) else: return await upload_msg.edit(str(retcode)) + if not inline_mode: + return refresh_vid = await userge.bot.get_messages( Config.LOG_CHANNEL_ID, uploaded_vid.message_id ) f_id, f_ref = get_file_id_and_ref(refresh_vid) - if hasattr(refresh_vid.video, "thumbs"): - try: - video_thumb = await userge.bot.download_media( - refresh_vid.video.thumbs[0].file_id - ) - except TypeError: - video_thumb = None + video_thumb = None + if refresh_vid.video.thumbs: + video_thumb = await userge.bot.download_media( + refresh_vid.video.thumbs[0].file_id + ) else: - video_thumb = None - await c_q.edit_message_media( - media=InputMediaVideo( - media=f_id, - file_ref=f_ref, - thumb=video_thumb, - caption=f"๐Ÿ“น [{uploaded_vid.caption}]({yt_url})", - supports_streaming=True, - ), - reply_markup=None, - ) + video_thumb = download(get_ytthumb(yt_code)) + + if inline_mode: + await c_q.edit_message_media( + media=InputMediaVideo( + media=f_id, + file_ref=f_ref, + thumb=video_thumb, + caption=f"๐Ÿ“น [{uploaded_vid.caption}]({yt_url})", + supports_streaming=True, + ), + reply_markup=None, + ) await uploaded_vid.delete() @pool.run_in_thread def _tubeDl(url: list, starttime, uid): ydl_opts = { + "addmetadata": True, + "geo_bypass": True, + "nocheckcertificate": True, "outtmpl": os.path.join( Config.DOWN_PATH, str(starttime), "%(title)s-%(format)s.%(ext)s" ), "logger": LOGGER, - "format": f"{uid}+bestaudio", + "format": f"{uid}+bestaudio/best", "writethumbnail": True, "prefer_ffmpeg": True, "postprocessors": [{"key": "FFmpegMetadata"}], } with youtube_dl.YoutubeDL(ydl_opts) as ydl: - x = ydl.download([url]) + try: + x = ydl.download([url]) + except DownloadError as e: + CHANNEL.log(str(e)) + x = None return x diff --git a/userge/plugins/fun/gizoogle.py b/userge/plugins/fun/gizoogle.py index b0ff161d4..7c992428f 100644 --- a/userge/plugins/fun/gizoogle.py +++ b/userge/plugins/fun/gizoogle.py @@ -17,7 +17,7 @@ async def gizoo_(message: Message): """ gizoogle the text """ input_str = message.input_or_reply_str - if not text: + if not input_str: await message.edit("```You didn't gave the text```", del_in=3) return try: diff --git a/userge/plugins/fun/nekos.py b/userge/plugins/fun/nekos.py index 7cc5e1b3b..9d873fec7 100644 --- a/userge/plugins/fun/nekos.py +++ b/userge/plugins/fun/nekos.py @@ -110,17 +110,14 @@ async def neko_life(message: Message): reply_id = reply.message_id if reply else None await message.delete() if link.endswith(".gif"): - if message.client.is_bot: # Bots can't use "unsave=True" - await userge.bot.send_animation( - chat_id=message.chat.id, animation=link, reply_to_message_id=reply_id - ) - else: - await userge.send_animation( - chat_id=message.chat.id, - animation=link, - unsave=True, - reply_to_message_id=reply_id, - ) + # Bots can't use "unsave=True" + bool_unsave = False if message.client.is_bot else True + await message.client.send_animation( + chat_id=message.chat.id, + animation=link, + unsave=bool_unsave, + reply_to_message_id=reply_id, + ) else: await message.client.send_photo( chat_id=message.chat.id, photo=link, reply_to_message_id=reply_id diff --git a/userge/plugins/fun/nsfw.py b/userge/plugins/fun/nsfw.py index e75a6fdda..b7c496450 100644 --- a/userge/plugins/fun/nsfw.py +++ b/userge/plugins/fun/nsfw.py @@ -28,7 +28,7 @@ async def age_verification(msg): @userge.bot.on_callback_query(filters.regex(pattern=r"^age_verification_true")) async def age_verification_true(_, c_q: CallbackQuery): u_id = c_q.from_user.id - if u_id != Config.OWNER_ID and u_id not in Config.SUDO_USERS: + if u_id not in Config.OWNER_ID and u_id not in Config.SUDO_USERS: return await c_q.answer( "Given That It's A Stupid-Ass Decision, I've Elected To Ignore It.", show_alert=True, @@ -59,7 +59,7 @@ async def age_verification_true(_, c_q: CallbackQuery): @userge.bot.on_callback_query(filters.regex(pattern=r"^age_verification_false")) async def age_verification_false(_, c_q: CallbackQuery): u_id = c_q.from_user.id - if u_id != Config.OWNER_ID and u_id not in Config.SUDO_USERS: + if u_id not in Config.OWNER_ID and u_id not in Config.SUDO_USERS: return await c_q.answer( "Given That It's A Stupid-Ass Decision, I've Elected To Ignore It.", show_alert=True, @@ -87,7 +87,7 @@ async def age_verification_false(_, c_q: CallbackQuery): @userge.bot.on_callback_query(filters.regex(pattern=r"^chg_of_decision_")) async def chg_of_decision_(_, c_q: CallbackQuery): u_id = c_q.from_user.id - if u_id != Config.OWNER_ID and u_id not in Config.SUDO_USERS: + if u_id not in Config.OWNER_ID and u_id not in Config.SUDO_USERS: return await c_q.answer( "Given That It's A Stupid-Ass Decision, I've Elected To Ignore It.", show_alert=True, diff --git a/userge/plugins/fun/spotify_autobio.py b/userge/plugins/fun/spotify_autobio.py index 478d70e85..31bd7e56c 100644 --- a/userge/plugins/fun/spotify_autobio.py +++ b/userge/plugins/fun/spotify_autobio.py @@ -78,7 +78,7 @@ async def spotify_bio_(message: Message): del_in=5, ) USER_INITIAL_BIO["bio"] = ( - await userge.get_chat(Config.OWNER_ID) + await userge.get_chat((await userge.get_me()).id) ).description or "" Config.SPOTIFY_MODE = True await spotify_biox() @@ -291,7 +291,7 @@ async def spotify_biox(): # TELEGRAM try: # full needed, since we dont get a bio with the normal request - full = await userge.get_chat(Config.OWNER_ID) + full = await userge.get_chat((await userge.get_me()).id) bio = full.description # to_insert means we have a successful playback if to_insert: diff --git a/userge/plugins/help.py b/userge/plugins/help.py index 4afe12cfd..8a86d5a68 100644 --- a/userge/plugins/help.py +++ b/userge/plugins/help.py @@ -25,6 +25,7 @@ ) from userge import Config, Message, get_collection, get_version, userge, versions +from userge.core.ext import RawClient from userge.utils import get_file_id_and_ref from userge.utils import parse_buttons as pb @@ -82,6 +83,14 @@ ] +def _get_mode() -> str: + if RawClient.DUAL_MODE: + return "โ†•๏ธ **DUAL**" + if Config.BOT_TOKEN: + return "๐Ÿค– **BOT**" + return "๐Ÿ‘ค **USER**" + + async def _init() -> None: data = await SAVED_SETTINGS.find_one({"_id": "CURRENT_CLIENT"}) if data: @@ -99,7 +108,7 @@ async def helpme( out_str = ( f"""โš’ ({len(plugins)}) Plugin(s) Available\n\n""" ) - cat_plugins = userge.manager.get_all_plugins() + cat_plugins = userge.manager.get_plugins() for cat in sorted(cat_plugins): if cat == "plugins": continue @@ -153,7 +162,7 @@ async def helpme( def check_owner(func): async def wrapper(_, c_q: CallbackQuery): - if c_q.from_user and c_q.from_user.id == Config.OWNER_ID: + if c_q.from_user and c_q.from_user.id in Config.OWNER_ID: try: await func(c_q) except MessageNotModified: @@ -164,7 +173,7 @@ async def wrapper(_, c_q: CallbackQuery): show_alert=True, ) else: - user_dict = await userge.bot.get_user_dict(Config.OWNER_ID) + user_dict = await userge.bot.get_user_dict(Config.OWNER_ID[0]) await c_q.answer( f"Only {user_dict['flname']} Can Access this...! Build Your USERGE-X", show_alert=True, @@ -512,7 +521,7 @@ async def inline_answer(_, inline_query: InlineQuery): string_split = string.split() # All lower and Split each word if ( - inline_query.from_user.id == Config.OWNER_ID + inline_query.from_user.id in Config.OWNER_ID or inline_query.from_user.id in Config.SUDO_USERS ): @@ -545,7 +554,7 @@ async def inline_answer(_, inline_query: InlineQuery): vid_title = x.get("title", None) # upload_date = date_formatter(str(x.get('upload_date', None))) vid_thumb = get_ytthumb(ytlink_code) - buttons = ytdl_btn_generator(formats, ytlink_code) + buttons = ytdl_btn_generator(formats, ytlink_code, inline_query.id) caption_text = f"**{vid_title}**" # caption_text += f"๐Ÿ”— [Link]({link}) | ๐Ÿ“… : {upload_date}" # caption_text += f"๐Ÿ“น : [{uploader}]({channel_url})" @@ -696,7 +705,7 @@ async def inline_answer(_, inline_query: InlineQuery): โ€ข ๐Ÿ”ฅ Pyrogram : `v{versions.__pyro_version__}` โ€ข ๐Ÿงฌ ๐‘ฟ : `v{get_version()}` - ๐Ÿ•” Uptime : {userge.uptime} +{_get_mode()} | ๐Ÿ•”: {userge.uptime} """ if not MEDIA_URL and Config.ALIVE_MEDIA: diff --git a/userge/plugins/misc/download.py b/userge/plugins/misc/download.py index bf86a4610..8b8bc7b5a 100644 --- a/userge/plugins/misc/download.py +++ b/userge/plugins/misc/download.py @@ -1,21 +1,18 @@ -# 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. +""" downloader """ + import asyncio import math import os from datetime import datetime +from typing import Tuple, Union from urllib.parse import unquote_plus from pySmartDL import SmartDL from userge import Config, Message, userge from userge.utils import humanbytes, progress +from userge.utils.exceptions import ProcessCanceled LOGGER = userge.getLogger(__name__) @@ -30,89 +27,110 @@ check_downpath=True, ) async def down_load_media(message: Message): - await message.edit("`Trying to Download...`") + """ download from tg and url """ if message.reply_to_message and message.reply_to_message.media: - start_t = datetime.now() - dl_loc = await message.client.download_media( - message=message.reply_to_message, - file_name=Config.DOWN_PATH, - progress=progress, - progress_args=(message, "trying to download"), - ) - if message.process_is_canceled: - await message.edit("`Process Canceled!`", del_in=5) - else: - dl_loc = os.path.join(Config.DOWN_PATH, os.path.basename(dl_loc)) - end_t = datetime.now() - m_s = (end_t - start_t).seconds - await message.edit(f"Downloaded to `{dl_loc}` in {m_s} seconds") + resource = message.reply_to_message elif message.input_str: - start_t = datetime.now() - url = message.input_str - custom_file_name = unquote_plus(os.path.basename(url)) - if "|" in url: - url, custom_file_name = url.split("|") - url = url.strip() - custom_file_name = custom_file_name.strip() - download_file_path = os.path.join(Config.DOWN_PATH, custom_file_name) - try: - downloader = SmartDL(url, download_file_path, progress_bar=False) - downloader.start(blocking=False) - count = 0 - while not downloader.isFinished(): - if message.process_is_canceled: - downloader.stop() - raise Exception("Process Canceled!") - total_length = downloader.filesize or 0 - downloaded = downloader.get_dl_size() - percentage = downloader.get_progress() * 100 - speed = downloader.get_speed(human=True) - estimated_total_time = downloader.get_eta(human=True) - progress_str = ( - "__{}__\n" - + "```[{}{}]```\n" - + "**Progress** : `{}%`\n" - + "**URL** : `{}`\n" - + "**FILENAME** : `{}`\n" - + "**Completed** : `{}`\n" - + "**Total** : `{}`\n" - + "**Speed** : `{}`\n" - + "**ETA** : `{}`" - ) - progress_str = progress_str.format( - "trying to download", - "".join( - ( - Config.FINISHED_PROGRESS_STR - for i in range(math.floor(percentage / 5)) - ) - ), - "".join( - ( - Config.UNFINISHED_PROGRESS_STR - for i in range(20 - math.floor(percentage / 5)) - ) - ), - round(percentage, 2), - url, - custom_file_name, - humanbytes(downloaded), - humanbytes(total_length), - speed, - estimated_total_time, - ) - count += 1 - if count >= Config.EDIT_SLEEP_TIMEOUT: - count = 0 - await message.try_to_edit( - progress_str, disable_web_page_preview=True - ) - await asyncio.sleep(1) - except Exception as e: - await message.err(e) - else: - end_t = datetime.now() - m_s = (end_t - start_t).seconds - await message.edit(f"Downloaded to `{download_file_path}` in {m_s} seconds") + resource = message.input_str else: await message.edit("Please read `.help download`", del_in=5) + return + try: + dl_loc, d_in = await handle_download(message, resource) + except ProcessCanceled: + await message.edit("`Process Canceled!`", del_in=5) + except Exception as e_e: # pylint: disable=broad-except + await message.err(e_e) + else: + await message.edit(f"Downloaded to `{dl_loc}` in {d_in} seconds") + + +async def handle_download( + message: Message, resource: Union[Message, str] +) -> Tuple[str, int]: + """ download from resource """ + if isinstance(resource, Message): + return await tg_download(message, resource) + return await url_download(message, resource) + + +async def url_download(message: Message, url: str) -> Tuple[str, int]: + """ download from link """ + await message.edit("`Downloading From URL...`") + start_t = datetime.now() + custom_file_name = unquote_plus(os.path.basename(url)) + if "|" in url: + url, c_file_name = url.split("|", maxsplit=1) + url = url.strip() + if c_file_name: + custom_file_name = c_file_name.strip() + dl_loc = os.path.join(Config.DOWN_PATH, custom_file_name) + downloader = SmartDL(url, dl_loc, progress_bar=False) + downloader.start(blocking=False) + count = 0 + while not downloader.isFinished(): + if message.process_is_canceled: + downloader.stop() + raise ProcessCanceled + total_length = downloader.filesize if downloader.filesize else 0 + downloaded = downloader.get_dl_size() + percentage = downloader.get_progress() * 100 + speed = downloader.get_speed(human=True) + estimated_total_time = downloader.get_eta(human=True) + progress_str = ( + "__{}__\n" + + "```[{}{}]```\n" + + "**Progress** : `{}%`\n" + + "**URL** : `{}`\n" + + "**FILENAME** : `{}`\n" + + "**Completed** : `{}`\n" + + "**Total** : `{}`\n" + + "**Speed** : `{}`\n" + + "**ETA** : `{}`" + ) + progress_str = progress_str.format( + "trying to download", + "".join( + ( + Config.FINISHED_PROGRESS_STR + for i in range(math.floor(percentage / 5)) + ) + ), + "".join( + ( + Config.UNFINISHED_PROGRESS_STR + for i in range(20 - math.floor(percentage / 5)) + ) + ), + round(percentage, 2), + url, + custom_file_name, + humanbytes(downloaded), + humanbytes(total_length), + speed, + estimated_total_time, + ) + count += 1 + if count >= Config.EDIT_SLEEP_TIMEOUT: + count = 0 + await message.try_to_edit(progress_str, disable_web_page_preview=True) + await asyncio.sleep(1) + return dl_loc, (datetime.now() - start_t).seconds + + +async def tg_download(message: Message, to_download: Message) -> Tuple[str, int]: + """ download from tg file """ + await message.edit("`Downloading From TG...`") + start_t = datetime.now() + dl_loc = await message.client.download_media( + message=to_download, + file_name=Config.DOWN_PATH, + progress=progress, + progress_args=(message, "trying to download"), + ) + if message.process_is_canceled: + raise ProcessCanceled + if not isinstance(dl_loc, str): + raise TypeError("File Corrupted!") + dl_loc = os.path.join(Config.DOWN_PATH, os.path.basename(dl_loc)) + return dl_loc, (datetime.now() - start_t).seconds diff --git a/userge/plugins/misc/gdrive.py b/userge/plugins/misc/gdrive.py index 14d41a755..4f5660cfb 100644 --- a/userge/plugins/misc/gdrive.py +++ b/userge/plugins/misc/gdrive.py @@ -12,7 +12,7 @@ from functools import wraps from json import dumps from mimetypes import guess_type -from urllib.parse import quote, unquote_plus +from urllib.parse import quote from googleapiclient.discovery import build from googleapiclient.errors import HttpError @@ -23,10 +23,10 @@ HttpAccessTokenRefreshError, OAuth2WebServerFlow, ) -from pySmartDL import SmartDL from userge import Config, Message, get_collection, pool, userge -from userge.utils import humanbytes, progress, time_formatter +from userge.plugins.misc.download import tg_download, url_download +from userge.utils import humanbytes, time_formatter from userge.utils.exceptions import ProcessCanceled _CREDS: object = None @@ -914,84 +914,24 @@ async def upload(self) -> None: is_url = re.search( r"(?:https?|ftp)://[^\|\s]+\.[^\|\s]+", self._message.input_str ) - dl_loc = None + dl_loc = "" if replied and replied.media: - await self._message.edit("`Downloading From TG...`") - file_name = Config.DOWN_PATH - if self._message.input_str: - file_name = os.path.join(Config.DOWN_PATH, self._message.input_str) - dl_loc = await self._message.client.download_media( - message=replied, - file_name=file_name, - progress=progress, - progress_args=(self._message, "trying to download"), - ) - if self._message.process_is_canceled: + try: + dl_loc, _ = await tg_download(self._message, replied) + except ProcessCanceled: await self._message.edit("`Process Canceled!`", del_in=5) return - dl_loc = os.path.join(Config.DOWN_PATH, os.path.basename(dl_loc)) + except Exception as e_e: + await self._message.err(e_e) + return elif is_url: - await self._message.edit("`Downloading From URL...`") - url = is_url[0] - file_name = unquote_plus(os.path.basename(url)) - if "|" in self._message.input_str: - file_name = self._message.input_str.split("|")[1].strip() - dl_loc = os.path.join(Config.DOWN_PATH, file_name) try: - downloader = SmartDL(url, dl_loc, progress_bar=False) - downloader.start(blocking=False) - count = 0 - while not downloader.isFinished(): - if self._message.process_is_canceled: - downloader.stop() - raise Exception("Process Canceled!") - total_length = downloader.filesize if downloader.filesize else 0 - downloaded = downloader.get_dl_size() - percentage = downloader.get_progress() * 100 - speed = downloader.get_speed(human=True) - estimated_total_time = downloader.get_eta(human=True) - progress_str = ( - "__{}__\n" - + "```[{}{}]```\n" - + "**Progress** : `{}%`\n" - + "**URL** : `{}`\n" - + "**FILENAME** : `{}`\n" - + "**Completed** : `{}`\n" - + "**Total** : `{}`\n" - + "**Speed** : `{}`\n" - + "**ETA** : `{}`" - ) - progress_str = progress_str.format( - "trying to download", - "".join( - ( - Config.FINISHED_PROGRESS_STR - for i in range(math.floor(percentage / 5)) - ) - ), - "".join( - ( - Config.UNFINISHED_PROGRESS_STR - for i in range(20 - math.floor(percentage / 5)) - ) - ), - round(percentage, 2), - url, - file_name, - humanbytes(downloaded), - humanbytes(total_length), - speed, - estimated_total_time, - ) - count += 1 - if count >= Config.EDIT_SLEEP_TIMEOUT: - count = 0 - await self._message.try_to_edit( - progress_str, disable_web_page_preview=True - ) - await asyncio.sleep(1) - except Exception as d_e: - await self._message.err(d_e) + dl_loc, _ = await url_download(self._message, self._message.input_str) + except ProcessCanceled: + await self._message.edit("`Process Canceled!`", del_in=5) + return + except Exception as e_e: + await self._message.err(e_e) return file_path = dl_loc if dl_loc else self._message.input_str if not os.path.exists(file_path): diff --git a/userge/plugins/misc/upload.py b/userge/plugins/misc/upload.py index c3e351979..f2a97c9ed 100644 --- a/userge/plugins/misc/upload.py +++ b/userge/plugins/misc/upload.py @@ -1,37 +1,28 @@ """ upload , rename and convert telegram files """ -# 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 io -import math import os import re import time from datetime import datetime from pathlib import Path -from urllib.parse import unquote_plus import stagger from hachoir.metadata import extractMetadata from hachoir.parser import createParser from PIL import Image from pyrogram.errors.exceptions import FloodWait -from pySmartDL import SmartDL 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.exceptions import ProcessCanceled LOGGER = userge.getLogger(__name__) CHANNEL = userge.getCLogger(__name__) -LOGO_PATH = "resources/userge.png" +LOGO_PATH = "resources/logo.png" @userge.on_cmd( @@ -52,17 +43,14 @@ async def rename_(message: Message): return await message.edit("`Trying to Rename ...`") if message.reply_to_message and message.reply_to_message.media: - dl_loc = await message.client.download_media( - message=message.reply_to_message, - file_name=Config.DOWN_PATH, - progress=progress, - progress_args=(message, "trying to download"), - ) - if message.process_is_canceled: + try: + dl_loc, _ = await tg_download(message, message.reply_to_message) + except ProcessCanceled: await message.edit("`Process Canceled!`", del_in=5) + except Exception as e_e: # pylint: disable=broad-except + await message.err(e_e) else: await message.delete() - dl_loc = os.path.join(Config.DOWN_PATH, os.path.basename(dl_loc)) new_loc = os.path.join(Config.DOWN_PATH, message.filtered_input_str) os.rename(dl_loc, new_loc) await upload(message, Path(new_loc), True) @@ -83,17 +71,14 @@ async def convert_(message: Message): """ convert telegram files """ await message.edit("`Trying to Convert ...`") if message.reply_to_message and message.reply_to_message.media: - dl_loc = await message.client.download_media( - message=message.reply_to_message, - file_name=Config.DOWN_PATH, - progress=progress, - progress_args=(message, "trying to download"), - ) - if message.process_is_canceled: + try: + dl_loc, _ = await tg_download(message, message.reply_to_message) + except ProcessCanceled: await message.edit("`Process Canceled!`", del_in=5) + except Exception as e_e: # pylint: disable=broad-except + await message.err(e_e) else: await message.delete() - dl_loc = os.path.join(Config.DOWN_PATH, os.path.basename(dl_loc)) message.text = "" if message.reply_to_message.document else ". -d" await upload(message, Path(dl_loc), True) else: @@ -124,67 +109,13 @@ async def uploadtotg(message: Message): del_path = False if is_url: del_path = True - await message.edit("`Downloading From URL...`") - url = is_url[0] - file_name = unquote_plus(os.path.basename(url)) - if "|" in path_: - file_name = path_.split("|")[1].strip() - path_ = os.path.join(Config.DOWN_PATH, file_name) try: - downloader = SmartDL(url, path_, progress_bar=False) - downloader.start(blocking=False) - count = 0 - while not downloader.isFinished(): - if message.process_is_canceled: - downloader.stop() - raise Exception("Process Canceled!") - total_length = downloader.filesize or 0 - downloaded = downloader.get_dl_size() - percentage = downloader.get_progress() * 100 - speed = downloader.get_speed(human=True) - estimated_total_time = downloader.get_eta(human=True) - progress_str = ( - "__{}__\n" - + "```[{}{}]```\n" - + "**Progress** : `{}%`\n" - + "**URL** : `{}`\n" - + "**FILENAME** : `{}`\n" - + "**Completed** : `{}`\n" - + "**Total** : `{}`\n" - + "**Speed** : `{}`\n" - + "**ETA** : `{}`" - ) - progress_str = progress_str.format( - "trying to download", - "".join( - ( - Config.FINISHED_PROGRESS_STR - for i in range(math.floor(percentage / 5)) - ) - ), - "".join( - ( - Config.UNFINISHED_PROGRESS_STR - for i in range(20 - math.floor(percentage / 5)) - ) - ), - round(percentage, 2), - url, - file_name, - humanbytes(downloaded), - humanbytes(total_length), - speed, - estimated_total_time, - ) - count += 1 - if count >= Config.EDIT_SLEEP_TIMEOUT: - count = 0 - await message.try_to_edit( - progress_str, disable_web_page_preview=True - ) - await asyncio.sleep(1) - except Exception as d_e: # pylint: disable=broad-except - await message.err(d_e) + path_, _ = await url_download(message, path_) + except ProcessCanceled: + await message.edit("`Process Canceled!`", del_in=5) + return + except Exception as e_e: # pylint: disable=broad-except + await message.err(e_e) return if "|" in path_: path_, file_name = path_.split("|") diff --git a/userge/plugins/tools/json.py b/userge/plugins/tools/json.py index 3108f47e4..643be267c 100644 --- a/userge/plugins/tools/json.py +++ b/userge/plugins/tools/json.py @@ -62,4 +62,4 @@ def convert(obj): def bool_emoji(choice: bool) -> str: - return "โœ”๏ธ" if choice else "โœ–๏ธ" + return "โœ”" if choice else "โœ–" diff --git a/userge/plugins/tools/neofetch.py b/userge/plugins/tools/neofetch.py index 5ef13ff6f..f4a6cc3aa 100644 --- a/userge/plugins/tools/neofetch.py +++ b/userge/plugins/tools/neofetch.py @@ -2,8 +2,6 @@ # All rights reserved. -import os -import shutil from io import BytesIO from PIL import Image, ImageDraw, ImageFont @@ -25,12 +23,6 @@ ) async def neofetch_(message: Message): await message.edit("Getting System Info ...") - # Checking if using Heroku and config file is not present - if os.path.abspath("") == "/app" and not os.path.exists( - "/app/.apt/usr/bin/config/" - ): - os.makedirs("/app/.apt/usr/bin/config/") - shutil.move("resources/config.conf", "/app/.apt/usr/bin/config/") reply = message.reply_to_message reply_id = reply.message_id if reply else None if "-img" in message.flags: diff --git a/userge/plugins/tools/updater.py b/userge/plugins/tools/updater.py index a7c6ef0d5..c00c88b88 100644 --- a/userge/plugins/tools/updater.py +++ b/userge/plugins/tools/updater.py @@ -46,6 +46,7 @@ async def check_update(message: Message): flags.remove("push") if len(flags) == 1: branch = flags[0] + repo = Repo() if branch not in repo.branches: await message.err(f"invalid branch name : {branch}") @@ -125,9 +126,6 @@ async def _push_to_heroku(msg: Message, repo: Repo, branch: str) -> None: await _heroku_helper(sent, repo, branch) except GitCommandError as g_e: LOG.exception(g_e) - if str(g_e.status).isdigit() and int(g_e.status) == -15: - return - await sent.err(f"{g_e}\n\n{Config.CMD_TRIGGER}restart -h and try again!") else: await sent.edit( f"**HEROKU APP : {Config.HEROKU_APP.name} is up-to-date with [{branch}]**" diff --git a/userge/plugins/utils/direct_links.py b/userge/plugins/utils/direct_links.py index 4b92a13b9..e47a2dd5a 100644 --- a/userge/plugins/utils/direct_links.py +++ b/userge/plugins/utils/direct_links.py @@ -1,11 +1,3 @@ -# 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 json import re import urllib.parse @@ -25,99 +17,70 @@ "header": "Generate a direct download link", "supported links": [ "Google Drive", - "MEGA.nz", "Cloud Mail", "Yandex.Disk", "AFH", - "ZippyShare", "MediaFire", "SourceForge", "OSDN", "GitHub", ], "usage": "{tr}direct [link]", - "others": "MEGA.nz and ZippyShare **DISABLED**", }, ) async def direct_(message: Message): """direct links generator""" - text = message.input_or_reply_str if not text: await message.err("input not found!") return - await message.edit("`Processing...`") - links = re.findall(r"\bhttps?://.*\.\S+", text) if not links: await message.err("No links found!") return - reply = "**Direct Links** :\n\n" for link in links: if "drive.google.com" in link: reply += f" ๐Ÿ‘‰ {gdrive(link)}\n" - - # elif 'zippyshare.com' in link: - # reply += f" ๐Ÿ‘‰ {zippy_share(link)}\n" - - elif "mega." in link: - reply += f" ๐Ÿ‘‰ {mega_dl(link)}\n" - elif "yadi.sk" in link: reply += f" ๐Ÿ‘‰ {yandex_disk(link)}\n" - elif "cloud.mail.ru" in link: reply += f" ๐Ÿ‘‰ {cm_ru(link)}\n" - elif "mediafire.com" in link: reply += f" ๐Ÿ‘‰ {mediafire(link)}\n" - elif "sourceforge.net" in link: reply += f" ๐Ÿ‘‰ {sourceforge(link)}\n" - elif "osdn.net" in link: reply += f" ๐Ÿ‘‰ {osdn(link)}\n" - elif "github.com" in link: reply += f" ๐Ÿ‘‰ {github(link)}\n" - elif "androidfilehost.com" in link: reply += f" ๐Ÿ‘‰ {androidfilehost(link)}\n" - else: reply += f" ๐Ÿ‘€ {link} is not supported!\n" - await message.edit(reply) def gdrive(url: str) -> str: """GDrive direct links generator""" - drive = "https://drive.google.com" try: link = re.findall(r"\bhttps?://drive\.google\.com\S+", url)[0] except IndexError: reply = "`No Google drive links found`\n" return reply - file_id = "" reply = "" - if link.find("view") != -1: file_id = link.split("/")[-2] - elif link.find("open?id=") != -1: file_id = link.split("open?id=")[1].strip() - elif link.find("uc?id=") != -1: file_id = link.split("uc?id=")[1].strip() - url = f"{drive}/uc?export=download&id={file_id}" download = requests.get(url, stream=True, allow_redirects=False) cookies = download.cookies - try: # In case of small file size, Google downloads directly dl_url = download.headers["location"] @@ -125,161 +88,73 @@ def gdrive(url: str) -> str: reply += "`Link is not public!`\n" return reply name = "Direct Download Link" - except KeyError: # In case of download warning page page = BeautifulSoup(download.content, "lxml") export = drive + page.find("a", {"id": "uc-download-link"}).get("href") name = page.find("span", {"class": "uc-name-size"}).text - response = requests.get( export, stream=True, allow_redirects=False, cookies=cookies ) - dl_url = response.headers["location"] if "accounts.google.com" in dl_url: reply += "Link is not public!" return reply - reply += f"[{name}]({dl_url})\n" return reply -def zippy_share(url: str) -> str: - """ZippyShare direct links generator - Based on https://github.com/LameLemon/ziggy""" - - reply = "" - dl_url = "" - - try: - link = re.findall(r"\bhttps?://.*zippyshare\.com\S+", url)[0] - except IndexError: - reply = "`No ZippyShare links found`\n" - return reply - - session = requests.Session() - base_url = re.search("http.+.com", link).group() - response = session.get(link) - page_soup = BeautifulSoup(response.content, "lxml") - scripts = page_soup.find_all("script", {"type": "text/javascript"}) - - for script in scripts: - if "getElementById('dlbutton')" in script.text: - url_raw = re.search( - r"= (?P\".+\" \+ (?P\(.+\)) .+);", script.text - ).group("url") - math = re.search( - r"= (?P\".+\" \+ (?P\(.+\)) .+);", script.text - ).group("math") - dl_url = url_raw.replace( - math, '"' + str(eval(math)) + '"' - ) # pylint: disable=W0123 - break - - dl_url = base_url + eval(dl_url) # pylint: disable=W0123 - name = urllib.parse.unquote(dl_url.split("/")[-1]) - reply += f"[{name}]({dl_url})\n" - - return reply - - def yandex_disk(url: str) -> str: """Yandex.Disk direct links generator Based on https://github.com/wldhx/yadisk-direct""" - reply = "" - try: link = re.findall(r"\bhttps?://.*yadi\.sk\S+", url)[0] except IndexError: reply = "`No Yandex.Disk links found`\n" return reply - api = "https://cloud-api.yandex.net/v1/disk/public/resources/download?public_key={}" - try: dl_url = requests.get(api.format(link)).json()["href"] name = dl_url.split("filename=")[1].split("&disposition")[0] reply += f"[{name}]({dl_url})\n" - except KeyError: reply += "`Error: File not found / Download limit reached`\n" - - return reply - - return reply - - -def mega_dl(url: str) -> str: - """MEGA.nz direct links generator - Using https://github.com/tonikelope/megadown""" - - reply = "" - - try: - link = re.findall(r"\bhttps?://.*mega.*\.nz\S+", url)[0] - except IndexError: - reply = "`No MEGA.nz links found`\n" - return reply - - command = f"bin/megadown -q -m {link}" - result = popen(command).read() # nosec - - try: - data = json.loads(result) - - except json.JSONDecodeError: - reply += "`Error: Can't extract the link`\n" return reply - - dl_url = data["url"] - name = data["file_name"] - size = humanbytes(int(data["file_size"])) - reply += f"[{name} ({size})]({dl_url})\n" - return reply def cm_ru(url: str) -> str: """cloud.mail.ru direct links generator Using https://github.com/JrMasterModelBuilder/cmrudl.py""" - reply = "" - try: link = re.findall(r"\bhttps?://.*cloud\.mail\.ru\S+", url)[0] except IndexError: reply = "`No cloud.mail.ru links found`\n" return reply - command = f"bin/cmrudl -s {link}" result = popen(command).read() # nosec result = result.splitlines()[-1] - try: data = json.loads(result) except json.decoder.JSONDecodeError: reply += "`Error: Can't extract the link`\n" return reply - dl_url = data["download"] name = data["file_name"] size = humanbytes(int(data["file_size"])) reply += f"[{name} ({size})]({dl_url})\n" - return reply def mediafire(url: str) -> str: """MediaFire direct links generator""" - try: link = re.findall(r"\bhttps?://.*mediafire\.com\S+", url)[0] except IndexError: reply = "`No MediaFire links found`\n" return reply - reply = "" page = BeautifulSoup(requests.get(link).content, "lxml") info = page.find("a", {"aria-label": "Download file"}) @@ -287,105 +162,84 @@ def mediafire(url: str) -> str: size = re.findall(r"\(.*\)", info.text)[0] name = page.find("div", {"class": "filename"}).text reply += f"[{name} {size}]({dl_url})\n" - return reply def sourceforge(url: str) -> str: """SourceForge direct links generator""" - try: link = re.findall(r"\bhttps?://.*sourceforge\.net\S+", url)[0] except IndexError: reply = "`No SourceForge links found`\n" return reply - file_path = re.findall(r"files(.*)/download", link)[0] reply = f"Mirrors for __{file_path.split('/')[-1]}__\n" project = re.findall(r"projects?/(.*?)/files", link)[0] - mirrors = ( f"https://sourceforge.net/settings/mirror_choices?" f"projectname={project}&filename={file_path}" ) - page = BeautifulSoup(requests.get(mirrors).content, "html.parser") info = page.find("ul", {"id": "mirrorList"}).findAll("li") - for mirror in info[1:]: name = re.findall(r"\((.*)\)", mirror.text.strip())[0] dl_url = ( f'https://{mirror["id"]}.dl.sourceforge.net/project/{project}/{file_path}' ) reply += f"[{name}]({dl_url}) " - return reply def osdn(url: str) -> str: """OSDN direct links generator""" - osdn_link = "https://osdn.net" - try: link = re.findall(r"\bhttps?://.*osdn\.net\S+", url)[0] except IndexError: reply = "`No OSDN links found`\n" return reply - page = BeautifulSoup(requests.get(link, allow_redirects=True).content, "lxml") - info = page.find("a", {"class": "mirror_link"}) link = urllib.parse.unquote(osdn_link + info["href"]) reply = f"Mirrors for __{link.split('/')[-1]}__\n" mirrors = page.find("form", {"id": "mirror-select-form"}).findAll("tr") - for data in mirrors[1:]: mirror = data.find("input")["value"] name = re.findall(r"\((.*)\)", data.findAll("td")[-1].text.strip())[0] dl_url = re.sub(r"m=(.*)&f", f"m={mirror}&f", link) reply += f"[{name}]({dl_url}) " - return reply def github(url: str) -> str: """GitHub direct links generator""" - try: link = re.findall(r"\bhttps?://.*github\.com.*releases\S+", url)[0] except IndexError: reply = "`No GitHub Releases links found`\n" return reply - reply = "" dl_url = "" download = requests.get(url, stream=True, allow_redirects=False) - try: dl_url = download.headers["location"] except KeyError: reply += "`Error: Can't extract the link`\n" - name = link.split("/")[-1] reply += f"[{name}]({dl_url}) " - return reply def androidfilehost(url: str) -> str: """AFH direct links generator""" - try: link = re.findall(r"\bhttps?://.*androidfilehost.*fid.*\S+", url)[0] except IndexError: reply = "`No AFH links found`\n" return reply - fid = re.findall(r"\?fid=(.*)", link)[0] session = requests.Session() user_agent = useragent() - headers = {"user-agent": user_agent} res = session.get(link, headers=headers, allow_redirects=True) headers = { @@ -400,13 +254,10 @@ def androidfilehost(url: str) -> str: "authority": "androidfilehost.com", "x-requested-with": "XMLHttpRequest", } - data = {"submit": "submit", "action": "getdownloadmirrors", "fid": f"{fid}"} - mirrors = None reply = "" error = "`Error: Can't find Mirrors for the link`\n" - try: req = session.post( "https://androidfilehost.com/libs/otf/mirrors.otf.php", @@ -417,22 +268,18 @@ def androidfilehost(url: str) -> str: mirrors = req.json()["MIRRORS"] except (json.decoder.JSONDecodeError, TypeError): reply += error - if not mirrors: reply += error return reply - for item in mirrors: name = item["name"] dl_url = item["url"] reply += f"[{name}]({dl_url}) " - return reply def useragent(): """useragent random setter""" - useragents = BeautifulSoup( requests.get( "https://developers.whatismybrowser.com/" @@ -440,7 +287,5 @@ def useragent(): ).content, "lxml", ).findAll("td", {"class": "useragent"}) - user_agent = choice(useragents) - return user_agent.text diff --git a/userge/plugins/utils/notes.py b/userge/plugins/utils/notes.py index 93f63e92e..89d814a20 100644 --- a/userge/plugins/utils/notes.py +++ b/userge/plugins/utils/notes.py @@ -201,7 +201,7 @@ async def get_note(message: Message) -> None: return can_access = message.from_user.is_self or message.from_user.id in Config.SUDO_USERS if Config.OWNER_ID: - can_access = can_access or message.from_user.id == Config.OWNER_ID + can_access = can_access or message.from_user.id in Config.OWNER_ID notename = message.matches[0].group(1).lower() mid, is_global = (0, False) for note in NOTES_DATA[message.chat.id]: diff --git a/userge/utils/helper/aiohttp_helper.py b/userge/utils/helper/aiohttp_helper.py index 04974eef9..0f8be4047 100644 --- a/userge/utils/helper/aiohttp_helper.py +++ b/userge/utils/helper/aiohttp_helper.py @@ -1,3 +1,8 @@ +""" +From Nana-Remix (https://github.com/pokurt/Nana-Remix) +Author: https://github.com/pokurt +""" + import aiohttp