diff --git a/.dockerignore b/.dockerignore index e9a0f31..f356d3f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,11 +3,8 @@ *.png .git/ .idea/ -str.py -Procfile README.md downloads/ raw_files/ .gitignore -runtime.txt __pycache__/ diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index c6a5f54..72cb4f9 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -12,9 +12,9 @@ jobs: python-version: [3.9] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -31,6 +31,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Check for install script errors uses: ludeeus/action-shellcheck@0.1.0 diff --git a/.gitignore b/.gitignore index 8040e00..03d636a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ __pycache__ raw_files downloads venv -local.env *.jpg *png *.raw diff --git a/Dockerfile b/Dockerfile index 36123be..c656865 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,9 @@ -FROM nikolaik/python-nodejs:python3.9-nodejs17 +FROM nikolaik/python-nodejs:latest RUN apt-get update \ && apt-get install -y --no-install-recommends ffmpeg \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -COPY . /app -WORKDIR /app +COPY . /app/ +WORKDIR /app/ RUN pip3 install --no-cache-dir --upgrade --requirement requirements.txt - CMD ["python3", "main.py"] diff --git a/Procfile b/Procfile deleted file mode 100644 index eb131d6..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -worker: python3 main.py diff --git a/README.md b/README.md index f37d95b..79df8e0 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ ## Heroku Deployment 💜 The easy way to host this bot, deploy to Heroku, Change the app country to Europe (it will help to make the bot stable). -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/levina-lab/video-stream) +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) ## VPS Deployment 📡 Get the best Quality of streaming performance by hosting it on VPS, here's the step's: @@ -95,7 +95,6 @@ python3 main.py # run the bot. - [Zxce3](https://github.com/Zxce3) ``Dev`` - [DoellBarr](https://github.com/DoellBarr) ``Dev`` - [tofikdn](https://github.com/tofikdn) ``Dev`` -- [Makoto-XD](https://github.com/Makoto-XD) ``Supporter`` - [Laky's](https://github.com/Laky-64) for [``py-tgcalls``](https://github.com/pytgcalls/pytgcalls) - [Dan](https://github.com/delivrance) for [``Pyrogram``](https://github.com/pyrogram) diff --git a/app.json b/app.json index 36537fb..d73e680 100644 --- a/app.json +++ b/app.json @@ -1,11 +1,14 @@ { "name": "Video x Music Stream Bot", - "description": "Telegram bot for Streaming Video & Music trought the Telegram Group Video Chat, powered by pytgcalls and pyrogram", + "description": "Telegram bot for Streaming Video & Music trought the Telegram Group Video Chat, powered by PyTgCalls and Pyrogram", "logo": "https://telegra.ph/file/1c41ded2dd871eb36bd7e.png", "keywords": [ - "pytgcalls", + "py-tgcalls", "telegram bot", "video stream", + "live stream", + "music stream", + "mongodb", "pyrogram" ], "website": "https://t.me/levinachannel", @@ -25,7 +28,7 @@ "required": true }, "BOT_USERNAME": { - "description": "your bot username from @BotFather", + "description": "fill with your bot username from @BotFather but without using '@' symbol", "required": true }, "BOT_NAME": { @@ -40,10 +43,20 @@ "description": "fill with the pyrogram String Session", "required": true }, - "SUDO_USERS": { - "description": "list of user ids to be added to sudo member list, or just fill with your id", + "MONGODB_URL": { + "description": "fill with the mongodb url you created from cloud.mongodb.com (tutorial about how to make it, find it on @VeezSupportGroup)", "required": true }, + "SUDO_USERS": { + "description": "list of user id to be added to sudo member list, or just fill with your id", + "required": true, + "value": "1757169682" + }, + "UPSTREAM_REPO": { + "description": "This is needed for update feature, if you deployed forked repo put your forked repo link here, if not just leave it as it", + "required": true, + "value": "https://github.com/levina-lab/video-stream" + }, "GROUP_SUPPORT": { "description": "if you have group, then fill the group username here without @", "required": true, diff --git a/config.py b/config.py index 6bc5da3..d5f8170 100644 --- a/config.py +++ b/config.py @@ -2,27 +2,25 @@ import os from os import getenv from dotenv import load_dotenv -if os.path.exists("local.env"): - load_dotenv("local.env") - load_dotenv() admins = {} SESSION_NAME = getenv("SESSION_NAME", "session") BOT_TOKEN = getenv("BOT_TOKEN") -BOT_NAME = getenv("BOT_NAME", "Video Stream") +BOT_NAME = getenv("BOT_NAME") API_ID = int(getenv("API_ID")) API_HASH = getenv("API_HASH") -OWNER_NAME = getenv("OWNER_NAME", "dlwrml") -ALIVE_NAME = getenv("ALIVE_NAME", "Levina") -BOT_USERNAME = getenv("BOT_USERNAME", "veezvideobot") -ASSISTANT_NAME = getenv("ASSISTANT_NAME", "cleo_invida") +MONGODB_URL = getenv("MONGODB_URL") +OWNER_NAME = getenv("OWNER_NAME") +ALIVE_NAME = getenv("ALIVE_NAME") +BOT_USERNAME = getenv("BOT_USERNAME") +ASSISTANT_NAME = getenv("ASSISTANT_NAME") GROUP_SUPPORT = getenv("GROUP_SUPPORT", "VeezSupportGroup") UPDATES_CHANNEL = getenv("UPDATES_CHANNEL", "levinachannel") SUDO_USERS = list(map(int, getenv("SUDO_USERS").split())) COMMAND_PREFIXES = list(getenv("COMMAND_PREFIXES", "/ ! .").split()) ALIVE_IMG = getenv("ALIVE_IMG", "https://telegra.ph/file/c83b000f004f01897fe18.png") DURATION_LIMIT = int(getenv("DURATION_LIMIT", "60")) -UPSTREAM_REPO = getenv("UPSTREAM_REPO", "https://github.com/levina-lab/video-stream") +UPSTREAM_REPO = getenv("UPSTREAM_REPO") IMG_1 = getenv("IMG_1", "https://telegra.ph/file/d6f92c979ad96b2031cba.png") IMG_2 = getenv("IMG_2", "https://telegra.ph/file/6213d2673486beca02967.png") IMG_3 = getenv("IMG_3", "https://telegra.ph/file/f02efde766160d3ff52d6.png") diff --git a/driver/database/dbchat.py b/driver/database/dbchat.py new file mode 100644 index 0000000..1b881c5 --- /dev/null +++ b/driver/database/dbchat.py @@ -0,0 +1,38 @@ +""" chat database """ + +from typing import Dict, List, Union + +from driver.database.dblocal import db + +chatsdb = db.chats + + +async def get_served_chats() -> list: + chats = chatsdb.find({"chat_id": {"$lt": 0}}) + if not chats: + return [] + chats_list = [] + for chat in await chats.to_list(length=1000000000): + chats_list.append(chat) + return chats_list + + +async def is_served_chat(chat_id: int) -> bool: + chat = await chatsdb.find_one({"chat_id": chat_id}) + if not chat: + return False + return True + + +async def add_served_chat(chat_id: int): + is_served = await is_served_chat(chat_id) + if is_served: + return + return await chatsdb.insert_one({"chat_id": chat_id}) + + +async def remove_served_chat(chat_id: int): + is_served = await is_served_chat(chat_id) + if not is_served: + return + return await chatsdb.delete_one({"chat_id": chat_id}) diff --git a/driver/database/dblocal.py b/driver/database/dblocal.py new file mode 100644 index 0000000..9d1856f --- /dev/null +++ b/driver/database/dblocal.py @@ -0,0 +1,8 @@ +""" mongo database """ + +from motor.motor_asyncio import AsyncIOMotorClient as Bot +from config import MONGODB_URL as tmo + + +MONGODB_CLI = Bot(tmo) +db = MONGODB_CLI.program diff --git a/driver/database/dbpunish.py b/driver/database/dbpunish.py new file mode 100644 index 0000000..029fe1c --- /dev/null +++ b/driver/database/dbpunish.py @@ -0,0 +1,32 @@ +from typing import Dict, List, Union + +from driver.database.dblocal import db + +gbansdb = db.gban + + +async def get_gbans_count() -> int: + users = gbansdb.find({"user_id": {"$gt": 0}}) + users = await users.to_list(length=100000) + return len(users) + + +async def is_gbanned_user(user_id: int) -> bool: + user = await gbansdb.find_one({"user_id": user_id}) + if not user: + return False + return True + + +async def add_gban_user(user_id: int): + is_gbanned = await is_gbanned_user(user_id) + if is_gbanned: + return + return await gbansdb.insert_one({"user_id": user_id}) + + +async def remove_gban_user(user_id: int): + is_gbanned = await is_gbanned_user(user_id) + if not is_gbanned: + return + return await gbansdb.delete_one({"user_id": user_id}) diff --git a/driver/utils.py b/driver/utils.py index 3af746a..5f4671b 100644 --- a/driver/utils.py +++ b/driver/utils.py @@ -42,6 +42,7 @@ async def skip_current_song(chat_id): chat_id, AudioPiped( url, + HighQualityAudio(), ), ) elif type == "Video": @@ -52,7 +53,12 @@ async def skip_current_song(chat_id): elif Q == 360: hm = LowQualityVideo() await call_py.change_stream( - chat_id, AudioVideoPiped(url, HighQualityAudio(), hm) + chat_id, + AudioVideoPiped( + url, + HighQualityAudio(), + hm, + ), ) pop_an_item(chat_id) return [songname, link, type] diff --git a/example.env b/example.env index fdf2ce4..7f9e586 100644 --- a/example.env +++ b/example.env @@ -2,19 +2,19 @@ SESSION_NAME= Your Session # Your music bot username -BOT_USERNAME= +BOT_USERNAME= # Your Bot Token -BOT_TOKEN= +BOT_TOKEN= # Your music bot name -BOT_NAME= +BOT_NAME= # Your API ID from my.telegram.org -API_ID= +API_ID= # Your API HASH from my.telegram.org -API_HASH= +API_HASH= # List of user IDs separated by space (you can fill this with your id too) SUDO_USERS=1757169682 1670523611 1727937540 @@ -23,16 +23,19 @@ SUDO_USERS=1757169682 1670523611 1727937540 DURATION_LIMIT=240 # if you have channel, fill the channel username here without @ -UPDATES_CHANNEL=levinachannel +UPDATES_CHANNEL=levinachannel # # if you have group, fill the group username here without @ -GROUP_SUPPORT=VeezSupportGroup +GROUP_SUPPORT=VeezSupportGroup # fill with the assistant username without @ -ASSISTANT_NAME=veezassistant +ASSISTANT_NAME=VeezMusicAssistant # fill with username of your telegram account OWNER_NAME=dlwrml # fill with nickname/name of your telegram account -ALIVE_NAME=Levina \ No newline at end of file +ALIVE_NAME=Levina + +# fill with the mongodb url you created from cloud.mongodb.com +MONGODB_URL= diff --git a/heroku.yml b/heroku.yml index cdeba04..5f17c5c 100644 --- a/heroku.yml +++ b/heroku.yml @@ -1,3 +1,5 @@ build: docker: - worker: Dockerfile + worker: Dockerfile +run: + worker: python3 main.py diff --git a/main.py b/main.py index 5aa12d3..2962be8 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,12 @@ import asyncio from pytgcalls import idle from driver.veez import call_py, bot + async def start_bot(): await bot.start() print("[INFO]: BOT & UBOT CLIENT STARTED !!") await call_py.start() - print("[INFO]: PYTGCALLS CLIENT STARTED !!") + print("[INFO]: PY-TGCALLS CLIENT STARTED !!") await idle() print("[INFO]: STOPPING BOT & USERBOT") await bot.stop() diff --git a/program/__init__.py b/program/__init__.py index 22049ab..4a13052 100644 --- a/program/__init__.py +++ b/program/__init__.py @@ -1 +1 @@ -__version__ = "0.6.2" +__version__ = "0.6.2 Beta" diff --git a/program/callback.py b/program/callback.py index f23efbd..dbd4968 100644 --- a/program/callback.py +++ b/program/callback.py @@ -85,7 +85,7 @@ async def cbcmds(_, query: CallbackQuery): await query.edit_message_text( f"""✨ **Hello [{query.message.chat.first_name}](tg://user?id={query.message.chat.id}) !** -» **press the button below to read the explanation and see the list of available commands !** +» Choose the menu below to read the explanation & see the list of available Commands ! ⚡ __Powered by {BOT_NAME} A.I__""", reply_markup=InlineKeyboardMarkup( @@ -119,9 +119,8 @@ async def cbbasic(_, query: CallbackQuery): » /search (query) - search a youtube video link » /ping - show the bot ping status -» /speedtest - run the bot server speedtest » /uptime - show the bot uptime status -» /alive - show the bot alive info (in group) +» /alive - show the bot alive info (in Group only) ⚡️ __Powered by {BOT_NAME} AI__""", reply_markup=InlineKeyboardMarkup( @@ -159,13 +158,17 @@ async def cbsudo(_, query: CallbackQuery): await query.edit_message_text( f"""🏮 here is the sudo commands: -» /rmw - clean all raw files -» /rmd - clean all downloaded files +» /gban (`username` or `user id`) - for global banned people +» /ungban (`username` or `user id`) - for un-global banned people +» /speedtest - run the bot server speedtest » /sysinfo - show the system information » /update - update your bot to latest version » /restart - restart your bot » /leaveall - order userbot to leave from all group +» /broadcast (`message`) - send a broadcast message to all groups entered by bot +» /broadcast_pin (`message`) - send a broadcast message to all groups entered by bot with the chat pin + ⚡ __Powered by {BOT_NAME} AI__""", reply_markup=InlineKeyboardMarkup( [[InlineKeyboardButton("🔙 Go Back", callback_data="cbcmds")]] diff --git a/program/developer.py b/program/developer.py new file mode 100644 index 0000000..e9aad80 --- /dev/null +++ b/program/developer.py @@ -0,0 +1,188 @@ +import os +import re +import sys +import shutil +import subprocess +import traceback + +from time import time +from io import StringIO +from sys import version as pyver +from inspect import getfullargspec + +from config import BOT_USERNAME as bname +from driver.veez import bot +from driver.filters import command, other_filters +from pyrogram import Client, filters +from driver.decorators import sudo_users_only, errors +from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup + + +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}) + + +@Client.on_message(command(["eval", f"eval{bname}"]) & other_filters) +@sudo_users_only +async def executor(client, message): + if len(message.command) < 2: + return await edit_or_reply(message, text="» Give a command to execute") + 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\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", + ) + ] + ] + ) + await edit_or_reply(message, text=final_output, reply_markup=keyboard) + + +@Client.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) + + +@Client.on_message(command(["sh", f"sh{bname}"]) & other_filters) +@sudo_users_only +async def shellrunner(client, message): + if len(message.command) < 2: + return await edit_or_reply(message, text="**usage:**\n\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: + print(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: + print(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 bot.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`") + + +@Client.on_message(command(["leavebot", f"leavebot{bname}"]) & other_filters) +@sudo_users_only +async def bot_leave_group(_, message): + if len(message.command) != 2: + await message.reply_text( + "**usage:**\n\n» /leavebot [chat id]" + ) + return + chat = message.text.split(None, 2)[1] + try: + await bot.leave_chat(chat) + except Exception as e: + await message.reply_text(f"❌ procces failed\n\nreason: `{e}`") + print(e) + return + await message.reply_text(f"✅ Bot successfully left from chat: `{chat}`") diff --git a/program/downloader.py b/program/downloader.py index 8375b1b..45c15cb 100644 --- a/program/downloader.py +++ b/program/downloader.py @@ -63,7 +63,7 @@ def song(_, message): info_dict = ydl.extract_info(link, download=False) audio_file = ydl.prepare_filename(info_dict) ydl.process_info(info_dict) - rep = f"**🎧 Uploader @{bn}**" + rep = f"• uploader @{bn}" secmul, dur, dur_arr = 1, 0, duration.split(":") for i in range(len(dur_arr) - 1, -1, -1): dur += int(float(dur_arr[i])) * secmul diff --git a/program/extra.py b/program/extra.py new file mode 100644 index 0000000..782c50c --- /dev/null +++ b/program/extra.py @@ -0,0 +1,112 @@ +""" broadcast & statistic collector """ + +import asyncio +from pyrogram import Client, filters +from pyrogram.types import Message +from driver.filters import command +from driver.decorators import sudo_users_only +from driver.database.dbchat import get_served_chats + +from config import BOT_USERNAME as bn + + +@Client.on_message(command(["broadcast", f"broadcast@{bn}"]) & ~filters.edited) +@sudo_users_only +async def broadcast(c: Client, message: Message): + if not message.reply_to_message: + pass + else: + x = message.reply_to_message.message_id + y = message.chat.id + sent = 0 + chats = [] + schats = await get_served_chats() + for chat in schats: + chats.append(int(chat["chat_id"])) + for i in chats: + try: + m = await c.forward_messages(i, y, x) + await asyncio.sleep(0.3) + sent += 1 + except Exception: + pass + await message.reply_text(f"✅ Broadcast complete in {sent} Group.") + return + if len(message.command) < 2: + await message.reply_text( + "**usage**:\n\n/broadcast (`message`) or (`reply to message`)" + ) + return + text = message.text.split(None, 1)[1] + sent = 0 + chats = [] + schats = await get_served_chats() + for chat in schats: + chats.append(int(chat["chat_id"])) + for i in chats: + try: + m = await c.send_message(i, text=text) + await asyncio.sleep(0.3) + sent += 1 + except Exception: + pass + await message.reply_text(f"✅ Broadcast complete in {sent} Group.") + + +@Client.on_message(command(["broadcast_pin", f"broadcast_pin@{bn}"]) & ~filters.edited) +@sudo_users_only +async def broadcast_pin(c: Client, message: Message): + if not message.reply_to_message: + pass + else: + x = message.reply_to_message.message_id + y = message.chat.id + sent = 0 + pin = 0 + chats = [] + schats = await get_served_chats() + for chat in schats: + chats.append(int(chat["chat_id"])) + for i in chats: + try: + m = await c.forward_messages(i, y, x) + try: + await m.pin(disable_notification=True) + pin += 1 + except Exception: + pass + await asyncio.sleep(0.3) + sent += 1 + except Exception: + pass + await message.reply_text( + f"✅ Broadcast complete in {sent} Group.\n📌 With the {pin} pins." + ) + return + if len(message.command) < 2: + await message.reply_text( + "**usage**:\n\n/broadcast (`message`) or (`reply to message`)" + ) + return + text = message.text.split(None, 1)[1] + sent = 0 + pin = 0 + chats = [] + schats = await get_served_chats() + for chat in schats: + chats.append(int(chat["chat_id"])) + for i in chats: + try: + m = await c.send_message(i, text=text) + try: + await m.pin(disable_notification=True) + pin += 1 + except Exception: + pass + await asyncio.sleep(0.3) + sent += 1 + except Exception: + pass + await message.reply_text( + f"✅ Broadcast complete in {sent} Group.\n📌 With the {pin} pins." + ) diff --git a/program/music.py b/program/music.py index 41d8ea0..48d6b8d 100644 --- a/program/music.py +++ b/program/music.py @@ -23,6 +23,17 @@ from pyrogram.types import InlineKeyboardMarkup, Message from pytgcalls import StreamType from pytgcalls.types.input_stream import AudioPiped +from pytgcalls.types.input_stream.quality import HighQualityAudio +# repository stuff +from program.utils.inline import stream_markup +from driver.design.thumbnail import thumb +from driver.design.chatname import CHAT_TITLE +from driver.filters import command, other_filters +from driver.queues import QUEUE, add_to_queue +from driver.veez import call_py, user +from driver.utils import bash +from config import ASSISTANT_NAME, BOT_USERNAME, IMG_1, IMG_2 + # youtube-dl stuff from youtubesearchpython import VideosSearch @@ -118,16 +129,18 @@ async def play(c: Client, m: Message): suhu = await replied.reply("📥 **downloading audio...**") dl = await replied.download() link = replied.link - if replied.audio: - if replied.audio.title: + + try: + if replied.audio: songname = replied.audio.title[:70] - else: - if replied.audio.file_name: - songname = replied.audio.file_name[:70] - else: - songname = "Audio" - elif replied.voice: - songname = "Voice Note" + songname = replied.audio.file_name[:70] + duration = replied.audio.duration + elif replied.voice: + songname = "Voice Note" + duration = replied.voice.duration + except BaseException: + songname = "Audio" + if chat_id in QUEUE: pos = add_to_queue(chat_id, songname, dl, link, "Audio", 0) requester = f"[{m.from_user.first_name}](tg://user?id={m.from_user.id})" @@ -136,9 +149,10 @@ async def play(c: Client, m: Message): await m.reply_photo( photo=f"{IMG_1}", reply_markup=InlineKeyboardMarkup(buttons), - caption=f"💡 **Track added to queue »** `{pos}`\n\n🗂 **Name:** [{songname}]({link}) | `music`\n💭 **Chat:** `{chat_id}`\n🧸 **Request by:** {requester}", + caption=f"💡 **Track added to queue »** `{pos}`\n\n🗂 **Name:** [{songname}]({link}) | `music`\n⏱️ **Duration:** `{duration}`\n🧸 **Request by:** {requester}", ) else: + try: await suhu.edit("🔄 **Joining vc...**") await call_py.join_group_call( @@ -162,6 +176,30 @@ async def play(c: Client, m: Message): except Exception as e: await suhu.delete() await m.reply_text(f"🚫 error:\n\n» {e}") + + try: + await suhu.edit("🔄 **Joining vc...**") + await call_py.join_group_call( + chat_id, + AudioPiped( + dl, + HighQualityAudio(), + ), + stream_type=StreamType().local_stream, + ) + add_to_queue(chat_id, songname, dl, link, "Audio", 0) + await suhu.delete() + buttons = stream_markup(user_id) + requester = f"[{m.from_user.first_name}](tg://user?id={m.from_user.id})" + await m.reply_photo( + photo=f"{IMG_2}", + reply_markup=InlineKeyboardMarkup(buttons), + caption=f"🗂 **Name:** [{songname}]({link}) | `music`\n⏱️ **Duration:** `{duration}`\n🧸 **Request by:** {requester}", + ) + except Exception as e: + await suhu.delete() + await m.reply_text(f"🚫 error:\n\n» {e}") + else: if len(m.command) < 2: await m.reply( @@ -206,6 +244,7 @@ async def play(c: Client, m: Message): chat_id, AudioPiped( ytlink, + HighQualityAudio(), ), stream_type=StreamType().local_stream, ) @@ -266,6 +305,7 @@ async def play(c: Client, m: Message): chat_id, AudioPiped( ytlink, + HighQualityAudio(), ), stream_type=StreamType().local_stream, ) diff --git a/program/punishment.py b/program/punishment.py new file mode 100644 index 0000000..ae3129f --- /dev/null +++ b/program/punishment.py @@ -0,0 +1,173 @@ +""" global banned and un-global banned module """ + +import asyncio + +from pyrogram import Client, filters +from pyrogram.types import Message +from pyrogram.errors import FloodWait +from driver.filters import command +from driver.decorators import sudo_users_only +from driver.database.dbchat import get_served_chats +from driver.database.dbpunish import add_gban_user, is_gbanned_user, remove_gban_user + +from config import BOT_NAME, SUDO_USERS, BOT_USERNAME as bn + + +@Client.on_message(command(["gban", f"gban@{bn}"]) & ~filters.edited) +@sudo_users_only +async def global_banned(c: Client, message: Message): + if not message.reply_to_message: + if len(message.command) < 2: + await message.reply_text("**usage:**\n\n/gban [username | user_id]") + return + user = message.text.split(None, 2)[1] + if "@" in user: + user = user.replace("@", "") + user = await c.get_users(user) + from_user = message.from_user + BOT_ID = await c.get_me() + if user.id == from_user.id: + return await message.reply_text( + "You can't gban yourself !" + ) + elif user.id == BOT_ID: + await message.reply_text("I can't gban myself !") + elif user.id in SUDO_USERS: + await message.reply_text("You can't gban sudo user !") + else: + await add_gban_user(user.id) + served_chats = [] + chats = await get_served_chats() + for chat in chats: + served_chats.append(int(chat["chat_id"])) + m = await message.reply_text( + f"🚷 **Globally banning {user.mention}**\n⏱ Expected time: `{len(served_chats)}`" + ) + number_of_chats = 0 + for num in served_chats: + try: + await c.ban_chat_member(num, user.id) + number_of_chats += 1 + await asyncio.sleep(1) + except FloodWait as e: + await asyncio.sleep(int(e.x)) + except Exception: + pass + ban_text = f""" +🚷 **New Global ban on [{BOT_NAME}](https://t.me/{bn}) + +**Origin:** {message.chat.title} [`{message.chat.id}`] +**Sudo User:** {from_user.mention} +**Banned User:** {user.mention} +**Banned User ID:** `{user.id}` +**Chats:** `{number_of_chats}`""" + try: + await m.delete() + except Exception: + pass + await message.reply_text( + f"{ban_text}", + disable_web_page_preview=True, + ) + return + from_user_id = message.from_user.id + from_user_mention = message.from_user.mention + user_id = message.reply_to_message.from_user.id + mention = message.reply_to_message.from_user.mention + BOT_ID = await c.get_me() + if user_id == from_user_id: + await message.reply_text("You can't gban yourself !") + elif user_id == BOT_ID: + await message.reply_text("I can't gban myself !") + elif user_id in SUDO_USERS: + await message.reply_text("You can't gban sudo user !") + else: + is_gbanned = await is_gbanned_user(user_id) + if is_gbanned: + await message.reply_text("This user already gbanned !") + else: + await add_gban_user(user_id) + served_chats = [] + chats = await get_served_chats() + for chat in chats: + served_chats.append(int(chat["chat_id"])) + m = await message.reply_text( + f"🚷 **Globally banning {mention}**\n⏱ Expected time: `{len(served_chats)}`" + ) + number_of_chats = 0 + for num in served_chats: + try: + await c.ban_chat_member(num, user_id) + number_of_chats += 1 + await asyncio.sleep(1) + except FloodWait as e: + await asyncio.sleep(int(e.x)) + except Exception: + pass + ban_text = f""" +🚷 **New Global ban on [{BOT_NAME}](https://t.me/{bn}) + +**Origin:** {message.chat.title} [`{message.chat.id}`] +**Sudo User:** {from_user_mention} +**Banned User:** {mention} +**Banned User ID:** `{user_id}` +**Chats:** `{number_of_chats}`""" + try: + await m.delete() + except Exception: + pass + await message.reply_text( + f"{ban_text}", + disable_web_page_preview=True, + ) + return + + +@Client.on_message(command(["ungban", f"ungban@{bn}"]) & ~filters.edited) +@sudo_users_only +async def ungban_global(c: Client, message: Message): + if not message.reply_to_message: + if len(message.command) != 2: + await message.reply_text( + "**usage:**\n\n/ungban [username | user_id]" + ) + return + user = message.text.split(None, 1)[1] + if "@" in user: + user = user.replace("@", "") + user = await c.get_users(user) + from_user = message.from_user + BOT_ID = await c.get_me() + if user.id == from_user.id: + await message.reply_text("You can't ungban yourself because you can't be gbanned !") + elif user.id == BOT_ID: + await message.reply_text("I can't ungban myself because i can't be gbanned !") + elif user.id in SUDO_USERS: + await message.reply_text("Sudo users can't be gbanned/ungbanned !") + else: + is_gbanned = await is_gbanned_user(user.id) + if not is_gbanned: + await message.reply_text("This user already ungbanned.") + else: + await remove_gban_user(user.id) + await message.reply_text("✅ This user has ungbanned.") + return + from_user_id = message.from_user.id + user_id = message.reply_to_message.from_user.id + mention = message.reply_to_message.from_user.mention + BOT_ID = await c.get_me() + if user_id == from_user_id: + await message.reply_text("You can't ungban yourself because you can't be gbanned !") + elif user_id == BOT_ID: + await message.reply_text( + "I can't ungban myself because i can't be gbanned !" + ) + elif user_id in SUDO_USERS: + await message.reply_text("Sudo users can't be gbanned/ungbanned !") + else: + is_gbanned = await is_gbanned_user(user_id) + if not is_gbanned: + await message.reply_text("This user already un-gbanned") + else: + await remove_gban_user(user_id) + await message.reply_text("✅ This user has ungbanned.") diff --git a/program/rmtrash.py b/program/rmtrash similarity index 93% rename from program/rmtrash.py rename to program/rmtrash index 54649f0..b5e8ff1 100644 --- a/program/rmtrash.py +++ b/program/rmtrash @@ -48,3 +48,5 @@ async def cleanup(_, message: Message): await message.reply_text("✅ **cleaned**") else: await message.reply_text("✅ **already cleaned**") + +# this module has deactivated because no longer used if you want to take the code just take it and use it, Thanks diff --git a/program/speedtest.py b/program/speedtest.py index a7f94bd..2edbc9e 100644 --- a/program/speedtest.py +++ b/program/speedtest.py @@ -14,20 +14,22 @@ from pyrogram.types import Message @Client.on_message(command(["speedtest", f"speedtest@{bname}"]) & ~filters.edited) -async def statsguwid(_, message: Message): - m = await message.reply_text("Running server speedtest.") +@sudo_users_only +async def run_speedtest(_, message: Message): + m = await message.reply_text("⚡️ running server speedtest") try: test = speedtest.Speedtest() test.get_best_server() - m = await m.edit("Running download speedtest..") + m = await m.edit("⚡️ running download speedtest..") test.download() - m = await m.edit("Running upload speedtest...") + m = await m.edit("⚡️ running upload speedtest...") test.upload() test.results.share() result = test.results.dict() except Exception as e: - return await m.edit(e) - m = await m.edit("Sharing speedtest results....") + await m.edit(e) + return + m = await m.edit("🔄 sharing speedtest results") path = wget.download(result["share"]) output = f"""💡 **SpeedTest Results** diff --git a/program/start.py b/program/start.py index 7b99e55..b5c3679 100644 --- a/program/start.py +++ b/program/start.py @@ -14,6 +14,7 @@ from config import ( from program import __version__ from driver.veez import user from driver.filters import command, other_filters +from driver.database.dbpunish import is_gbanned_user from pyrogram import Client, filters from pyrogram import __version__ as pyrover from pytgcalls import (__version__ as pytover) @@ -164,3 +165,22 @@ async def new_chat(c: Client, m: Message): ] ) ) + + +chat_watcher_group = 5 + +@Client.on_message(group=chat_watcher_group) +async def chat_watcher_func(_, message: Message): + try: + userid = message.from_user.id + except Exception: + return + suspect = f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" + if await is_gbanned_user(userid): + try: + await message.chat.ban_member(userid) + except Exception: + return + await message.reply_text( + f"👮🏼 (> {suspect} <)\n\n**Gbanned** user joined, that user has been gbanned by sudo user and was blocked from this Chat !\n\n🚫 **Reason:** potential spammer and abuser." + ) diff --git a/program/video.py b/program/video.py index 1f90dd7..f3fdf52 100644 --- a/program/video.py +++ b/program/video.py @@ -140,8 +140,10 @@ async def vplay(c: Client, m: Message): try: if replied.video: songname = replied.video.file_name[:70] + duration = replied.video.duration elif replied.document: songname = replied.document.file_name[:70] + duration = replied.document.duration except BaseException: songname = "Video" @@ -153,7 +155,7 @@ async def vplay(c: Client, m: Message): await m.reply_photo( photo=f"{IMG_1}", reply_markup=InlineKeyboardMarkup(buttons), - caption=f"💡 **Track added to queue »** `{pos}`\n\n🗂 **Name:** [{songname}]({link}) | `video`\n💭 **Chat:** `{chat_id}`\n🧸 **Request by:** {requester}", + caption=f"💡 **Track added to queue »** `{pos}`\n\n🗂 **Name:** [{songname}]({link}) | `video`\n⏱️ **Duration:** `{duration}`\n🧸 **Request by:** {requester}", ) else: if Q == 720: @@ -179,7 +181,7 @@ async def vplay(c: Client, m: Message): await m.reply_photo( photo=f"{IMG_2}", reply_markup=InlineKeyboardMarkup(buttons), - caption=f"🗂 **Name:** [{songname}]({link}) | `video`\n💭 **Chat:** `{chat_id}`\n🧸 **Request by:** {requester}", + caption=f"🗂 **Name:** [{songname}]({link}) | `video`\n⏱️ **Duration:** `{duration}`\n🧸 **Request by:** {requester}", ) else: if len(m.command) < 2: diff --git a/requirements.txt b/requirements.txt index 739a514..dd3760d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,9 +4,10 @@ ffmpeg-python py-tgcalls pyrogram youtube-search-python -yt-dlp -speedtest-cli git+https://github.com/ytdl-org/youtube-dl@master +yt-dlp +lyricsgenius +speedtest-cli youtube-search python-dotenv dnspython @@ -19,4 +20,3 @@ motor psutil future wget -lyricsgenius diff --git a/runtime.txt b/runtime.txt deleted file mode 100644 index f72c511..0000000 --- a/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-3.9.0