├── Procfile
├── runtime.txt
├── start
├── cookies
└── cookies.txt
├── heroku.yml
├── DeadlineTech
├── utils
│ ├── decorators
│ │ ├── __init__.py
│ │ └── language.py
│ ├── exceptions.py
│ ├── inline
│ │ ├── __init__.py
│ │ ├── extras.py
│ │ ├── speed.py
│ │ ├── stats.py
│ │ ├── start.py
│ │ ├── queue.py
│ │ ├── settings.py
│ │ ├── help.py
│ │ └── play.py
│ ├── __init__.py
│ ├── sys.py
│ ├── stream
│ │ ├── autoclear.py
│ │ └── queue.py
│ ├── extraction.py
│ ├── pastebin.py
│ ├── channelplay.py
│ ├── logger.py
│ ├── crash_reporter.py
│ ├── inlinequery.py
│ ├── formatters.py
│ └── thumbnails.py
├── assets
│ ├── font.ttf
│ ├── font2.ttf
│ ├── font3.ttf
│ └── icons.png
├── platforms
│ ├── __init__.py
│ ├── Soundcloud.py
│ ├── Resso.py
│ ├── Apple.py
│ ├── Carbon.py
│ └── Spotify.py
├── plugins
│ ├── misc
│ │ ├── watcher.py
│ │ ├── seeker.py
│ │ ├── auto_leave.py
│ │ ├── clean_assistant.py
│ │ └── broadcast.py
│ ├── __init__.py
│ ├── admins
│ │ ├── stop.py
│ │ ├── resume.py
│ │ ├── pause.py
│ │ ├── shuffle.py
│ │ ├── loop.py
│ │ ├── seek.py
│ │ ├── auth.py
│ │ └── speed.py
│ ├── tools
│ │ ├── ping.py
│ │ ├── speedtest.py
│ │ ├── language.py
│ │ ├── active.py
│ │ ├── reload.py
│ │ ├── stats.py
│ │ └── dev.py
│ ├── sudo
│ │ ├── logger.py
│ │ ├── maintenance.py
│ │ ├── crash_reporter.py
│ │ ├── blchat.py
│ │ ├── block.py
│ │ ├── chatlog.py
│ │ ├── sudoers.py
│ │ ├── gban.py
│ │ └── restart.py
│ ├── play
│ │ ├── playmode.py
│ │ ├── channel.py
│ │ └── live.py
│ └── bot
│ │ ├── privacy.py
│ │ ├── inline.py
│ │ ├── help.py
│ │ └── start.py
├── logging.py
├── __init__.py
├── core
│ ├── mongo.py
│ ├── dir.py
│ ├── git.py
│ ├── bot.py
│ └── userbot.py
├── misc.py
└── __main__.py
├── sample.env
├── .gitignore
├── .dockerignore
├── Dockerfile
├── requirements.txt
├── LICENSE
├── strings
└── __init__.py
├── app.json
├── setup
├── config.py
└── .github
└── README.md
/Procfile:
--------------------------------------------------------------------------------
1 | worker: bash start
2 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.11.4
2 |
--------------------------------------------------------------------------------
/start:
--------------------------------------------------------------------------------
1 | python3 -m DeadlineTech
2 |
--------------------------------------------------------------------------------
/cookies/cookies.txt:
--------------------------------------------------------------------------------
1 | # Paste your cookies here
2 |
--------------------------------------------------------------------------------
/heroku.yml:
--------------------------------------------------------------------------------
1 | build:
2 | docker:
3 | worker: Dockerfile
4 | run:
5 | worker: bash start
--------------------------------------------------------------------------------
/DeadlineTech/utils/decorators/__init__.py:
--------------------------------------------------------------------------------
1 | from .admins import *
2 | from .language import *
3 |
--------------------------------------------------------------------------------
/DeadlineTech/assets/font.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deadlineTech/music/HEAD/DeadlineTech/assets/font.ttf
--------------------------------------------------------------------------------
/DeadlineTech/assets/font2.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deadlineTech/music/HEAD/DeadlineTech/assets/font2.ttf
--------------------------------------------------------------------------------
/DeadlineTech/assets/font3.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deadlineTech/music/HEAD/DeadlineTech/assets/font3.ttf
--------------------------------------------------------------------------------
/DeadlineTech/assets/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deadlineTech/music/HEAD/DeadlineTech/assets/icons.png
--------------------------------------------------------------------------------
/sample.env:
--------------------------------------------------------------------------------
1 | API_ID=
2 | API_HASH=
3 | BOT_TOKEN=
4 | LOGGER_ID=
5 | API_KEY=
6 | MONGO_DB_URI=
7 | OWNER_ID=
8 | STRING_SESSION=
9 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/exceptions.py:
--------------------------------------------------------------------------------
1 | class AssistantErr(Exception):
2 | def __init__(self, errr: str):
3 | super().__init__(errr)
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | .cache
3 | log.txt
4 | .DS_Store
5 | *.session
6 | raw_files/
7 | cache/
8 | downloads/
9 | __pycache__/
10 | *.session-journal
11 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .env
2 | .cache
3 | log.txt
4 | .DS_Store
5 | *.session
6 | raw_files/
7 | cache/
8 | downloads/
9 | __pycache__/
10 | *.session-journal
11 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/__init__.py:
--------------------------------------------------------------------------------
1 | from .extras import *
2 | from .help import *
3 | from .play import *
4 | from .queue import *
5 | from .settings import *
6 | from .speed import *
7 | from .start import *
8 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .channelplay import *
2 | from .database import *
3 | from .decorators import *
4 | from .extraction import *
5 | from .formatters import *
6 | from .inline import *
7 | from .pastebin import *
8 | from .sys import *
9 |
--------------------------------------------------------------------------------
/DeadlineTech/platforms/__init__.py:
--------------------------------------------------------------------------------
1 | from .Apple import AppleAPI
2 | from .Carbon import CarbonAPI
3 | from .Resso import RessoAPI
4 | from .Soundcloud import SoundAPI
5 | from .Spotify import SpotifyAPI
6 | from .Telegram import TeleAPI
7 | from .Youtube import YouTubeAPI
8 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nikolaik/python-nodejs:python3.10-nodejs20
2 |
3 | RUN apt-get update \
4 | && apt-get install -y --no-install-recommends ffmpeg \
5 | && apt-get clean \
6 | && rm -rf /var/lib/apt/lists/*
7 |
8 | RUN python -m pip install --upgrade yt-dlp
9 |
10 | COPY . /app/
11 | WORKDIR /app/
12 | RUN python -m pip install --no-cache-dir --upgrade pip
13 | RUN pip3 install --no-cache-dir -U -r requirements.txt
14 |
15 | CMD bash start
16 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/misc/watcher.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.core.call import Anony
8 |
9 | welcome = 20
10 | close = 30
11 |
12 |
13 | @app.on_message(filters.video_chat_started, group=welcome)
14 | @app.on_message(filters.video_chat_ended, group=close)
15 | async def welcome(_, message: Message):
16 | await Anony.stop_stream_force(message.chat.id)
17 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/sys.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | import psutil
4 |
5 | from DeadlineTech.misc import _boot_
6 | from DeadlineTech.utils.formatters import get_readable_time
7 |
8 |
9 | async def bot_sys_stats():
10 | bot_uptime = int(time.time() - _boot_)
11 | UP = f"{get_readable_time(bot_uptime)}"
12 | CPU = f"{psutil.cpu_percent(interval=0.5)}%"
13 | RAM = f"{psutil.virtual_memory().percent}%"
14 | DISK = f"{psutil.disk_usage('/').percent}%"
15 | return UP, CPU, RAM, DISK
16 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/stream/autoclear.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from config import autoclean
4 |
5 |
6 | async def auto_clean(popped):
7 | try:
8 | rem = popped["file"]
9 | autoclean.remove(rem)
10 | count = autoclean.count(rem)
11 | if count == 0:
12 | if "vid_" not in rem or "live_" not in rem or "index_" not in rem:
13 | try:
14 | os.remove(rem)
15 | except:
16 | pass
17 | except:
18 | pass
19 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiofiles
2 | aiohttp
3 | apscheduler
4 | asyncio
5 | beautifulsoup4
6 | dnspython
7 | ffmpeg-python
8 | gitpython
9 | hachoir
10 | heroku3
11 | motor
12 | pillow==9.5.0
13 | psutil
14 | httpx==0.27.2
15 | py-tgcalls==0.9.7
16 | pykeyboard
17 | https://github.com/KurimuzonAkuma/pyrogram/archive/v2.1.23.zip
18 | python-dotenv
19 | pyyaml
20 | requests
21 | speedtest-cli
22 | spotipy
23 | tgcrypto
24 | unidecode
25 | git+https://github.com/yt-dlp/yt-dlp.git@master
26 | youtube-search
27 | youtube-search-python
28 | uvloop==0.21.0
29 | pytz
30 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/__init__.py:
--------------------------------------------------------------------------------
1 | import glob
2 | from os.path import dirname, isfile
3 |
4 |
5 | def __list_all_modules():
6 | work_dir = dirname(__file__)
7 | mod_paths = glob.glob(work_dir + "/*/*.py")
8 |
9 | all_modules = [
10 | (((f.replace(work_dir, "")).replace("/", "."))[:-3])
11 | for f in mod_paths
12 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py")
13 | ]
14 |
15 | return all_modules
16 |
17 |
18 | ALL_MODULES = sorted(__list_all_modules())
19 | __all__ = ALL_MODULES + ["ALL_MODULES"]
20 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/extraction.py:
--------------------------------------------------------------------------------
1 | from pyrogram.enums import MessageEntityType
2 | from pyrogram.types import Message, User
3 |
4 | from DeadlineTech import app
5 |
6 |
7 | async def extract_user(m: Message) -> User:
8 | if m.reply_to_message:
9 | return m.reply_to_message.from_user
10 | msg_entities = m.entities[1] if m.text.startswith("/") else m.entities[0]
11 | return await app.get_users(
12 | msg_entities.user.id
13 | if msg_entities.type == MessageEntityType.TEXT_MENTION
14 | else int(m.command[1])
15 | if m.command[1].isdecimal()
16 | else m.command[1]
17 | )
18 |
--------------------------------------------------------------------------------
/DeadlineTech/logging.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 | import logging
3 |
4 | logging.basicConfig(
5 | level=logging.INFO,
6 | format="[%(asctime)s - %(levelname)s] - %(name)s - %(message)s",
7 | datefmt="%d-%b-%y %H:%M:%S",
8 | handlers=[
9 | logging.FileHandler("log.txt"),
10 | logging.StreamHandler(),
11 | ],
12 | )
13 |
14 | logging.getLogger("httpx").setLevel(logging.ERROR)
15 | logging.getLogger("pyrogram").setLevel(logging.ERROR)
16 | logging.getLogger("pytgcalls").setLevel(logging.ERROR)
17 |
18 |
19 | def LOGGER(name: str) -> logging.Logger:
20 | return logging.getLogger(name)
21 |
--------------------------------------------------------------------------------
/DeadlineTech/__init__.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 | from DeadlineTech.core.bot import Anony
3 | from DeadlineTech.core.dir import dirr
4 | from DeadlineTech.core.git import git
5 | from DeadlineTech.core.userbot import Userbot
6 | from DeadlineTech.misc import dbb, heroku
7 |
8 | from .logging import LOGGER
9 |
10 | dirr()
11 | git()
12 | dbb()
13 | heroku()
14 |
15 | app = Anony()
16 | userbot = Userbot()
17 |
18 |
19 | from .platforms import *
20 |
21 | Apple = AppleAPI()
22 | Carbon = CarbonAPI()
23 | SoundCloud = SoundAPI()
24 | Spotify = SpotifyAPI()
25 | Resso = RessoAPI()
26 | Telegram = TeleAPI()
27 | YouTube = YouTubeAPI()
28 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/pastebin.py:
--------------------------------------------------------------------------------
1 | import aiohttp
2 |
3 | BASE = "https://batbin.me/"
4 |
5 |
6 | async def post(url: str, *args, **kwargs):
7 | async with aiohttp.ClientSession() as session:
8 | async with session.post(url, *args, **kwargs) as resp:
9 | try:
10 | data = await resp.json()
11 | except Exception:
12 | data = await resp.text()
13 | return data
14 |
15 |
16 | async def AnonyBin(text):
17 | resp = await post(f"{BASE}api/v2/paste", data=text)
18 | if not resp["success"]:
19 | return
20 | link = BASE + resp["message"]
21 | return link
22 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/channelplay.py:
--------------------------------------------------------------------------------
1 | from DeadlineTech import app
2 | from DeadlineTech.utils.database import get_cmode
3 |
4 |
5 | async def get_channeplayCB(_, command, CallbackQuery):
6 | if command == "c":
7 | chat_id = await get_cmode(CallbackQuery.message.chat.id)
8 | if chat_id is None:
9 | try:
10 | return await CallbackQuery.answer(_["setting_7"], show_alert=True)
11 | except:
12 | return
13 | try:
14 | channel = (await app.get_chat(chat_id)).title
15 | except:
16 | try:
17 | return await CallbackQuery.answer(_["cplay_4"], show_alert=True)
18 | except:
19 | return
20 | else:
21 | chat_id = CallbackQuery.message.chat.id
22 | channel = None
23 | return chat_id, channel
24 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/misc/seeker.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | import asyncio
4 |
5 | from DeadlineTech.misc import db
6 | from DeadlineTech.utils.database import get_active_chats, is_music_playing
7 |
8 |
9 | async def timer():
10 | while not await asyncio.sleep(1):
11 | active_chats = await get_active_chats()
12 | for chat_id in active_chats:
13 | if not await is_music_playing(chat_id):
14 | continue
15 | playing = db.get(chat_id)
16 | if not playing:
17 | continue
18 | duration = int(playing[0]["seconds"])
19 | if duration == 0:
20 | continue
21 | if db[chat_id][0]["played"] >= duration:
22 | continue
23 | db[chat_id][0]["played"] += 1
24 |
25 |
26 | asyncio.create_task(timer())
27 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/stop.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.core.call import Anony
8 | from DeadlineTech.utils.database import set_loop
9 | from DeadlineTech.utils.decorators import AdminRightsCheck
10 | from DeadlineTech.utils.inline import close_markup
11 | from config import BANNED_USERS
12 |
13 |
14 | @app.on_message(
15 | filters.command(["end", "stop", "cend", "cstop"]) & filters.group & ~BANNED_USERS
16 | )
17 | @AdminRightsCheck
18 | async def stop_music(cli, message: Message, _, chat_id):
19 | if not len(message.command) == 1:
20 | return
21 | await Anony.stop_stream(chat_id)
22 | await set_loop(chat_id, 0)
23 | await message.reply_text(
24 | _["admin_5"].format(message.from_user.mention), reply_markup=close_markup(_)
25 | )
26 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/resume.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.core.call import Anony
8 | from DeadlineTech.utils.database import is_music_playing, music_on
9 | from DeadlineTech.utils.decorators import AdminRightsCheck
10 | from DeadlineTech.utils.inline import close_markup
11 | from config import BANNED_USERS
12 |
13 |
14 | @app.on_message(filters.command(["resume", "cresume"]) & filters.group & ~BANNED_USERS)
15 | @AdminRightsCheck
16 | async def resume_com(cli, message: Message, _, chat_id):
17 | if await is_music_playing(chat_id):
18 | return await message.reply_text(_["admin_3"])
19 | await music_on(chat_id)
20 | await Anony.resume_stream(chat_id)
21 | await message.reply_text(
22 | _["admin_4"].format(message.from_user.mention), reply_markup=close_markup(_)
23 | )
24 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/pause.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.core.call import Anony
8 | from DeadlineTech.utils.database import is_music_playing, music_off
9 | from DeadlineTech.utils.decorators import AdminRightsCheck
10 | from DeadlineTech.utils.inline import close_markup
11 | from config import BANNED_USERS
12 |
13 |
14 | @app.on_message(filters.command(["pause", "cpause"]) & filters.group & ~BANNED_USERS)
15 | @AdminRightsCheck
16 | async def pause_admin(cli, message: Message, _, chat_id):
17 | if not await is_music_playing(chat_id):
18 | return await message.reply_text(_["admin_1"])
19 | await music_off(chat_id)
20 | await Anony.pause_stream(chat_id)
21 | await message.reply_text(
22 | _["admin_2"].format(message.from_user.mention), reply_markup=close_markup(_)
23 | )
24 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/extras.py:
--------------------------------------------------------------------------------
1 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
2 |
3 | from config import SUPPORT_CHAT
4 |
5 |
6 | def botplaylist_markup(_):
7 | buttons = [
8 | [
9 | InlineKeyboardButton(text=_["S_B_9"], url=SUPPORT_CHAT),
10 | InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data="close"),
11 | ],
12 | ]
13 | return buttons
14 |
15 |
16 | def close_markup(_):
17 | upl = InlineKeyboardMarkup(
18 | [
19 | [
20 | InlineKeyboardButton(
21 | text=_["CLOSE_BUTTON"],
22 | callback_data="close",
23 | ),
24 | ]
25 | ]
26 | )
27 | return upl
28 |
29 |
30 | def supp_markup(_):
31 | upl = InlineKeyboardMarkup(
32 | [
33 | [
34 | InlineKeyboardButton(
35 | text=_["S_B_9"],
36 | url=SUPPORT_CHAT,
37 | ),
38 | ]
39 | ]
40 | )
41 | return upl
42 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/ping.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.core.call import Anony
8 | from DeadlineTech.utils import bot_sys_stats
9 | from DeadlineTech.utils.decorators.language import language
10 | from DeadlineTech.utils.inline import supp_markup
11 | from config import BANNED_USERS, PING_IMG_URL
12 |
13 |
14 | @app.on_message(filters.command(["ping", "alive"]) & ~BANNED_USERS)
15 | @language
16 | async def ping_com(client, message: Message, _):
17 | start = datetime.now()
18 | response = await message.reply_photo(
19 | photo=PING_IMG_URL,
20 | caption=_["ping_1"].format(app.mention),
21 | )
22 | pytgping = await Anony.ping()
23 | UP, CPU, RAM, DISK = await bot_sys_stats()
24 | resp = (datetime.now() - start).microseconds / 1000
25 | await response.edit_text(
26 | _["ping_2"].format(resp, app.mention, UP, RAM, CPU, DISK, pytgping),
27 | reply_markup=supp_markup(_),
28 | )
29 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/logger.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters
2 |
3 | from DeadlineTech import app
4 | from DeadlineTech.misc import SUDOERS
5 | from DeadlineTech.utils.database import add_off, add_on
6 | from DeadlineTech.utils.decorators.language import language
7 |
8 |
9 | @app.on_message(filters.command(["logger"]) & SUDOERS)
10 | @language
11 | async def logger(client, message, _):
12 | usage = _["log_1"]
13 | if len(message.command) != 2:
14 | return await message.reply_text(usage)
15 | state = message.text.split(None, 1)[1].strip().lower()
16 | if state == "enable":
17 | await add_on(2)
18 | await message.reply_text(_["log_2"])
19 | elif state == "disable":
20 | await add_off(2)
21 | await message.reply_text(_["log_3"])
22 | else:
23 | await message.reply_text(usage)
24 |
25 | @app.on_message(filters.command(["cookies"]) & SUDOERS)
26 | @language
27 | async def logger(client, message, _):
28 | await message.reply_document("cookies/logs.csv")
29 | await message.reply_text("Please check given file to cookies file choosing logs...")
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Team Arc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/strings/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import List
3 |
4 | import yaml
5 |
6 | languages = {}
7 | languages_present = {}
8 |
9 |
10 | def get_string(lang: str):
11 | return languages[lang]
12 |
13 |
14 | for filename in os.listdir(r"./strings/langs/"):
15 | if "en" not in languages:
16 | languages["en"] = yaml.safe_load(
17 | open(r"./strings/langs/en.yml", encoding="utf8")
18 | )
19 | languages_present["en"] = languages["en"]["name"]
20 | if filename.endswith(".yml"):
21 | language_name = filename[:-4]
22 | if language_name == "en":
23 | continue
24 | languages[language_name] = yaml.safe_load(
25 | open(r"./strings/langs/" + filename, encoding="utf8")
26 | )
27 | for item in languages["en"]:
28 | if item not in languages[language_name]:
29 | languages[language_name][item] = languages["en"][item]
30 | try:
31 | languages_present[language_name] = languages[language_name]["name"]
32 | except:
33 | print("There is some issue with the language file inside bot.")
34 | exit()
35 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/shuffle.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | import random
4 |
5 | from pyrogram import filters
6 | from pyrogram.types import Message
7 |
8 | from DeadlineTech import app
9 | from DeadlineTech.misc import db
10 | from DeadlineTech.utils.decorators import AdminRightsCheck
11 | from DeadlineTech.utils.inline import close_markup
12 | from config import BANNED_USERS
13 |
14 |
15 | @app.on_message(
16 | filters.command(["shuffle", "cshuffle"]) & filters.group & ~BANNED_USERS
17 | )
18 | @AdminRightsCheck
19 | async def admins(Client, message: Message, _, chat_id):
20 | check = db.get(chat_id)
21 | if not check:
22 | return await message.reply_text(_["queue_2"])
23 | try:
24 | popped = check.pop(0)
25 | except:
26 | return await message.reply_text(_["admin_15"], reply_markup=close_markup(_))
27 | check = db.get(chat_id)
28 | if not check:
29 | check.insert(0, popped)
30 | return await message.reply_text(_["admin_15"], reply_markup=close_markup(_))
31 | random.shuffle(check)
32 | check.insert(0, popped)
33 | await message.reply_text(
34 | _["admin_16"].format(message.from_user.mention), reply_markup=close_markup(_)
35 | )
36 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/logger.py:
--------------------------------------------------------------------------------
1 | from pyrogram.enums import ParseMode
2 |
3 | from DeadlineTech import app
4 | from DeadlineTech.utils.database import is_on_off
5 | from config import LOGGER_ID
6 |
7 |
8 | async def play_logs(message, streamtype):
9 | if await is_on_off(2):
10 | logger_text = f"""
11 | ✨ {app.mention} 𝗉𝗅𝖺𝗒 𝗅𝗈𝗀
12 | ───────────────────────
13 |
14 | 🆔 𝖢𝗁𝖺𝗍 𝖨𝖣: {message.chat.id}
15 | 🏷️ 𝖢𝗁𝖺𝗍 𝖭𝖺𝗆𝖾: {message.chat.title}
16 | 🔗 𝖢𝗁𝖺𝗍 𝖴𝗌𝖾𝗋𝗇𝖺𝗆𝖾: @{message.chat.username}
17 |
18 | 👤 𝖴𝗌𝖾𝗋 𝖨𝖣: {message.from_user.id}
19 | 🙋♂️ 𝖭𝖺𝗆𝖾: {message.from_user.mention}
20 | 🌐 𝖴𝗌𝖾𝗋𝗇𝖺𝗆𝖾: @{message.from_user.username}
21 |
22 | ❓ 𝗊𝗎𝖾𝗋𝗒: {message.text.split(None, 1)[1]}
23 | 🎧 𝗌𝗍𝗋𝖾𝖺𝗆 𝗍𝗒𝗉𝖾: {streamtype}
24 | ───────────────────────
25 | """
26 | if message.chat.id != LOGGER_ID:
27 | try:
28 | await app.send_message(
29 | chat_id=LOGGER_ID,
30 | text=logger_text,
31 | parse_mode=ParseMode.HTML,
32 | disable_web_page_preview=True,
33 | )
34 | except:
35 | pass
36 | return
37 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/play/playmode.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import InlineKeyboardMarkup, Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.utils.database import get_playmode, get_playtype, is_nonadmin_chat
8 | from DeadlineTech.utils.decorators import language
9 | from DeadlineTech.utils.inline.settings import playmode_users_markup
10 | from config import BANNED_USERS
11 |
12 |
13 | @app.on_message(filters.command(["playmode", "mode"]) & filters.group & ~BANNED_USERS)
14 | @language
15 | async def playmode_(client, message: Message, _):
16 | playmode = await get_playmode(message.chat.id)
17 | if playmode == "Direct":
18 | Direct = True
19 | else:
20 | Direct = None
21 | is_non_admin = await is_nonadmin_chat(message.chat.id)
22 | if not is_non_admin:
23 | Group = True
24 | else:
25 | Group = None
26 | playty = await get_playtype(message.chat.id)
27 | if playty == "Everyone":
28 | Playtype = None
29 | else:
30 | Playtype = True
31 | buttons = playmode_users_markup(_, Direct, Group, Playtype)
32 | response = await message.reply_text(
33 | _["play_22"].format(message.chat.title),
34 | reply_markup=InlineKeyboardMarkup(buttons),
35 | )
36 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/speed.py:
--------------------------------------------------------------------------------
1 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
2 |
3 |
4 | def speed_markup(_, chat_id):
5 | upl = InlineKeyboardMarkup(
6 | [
7 | [
8 | InlineKeyboardButton(
9 | text="🕒 0.5x",
10 | callback_data=f"SpeedUP {chat_id}|0.5",
11 | ),
12 | InlineKeyboardButton(
13 | text="🕓 0.75x",
14 | callback_data=f"SpeedUP {chat_id}|0.75",
15 | ),
16 | ],
17 | [
18 | InlineKeyboardButton(
19 | text=_["P_B_4"],
20 | callback_data=f"SpeedUP {chat_id}|1.0",
21 | ),
22 | ],
23 | [
24 | InlineKeyboardButton(
25 | text="🕤 1.5x",
26 | callback_data=f"SpeedUP {chat_id}|1.5",
27 | ),
28 | InlineKeyboardButton(
29 | text="🕛 2.0x",
30 | callback_data=f"SpeedUP {chat_id}|2.0",
31 | ),
32 | ],
33 | [
34 | InlineKeyboardButton(
35 | text=_["CLOSE_BUTTON"],
36 | callback_data="close",
37 | ),
38 | ],
39 | ]
40 | )
41 | return upl
42 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/maintenance.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters
2 | from pyrogram.types import Message
3 |
4 | from DeadlineTech import app
5 | from DeadlineTech.misc import SUDOERS
6 | from DeadlineTech.utils.database import (
7 | get_lang,
8 | is_maintenance,
9 | maintenance_off,
10 | maintenance_on,
11 | )
12 | from strings import get_string
13 |
14 |
15 | @app.on_message(filters.command(["maintenance"]) & SUDOERS)
16 | async def maintenance(client, message: Message):
17 | try:
18 | language = await get_lang(message.chat.id)
19 | _ = get_string(language)
20 | except:
21 | _ = get_string("en")
22 | usage = _["maint_1"]
23 | if len(message.command) != 2:
24 | return await message.reply_text(usage)
25 | state = message.text.split(None, 1)[1].strip().lower()
26 | if state == "enable":
27 | if await is_maintenance() is False:
28 | await message.reply_text(_["maint_4"])
29 | else:
30 | await maintenance_on()
31 | await message.reply_text(_["maint_2"].format(app.mention))
32 | elif state == "disable":
33 | if await is_maintenance() is False:
34 | await maintenance_off()
35 | await message.reply_text(_["maint_3"].format(app.mention))
36 | else:
37 | await message.reply_text(_["maint_5"])
38 | else:
39 | await message.reply_text(usage)
40 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/crash_reporter.py:
--------------------------------------------------------------------------------
1 | # Powered By DeadlineTech
2 |
3 | import asyncio
4 | from traceback import format_exc
5 | from pyrogram.errors import RPCError
6 |
7 | from DeadlineTech import app
8 | from config import LOGGER_ID # Logger group ID
9 |
10 | async def notify_logger_about_crash(error: Exception):
11 | error_text = (
12 | "🚨 Bot Crash Alert\n\n"
13 | f"Error: {str(error)}\n\n"
14 | f"Traceback:\n
{format_exc()}"
15 | )
16 | try:
17 | await app.send_message(
18 | chat_id=LOGGER_ID,
19 | text=error_text,
20 | disable_web_page_preview=True
21 | )
22 | except RPCError:
23 | pass
24 |
25 | def logger_alert_on_crash(func):
26 | async def wrapper(client, *args, **kwargs):
27 | try:
28 | return await func(client, *args, **kwargs)
29 | except Exception as e:
30 | await notify_logger_about_crash(e)
31 | raise # Optional: re-raise for higher-level logging if needed
32 | return wrapper
33 |
34 | def setup_global_exception_handler():
35 | loop = asyncio.get_event_loop()
36 |
37 | def handle_exception(loop, context):
38 | error = context.get("exception")
39 | if error:
40 | asyncio.create_task(notify_logger_about_crash(error))
41 |
42 | loop.set_exception_handler(handle_exception)
43 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/stats.py:
--------------------------------------------------------------------------------
1 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
2 |
3 |
4 | def stats_buttons(_, status):
5 | not_sudo = [
6 | InlineKeyboardButton(
7 | text=_["SA_B_1"],
8 | callback_data="TopOverall",
9 | )
10 | ]
11 | sudo = [
12 | InlineKeyboardButton(
13 | text=_["SA_B_2"],
14 | callback_data="bot_stats_sudo",
15 | ),
16 | InlineKeyboardButton(
17 | text=_["SA_B_3"],
18 | callback_data="TopOverall",
19 | ),
20 | ]
21 | upl = InlineKeyboardMarkup(
22 | [
23 | sudo if status else not_sudo,
24 | [
25 | InlineKeyboardButton(
26 | text=_["CLOSE_BUTTON"],
27 | callback_data="close",
28 | ),
29 | ],
30 | ]
31 | )
32 | return upl
33 |
34 |
35 | def back_stats_buttons(_):
36 | upl = InlineKeyboardMarkup(
37 | [
38 | [
39 | InlineKeyboardButton(
40 | text=_["BACK_BUTTON"],
41 | callback_data="stats_back",
42 | ),
43 | InlineKeyboardButton(
44 | text=_["CLOSE_BUTTON"],
45 | callback_data="close",
46 | ),
47 | ],
48 | ]
49 | )
50 | return upl
51 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/start.py:
--------------------------------------------------------------------------------
1 | from pyrogram.types import InlineKeyboardButton, WebAppInfo
2 | import config
3 | from DeadlineTech import app
4 |
5 | def start_panel(_):
6 | buttons = [
7 | [
8 | InlineKeyboardButton(
9 | text=_["S_B_1"],
10 | url=f"https://t.me/{app.username}?startgroup=true"
11 | ),
12 | InlineKeyboardButton(text=_["S_B_2"], url=config.SUPPORT_CHAT)
13 | ],
14 | [
15 | InlineKeyboardButton(
16 | text=_["S_B_5"],
17 | url="https://github.com/DeadlineTech/music"
18 | )
19 | ]
20 | ]
21 | return buttons
22 |
23 |
24 | def private_panel(_):
25 | buttons = [
26 | [
27 | InlineKeyboardButton(
28 | text=_["S_B_3"],
29 | url=f"https://t.me/{app.username}?startgroup=true"
30 | )
31 | ],
32 | [
33 |
34 | InlineKeyboardButton(text=_["S_B_4"], callback_data="settings_back_helper")
35 | ],
36 |
37 | [
38 | InlineKeyboardButton(text=_["S_B_10"], user_id=config.OWNER_ID),
39 | InlineKeyboardButton(text=_["S_B_9"], url=config.SUPPORT_CHAT)
40 |
41 | ],
42 | [
43 | InlineKeyboardButton(text=_["S_B_7"], url=config.SUPPORT_CHANNEL),
44 | InlineKeyboardButton(text=_["S_B_5"], url="https://github.com/DeadlineTech/music")
45 | ]
46 | ]
47 | return buttons
48 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/bot/privacy.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import Client, filters
4 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
5 | from pyrogram.enums import ParseMode
6 |
7 | from DeadlineTech import app
8 | import config
9 |
10 |
11 | TEXT = f"""
12 | 🔒 **Privacy Policy for {app.mention}**
13 |
14 | We value your privacy and are committed to protecting your personal information when you use our Telegram voice chat player bot.
15 |
16 | **What Data We Collect:**
17 | We do **not** collect or store any personal data such as your name, phone number, messages, or media.
18 |
19 | **How We Use Your Data:**
20 | Your interaction (like commands or voice activity) remains confidential and is only used to provide requested services.
21 |
22 | **Data Sharing and Selling:**
23 | We do **not** share, sell, or distribute any information. Your data remains completely private.
24 |
25 | **Security Measures:**
26 | Our bot operates under Telegram’s secure infrastructure, with no external data logging.
27 |
28 | **Your Control:**
29 | You're free to remove the bot or revoke access anytime.
30 |
31 | **Updates to this Policy:**
32 | This policy may be updated. We recommend reviewing it periodically.
33 |
34 | 📎 **Full Privacy Document**: [View Here](https://telegra.ph/Privacy-Policy-Bot-Hub-12-18-2)
35 |
36 | ---
37 |
38 | 🤖 Powered with ❤️ by **Team DeadlineTech** – committed to open, safe, and secure bot experiences.
39 | """
40 |
41 | # 📍 Privacy Command Handler
42 | @app.on_message(filters.command("privacy"))
43 | async def privacy(client, message: Message):
44 |
45 | # 💬 Reply with UI and text
46 | await message.reply_text(
47 | TEXT,
48 | parse_mode=ParseMode.MARKDOWN,
49 | disable_web_page_preview=True
50 | )
51 |
--------------------------------------------------------------------------------
/DeadlineTech/core/mongo.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 |
27 | from motor.motor_asyncio import AsyncIOMotorClient
28 |
29 | from config import MONGO_DB_URI
30 |
31 | from ..logging import LOGGER
32 |
33 | LOGGER(__name__).info("⏳ Establishing a secure link to your MongoDB database...")
34 | try:
35 | _mongo_async_ = AsyncIOMotorClient(MONGO_DB_URI)
36 | mongodb = _mongo_async_.deadline
37 | LOGGER(__name__).info("✅ Successfully connected to MongoDB. All systems are ready!")
38 | except:
39 | LOGGER(__name__).error("❌ MongoDB connection failed!")
40 | exit()
41 |
--------------------------------------------------------------------------------
/DeadlineTech/core/dir.py:
--------------------------------------------------------------------------------
1 | # ==========================================================
2 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
3 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
4 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
5 | #
6 | # This file is part of a publicly available and open-source Telegram music bot
7 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
8 | # chats using YouTube as a source, supported by session-based assistant accounts and
9 | # YouTube cookie integration for improved access and performance.
10 | #
11 | # 💡 This source code is released for educational and community purposes. You're free
12 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
13 | # removal of credits, or false ownership claims will be considered a violation of our
14 | # community standards and may lead to denial of support or blacklisting.
15 | #
16 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
17 | # premium API service: https://DeadlineTech.site
18 | #
19 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
20 | # ==========================================================
21 |
22 |
23 | import os
24 |
25 | from ..logging import LOGGER
26 |
27 |
28 | def dirr():
29 | for file in os.listdir():
30 | if file.endswith(".jpg"):
31 | os.remove(file)
32 | elif file.endswith(".jpeg"):
33 | os.remove(file)
34 | elif file.endswith(".png"):
35 | os.remove(file)
36 |
37 | if "downloads" not in os.listdir():
38 | os.mkdir("downloads")
39 | if "cache" not in os.listdir():
40 | os.mkdir("cache")
41 |
42 | LOGGER(__name__).info("✔ Directory structure successfully updated.")
43 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/loop.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.utils.database import get_loop, set_loop
8 | from DeadlineTech.utils.decorators import AdminRightsCheck
9 | from DeadlineTech.utils.inline import close_markup
10 | from config import BANNED_USERS
11 |
12 |
13 | @app.on_message(filters.command(["loop", "cloop"]) & filters.group & ~BANNED_USERS)
14 | @AdminRightsCheck
15 | async def admins(cli, message: Message, _, chat_id):
16 | usage = _["admin_17"]
17 | if len(message.command) != 2:
18 | return await message.reply_text(usage)
19 | state = message.text.split(None, 1)[1].strip()
20 | if state.isnumeric():
21 | state = int(state)
22 | if 1 <= state <= 10:
23 | got = await get_loop(chat_id)
24 | if got != 0:
25 | state = got + state
26 | if int(state) > 10:
27 | state = 10
28 | await set_loop(chat_id, state)
29 | return await message.reply_text(
30 | text=_["admin_18"].format(state, message.from_user.mention),
31 | reply_markup=close_markup(_),
32 | )
33 | else:
34 | return await message.reply_text(_["admin_17"])
35 | elif state.lower() == "enable":
36 | await set_loop(chat_id, 10)
37 | return await message.reply_text(
38 | text=_["admin_18"].format(state, message.from_user.mention),
39 | reply_markup=close_markup(_),
40 | )
41 | elif state.lower() == "disable":
42 | await set_loop(chat_id, 0)
43 | return await message.reply_text(
44 | _["admin_19"].format(message.from_user.mention),
45 | reply_markup=close_markup(_),
46 | )
47 | else:
48 | return await message.reply_text(usage)
49 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inlinequery.py:
--------------------------------------------------------------------------------
1 | from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent
2 |
3 | answer = []
4 |
5 | answer.extend(
6 | [
7 | InlineQueryResultArticle(
8 | title="Pᴀᴜsᴇ",
9 | description=f"ᴩᴀᴜsᴇ ᴛʜᴇ ᴄᴜʀʀᴇɴᴛ ᴩʟᴀʏɪɴɢ sᴛʀᴇᴀᴍ ᴏɴ ᴠɪᴅᴇᴏᴄʜᴀᴛ.",
10 | thumb_url="https://telegra.ph/file/c5952790fa8235f499749.jpg",
11 | input_message_content=InputTextMessageContent("/pause"),
12 | ),
13 | InlineQueryResultArticle(
14 | title="Rᴇsᴜᴍᴇ",
15 | description=f"ʀᴇsᴜᴍᴇ ᴛʜᴇ ᴩᴀᴜsᴇᴅ sᴛʀᴇᴀᴍ ᴏɴ ᴠɪᴅᴇᴏᴄʜᴀᴛ.",
16 | thumb_url="https://telegra.ph/file/c5952790fa8235f499749.jpg",
17 | input_message_content=InputTextMessageContent("/resume"),
18 | ),
19 | InlineQueryResultArticle(
20 | title="Sᴋɪᴩ",
21 | description=f"sᴋɪᴩ ᴛʜᴇ ᴄᴜʀʀᴇɴᴛ ᴩʟᴀʏɪɴɢ sᴛʀᴇᴀᴍ ᴏɴ ᴠɪᴅᴇᴏᴄʜᴀᴛ ᴀɴᴅ ᴍᴏᴠᴇs ᴛᴏ ᴛʜᴇ ɴᴇxᴛ sᴛʀᴇᴀᴍ.",
22 | thumb_url="https://telegra.ph/file/c5952790fa8235f499749.jpg",
23 | input_message_content=InputTextMessageContent("/skip"),
24 | ),
25 | InlineQueryResultArticle(
26 | title="Eɴᴅ",
27 | description="ᴇɴᴅ ᴛʜᴇ ᴄᴜʀʀᴇɴᴛ ᴩʟᴀʏɪɴɢ sᴛʀᴇᴀᴍ ᴏɴ ᴠɪᴅᴇᴏᴄʜᴀᴛ.",
28 | thumb_url="https://telegra.ph/file/c5952790fa8235f499749.jpg",
29 | input_message_content=InputTextMessageContent("/end"),
30 | ),
31 | InlineQueryResultArticle(
32 | title="Sʜᴜғғʟᴇ",
33 | description="sʜᴜғғʟᴇ ᴛʜᴇ ǫᴜᴇᴜᴇᴅ sᴏɴɢs ɪɴ ᴩʟᴀʏʟɪsᴛ.",
34 | thumb_url="https://telegra.ph/file/c5952790fa8235f499749.jpg",
35 | input_message_content=InputTextMessageContent("/shuffle"),
36 | ),
37 | InlineQueryResultArticle(
38 | title="Lᴏᴏᴩ",
39 | description="ʟᴏᴏᴩ ᴛʜᴇ ᴄᴜʀʀᴇɴᴛ ᴩʟᴀʏɪɴɢ ᴛʀᴀᴄᴋ ᴏɴ ᴠɪᴅᴇᴏᴄʜᴀᴛ.",
40 | thumb_url="https://telegra.ph/file/c5952790fa8235f499749.jpg",
41 | input_message_content=InputTextMessageContent("/loop 3"),
42 | ),
43 | ]
44 | )
45 |
--------------------------------------------------------------------------------
/DeadlineTech/misc.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | import socket
4 | import time
5 |
6 | import heroku3
7 | from pyrogram import filters
8 |
9 | import config
10 | from DeadlineTech.core.mongo import mongodb
11 |
12 | from .logging import LOGGER
13 |
14 | SUDOERS = filters.user()
15 |
16 | HAPP = None
17 | _boot_ = time.time()
18 |
19 |
20 | def is_heroku():
21 | return "heroku" in socket.getfqdn()
22 |
23 |
24 | XCB = [
25 | "/",
26 | "@",
27 | ".",
28 | "com",
29 | ":",
30 | "git",
31 | "heroku",
32 | "push",
33 | str(config.HEROKU_API_KEY),
34 | "https",
35 | str(config.HEROKU_APP_NAME),
36 | "HEAD",
37 | "master",
38 | ]
39 |
40 |
41 | def dbb():
42 | global db
43 | db = {}
44 | LOGGER(__name__).info(f"🧺 Local database initialized successfully.")
45 |
46 |
47 | async def sudo():
48 | global SUDOERS
49 | SUDOERS.add(config.OWNER_ID)
50 | sudoersdb = mongodb.sudoers
51 | sudoers = await sudoersdb.find_one({"sudo": "sudo"})
52 | sudoers = [] if not sudoers else sudoers["sudoers"]
53 | if config.OWNER_ID not in sudoers:
54 | sudoers.append(config.OWNER_ID)
55 | await sudoersdb.update_one(
56 | {"sudo": "sudo"},
57 | {"$set": {"sudoers": sudoers}},
58 | upsert=True,
59 | )
60 | if sudoers:
61 | for user_id in sudoers:
62 | SUDOERS.add(user_id)
63 | LOGGER(__name__).info(f"💾 Sudoers have been set")
64 |
65 |
66 | def heroku():
67 | global HAPP
68 | if is_heroku:
69 | if config.HEROKU_API_KEY and config.HEROKU_APP_NAME:
70 | try:
71 | Heroku = heroku3.from_key(config.HEROKU_API_KEY)
72 | HAPP = Heroku.app(config.HEROKU_APP_NAME)
73 | LOGGER(__name__).info(f"Heroku App Configured")
74 | except BaseException:
75 | LOGGER(__name__).warning(
76 | f"Please make sure your Heroku API Key and Your App name are configured correctly in the heroku."
77 | )
78 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/speedtest.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import speedtest
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 | from DeadlineTech import app
6 | from DeadlineTech.misc import SUDOERS
7 | from DeadlineTech.utils.decorators.language import language
8 |
9 |
10 | def perform_speedtest():
11 | try:
12 | st = speedtest.Speedtest()
13 | st.get_best_server()
14 | st.download()
15 | st.upload()
16 | st.results.share()
17 | return st.results.dict()
18 | except Exception as e:
19 | return {"error": str(e)}
20 |
21 |
22 | @app.on_message(filters.command(["speedtest", "spt"]) & SUDOERS)
23 | @language
24 | async def speedtest_function(client, message: Message, _):
25 | status = await message.reply_text("⚡ Running SpeedTest...\nConnecting to best server...")
26 |
27 | loop = asyncio.get_event_loop()
28 | result = await loop.run_in_executor(None, perform_speedtest)
29 |
30 | if "error" in result:
31 | return await status.edit_text(f"❌ Speedtest failed\n{result['error']}")
32 |
33 | download_speed = round(result['download'] / 1_000_000, 2)
34 | upload_speed = round(result['upload'] / 1_000_000, 2)
35 |
36 | output = (
37 | "🌐 SpeedTest Results\n\n"
38 | f"🧑 ISP: {result['client']['isp']}\n"
39 | f"🌍 Country: {result['client']['country']}\n\n"
40 | f"🏢 Server: {result['server']['name']} ({result['server']['country']} - {result['server']['cc']})\n"
41 | f"🤝 Sponsor: {result['server']['sponsor']}\n"
42 | f"⏱ Latency: {round(result['server']['latency'], 2)} ms\n"
43 | f"📶 Ping: {result['ping']} ms\n\n"
44 | f"⬇️ Download: {download_speed} Mbps\n"
45 | f"⬆️ Upload: {upload_speed} Mbps\n"
46 | )
47 |
48 | try:
49 | await client.send_photo(message.chat.id, photo=result["share"], caption=output)
50 | except Exception:
51 | await status.edit_text(output)
52 | else:
53 | await status.delete()
54 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/play/channel.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.enums import ChatMembersFilter, ChatMemberStatus, ChatType
5 | from pyrogram.types import Message
6 |
7 | from DeadlineTech import app
8 | from DeadlineTech.utils.database import set_cmode
9 | from DeadlineTech.utils.decorators.admins import AdminActual
10 | from config import BANNED_USERS
11 |
12 |
13 | @app.on_message(filters.command(["channelplay"]) & filters.group & ~BANNED_USERS)
14 | @AdminActual
15 | async def playmode_(client, message: Message, _):
16 | if len(message.command) < 2:
17 | return await message.reply_text(_["cplay_1"].format(message.chat.title))
18 | query = message.text.split(None, 2)[1].lower().strip()
19 | if (str(query)).lower() == "disable":
20 | await set_cmode(message.chat.id, None)
21 | return await message.reply_text(_["cplay_7"])
22 | elif str(query) == "linked":
23 | chat = await app.get_chat(message.chat.id)
24 | if chat.linked_chat:
25 | chat_id = chat.linked_chat.id
26 | await set_cmode(message.chat.id, chat_id)
27 | return await message.reply_text(
28 | _["cplay_3"].format(chat.linked_chat.title, chat.linked_chat.id)
29 | )
30 | else:
31 | return await message.reply_text(_["cplay_2"])
32 | else:
33 | try:
34 | chat = await app.get_chat(query)
35 | except:
36 | return await message.reply_text(_["cplay_4"])
37 | if chat.type != ChatType.CHANNEL:
38 | return await message.reply_text(_["cplay_5"])
39 | try:
40 | async for user in app.get_chat_members(
41 | chat.id, filter=ChatMembersFilter.ADMINISTRATORS
42 | ):
43 | if user.status == ChatMemberStatus.OWNER:
44 | cusn = user.user.username
45 | crid = user.user.id
46 | except:
47 | return await message.reply_text(_["cplay_4"])
48 | if crid != message.from_user.id:
49 | return await message.reply_text(_["cplay_6"].format(chat.title, cusn))
50 | await set_cmode(message.chat.id, chat.id)
51 | return await message.reply_text(_["cplay_3"].format(chat.title, chat.id))
52 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/queue.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 |
3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
4 |
5 |
6 | def queue_markup(
7 | _,
8 | DURATION,
9 | CPLAY,
10 | videoid,
11 | played: Union[bool, int] = None,
12 | dur: Union[bool, int] = None,
13 | ):
14 | not_dur = [
15 | [
16 | InlineKeyboardButton(
17 | text=_["QU_B_1"],
18 | callback_data=f"GetQueued {CPLAY}|{videoid}",
19 | ),
20 | InlineKeyboardButton(
21 | text=_["CLOSE_BUTTON"],
22 | callback_data="close",
23 | ),
24 | ]
25 | ]
26 | dur = [
27 | [
28 | InlineKeyboardButton(
29 | text=_["QU_B_2"].format(played, dur),
30 | callback_data="GetTimer",
31 | )
32 | ],
33 | [
34 | InlineKeyboardButton(
35 | text=_["QU_B_1"],
36 | callback_data=f"GetQueued {CPLAY}|{videoid}",
37 | ),
38 | InlineKeyboardButton(
39 | text=_["CLOSE_BUTTON"],
40 | callback_data="close",
41 | ),
42 | ],
43 | ]
44 | upl = InlineKeyboardMarkup(not_dur if DURATION == "Unknown" else dur)
45 | return upl
46 |
47 |
48 | def queue_back_markup(_, CPLAY):
49 | upl = InlineKeyboardMarkup(
50 | [
51 | [
52 | InlineKeyboardButton(
53 | text=_["BACK_BUTTON"],
54 | callback_data=f"queue_back_timer {CPLAY}",
55 | ),
56 | InlineKeyboardButton(
57 | text=_["CLOSE_BUTTON"],
58 | callback_data="close",
59 | ),
60 | ]
61 | ]
62 | )
63 | return upl
64 |
65 |
66 | def aq_markup(_, chat_id):
67 | buttons = [
68 | [
69 | InlineKeyboardButton(text="▷", callback_data=f"ADMIN Resume|{chat_id}"),
70 | InlineKeyboardButton(text="II", callback_data=f"ADMIN Pause|{chat_id}"),
71 | InlineKeyboardButton(text="‣‣I", callback_data=f"ADMIN Skip|{chat_id}"),
72 | InlineKeyboardButton(text="▢", callback_data=f"ADMIN Stop|{chat_id}"),
73 | ],
74 | ]
75 | return buttons
76 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/crash_reporter.py:
--------------------------------------------------------------------------------
1 | # Powered by DeadlineTech
2 |
3 |
4 | import logging
5 | from pyrogram import Client, filters
6 | from DeadlineTech import app
7 | from pyrogram.types import Message, ChatMemberUpdated
8 | from pyrogram.enums import ChatMemberStatus
9 |
10 | # Setup logging
11 | logger = logging.getLogger(__name__)
12 | logging.basicConfig(level=logging.INFO)
13 |
14 |
15 | # ✅ Handle member joins, leaves, promotions, demotions
16 | @app.on_chat_member_updated()
17 | async def handle_member_update(client: Client, update: ChatMemberUpdated):
18 | user = update.from_user
19 | chat = update.chat
20 | old = update.old_chat_member
21 | new = update.new_chat_member
22 |
23 | # Safely handle cases where old/new is None
24 | if not old or not new:
25 | return
26 |
27 | if old.status != new.status:
28 | if new.status == ChatMemberStatus.MEMBER:
29 | logger.info(f"{user.id} joined {chat.id}")
30 | elif new.status == ChatMemberStatus.LEFT:
31 | logger.info(f"{user.id} left {chat.id}")
32 | elif new.status == ChatMemberStatus.ADMINISTRATOR:
33 | logger.info(f"{user.id} was promoted in {chat.id}")
34 | elif old.status == ChatMemberStatus.ADMINISTRATOR and new.status != ChatMemberStatus.ADMINISTRATOR:
35 | logger.info(f"{user.id} was demoted in {chat.id}")
36 |
37 |
38 | # ✅ Handle video chat started (includes voice chats)
39 | @app.on_message(filters.video_chat_started)
40 | async def video_chat_started_handler(client: Client, message: Message):
41 | chat = message.chat
42 | logger.info(f"Video chat started in {chat.id}")
43 |
44 |
45 | # ✅ Handle video chat ended
46 | @app.on_message(filters.video_chat_ended)
47 | async def video_chat_ended_handler(client: Client, message: Message):
48 | chat = message.chat
49 | logger.info(f" Video chat ended in {chat.id}")
50 |
51 |
52 | # ✅ Handle pinned messages
53 | @app.on_message(filters.pinned_message)
54 | async def pinned_message_handler(client: Client, message: Message):
55 | chat = message.chat
56 | pinned = message.pinned_message
57 |
58 | if pinned:
59 | logger.info(f"Message pinned in {chat.id} - Pinned Msg ID: {pinned.id}")
60 | else:
61 | logger.info(f"A message was pinned in {chat.id}, but content is not accessible.")
62 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/play/live.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 |
5 | from DeadlineTech import YouTube, app
6 | from DeadlineTech.utils.channelplay import get_channeplayCB
7 | from DeadlineTech.utils.decorators.language import languageCB
8 | from DeadlineTech.utils.stream.stream import stream
9 | from config import BANNED_USERS
10 |
11 |
12 | @app.on_callback_query(filters.regex("LiveStream") & ~BANNED_USERS)
13 | @languageCB
14 | async def play_live_stream(client, CallbackQuery, _):
15 | callback_data = CallbackQuery.data.strip()
16 | callback_request = callback_data.split(None, 1)[1]
17 | vidid, user_id, mode, cplay, fplay = callback_request.split("|")
18 | if CallbackQuery.from_user.id != int(user_id):
19 | try:
20 | return await CallbackQuery.answer(_["playcb_1"], show_alert=True)
21 | except:
22 | return
23 | try:
24 | chat_id, channel = await get_channeplayCB(_, cplay, CallbackQuery)
25 | except:
26 | return
27 | video = True if mode == "v" else None
28 | user_name = CallbackQuery.from_user.first_name
29 | await CallbackQuery.message.delete()
30 | try:
31 | await CallbackQuery.answer()
32 | except:
33 | pass
34 | mystic = await CallbackQuery.message.reply_text(
35 | _["play_2"].format(channel) if channel else _["play_1"]
36 | )
37 | try:
38 | details, track_id = await YouTube.track(vidid, True)
39 | except:
40 | return await mystic.edit_text(_["play_3"])
41 | ffplay = True if fplay == "f" else None
42 | if not details["duration_min"]:
43 | try:
44 | await stream(
45 | _,
46 | mystic,
47 | user_id,
48 | details,
49 | chat_id,
50 | user_name,
51 | CallbackQuery.message.chat.id,
52 | video,
53 | streamtype="live",
54 | forceplay=ffplay,
55 | )
56 | except Exception as e:
57 | ex_type = type(e).__name__
58 | err = e if ex_type == "AssistantErr" else _["general_2"].format(ex_type)
59 | return await mystic.edit_text(err)
60 | else:
61 | return await mystic.edit_text("» ɴᴏᴛ ᴀ ʟɪᴠᴇ sᴛʀᴇᴀᴍ.")
62 | await mystic.delete()
63 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/blchat.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.misc import SUDOERS
8 | from DeadlineTech.utils.database import blacklist_chat, blacklisted_chats, whitelist_chat
9 | from DeadlineTech.utils.decorators.language import language
10 | from config import BANNED_USERS
11 |
12 |
13 | @app.on_message(filters.command(["blchat", "blacklistchat"]) & SUDOERS)
14 | @language
15 | async def blacklist_chat_func(client, message: Message, _):
16 | if len(message.command) != 2:
17 | return await message.reply_text(_["black_1"])
18 | chat_id = int(message.text.strip().split()[1])
19 | if chat_id in await blacklisted_chats():
20 | return await message.reply_text(_["black_2"])
21 | blacklisted = await blacklist_chat(chat_id)
22 | if blacklisted:
23 | await message.reply_text(_["black_3"])
24 | else:
25 | await message.reply_text(_["black_9"])
26 | try:
27 | await app.leave_chat(chat_id)
28 | except:
29 | pass
30 |
31 |
32 | @app.on_message(
33 | filters.command(["whitelistchat", "unblacklistchat", "unblchat"]) & SUDOERS
34 | )
35 | @language
36 | async def white_funciton(client, message: Message, _):
37 | if len(message.command) != 2:
38 | return await message.reply_text(_["black_4"])
39 | chat_id = int(message.text.strip().split()[1])
40 | if chat_id not in await blacklisted_chats():
41 | return await message.reply_text(_["black_5"])
42 | whitelisted = await whitelist_chat(chat_id)
43 | if whitelisted:
44 | return await message.reply_text(_["black_6"])
45 | await message.reply_text(_["black_9"])
46 |
47 |
48 | @app.on_message(filters.command(["blchats", "blacklistedchats"]) & ~BANNED_USERS)
49 | @language
50 | async def all_chats(client, message: Message, _):
51 | text = _["black_7"]
52 | j = 0
53 | for count, chat_id in enumerate(await blacklisted_chats(), 1):
54 | try:
55 | title = (await app.get_chat(chat_id)).title
56 | except:
57 | title = "ᴘʀɪᴠᴀᴛᴇ ᴄʜᴀᴛ"
58 | j = 1
59 | text += f"{count}. {title}[{chat_id}]\n"
60 | if j == 0:
61 | await message.reply_text(_["black_8"].format(app.mention))
62 | else:
63 | await message.reply_text(text)
64 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/block.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.misc import SUDOERS
8 | from DeadlineTech.utils.database import add_gban_user, remove_gban_user
9 | from DeadlineTech.utils.decorators.language import language
10 | from DeadlineTech.utils.extraction import extract_user
11 | from config import BANNED_USERS
12 |
13 |
14 | @app.on_message(filters.command(["block"]) & SUDOERS)
15 | @language
16 | async def useradd(client, message: Message, _):
17 | if not message.reply_to_message:
18 | if len(message.command) != 2:
19 | return await message.reply_text(_["general_1"])
20 | user = await extract_user(message)
21 | if user.id in BANNED_USERS:
22 | return await message.reply_text(_["block_1"].format(user.mention))
23 | await add_gban_user(user.id)
24 | BANNED_USERS.add(user.id)
25 | await message.reply_text(_["block_2"].format(user.mention))
26 |
27 |
28 | @app.on_message(filters.command(["unblock"]) & SUDOERS)
29 | @language
30 | async def userdel(client, message: Message, _):
31 | if not message.reply_to_message:
32 | if len(message.command) != 2:
33 | return await message.reply_text(_["general_1"])
34 | user = await extract_user(message)
35 | if user.id not in BANNED_USERS:
36 | return await message.reply_text(_["block_3"].format(user.mention))
37 | await remove_gban_user(user.id)
38 | BANNED_USERS.remove(user.id)
39 | await message.reply_text(_["block_4"].format(user.mention))
40 |
41 |
42 | @app.on_message(filters.command(["blocked", "blockedusers", "blusers"]) & SUDOERS)
43 | @language
44 | async def sudoers_list(client, message: Message, _):
45 | if not BANNED_USERS:
46 | return await message.reply_text(_["block_5"])
47 | mystic = await message.reply_text(_["block_6"])
48 | msg = _["block_7"]
49 | count = 0
50 | for users in BANNED_USERS:
51 | try:
52 | user = await app.get_users(users)
53 | user = user.first_name if not user.mention else user.mention
54 | count += 1
55 | except:
56 | continue
57 | msg += f"{count}➤ {user}\n"
58 | if count == 0:
59 | return await mystic.edit_text(_["block_5"])
60 | else:
61 | return await mystic.edit_text(msg)
62 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/stream/queue.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from typing import Union
3 |
4 | from DeadlineTech.misc import db
5 | from DeadlineTech.utils.formatters import check_duration, seconds_to_min
6 | from config import autoclean, time_to_seconds
7 |
8 |
9 | async def put_queue(
10 | chat_id,
11 | original_chat_id,
12 | file,
13 | title,
14 | duration,
15 | user,
16 | vidid,
17 | user_id,
18 | stream,
19 | forceplay: Union[bool, str] = None,
20 | ):
21 | title = title.title()
22 | try:
23 | duration_in_seconds = time_to_seconds(duration) - 3
24 | except:
25 | duration_in_seconds = 0
26 | put = {
27 | "title": title,
28 | "dur": duration,
29 | "streamtype": stream,
30 | "by": user,
31 | "user_id": user_id,
32 | "chat_id": original_chat_id,
33 | "file": file,
34 | "vidid": vidid,
35 | "seconds": duration_in_seconds,
36 | "played": 0,
37 | }
38 | if forceplay:
39 | check = db.get(chat_id)
40 | if check:
41 | check.insert(0, put)
42 | else:
43 | db[chat_id] = []
44 | db[chat_id].append(put)
45 | else:
46 | db[chat_id].append(put)
47 | autoclean.append(file)
48 |
49 |
50 | async def put_queue_index(
51 | chat_id,
52 | original_chat_id,
53 | file,
54 | title,
55 | duration,
56 | user,
57 | vidid,
58 | stream,
59 | forceplay: Union[bool, str] = None,
60 | ):
61 | if "20.212.146.162" in vidid:
62 | try:
63 | dur = await asyncio.get_event_loop().run_in_executor(
64 | None, check_duration, vidid
65 | )
66 | duration = seconds_to_min(dur)
67 | except:
68 | duration = "ᴜʀʟ sᴛʀᴇᴀᴍ"
69 | dur = 0
70 | else:
71 | dur = 0
72 | put = {
73 | "title": title,
74 | "dur": duration,
75 | "streamtype": stream,
76 | "by": user,
77 | "chat_id": original_chat_id,
78 | "file": file,
79 | "vidid": vidid,
80 | "seconds": dur,
81 | "played": 0,
82 | }
83 | if forceplay:
84 | check = db.get(chat_id)
85 | if check:
86 | check.insert(0, put)
87 | else:
88 | db[chat_id] = []
89 | db[chat_id].append(put)
90 | else:
91 | db[chat_id].append(put)
92 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": " DeadlineTech Music",
3 | "description": "A Telegram Music Player Bot, written in Python with Pyrogram and Py-Tgcalls.",
4 | "logo": "https://files.catbox.moe/lxn8yz.jpg",
5 | "keywords": [
6 | "python3",
7 | "telegram",
8 | "bot",
9 | "DeadlineTech",
10 | "MusicBot",
11 | "telegram-bot",
12 | "pyrogram"
13 | ],
14 | "env": {
15 | "API_ID": {
16 | "description": "Get this value from https://my.telegram.org",
17 | "value": "",
18 | "required": true
19 | },
20 | "API_HASH": {
21 | "description": "Get this value from https://my.telegram.org",
22 | "value": "",
23 | "required": true
24 | },
25 | "BOT_TOKEN": {
26 | "description": "A Bot's token from Botfather",
27 | "value": "",
28 | "required": true
29 | },
30 | "MONGO_DB_URI": {
31 | "description": "Get a mongodb url from https://cloud.mongodb.com.",
32 | "value": "",
33 | "required": true
34 | },
35 | "OWNER_ID": {
36 | "description": "The user id of user whom you would like to add as OWNER.",
37 | "value": "",
38 | "required": true
39 | },
40 | "API_KEY": {
41 | "description": "Get your Music Api key from @ApixhubBot.",
42 | "value": "",
43 | "required": false
44 | },
45 | "STRING_SESSION": {
46 | "description": "A Pyrogram v2 String Session from @StringFatherBot on Telegram.",
47 | "value": "",
48 | "required": true
49 | },
50 | "HEROKU_API_KEY": {
51 | "description": "Your Heroku account's API key",
52 | "value": "",
53 | "required": false
54 | },
55 | "HEROKU_APP_NAME": {
56 | "description": "Your heroku app name",
57 | "value": "",
58 | "required": false
59 | },
60 | "LOGGER_ID": {
61 | "description": "Your Log Group ID, add your bot and promote as an admin with full rights!. Channel ki id mat daal dena bsdk.",
62 | "value": "",
63 | "required": true
64 | }
65 | },
66 | "buildpacks": [
67 | {
68 | "url": "heroku/python"
69 | },
70 | {
71 | "url": "heroku/nodejs"
72 | },
73 | {
74 | "url": "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git"
75 | }
76 | ],
77 | "stack": "container"
78 | }
79 |
--------------------------------------------------------------------------------
/DeadlineTech/platforms/Soundcloud.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 |
27 | from os import path
28 |
29 | from yt_dlp import YoutubeDL
30 |
31 | from DeadlineTech.utils.formatters import seconds_to_min
32 |
33 |
34 | class SoundAPI:
35 | def __init__(self):
36 | self.opts = {
37 | "outtmpl": "downloads/%(id)s.%(ext)s",
38 | "format": "best",
39 | "retries": 3,
40 | "nooverwrites": False,
41 | "continuedl": True,
42 | }
43 |
44 | async def valid(self, link: str):
45 | if "soundcloud" in link:
46 | return True
47 | else:
48 | return False
49 |
50 | async def download(self, url):
51 | d = YoutubeDL(self.opts)
52 | try:
53 | info = d.extract_info(url)
54 | except:
55 | return False
56 | xyz = path.join("downloads", f"{info['id']}.{info['ext']}")
57 | duration_min = seconds_to_min(info["duration"])
58 | track_details = {
59 | "title": info["title"],
60 | "duration_sec": info["duration"],
61 | "duration_min": duration_min,
62 | "uploader": info["uploader"],
63 | "filepath": xyz,
64 | }
65 | return track_details, xyz
66 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/bot/inline.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram.types import (
4 | InlineKeyboardButton,
5 | InlineKeyboardMarkup,
6 | InlineQueryResultPhoto,
7 | )
8 | from youtubesearchpython.__future__ import VideosSearch
9 |
10 | from DeadlineTech import app
11 | from DeadlineTech.utils.inlinequery import answer
12 | from config import BANNED_USERS
13 |
14 |
15 | @app.on_inline_query(~BANNED_USERS)
16 | async def inline_query_handler(client, query):
17 | text = query.query.strip().lower()
18 | answers = []
19 | if text.strip() == "":
20 | try:
21 | await client.answer_inline_query(query.id, results=answer, cache_time=10)
22 | except:
23 | return
24 | else:
25 | a = VideosSearch(text, limit=20)
26 | result = (await a.next()).get("result")
27 | for x in range(15):
28 | title = (result[x]["title"]).title()
29 | duration = result[x]["duration"]
30 | views = result[x]["viewCount"]["short"]
31 | thumbnail = result[x]["thumbnails"][0]["url"].split("?")[0]
32 | channellink = result[x]["channel"]["link"]
33 | channel = result[x]["channel"]["name"]
34 | link = result[x]["link"]
35 | published = result[x]["publishedTime"]
36 | description = f"{views} | {duration} ᴍɪɴᴜᴛᴇs | {channel} | {published}"
37 | buttons = InlineKeyboardMarkup(
38 | [
39 | [
40 | InlineKeyboardButton(
41 | text="ʏᴏᴜᴛᴜʙᴇ 🎄",
42 | url=link,
43 | )
44 | ],
45 | ]
46 | )
47 | searched_text = f"""
48 | ❄ ᴛɪᴛʟᴇ : {title}
49 |
50 | ⏳ ᴅᴜʀᴀᴛɪᴏɴ : {duration} ᴍɪɴᴜᴛᴇs
51 | 👀 ᴠɪᴇᴡs : {views}
52 | 🎥 ᴄʜᴀɴɴᴇʟ : {channel}
53 | ⏰ ᴘᴜʙʟɪsʜᴇᴅ ᴏɴ : {published}
54 |
55 |
56 | ➻ ɪɴʟɪɴᴇ sᴇᴀʀᴄʜ ᴍᴏᴅᴇ ʙʏ {app.name}"""
57 | answers.append(
58 | InlineQueryResultPhoto(
59 | photo_url=thumbnail,
60 | title=title,
61 | thumb_url=thumbnail,
62 | description=description,
63 | caption=searched_text,
64 | reply_markup=buttons,
65 | )
66 | )
67 | try:
68 | return await client.answer_inline_query(query.id, results=answers)
69 | except:
70 | return
71 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/language.py:
--------------------------------------------------------------------------------
1 | from pykeyboard import InlineKeyboard
2 | from pyrogram import filters
3 | from pyrogram.types import InlineKeyboardButton, Message
4 |
5 | from DeadlineTech import app
6 | from DeadlineTech.utils.database import get_lang, set_lang
7 | from DeadlineTech.utils.decorators import ActualAdminCB, language, languageCB
8 | from config import BANNED_USERS
9 | from strings import get_string, languages_present
10 |
11 |
12 | def lanuages_keyboard(_):
13 | keyboard = InlineKeyboard(row_width=2)
14 | keyboard.add(
15 | *[
16 | (
17 | InlineKeyboardButton(
18 | text=languages_present[i],
19 | callback_data=f"languages:{i}",
20 | )
21 | )
22 | for i in languages_present
23 | ]
24 | )
25 | keyboard.row(
26 | InlineKeyboardButton(
27 | text=_["BACK_BUTTON"],
28 | callback_data=f"settingsback_helper",
29 | ),
30 | InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data=f"close"),
31 | )
32 | return keyboard
33 |
34 |
35 | @app.on_message(filters.command(["lang", "setlang", "language"]) & ~BANNED_USERS)
36 | @language
37 | async def langs_command(client, message: Message, _):
38 | keyboard = lanuages_keyboard(_)
39 | await message.reply_text(
40 | _["lang_1"],
41 | reply_markup=keyboard,
42 | )
43 |
44 |
45 | @app.on_callback_query(filters.regex("LG") & ~BANNED_USERS)
46 | @languageCB
47 | async def lanuagecb(client, CallbackQuery, _):
48 | try:
49 | await CallbackQuery.answer()
50 | except:
51 | pass
52 | keyboard = lanuages_keyboard(_)
53 | return await CallbackQuery.edit_message_reply_markup(reply_markup=keyboard)
54 |
55 |
56 | @app.on_callback_query(filters.regex(r"languages:(.*?)") & ~BANNED_USERS)
57 | @ActualAdminCB
58 | async def language_markup(client, CallbackQuery, _):
59 | langauge = (CallbackQuery.data).split(":")[1]
60 | old = await get_lang(CallbackQuery.message.chat.id)
61 | if str(old) == str(langauge):
62 | return await CallbackQuery.answer(_["lang_4"], show_alert=True)
63 | try:
64 | _ = get_string(langauge)
65 | await CallbackQuery.answer(_["lang_2"], show_alert=True)
66 | except:
67 | _ = get_string(old)
68 | return await CallbackQuery.answer(
69 | _["lang_3"],
70 | show_alert=True,
71 | )
72 | await set_lang(CallbackQuery.message.chat.id, langauge)
73 | keyboard = lanuages_keyboard(_)
74 | return await CallbackQuery.edit_message_reply_markup(reply_markup=keyboard)
75 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/chatlog.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from pyrogram import Client, filters
3 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup
4 | from DeadlineTech import app
5 | from config import LOGGER_ID as JOINLOGS
6 |
7 | # Setup logging
8 | logger = logging.getLogger(__name__)
9 | logging.basicConfig(level=logging.INFO)
10 |
11 | # Cache the bot's ID at startup
12 | BOT_ID = None
13 |
14 |
15 | @app.on_message(filters.new_chat_members)
16 | async def on_new_chat_members(client: Client, message: Message):
17 | global BOT_ID
18 |
19 | try:
20 | if BOT_ID is None:
21 | bot_user = await client.get_me()
22 | BOT_ID = bot_user.id
23 | logger.info(f"Cached bot ID: {BOT_ID}")
24 | except Exception as e:
25 | logger.exception("Failed to get bot info")
26 | return # Early exit to prevent further failures
27 |
28 | for new_member in message.new_chat_members:
29 | if new_member.id == BOT_ID:
30 | try:
31 | added_by = (
32 | f"👤{message.from_user.first_name}"
33 | if message.from_user else "Unknown User"
34 | )
35 |
36 | chat_title = message.chat.title
37 | chat_id = message.chat.id
38 | chat_username = f"@{message.chat.username}" if message.chat.username else "Private Group"
39 | chat_link = (
40 | f"https://t.me/{message.chat.username}"
41 | if message.chat.username else None
42 | )
43 |
44 | log_text = (
45 | "🚀 Bot Added Successfully!\n\n"
46 | "╭───────⍟\n"
47 | f"├ 💬 Chat Name: {chat_title}\n"
48 | f"├ 🆔 Chat ID: {chat_id}\n"
49 | f"├ 🌐 Username: {chat_username}\n"
50 | f"└ 👤 Added By: {added_by}\n"
51 | "╰─────────────⍟"
52 | )
53 |
54 | buttons = [[InlineKeyboardButton("➤ Link 🔗", url=chat_link)]] if chat_link else None
55 |
56 | await client.send_message(
57 | JOINLOGS,
58 | text=log_text,
59 | reply_markup=InlineKeyboardMarkup(buttons) if buttons else None,
60 | disable_web_page_preview=True
61 | )
62 | logger.info(f"Join log sent for chat ID: {chat_id}")
63 | except Exception as e:
64 | logger.exception(f"[JOINLOG ERROR] Failed to send join log for chat ID: {message.chat.id}")
65 |
66 |
67 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/active.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from pyrogram import filters
3 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
4 | from datetime import datetime
5 | from zoneinfo import ZoneInfo
6 |
7 | from DeadlineTech import app
8 | from DeadlineTech.misc import SUDOERS
9 | from DeadlineTech.utils.database import (
10 | get_active_chats,
11 | get_active_video_chats,
12 | )
13 |
14 | # Setup logger
15 | logger = logging.getLogger(__name__)
16 | logging.basicConfig(level=logging.INFO)
17 |
18 | CALLS_CLOSE = "calls_close"
19 | TIMEZONE = "Asia/Kolkata"
20 |
21 |
22 | def get_current_time():
23 | try:
24 | now = datetime.now(ZoneInfo(TIMEZONE))
25 | return now.strftime("%d %b %Y • %I:%M %p")
26 | except Exception as e:
27 | logger.exception(f"Error getting current time: {e}")
28 | return "Unknown Time"
29 |
30 |
31 | def generate_summary_text(voice_count, video_count):
32 | total = voice_count + video_count
33 | return (
34 | "📊 Call Activity Summary\n"
35 | "━━━━━━━━━━━━━━━━━━━━━━\n"
36 | f"🔊 Voice Chats: {voice_count}\n"
37 | f"🎥 Video Chats: {video_count}\n"
38 | f"📞 Total: {total}\n"
39 | f"🕒 Updated: {get_current_time()}"
40 | )
41 |
42 |
43 | @app.on_message(filters.command(["activecalls", "acalls"]) & SUDOERS)
44 | async def active_calls(_, message: Message):
45 | try:
46 | voice_ids = await get_active_chats()
47 | video_ids = await get_active_video_chats()
48 | except Exception as e:
49 | logger.exception("Error fetching active chats or video chats.")
50 | return await message.reply_text("❌ Failed to fetch active calls. Check logs for details.")
51 |
52 | try:
53 | text = generate_summary_text(len(voice_ids), len(video_ids))
54 | button = InlineKeyboardMarkup(
55 | [[InlineKeyboardButton("✖ Close", callback_data=CALLS_CLOSE)]]
56 | )
57 | await message.reply_text(text, reply_markup=button)
58 | except Exception as e:
59 | logger.exception("Failed to send summary message.")
60 | await message.reply_text("❌ Error displaying call summary.")
61 |
62 |
63 | @app.on_callback_query(filters.regex(CALLS_CLOSE) & SUDOERS)
64 | async def close_calls(_, query: CallbackQuery):
65 | try:
66 | await query.message.delete()
67 | await query.answer("Closed!")
68 | except Exception as e:
69 | logger.exception("Failed to close the inline message.")
70 | try:
71 | await query.answer("❌ Couldn't close the message.", show_alert=True)
72 | except:
73 | pass
74 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/sudoers.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters
2 | from pyrogram.types import Message
3 |
4 | from DeadlineTech import app
5 | from DeadlineTech.misc import SUDOERS
6 | from DeadlineTech.utils.database import add_sudo, remove_sudo
7 | from DeadlineTech.utils.decorators.language import language
8 | from DeadlineTech.utils.extraction import extract_user
9 | from DeadlineTech.utils.inline import close_markup
10 | from config import BANNED_USERS, OWNER_ID
11 |
12 |
13 | @app.on_message(filters.command(["addsudo"]) & filters.user(OWNER_ID))
14 | @language
15 | async def useradd(client, message: Message, _):
16 | if not message.reply_to_message:
17 | if len(message.command) != 2:
18 | return await message.reply_text(_["general_1"])
19 | user = await extract_user(message)
20 | if user.id in SUDOERS:
21 | return await message.reply_text(_["sudo_1"].format(user.mention))
22 | added = await add_sudo(user.id)
23 | if added:
24 | SUDOERS.add(user.id)
25 | await message.reply_text(_["sudo_2"].format(user.mention))
26 | else:
27 | await message.reply_text(_["sudo_8"])
28 |
29 |
30 | @app.on_message(filters.command(["delsudo", "rmsudo"]) & filters.user(OWNER_ID))
31 | @language
32 | async def userdel(client, message: Message, _):
33 | if not message.reply_to_message:
34 | if len(message.command) != 2:
35 | return await message.reply_text(_["general_1"])
36 | user = await extract_user(message)
37 | if user.id not in SUDOERS:
38 | return await message.reply_text(_["sudo_3"].format(user.mention))
39 | removed = await remove_sudo(user.id)
40 | if removed:
41 | SUDOERS.remove(user.id)
42 | await message.reply_text(_["sudo_4"].format(user.mention))
43 | else:
44 | await message.reply_text(_["sudo_8"])
45 |
46 |
47 | @app.on_message(filters.command(["sudolist", "listsudo", "sudoers"]) & ~BANNED_USERS)
48 | @language
49 | async def sudoers_list(client, message: Message, _):
50 | text = _["sudo_5"]
51 | user = await app.get_users(OWNER_ID)
52 | user = user.first_name if not user.mention else user.mention
53 | text += f"1➤ {user}\n"
54 | count = 0
55 | smex = 0
56 | for user_id in SUDOERS:
57 | if user_id != OWNER_ID:
58 | try:
59 | user = await app.get_users(user_id)
60 | user = user.first_name if not user.mention else user.mention
61 | if smex == 0:
62 | smex += 1
63 | text += _["sudo_6"]
64 | count += 1
65 | text += f"{count}➤ {user}\n"
66 | except:
67 | continue
68 | if not text:
69 | await message.reply_text(_["sudo_7"])
70 | else:
71 | await message.reply_text(text, reply_markup=close_markup(_))
72 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/seek.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import YouTube, app
7 | from DeadlineTech.core.call import Anony
8 | from DeadlineTech.misc import db
9 | from DeadlineTech.utils import AdminRightsCheck, seconds_to_min
10 | from DeadlineTech.utils.inline import close_markup
11 | from config import BANNED_USERS
12 |
13 |
14 | @app.on_message(
15 | filters.command(["seek", "cseek", "seekback", "cseekback"])
16 | & filters.group
17 | & ~BANNED_USERS
18 | )
19 | @AdminRightsCheck
20 | async def seek_comm(cli, message: Message, _, chat_id):
21 | if len(message.command) == 1:
22 | return await message.reply_text(_["admin_20"])
23 | query = message.text.split(None, 1)[1].strip()
24 | if not query.isnumeric():
25 | return await message.reply_text(_["admin_21"])
26 | playing = db.get(chat_id)
27 | if not playing:
28 | return await message.reply_text(_["queue_2"])
29 | duration_seconds = int(playing[0]["seconds"])
30 | if duration_seconds == 0:
31 | return await message.reply_text(_["admin_22"])
32 | file_path = playing[0]["file"]
33 | duration_played = int(playing[0]["played"])
34 | duration_to_skip = int(query)
35 | duration = playing[0]["dur"]
36 | if message.command[0][-2] == "c":
37 | if (duration_played - duration_to_skip) <= 10:
38 | return await message.reply_text(
39 | text=_["admin_23"].format(seconds_to_min(duration_played), duration),
40 | reply_markup=close_markup(_),
41 | )
42 | to_seek = duration_played - duration_to_skip + 1
43 | else:
44 | if (duration_seconds - (duration_played + duration_to_skip)) <= 10:
45 | return await message.reply_text(
46 | text=_["admin_23"].format(seconds_to_min(duration_played), duration),
47 | reply_markup=close_markup(_),
48 | )
49 | to_seek = duration_played + duration_to_skip + 1
50 | mystic = await message.reply_text(_["admin_24"])
51 | if "vid_" in file_path:
52 | n, file_path = await YouTube.video(playing[0]["vidid"], True)
53 | if n == 0:
54 | return await message.reply_text(_["admin_22"])
55 | check = (playing[0]).get("speed_path")
56 | if check:
57 | file_path = check
58 | if "index_" in file_path:
59 | file_path = playing[0]["vidid"]
60 | try:
61 | await Anony.seek_stream(
62 | chat_id,
63 | file_path,
64 | seconds_to_min(to_seek),
65 | duration,
66 | playing[0]["streamtype"],
67 | )
68 | except:
69 | return await mystic.edit_text(_["admin_26"], reply_markup=close_markup(_))
70 | if message.command[0][-2] == "c":
71 | db[chat_id][0]["played"] -= duration_to_skip
72 | else:
73 | db[chat_id][0]["played"] += duration_to_skip
74 | await mystic.edit_text(
75 | text=_["admin_25"].format(seconds_to_min(to_seek), message.from_user.mention),
76 | reply_markup=close_markup(_),
77 | )
78 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/misc/auto_leave.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import logging
3 | from datetime import datetime, timedelta
4 | import pytz
5 |
6 | from pyrogram.enums import ChatType
7 |
8 | import config
9 | from DeadlineTech import app
10 | from DeadlineTech.utils.database import get_client, is_active_chat
11 |
12 | # Set up logging
13 | logging.basicConfig(
14 | level=logging.INFO,
15 | format="%(asctime)s - [%(levelname)s] - %(message)s",
16 | datefmt="%Y-%m-%d %H:%M:%S",
17 | )
18 | logger = logging.getLogger("AutoLeave")
19 |
20 | # Constants
21 | EXCLUDED_CHAT_IDS = {config.LOGGER_ID}
22 | MAX_LEAVES_PER_RUN = 120
23 | TIMEZONE = "Asia/Kolkata"
24 | TARGET_HOUR = 4
25 | TARGET_MINUTE = 35
26 |
27 | def seconds_until_target_time(hour: int = TARGET_HOUR, minute: int = TARGET_MINUTE) -> float:
28 | """Calculate seconds remaining until the next target time (default: 4:35 AM IST)."""
29 | tz = pytz.timezone(TIMEZONE)
30 | now = datetime.now(tz)
31 | target = now.replace(hour=hour, minute=minute, second=0, microsecond=0)
32 | if now >= target:
33 | target += timedelta(days=1)
34 | return (target - now).total_seconds()
35 |
36 | async def leave_inactive_chats(client, client_num: int):
37 | """Make the client leave inactive chats."""
38 | left_count = 0
39 | try:
40 | async for dialog in client.get_dialogs():
41 | chat = dialog.chat
42 | if chat.type in {ChatType.SUPERGROUP, ChatType.GROUP, ChatType.CHANNEL}:
43 | if chat.id in EXCLUDED_CHAT_IDS:
44 | continue
45 | if left_count >= MAX_LEAVES_PER_RUN:
46 | break
47 | if not await is_active_chat(chat.id):
48 | try:
49 | await client.leave_chat(chat.id)
50 | logger.info(f"{client.me.first_name} left inactive chat: {chat.title} ({chat.id})")
51 | left_count += 1
52 | except Exception as e:
53 | logger.warning(f"Failed to leave chat {chat.title} ({chat.id}): {e}")
54 | except Exception as e:
55 | logger.error(f"Assistant {client_num} failed to fetch dialogs: {e}")
56 |
57 | async def auto_leave():
58 | """Run auto leave job daily at 4:35 AM IST."""
59 | if not config.AUTO_LEAVING_ASSISTANT:
60 | logger.info("AUTO_LEAVING_ASSISTANT is disabled. Exiting auto_leave task.")
61 | return
62 |
63 | logger.info("AutoLeave task started and running in background.")
64 | from DeadlineTech.core.userbot import assistants
65 |
66 | while True:
67 | seconds_to_sleep = seconds_until_target_time()
68 | hrs, mins = divmod(seconds_to_sleep // 60, 60)
69 | logger.info(f"Sleeping for {int(hrs)}h {int(mins)}m until 4:35 AM IST.")
70 | await asyncio.sleep(seconds_to_sleep)
71 |
72 | logger.info("Running cleanup of inactive chats...")
73 | for num in assistants:
74 | client = await get_client(num)
75 | await leave_inactive_chats(client, num)
76 | logger.info("Cleanup complete. Sleeping again until next 4:35 AM.")
77 |
78 | # Start the background auto leave task
79 | asyncio.create_task(auto_leave())
80 |
--------------------------------------------------------------------------------
/DeadlineTech/platforms/Resso.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 |
27 | import re
28 | from typing import Union
29 |
30 | import aiohttp
31 | from bs4 import BeautifulSoup
32 | from youtubesearchpython.__future__ import VideosSearch
33 |
34 |
35 | class RessoAPI:
36 | def __init__(self):
37 | self.regex = r"^(https:\/\/m.resso.com\/)(.*)$"
38 | self.base = "https://m.resso.com/"
39 |
40 | async def valid(self, link: str):
41 | if re.search(self.regex, link):
42 | return True
43 | else:
44 | return False
45 |
46 | async def track(self, url, playid: Union[bool, str] = None):
47 | if playid:
48 | url = self.base + url
49 | async with aiohttp.ClientSession() as session:
50 | async with session.get(url) as response:
51 | if response.status != 200:
52 | return False
53 | html = await response.text()
54 | soup = BeautifulSoup(html, "html.parser")
55 | for tag in soup.find_all("meta"):
56 | if tag.get("property", None) == "og:title":
57 | title = tag.get("content", None)
58 | if tag.get("property", None) == "og:description":
59 | des = tag.get("content", None)
60 | try:
61 | des = des.split("·")[0]
62 | except:
63 | pass
64 | if des == "":
65 | return
66 | results = VideosSearch(title, limit=1)
67 | for result in (await results.next())["result"]:
68 | title = result["title"]
69 | ytlink = result["link"]
70 | vidid = result["id"]
71 | duration_min = result["duration"]
72 | thumbnail = result["thumbnails"][0]["url"].split("?")[0]
73 | track_details = {
74 | "title": title,
75 | "link": ytlink,
76 | "vidid": vidid,
77 | "duration_min": duration_min,
78 | "thumb": thumbnail,
79 | }
80 | return track_details, vidid
81 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/auth.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.utils import extract_user, int_to_alpha
8 | from DeadlineTech.utils.database import (
9 | delete_authuser,
10 | get_authuser,
11 | get_authuser_names,
12 | save_authuser,
13 | )
14 | from DeadlineTech.utils.decorators import AdminActual, language
15 | from DeadlineTech.utils.inline import close_markup
16 | from config import BANNED_USERS, adminlist
17 |
18 |
19 | @app.on_message(filters.command("auth") & filters.group & ~BANNED_USERS)
20 | @AdminActual
21 | async def auth(client, message: Message, _):
22 | if not message.reply_to_message:
23 | if len(message.command) != 2:
24 | return await message.reply_text(_["general_1"])
25 | user = await extract_user(message)
26 | token = await int_to_alpha(user.id)
27 | _check = await get_authuser_names(message.chat.id)
28 | count = len(_check)
29 | if int(count) == 25:
30 | return await message.reply_text(_["auth_1"])
31 | if token not in _check:
32 | assis = {
33 | "auth_user_id": user.id,
34 | "auth_name": user.first_name,
35 | "admin_id": message.from_user.id,
36 | "admin_name": message.from_user.first_name,
37 | }
38 | get = adminlist.get(message.chat.id)
39 | if get:
40 | if user.id not in get:
41 | get.append(user.id)
42 | await save_authuser(message.chat.id, token, assis)
43 | return await message.reply_text(_["auth_2"].format(user.mention))
44 | else:
45 | return await message.reply_text(_["auth_3"].format(user.mention))
46 |
47 |
48 | @app.on_message(filters.command("unauth") & filters.group & ~BANNED_USERS)
49 | @AdminActual
50 | async def unauthusers(client, message: Message, _):
51 | if not message.reply_to_message:
52 | if len(message.command) != 2:
53 | return await message.reply_text(_["general_1"])
54 | user = await extract_user(message)
55 | token = await int_to_alpha(user.id)
56 | deleted = await delete_authuser(message.chat.id, token)
57 | get = adminlist.get(message.chat.id)
58 | if get:
59 | if user.id in get:
60 | get.remove(user.id)
61 | if deleted:
62 | return await message.reply_text(_["auth_4"].format(user.mention))
63 | else:
64 | return await message.reply_text(_["auth_5"].format(user.mention))
65 |
66 |
67 | @app.on_message(
68 | filters.command(["authlist", "authusers"]) & filters.group & ~BANNED_USERS
69 | )
70 | @language
71 | async def authusers(client, message: Message, _):
72 | _wtf = await get_authuser_names(message.chat.id)
73 | if not _wtf:
74 | return await message.reply_text(_["setting_4"])
75 | else:
76 | j = 0
77 | mystic = await message.reply_text(_["auth_6"])
78 | text = _["auth_7"].format(message.chat.title)
79 | for umm in _wtf:
80 | _umm = await get_authuser(message.chat.id, umm)
81 | user_id = _umm["auth_user_id"]
82 | admin_id = _umm["admin_id"]
83 | admin_name = _umm["admin_name"]
84 | try:
85 | user = (await app.get_users(user_id)).first_name
86 | j += 1
87 | except:
88 | continue
89 | text += f"{j}➤ {user}[{user_id}]\n"
90 | text += f" {_['auth_8']} {admin_name}[{admin_id}]\n\n"
91 | await mystic.edit_text(text, reply_markup=close_markup(_))
92 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/decorators/language.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from DeadlineTech.misc import SUDOERS
3 | from DeadlineTech.utils.database import get_lang, is_maintenance
4 | from config import SUPPORT_CHAT
5 | from strings import get_string
6 | from DeadlineTech import app
7 |
8 | # Setup logger
9 | logger = logging.getLogger(__name__)
10 | logging.basicConfig(level=logging.INFO)
11 |
12 | # Safe fallback to English
13 | def safe_get_string(lang_code):
14 | try:
15 | return get_string(lang_code)
16 | except Exception as e:
17 | logger.warning(f"Failed to load language string for {lang_code}: {e}")
18 | return get_string("en")
19 |
20 |
21 | def language(mystic):
22 | async def wrapper(_, message, **kwargs):
23 | try:
24 | if await is_maintenance() is False and message.from_user.id not in SUDOERS:
25 | return await message.reply_text(
26 | text=f"{app.mention} ɪs ᴜɴᴅᴇʀ ᴍᴀɪɴᴛᴇɴᴀɴᴄᴇ, ᴠɪsɪᴛ sᴜᴘᴘᴏʀᴛ ᴄʜᴀᴛ ғᴏʀ ᴋɴᴏᴡɪɴɢ ᴛʜᴇ ʀᴇᴀsᴏɴ.",
27 | disable_web_page_preview=True,
28 | )
29 | except Exception as e:
30 | logger.error(f"Maintenance check failed: {e}")
31 |
32 | try:
33 | await message.delete()
34 | except Exception as e:
35 | logger.debug(f"Failed to delete user message: {e}")
36 |
37 | try:
38 | lang_code = await get_lang(message.chat.id)
39 | except Exception as e:
40 | logger.warning(f"Failed to fetch language from DB: {e}")
41 | lang_code = "en"
42 |
43 | language = safe_get_string(lang_code)
44 |
45 | try:
46 | return await mystic(_, message, language)
47 | except Exception as e:
48 | logger.exception(f"Error in wrapped language function: {e}")
49 | return await message.reply_text("⚠️ Something went wrong. Please try again later.")
50 |
51 | return wrapper
52 |
53 |
54 | def languageCB(mystic):
55 | async def wrapper(_, CallbackQuery, **kwargs):
56 | try:
57 | if await is_maintenance() is False and CallbackQuery.from_user.id not in SUDOERS:
58 | return await CallbackQuery.answer(
59 | f"{app.mention} ɪs ᴜɴᴅᴇʀ ᴍᴀɪɴᴛᴇɴᴀɴᴄᴇ. ᴘʟᴇᴀsᴇ ᴄʜᴇᴄᴋ {SUPPORT_CHAT}.",
60 | show_alert=True,
61 | )
62 | except Exception as e:
63 | logger.error(f"Maintenance check failed in callback: {e}")
64 |
65 | try:
66 | lang_code = await get_lang(CallbackQuery.message.chat.id)
67 | except Exception as e:
68 | logger.warning(f"Failed to fetch language from DB (CB): {e}")
69 | lang_code = "en"
70 |
71 | language = safe_get_string(lang_code)
72 |
73 | try:
74 | return await mystic(_, CallbackQuery, language)
75 | except Exception as e:
76 | logger.exception(f"Error in wrapped languageCB function: {e}")
77 | return await CallbackQuery.answer("⚠️ Something went wrong. Please try again later.", show_alert=True)
78 |
79 | return wrapper
80 |
81 |
82 | def LanguageStart(mystic):
83 | async def wrapper(_, message, **kwargs):
84 | try:
85 | lang_code = await get_lang(message.chat.id)
86 | except Exception as e:
87 | logger.warning(f"Failed to fetch language from DB (start): {e}")
88 | lang_code = "en"
89 |
90 | language = safe_get_string(lang_code)
91 |
92 | try:
93 | return await mystic(_, message, language)
94 | except Exception as e:
95 | logger.exception(f"Error in wrapped LanguageStart function: {e}")
96 | return await message.reply_text("⚠️ An unexpected error occurred during startup.")
97 |
98 | return wrapper
99 |
--------------------------------------------------------------------------------
/DeadlineTech/core/git.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 | import asyncio
27 | import shlex
28 | from typing import Tuple
29 |
30 | from git import Repo
31 | from git.exc import GitCommandError, InvalidGitRepositoryError
32 |
33 | import config
34 |
35 | from ..logging import LOGGER
36 |
37 |
38 | def install_req(cmd: str) -> Tuple[str, str, int, int]:
39 | async def install_requirements():
40 | args = shlex.split(cmd)
41 | process = await asyncio.create_subprocess_exec(
42 | *args,
43 | stdout=asyncio.subprocess.PIPE,
44 | stderr=asyncio.subprocess.PIPE,
45 | )
46 | stdout, stderr = await process.communicate()
47 | return (
48 | stdout.decode("utf-8", "replace").strip(),
49 | stderr.decode("utf-8", "replace").strip(),
50 | process.returncode,
51 | process.pid,
52 | )
53 |
54 | return asyncio.get_event_loop().run_until_complete(install_requirements())
55 |
56 |
57 | def git():
58 | REPO_LINK = config.UPSTREAM_REPO
59 | if config.GIT_TOKEN:
60 | GIT_USERNAME = REPO_LINK.split("com/")[1].split("/")[0]
61 | TEMP_REPO = REPO_LINK.split("https://")[1]
62 | UPSTREAM_REPO = f"https://{GIT_USERNAME}:{config.GIT_TOKEN}@{TEMP_REPO}"
63 | else:
64 | UPSTREAM_REPO = config.UPSTREAM_REPO
65 | try:
66 | repo = Repo()
67 | LOGGER(__name__).info(f"[+] Git client located. Initializing VPS deployment process..")
68 | except GitCommandError:
69 | LOGGER(__name__).info(f"Invalid Git Command")
70 | except InvalidGitRepositoryError:
71 | repo = Repo.init()
72 | if "origin" in repo.remotes:
73 | origin = repo.remote("origin")
74 | else:
75 | origin = repo.create_remote("origin", UPSTREAM_REPO)
76 | origin.fetch()
77 | repo.create_head(
78 | config.UPSTREAM_BRANCH,
79 | origin.refs[config.UPSTREAM_BRANCH],
80 | )
81 | repo.heads[config.UPSTREAM_BRANCH].set_tracking_branch(
82 | origin.refs[config.UPSTREAM_BRANCH]
83 | )
84 | repo.heads[config.UPSTREAM_BRANCH].checkout(True)
85 | try:
86 | repo.create_remote("origin", config.UPSTREAM_REPO)
87 | except BaseException:
88 | pass
89 | nrs = repo.remote("origin")
90 | nrs.fetch(config.UPSTREAM_BRANCH)
91 | try:
92 | nrs.pull(config.UPSTREAM_BRANCH)
93 | except GitCommandError:
94 | repo.git.reset("--hard", "FETCH_HEAD")
95 | install_req("pip3 install --no-cache-dir -r requirements.txt")
96 | LOGGER(__name__).info(f"Fetching updates from upstream repository...")
97 |
--------------------------------------------------------------------------------
/DeadlineTech/core/bot.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 | import uvloop
26 | uvloop.install()
27 |
28 | import asyncio
29 | from pyrogram import Client, errors
30 | from pyrogram.enums import ChatMemberStatus, ParseMode
31 |
32 | import config
33 | from ..logging import LOGGER
34 |
35 |
36 | class Anony(Client):
37 | def __init__(self):
38 | LOGGER(__name__).info("🛠️ Initializing DeadlineTech Bot...")
39 | super().__init__(
40 | name="DeadlineTech",
41 | api_id=config.API_ID,
42 | api_hash=config.API_HASH,
43 | bot_token=config.BOT_TOKEN,
44 | in_memory=True,
45 | parse_mode=ParseMode.HTML,
46 | max_concurrent_transmissions=7,
47 | )
48 |
49 | async def start(self):
50 | await super().start()
51 |
52 | self.id = self.me.id
53 | self.name = f"{self.me.first_name} {self.me.last_name or ''}".strip()
54 | self.username = self.me.username
55 | self.mention = self.me.mention
56 |
57 | try:
58 | await self.send_message(
59 | chat_id=config.LOGGER_ID,
60 | text=(
61 | f"✅ Bot Started Successfully!\n\n"
62 | f"Name: {self.name}\n"
63 | f"Username: @{self.username}\n"
64 | f"User ID: {self.id}"
65 | ),
66 | )
67 | except (errors.ChannelInvalid, errors.PeerIdInvalid):
68 | LOGGER(__name__).error(
69 | "❌ Unable to send message to the log group/channel. "
70 | "Ensure the bot is added and not banned."
71 | )
72 | exit()
73 | except Exception as ex:
74 | LOGGER(__name__).error(
75 | f"❌ Failed to access the log group/channel.\nReason: {type(ex).__name__}"
76 | )
77 | exit()
78 |
79 | try:
80 | member = await self.get_chat_member(config.LOGGER_ID, self.id)
81 | if member.status != ChatMemberStatus.ADMINISTRATOR:
82 | LOGGER(__name__).error(
83 | "⚠️ Bot is not an admin in the log group/channel. Please promote it as admin."
84 | )
85 | exit()
86 | except Exception as ex:
87 | LOGGER(__name__).error(
88 | f"❌ Failed to fetch bot status in log group. Reason: {type(ex).__name__}"
89 | )
90 | exit()
91 |
92 | LOGGER(__name__).info(f"🎶 Bot is online and ready as {self.name} (@{self.username})")
93 |
94 | async def stop(self):
95 | LOGGER(__name__).info("🛑 Stopping DeadlineTech Bot...")
96 | await super().stop()
97 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/settings.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 |
3 | from pyrogram.types import InlineKeyboardButton
4 |
5 |
6 | def setting_markup(_):
7 | buttons = [
8 | [
9 | InlineKeyboardButton(text=_["ST_B_1"], callback_data="AU"),
10 | InlineKeyboardButton(text=_["ST_B_3"], callback_data="LG"),
11 | ],
12 | [
13 | InlineKeyboardButton(text=_["ST_B_2"], callback_data="PM"),
14 | ],
15 | [
16 | InlineKeyboardButton(text=_["ST_B_4"], callback_data="VM"),
17 | ],
18 | [
19 | InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data="close"),
20 | ],
21 | ]
22 | return buttons
23 |
24 |
25 | def vote_mode_markup(_, current, mode: Union[bool, str] = None):
26 | buttons = [
27 | [
28 | InlineKeyboardButton(text="Vᴏᴛɪɴɢ ᴍᴏᴅᴇ ➜", callback_data="VOTEANSWER"),
29 | InlineKeyboardButton(
30 | text=_["ST_B_5"] if mode == True else _["ST_B_6"],
31 | callback_data="VOMODECHANGE",
32 | ),
33 | ],
34 | [
35 | InlineKeyboardButton(text="-2", callback_data="FERRARIUDTI M"),
36 | InlineKeyboardButton(
37 | text=f"ᴄᴜʀʀᴇɴᴛ : {current}",
38 | callback_data="ANSWERVOMODE",
39 | ),
40 | InlineKeyboardButton(text="+2", callback_data="FERRARIUDTI A"),
41 | ],
42 | [
43 | InlineKeyboardButton(
44 | text=_["BACK_BUTTON"],
45 | callback_data="settings_helper",
46 | ),
47 | InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data="close"),
48 | ],
49 | ]
50 | return buttons
51 |
52 |
53 | def auth_users_markup(_, status: Union[bool, str] = None):
54 | buttons = [
55 | [
56 | InlineKeyboardButton(text=_["ST_B_7"], callback_data="AUTHANSWER"),
57 | InlineKeyboardButton(
58 | text=_["ST_B_8"] if status == True else _["ST_B_9"],
59 | callback_data="AUTH",
60 | ),
61 | ],
62 | [
63 | InlineKeyboardButton(text=_["ST_B_1"], callback_data="AUTHLIST"),
64 | ],
65 | [
66 | InlineKeyboardButton(
67 | text=_["BACK_BUTTON"],
68 | callback_data="settings_helper",
69 | ),
70 | InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data="close"),
71 | ],
72 | ]
73 | return buttons
74 |
75 |
76 | def playmode_users_markup(
77 | _,
78 | Direct: Union[bool, str] = None,
79 | Group: Union[bool, str] = None,
80 | Playtype: Union[bool, str] = None,
81 | ):
82 | buttons = [
83 | [
84 | InlineKeyboardButton(text=_["ST_B_10"], callback_data="SEARCHANSWER"),
85 | InlineKeyboardButton(
86 | text=_["ST_B_11"] if Direct == True else _["ST_B_12"],
87 | callback_data="MODECHANGE",
88 | ),
89 | ],
90 | [
91 | InlineKeyboardButton(text=_["ST_B_13"], callback_data="AUTHANSWER"),
92 | InlineKeyboardButton(
93 | text=_["ST_B_8"] if Group == True else _["ST_B_9"],
94 | callback_data="CHANNELMODECHANGE",
95 | ),
96 | ],
97 | [
98 | InlineKeyboardButton(text=_["ST_B_14"], callback_data="PLAYTYPEANSWER"),
99 | InlineKeyboardButton(
100 | text=_["ST_B_8"] if Playtype == True else _["ST_B_9"],
101 | callback_data="PLAYTYPECHANGE",
102 | ),
103 | ],
104 | [
105 | InlineKeyboardButton(
106 | text=_["BACK_BUTTON"],
107 | callback_data="settings_helper",
108 | ),
109 | InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data="close"),
110 | ],
111 | ]
112 | return buttons
113 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/inline/help.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 |
3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
4 |
5 | from DeadlineTech import app
6 |
7 |
8 | def help_pannel(_, START: Union[bool, int] = None):
9 | first = [InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data=f"close")]
10 | second = [
11 | InlineKeyboardButton(
12 | text=_["BACK_BUTTON"],
13 | callback_data=f"settingsback_helper",
14 | ),
15 | ]
16 | mark = second if START else first
17 | upl = InlineKeyboardMarkup(
18 | [
19 | [
20 | InlineKeyboardButton(
21 | text=_["H_B_1"],
22 | callback_data="help_callback hb1",
23 | ),
24 | InlineKeyboardButton(
25 | text=_["H_B_2"],
26 | callback_data="help_callback hb2",
27 | ),
28 | InlineKeyboardButton(
29 | text=_["H_B_3"],
30 | callback_data="help_callback hb3",
31 | ),
32 | ],
33 | [
34 | InlineKeyboardButton(
35 | text=_["H_B_4"],
36 | callback_data="help_callback hb4",
37 | ),
38 | InlineKeyboardButton(
39 | text=_["H_B_5"],
40 | callback_data="help_callback hb5",
41 | ),
42 | InlineKeyboardButton(
43 | text=_["H_B_6"],
44 | callback_data="help_callback hb6",
45 | ),
46 | ],
47 | [
48 | InlineKeyboardButton(
49 | text=_["H_B_7"],
50 | callback_data="help_callback hb7",
51 | ),
52 | InlineKeyboardButton(
53 | text=_["H_B_8"],
54 | callback_data="help_callback hb8",
55 | ),
56 | InlineKeyboardButton(
57 | text=_["H_B_9"],
58 | callback_data="help_callback hb9",
59 | ),
60 | ],
61 | [
62 | InlineKeyboardButton(
63 | text=_["H_B_10"],
64 | callback_data="help_callback hb10",
65 | ),
66 | InlineKeyboardButton(
67 | text=_["H_B_11"],
68 | callback_data="help_callback hb11",
69 | ),
70 | InlineKeyboardButton(
71 | text=_["H_B_12"],
72 | callback_data="help_callback hb12",
73 | ),
74 | ],
75 | [
76 | InlineKeyboardButton(
77 | text=_["H_B_13"],
78 | callback_data="help_callback hb13",
79 | ),
80 | InlineKeyboardButton(
81 | text=_["H_B_14"],
82 | callback_data="help_callback hb14",
83 | ),
84 | InlineKeyboardButton(
85 | text=_["H_B_15"],
86 | callback_data="help_callback hb15",
87 | ),
88 | ],
89 | mark,
90 | ]
91 | )
92 | return upl
93 |
94 |
95 | def help_back_markup(_):
96 | upl = InlineKeyboardMarkup(
97 | [
98 | [
99 | InlineKeyboardButton(
100 | text=_["BACK_BUTTON"],
101 | callback_data=f"settings_back_helper",
102 | ),
103 | ]
104 | ]
105 | )
106 | return upl
107 |
108 |
109 | def private_help_panel(_):
110 | buttons = [
111 | [
112 | InlineKeyboardButton(
113 | text=_["S_B_4"],
114 | url=f"https://t.me/{app.username}?start=help",
115 | ),
116 | ],
117 | ]
118 | return buttons
119 |
--------------------------------------------------------------------------------
/DeadlineTech/platforms/Apple.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 |
27 | import re
28 | from typing import Union
29 |
30 | import aiohttp
31 | from bs4 import BeautifulSoup
32 | from youtubesearchpython.__future__ import VideosSearch
33 |
34 |
35 | class AppleAPI:
36 | def __init__(self):
37 | self.regex = r"^(https:\/\/music.apple.com\/)(.*)$"
38 | self.base = "https://music.apple.com/in/playlist/"
39 |
40 | async def valid(self, link: str):
41 | if re.search(self.regex, link):
42 | return True
43 | else:
44 | return False
45 |
46 | async def track(self, url, playid: Union[bool, str] = None):
47 | if playid:
48 | url = self.base + url
49 | async with aiohttp.ClientSession() as session:
50 | async with session.get(url) as response:
51 | if response.status != 200:
52 | return False
53 | html = await response.text()
54 | soup = BeautifulSoup(html, "html.parser")
55 | search = None
56 | for tag in soup.find_all("meta"):
57 | if tag.get("property", None) == "og:title":
58 | search = tag.get("content", None)
59 | if search is None:
60 | return False
61 | results = VideosSearch(search, limit=1)
62 | for result in (await results.next())["result"]:
63 | title = result["title"]
64 | ytlink = result["link"]
65 | vidid = result["id"]
66 | duration_min = result["duration"]
67 | thumbnail = result["thumbnails"][0]["url"].split("?")[0]
68 | track_details = {
69 | "title": title,
70 | "link": ytlink,
71 | "vidid": vidid,
72 | "duration_min": duration_min,
73 | "thumb": thumbnail,
74 | }
75 | return track_details, vidid
76 |
77 | async def playlist(self, url, playid: Union[bool, str] = None):
78 | if playid:
79 | url = self.base + url
80 | playlist_id = url.split("playlist/")[1]
81 | async with aiohttp.ClientSession() as session:
82 | async with session.get(url) as response:
83 | if response.status != 200:
84 | return False
85 | html = await response.text()
86 | soup = BeautifulSoup(html, "html.parser")
87 | applelinks = soup.find_all("meta", attrs={"property": "music:song"})
88 | results = []
89 | for item in applelinks:
90 | try:
91 | xx = (((item["content"]).split("album/")[1]).split("/")[0]).replace(
92 | "-", " "
93 | )
94 | except:
95 | xx = ((item["content"]).split("album/")[1]).split("/")[0]
96 | results.append(xx)
97 | return results, playlist_id
98 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/bot/help.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from typing import Union
4 |
5 | from pyrogram import filters, types
6 | from pyrogram.types import InlineKeyboardMarkup, Message
7 |
8 | from DeadlineTech import app
9 | from DeadlineTech.utils import help_pannel
10 | from DeadlineTech.utils.database import get_lang
11 | from DeadlineTech.utils.decorators.language import LanguageStart, languageCB
12 | from DeadlineTech.utils.inline.help import help_back_markup, private_help_panel
13 | from config import BANNED_USERS, START_IMG_URL, SUPPORT_CHAT
14 | from strings import get_string, helpers
15 |
16 |
17 | @app.on_message(filters.command(["help"]) & filters.private & ~BANNED_USERS)
18 | @app.on_callback_query(filters.regex("settings_back_helper") & ~BANNED_USERS)
19 | async def helper_private(
20 | client: app, update: Union[types.Message, types.CallbackQuery]
21 | ):
22 | is_callback = isinstance(update, types.CallbackQuery)
23 | if is_callback:
24 | try:
25 | await update.answer()
26 | except:
27 | pass
28 | chat_id = update.message.chat.id
29 | language = await get_lang(chat_id)
30 | _ = get_string(language)
31 | keyboard = help_pannel(_, True)
32 | await update.edit_message_text(
33 | _["help_1"].format(SUPPORT_CHAT), reply_markup=keyboard
34 | )
35 | else:
36 | try:
37 | await update.delete()
38 | except:
39 | pass
40 | language = await get_lang(update.chat.id)
41 | _ = get_string(language)
42 | keyboard = help_pannel(_)
43 | await update.reply_photo(
44 | photo=START_IMG_URL,
45 | caption=_["help_1"].format(SUPPORT_CHAT),
46 | reply_markup=keyboard,
47 | )
48 |
49 |
50 | @app.on_message(filters.command(["help"]) & filters.group & ~BANNED_USERS)
51 | @LanguageStart
52 | async def help_com_group(client, message: Message, _):
53 | keyboard = private_help_panel(_)
54 | await message.reply_text(_["help_2"], reply_markup=InlineKeyboardMarkup(keyboard))
55 |
56 |
57 | @app.on_callback_query(filters.regex("help_callback") & ~BANNED_USERS)
58 | @languageCB
59 | async def helper_cb(client, CallbackQuery, _):
60 | callback_data = CallbackQuery.data.strip()
61 | cb = callback_data.split(None, 1)[1]
62 | keyboard = help_back_markup(_)
63 | if cb == "hb1":
64 | await CallbackQuery.edit_message_text(helpers.HELP_1, reply_markup=keyboard)
65 | elif cb == "hb2":
66 | await CallbackQuery.edit_message_text(helpers.HELP_2, reply_markup=keyboard)
67 | elif cb == "hb3":
68 | await CallbackQuery.edit_message_text(helpers.HELP_3, reply_markup=keyboard)
69 | elif cb == "hb4":
70 | await CallbackQuery.edit_message_text(helpers.HELP_4, reply_markup=keyboard)
71 | elif cb == "hb5":
72 | await CallbackQuery.edit_message_text(helpers.HELP_5, reply_markup=keyboard)
73 | elif cb == "hb6":
74 | await CallbackQuery.edit_message_text(helpers.HELP_6, reply_markup=keyboard)
75 | elif cb == "hb7":
76 | await CallbackQuery.edit_message_text(helpers.HELP_7, reply_markup=keyboard)
77 | elif cb == "hb8":
78 | await CallbackQuery.edit_message_text(helpers.HELP_8, reply_markup=keyboard)
79 | elif cb == "hb9":
80 | await CallbackQuery.edit_message_text(helpers.HELP_9, reply_markup=keyboard)
81 | elif cb == "hb10":
82 | await CallbackQuery.edit_message_text(helpers.HELP_10, reply_markup=keyboard)
83 | elif cb == "hb11":
84 | await CallbackQuery.edit_message_text(helpers.HELP_11, reply_markup=keyboard)
85 | elif cb == "hb12":
86 | await CallbackQuery.edit_message_text(helpers.HELP_12, reply_markup=keyboard)
87 | elif cb == "hb13":
88 | await CallbackQuery.edit_message_text(helpers.HELP_13, reply_markup=keyboard)
89 | elif cb == "hb14":
90 | await CallbackQuery.edit_message_text(helpers.HELP_14, reply_markup=keyboard)
91 | elif cb == "hb15":
92 | await CallbackQuery.edit_message_text(helpers.HELP_15, reply_markup=keyboard)
93 |
--------------------------------------------------------------------------------
/DeadlineTech/__main__.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | import asyncio
4 | import importlib
5 |
6 | from pyrogram.types import BotCommand
7 | from pyrogram import idle
8 | from pytgcalls.exceptions import NoActiveGroupCall
9 |
10 | import config
11 | from DeadlineTech import LOGGER, app, userbot
12 | from DeadlineTech.core.call import Anony
13 | from DeadlineTech.misc import sudo
14 | from DeadlineTech.plugins import ALL_MODULES
15 | from DeadlineTech.utils.database import get_banned_users, get_gbanned
16 | from DeadlineTech.utils.crash_reporter import setup_global_exception_handler # ✅ Import crash handler
17 | from config import BANNED_USERS
18 |
19 | async def init():
20 | # ✅ Enable global crash handler
21 | setup_global_exception_handler()
22 |
23 |
24 | if (
25 | not config.STRING1
26 | and not config.STRING2
27 | and not config.STRING3
28 | and not config.STRING4
29 | and not config.STRING5
30 | ):
31 | LOGGER(__name__).error("Assistant client variables not defined, exiting...")
32 | exit()
33 | await sudo()
34 | try:
35 | users = await get_gbanned()
36 | for user_id in users:
37 | BANNED_USERS.add(user_id)
38 | users = await get_banned_users()
39 | for user_id in users:
40 | BANNED_USERS.add(user_id)
41 | except:
42 | pass
43 | await app.start()
44 |
45 | await app.set_bot_commands([
46 | BotCommand("start", "Sᴛᴀʀᴛ's Tʜᴇ Bᴏᴛ"),
47 | BotCommand("clone", "start your own bot now"),
48 | BotCommand("ping", "Cʜᴇᴄᴋ ɪғ ʙᴏᴛ ɪs ᴀʟɪᴠᴇ"),
49 | BotCommand("help", "Gᴇᴛ Cᴏᴍᴍᴀɴᴅs Lɪsᴛ"),
50 | BotCommand("music", "download the songs 🎵"),
51 | BotCommand("play", "Pʟᴀʏ Mᴜsɪᴄ ɪɴ Vᴄ"),
52 | BotCommand("vplay", "starts Streaming the requested Video Song"),
53 | BotCommand("playforce", "forces to play your requested song"),
54 | BotCommand("vplayforce", "forces to play your requested Video song"),
55 | BotCommand("pause", "pause the current playing stream"),
56 | BotCommand("resume", "resume the paused stream"),
57 | BotCommand("skip", "skip the current playing stream"),
58 | BotCommand("end", "end the current stream"),
59 | BotCommand("player", "get a interactive player panel"),
60 | BotCommand("queue", "shows the queued tracks list"),
61 | BotCommand("auth", "add a user to auth list"),
62 | BotCommand("unauth", "remove a user from the auth list"),
63 | BotCommand("authusers", "shows the list of the auth users"),
64 | BotCommand("cplay", "starts streaming the requested audio on channel"),
65 | BotCommand("cvplay", "Starts Streaming the video track on channel"),
66 | BotCommand("channelplay", "connect channel to a group and start streaming"),
67 | BotCommand("shuffle", "shuffle's the queue"),
68 | BotCommand("seek", "seek the stream to the given duration"),
69 | BotCommand("seekback", "backward seek the stream"),
70 | BotCommand("speed", "for adjusting the audio playback speed"),
71 | BotCommand("loop", "enables the loop for the given value")
72 | ])
73 |
74 |
75 | for all_module in ALL_MODULES:
76 | importlib.import_module("DeadlineTech.plugins" + all_module)
77 | LOGGER("DeadlineTech.plugins").info("Successfully Imported Modules...")
78 | await userbot.start()
79 | await Anony.start()
80 | try:
81 | await Anony.stream_call("https://te.legra.ph/file/29f784eb49d230ab62e9e.mp4")
82 | except NoActiveGroupCall:
83 | LOGGER("DeadlineTech").error(
84 | "Please turn on the videochat of your log group\channel.\n\nStopping Bot..."
85 | )
86 | exit()
87 | except:
88 | pass
89 | await Anony.decorators()
90 | LOGGER("DeadlineTech").info(
91 | "DeadlineTech Music Bot started successfully"
92 | )
93 | await idle()
94 | await app.stop()
95 | await userbot.stop()
96 | LOGGER("DeadlineTech").info("Stopping DeadlineTech Music Bot...")
97 |
98 |
99 | if __name__ == "__main__":
100 | asyncio.get_event_loop().run_until_complete(init())
101 |
--------------------------------------------------------------------------------
/setup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pprint (){
4 | cred='\033[0;31m'
5 | cgreen='\033[0;32m'
6 | cyellow='\033[0;33m'
7 | cblue='\033[0;34m'
8 | cpurple='\033[0;35m'
9 | eval "export color='$cpurple'"
10 | [ ! -z $2 ] && eval "export color=\"\$$2\""
11 | printf "$color $1"
12 | }
13 |
14 | color_reset(){ printf '\033[0;37m';}
15 |
16 | yesnoprompt(){
17 | old_stty_cfg=$(stty -g)
18 | stty raw -echo ; answer=$(head -c 1)
19 | stty $old_stty_cfg
20 | echo "$answer" | grep -iq "^y"
21 | }
22 |
23 | update() {
24 | pprint "\n\nUpdating package list.. "
25 | sudo apt update 2>&1 | grep "can be upgraded" &>/dev/null
26 | if [ $? -eq 0 ]; then
27 | pprint "UPDATE AVAILABLE" "cgreen"
28 | pprint "\n\nDo you want to automatically upgrade (y/n)?"
29 | if yesnoprompt; then
30 | pprint "\n\nUpgrading packages.. "
31 | sudo apt upgrade -y &>/dev/null &&
32 | pprint "DONE!\n\n" "cgreen" || (pprint "FAIL.\n\n" "cred"; exit 1)
33 | else
34 | echo
35 | fi
36 | else
37 | pprint "ALREADY UP TO DATE\n\n" "cgreen"
38 | fi
39 | }
40 |
41 | packages(){
42 | if ! command -v pip &>/dev/null; then
43 | pprint "Couldn't found pip, installing now..."
44 | sudo apt install python3-pip -y 2>pypilog.txt 1>/dev/null &&
45 | pprint "SUCCESS.\n\n" "cgreen" || (pprint "FAIL.\n\n" "cred"; exit 1)
46 | fi
47 |
48 | if ! command -v ffmpeg &>/dev/null; then
49 | pprint "Couldn't found ffmpeg, installing now..."
50 | if sudo apt install ffmpeg -y &>/dev/null;then
51 | pprint "SUCCESS.\n\n" "cgreen"
52 | else
53 | pprint "FAIL.\n\n" "cred"
54 | pprint "You need to install ffmpeg manually in order to deploy AnonXMusic, exiting...\n" "cblue"
55 | exit 1
56 | fi
57 | fi
58 |
59 | # Check ffmpeg version and warn user if necessary.
60 | fv=$(grep -Po 'version (3.*?) ' <<< $(ffmpeg -version)) &&
61 | pprint "Playing live streams not going to work since you have ffmpeg $fv, live streams are supported by version 4+.\n" "cblue"
62 | }
63 |
64 |
65 | node(){
66 | command -v npm &>/dev/null && return
67 | pprint "Installing Nodejs and Npm.. "
68 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash && source ~/.bashrc && nvm install v18 &>nodelog.txt &&
69 | sudo apt install -y nodejs &>>nodelog.txt &&
70 | sudo npm i -g npm &>>nodelog.txt &&
71 | pprint "SUCCESS!\n" "cgreen" || (pprint "FAIL.\n" "cred"; exit 1)
72 | }
73 |
74 |
75 | installation(){
76 | pprint "\n\nUpgrading pip and installing dependency packages..."
77 | pip3 install -U pip &>>pypilog.txt &&
78 | pip3 install -U -r requirements.txt &>>pypilog.txt &&
79 | pprint "DONE.\n" "cgreen" && return
80 | pprint "FAIL.\n" "cred"
81 | exit 1
82 | }
83 |
84 | clear
85 | pprint "Welcome to DeadlineTech Music Setup Installer\n\n"
86 | pprint "If you see any error during Installation Process, Please refer to these files for logs: "
87 | pprint "\nFor node js errors , Checkout nodelog.txt"
88 | pprint "\nFor pypi packages errors , Checkout pypilog.txt"
89 | sleep 1
90 | pprint "\n\nScript needs sudo privileges in order to update & install packages.\n"
91 | sudo test
92 |
93 | update
94 | packages
95 | node
96 | installation
97 | pprint "\n\n\n\n\nDeadlineTech Installation Completed !" "cgreen"
98 | sleep 1
99 | clear
100 |
101 | pprint "\nEnter Your Values Below\n\n\n"
102 | pprint "API ID: "; color_reset; read api_id
103 | pprint "\nAPI HASH: "; color_reset; read api_hash
104 | pprint "\nBOT TOKEN: "; color_reset; read bot_token
105 | pprint "\nOWNER ID:"; color_reset; read ownid
106 | pprint "\nMONGO DB URI: "; color_reset; read mongo_db
107 | pprint "\nLOG GROUP ID: "; color_reset; read logger
108 | pprint "\nSTRING SESSION: "; color_reset; read string_session
109 |
110 | pprint "\n\nProcessing your vars, wait a while !" "cgreen"
111 |
112 | if [ -f .env ]; then
113 | rm .env
114 | fi
115 |
116 | echo """API_ID = $api_id
117 | API_HASH = $api_hash
118 | BOT_TOKEN = $bot_token
119 | MONGO_DB_URI = $mongo_db
120 | LOGGER_ID = $logger
121 | STRING_SESSION = $string_session
122 | OWNER_ID = $ownid""" > .env
123 | clear
124 |
125 | pprint "\n\n\nThanks for using DeadlineTech installer, your vars have been saved successfully ! \nIf you wanna add more variables add them in your env by : vi .env"
126 | pprint "\n\nNow you can start the bot by : bash start\n\n"
127 |
--------------------------------------------------------------------------------
/DeadlineTech/platforms/Carbon.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 |
27 | import random
28 | from os.path import realpath
29 |
30 | import aiohttp
31 | from aiohttp import client_exceptions
32 |
33 |
34 | class UnableToFetchCarbon(Exception):
35 | pass
36 |
37 |
38 | themes = [
39 | "3024-night",
40 | "a11y-dark",
41 | "blackboard",
42 | "base16-dark",
43 | "base16-light",
44 | "cobalt",
45 | "duotone-dark",
46 | "dracula-pro",
47 | "hopscotch",
48 | "lucario",
49 | "material",
50 | "monokai",
51 | "nightowl",
52 | "nord",
53 | "oceanic-next",
54 | "one-light",
55 | "one-dark",
56 | "panda-syntax",
57 | "parasio-dark",
58 | "seti",
59 | "shades-of-purple",
60 | "solarized+dark",
61 | "solarized+light",
62 | "synthwave-84",
63 | "twilight",
64 | "verminal",
65 | "vscode",
66 | "yeti",
67 | "zenburn",
68 | ]
69 |
70 | colour = [
71 | "#FF0000",
72 | "#FF5733",
73 | "#FFFF00",
74 | "#008000",
75 | "#0000FF",
76 | "#800080",
77 | "#A52A2A",
78 | "#FF00FF",
79 | "#D2B48C",
80 | "#00FFFF",
81 | "#808000",
82 | "#800000",
83 | "#00FFFF",
84 | "#30D5C8",
85 | "#00FF00",
86 | "#008080",
87 | "#4B0082",
88 | "#EE82EE",
89 | "#FFC0CB",
90 | "#000000",
91 | "#FFFFFF",
92 | "#808080",
93 | ]
94 |
95 |
96 | class CarbonAPI:
97 | def __init__(self):
98 | self.language = "auto"
99 | self.drop_shadow = True
100 | self.drop_shadow_blur = "68px"
101 | self.drop_shadow_offset = "20px"
102 | self.font_family = "JetBrains Mono"
103 | self.width_adjustment = True
104 | self.watermark = False
105 |
106 | async def generate(self, text: str, user_id):
107 | async with aiohttp.ClientSession(
108 | headers={"Content-Type": "application/json"},
109 | ) as ses:
110 | params = {
111 | "code": text,
112 | }
113 | params["backgroundColor"] = random.choice(colour)
114 | params["theme"] = random.choice(themes)
115 | params["dropShadow"] = self.drop_shadow
116 | params["dropShadowOffsetY"] = self.drop_shadow_offset
117 | params["dropShadowBlurRadius"] = self.drop_shadow_blur
118 | params["fontFamily"] = self.font_family
119 | params["language"] = self.language
120 | params["watermark"] = self.watermark
121 | params["widthAdjustment"] = self.width_adjustment
122 | try:
123 | request = await ses.post(
124 | "https://carbonara.solopov.dev/api/cook",
125 | json=params,
126 | )
127 | except client_exceptions.ClientConnectorError:
128 | raise UnableToFetchCarbon("Can not reach the Host!")
129 | resp = await request.read()
130 | with open(f"cache/carbon{user_id}.jpg", "wb") as f:
131 | f.write(resp)
132 | return realpath(f.name)
133 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | import re
2 | from os import getenv
3 |
4 | from dotenv import load_dotenv
5 | from pyrogram import filters
6 |
7 | load_dotenv()
8 |
9 | # Get this value from my.telegram.org/apps
10 | API_ID = int(getenv("API_ID"))
11 | API_HASH = getenv("API_HASH")
12 |
13 | # Get your token from @BotFather on Telegram.
14 | BOT_TOKEN = getenv("BOT_TOKEN")
15 |
16 | #Get API_KEY from @DeadlineTechOwner or @DeadlineApiBot
17 | API_URL = getenv("API_URL", "https://deadlinetech.site")
18 | API_KEY = getenv("API_KEY")
19 |
20 | # Get your mongo url from cloud.mongodb.com
21 | MONGO_DB_URI = getenv("MONGO_DB_URI", None)
22 |
23 | DURATION_LIMIT_MIN = int(getenv("DURATION_LIMIT", 60))
24 |
25 | # Chat id of a group for logging bot's activities
26 | LOGGER_ID = int(getenv("LOGGER_ID", None))
27 |
28 | # Get this value from @Harry_RoxBot on Telegram by /id
29 | OWNER_ID = int(getenv("OWNER_ID", 6848223695))
30 |
31 | ## Fill these variables if you're deploying on heroku.
32 | # Your heroku app name
33 | HEROKU_APP_NAME = getenv("HEROKU_APP_NAME")
34 | # Get it from http://dashboard.heroku.com/account
35 | HEROKU_API_KEY = getenv("HEROKU_API_KEY")
36 |
37 | UPSTREAM_REPO = getenv(
38 | "UPSTREAM_REPO",
39 | "https://github.com/DeadlineTech/music",
40 | )
41 | UPSTREAM_BRANCH = getenv("UPSTREAM_BRANCH", "master")
42 | GIT_TOKEN = getenv(
43 | "GIT_TOKEN", None
44 | ) # Fill this variable if your upstream repository is private
45 |
46 | SUPPORT_CHANNEL = getenv("SUPPORT_CHANNEL", "https://t.me/ArcUpdates")
47 | SUPPORT_CHAT = getenv("SUPPORT_CHAT", "https://t.me/ArcChatz")
48 |
49 | # Set this to True if you want the assistant to automatically leave chats after an interval
50 | AUTO_LEAVING_ASSISTANT = bool(getenv("AUTO_LEAVING_ASSISTANT", True))
51 |
52 |
53 | # Get this credentials from https://developer.spotify.com/dashboard
54 | SPOTIFY_CLIENT_ID = getenv("SPOTIFY_CLIENT_ID", None)
55 | SPOTIFY_CLIENT_SECRET = getenv("SPOTIFY_CLIENT_SECRET", None)
56 |
57 |
58 | # Maximum limit for fetching playlist's track from youtube, spotify, apple links.
59 | PLAYLIST_FETCH_LIMIT = int(getenv("PLAYLIST_FETCH_LIMIT", 25))
60 |
61 |
62 | # Telegram audio and video file size limit (in bytes)
63 | TG_AUDIO_FILESIZE_LIMIT = int(getenv("TG_AUDIO_FILESIZE_LIMIT", 104857600))
64 | TG_VIDEO_FILESIZE_LIMIT = int(getenv("TG_VIDEO_FILESIZE_LIMIT", 1073741824))
65 | # Checkout https://www.gbmb.org/mb-to-bytes for converting mb to bytes
66 |
67 |
68 | # Get your pyrogram v2 session from @StringFatherBot on Telegram
69 | STRING1 = getenv("STRING_SESSION", None)
70 | STRING2 = getenv("STRING_SESSION2", None)
71 | STRING3 = getenv("STRING_SESSION3", None)
72 | STRING4 = getenv("STRING_SESSION4", None)
73 | STRING5 = getenv("STRING_SESSION5", None)
74 |
75 |
76 | BANNED_USERS = filters.user()
77 | adminlist = {}
78 | lyrical = {}
79 | votemode = {}
80 | autoclean = []
81 | confirmer = {}
82 |
83 |
84 | START_IMG_URL = getenv(
85 | "START_IMG_URL", "https://files.catbox.moe/pjwlqg.jpg"
86 | )
87 | PING_IMG_URL = getenv(
88 | "PING_IMG_URL", "https://files.catbox.moe/ou29gb.jpg"
89 | )
90 | PLAYLIST_IMG_URL = "https://files.catbox.moe/tny9ug.jpg"
91 | STATS_IMG_URL = "https://files.catbox.moe/k3e3bg.jpg"
92 | TELEGRAM_AUDIO_URL = "https://files.catbox.moe/nknnw1.jpg"
93 | TELEGRAM_VIDEO_URL = "https://files.catbox.moe/1xn73k.jpg"
94 | STREAM_IMG_URL = "https://files.catbox.moe/tny9ug.jpg"
95 | SOUNCLOUD_IMG_URL = "https://files.catbox.moe/1xn73k.jpg"
96 | YOUTUBE_IMG_URL = "https://files.catbox.moe/fpknxj.jpg"
97 | SPOTIFY_ARTIST_IMG_URL = "https://files.catbox.moe/1xn73k.jpg"
98 | SPOTIFY_ALBUM_IMG_URL = "https://files.catbox.moe/1xn73k.jpg"
99 | SPOTIFY_PLAYLIST_IMG_URL = "https://files.catbox.moe/1xn73k.jpg"
100 |
101 |
102 | def time_to_seconds(time):
103 | stringt = str(time)
104 | return sum(int(x) * 60**i for i, x in enumerate(reversed(stringt.split(":"))))
105 |
106 |
107 | DURATION_LIMIT = int(time_to_seconds(f"{DURATION_LIMIT_MIN}:00"))
108 |
109 |
110 | if SUPPORT_CHANNEL:
111 | if not re.match("(?:http|https)://", SUPPORT_CHANNEL):
112 | raise SystemExit(
113 | "[ERROR] - Your SUPPORT_CHANNEL url is wrong. Please ensure that it starts with https://"
114 | )
115 |
116 | if SUPPORT_CHAT:
117 | if not re.match("(?:http|https)://", SUPPORT_CHAT):
118 | raise SystemExit(
119 | "[ERROR] - Your SUPPORT_CHAT url is wrong. Please ensure that it starts with https://"
120 | )
121 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/admins/speed.py:
--------------------------------------------------------------------------------
1 | # Powered By Team DeadlineTech
2 |
3 | from pyrogram import filters
4 | from pyrogram.types import Message
5 |
6 | from DeadlineTech import app
7 | from DeadlineTech.core.call import Anony
8 | from DeadlineTech.misc import SUDOERS, db
9 | from DeadlineTech.utils import AdminRightsCheck
10 | from DeadlineTech.utils.database import is_active_chat, is_nonadmin_chat
11 | from DeadlineTech.utils.decorators.language import languageCB
12 | from DeadlineTech.utils.inline import close_markup, speed_markup
13 | from config import BANNED_USERS, adminlist
14 |
15 | checker = []
16 |
17 |
18 | @app.on_message(
19 | filters.command(["cspeed", "speed", "cslow", "slow", "playback", "cplayback"])
20 | & filters.group
21 | & ~BANNED_USERS
22 | )
23 | @AdminRightsCheck
24 | async def playback(cli, message: Message, _, chat_id):
25 | playing = db.get(chat_id)
26 | if not playing:
27 | return await message.reply_text(_["queue_2"])
28 | duration_seconds = int(playing[0]["seconds"])
29 | if duration_seconds == 0:
30 | return await message.reply_text(_["admin_27"])
31 | file_path = playing[0]["file"]
32 | if "downloads" not in file_path:
33 | return await message.reply_text(_["admin_27"])
34 | upl = speed_markup(_, chat_id)
35 | return await message.reply_text(
36 | text=_["admin_28"].format(app.mention),
37 | reply_markup=upl,
38 | )
39 |
40 |
41 | @app.on_callback_query(filters.regex("SpeedUP") & ~BANNED_USERS)
42 | @languageCB
43 | async def del_back_playlist(client, CallbackQuery, _):
44 | callback_data = CallbackQuery.data.strip()
45 | callback_request = callback_data.split(None, 1)[1]
46 | chat, speed = callback_request.split("|")
47 | chat_id = int(chat)
48 | if not await is_active_chat(chat_id):
49 | return await CallbackQuery.answer(_["general_5"], show_alert=True)
50 | is_non_admin = await is_nonadmin_chat(CallbackQuery.message.chat.id)
51 | if not is_non_admin:
52 | if CallbackQuery.from_user.id not in SUDOERS:
53 | admins = adminlist.get(CallbackQuery.message.chat.id)
54 | if not admins:
55 | return await CallbackQuery.answer(_["admin_13"], show_alert=True)
56 | else:
57 | if CallbackQuery.from_user.id not in admins:
58 | return await CallbackQuery.answer(_["admin_14"], show_alert=True)
59 | playing = db.get(chat_id)
60 | if not playing:
61 | return await CallbackQuery.answer(_["queue_2"], show_alert=True)
62 | duration_seconds = int(playing[0]["seconds"])
63 | if duration_seconds == 0:
64 | return await CallbackQuery.answer(_["admin_27"], show_alert=True)
65 | file_path = playing[0]["file"]
66 | if "downloads" not in file_path:
67 | return await CallbackQuery.answer(_["admin_27"], show_alert=True)
68 | checkspeed = (playing[0]).get("speed")
69 | if checkspeed:
70 | if str(checkspeed) == str(speed):
71 | if str(speed) == str("1.0"):
72 | return await CallbackQuery.answer(
73 | _["admin_29"],
74 | show_alert=True,
75 | )
76 | else:
77 | if str(speed) == str("1.0"):
78 | return await CallbackQuery.answer(
79 | _["admin_29"],
80 | show_alert=True,
81 | )
82 | if chat_id in checker:
83 | return await CallbackQuery.answer(
84 | _["admin_30"],
85 | show_alert=True,
86 | )
87 | else:
88 | checker.append(chat_id)
89 | try:
90 | await CallbackQuery.answer(
91 | _["admin_31"],
92 | )
93 | except:
94 | pass
95 | mystic = await CallbackQuery.edit_message_text(
96 | text=_["admin_32"].format(CallbackQuery.from_user.mention),
97 | )
98 | try:
99 | await Anony.speedup_stream(
100 | chat_id,
101 | file_path,
102 | speed,
103 | playing,
104 | )
105 | except:
106 | if chat_id in checker:
107 | checker.remove(chat_id)
108 | return await mystic.edit_text(_["admin_33"], reply_markup=close_markup(_))
109 | if chat_id in checker:
110 | checker.remove(chat_id)
111 | await mystic.edit_text(
112 | text=_["admin_34"].format(speed, CallbackQuery.from_user.mention),
113 | reply_markup=close_markup(_),
114 | )
115 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/reload.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import time
3 |
4 | from pyrogram import filters
5 | from pyrogram.enums import ChatMembersFilter
6 | from pyrogram.types import CallbackQuery, Message
7 |
8 | from DeadlineTech import app
9 | from DeadlineTech.core.call import Anony
10 | from DeadlineTech.misc import db
11 | from DeadlineTech.utils.database import get_assistant, get_authuser_names, get_cmode
12 | from DeadlineTech.utils.decorators import ActualAdminCB, AdminActual, language
13 | from DeadlineTech.utils.formatters import alpha_to_int, get_readable_time
14 | from config import BANNED_USERS, adminlist, lyrical
15 |
16 | rel = {}
17 |
18 |
19 | @app.on_message(
20 | filters.command(["admincache", "reload", "refresh"]) & filters.group & ~BANNED_USERS
21 | )
22 | @language
23 | async def reload_admin_cache(client, message: Message, _):
24 | try:
25 | if message.chat.id not in rel:
26 | rel[message.chat.id] = {}
27 | else:
28 | saved = rel[message.chat.id]
29 | if saved > time.time():
30 | left = get_readable_time((int(saved) - int(time.time())))
31 | return await message.reply_text(_["reload_1"].format(left))
32 | adminlist[message.chat.id] = []
33 | async for user in app.get_chat_members(
34 | message.chat.id, filter=ChatMembersFilter.ADMINISTRATORS
35 | ):
36 | if user.privileges.can_manage_video_chats:
37 | adminlist[message.chat.id].append(user.user.id)
38 | authusers = await get_authuser_names(message.chat.id)
39 | for user in authusers:
40 | user_id = await alpha_to_int(user)
41 | adminlist[message.chat.id].append(user_id)
42 | now = int(time.time()) + 180
43 | rel[message.chat.id] = now
44 | await message.reply_text(_["reload_2"])
45 | except:
46 | await message.reply_text(_["reload_3"])
47 |
48 |
49 | @app.on_message(filters.command(["reboot"]) & filters.group & ~BANNED_USERS)
50 | @AdminActual
51 | async def restartbot(client, message: Message, _):
52 | mystic = await message.reply_text(_["reload_4"].format(app.mention))
53 | await asyncio.sleep(1)
54 | try:
55 | db[message.chat.id] = []
56 | await Anony.stop_stream_force(message.chat.id)
57 | except:
58 | pass
59 | userbot = await get_assistant(message.chat.id)
60 | try:
61 | if message.chat.username:
62 | await userbot.resolve_peer(message.chat.username)
63 | else:
64 | await userbot.resolve_peer(message.chat.id)
65 | except:
66 | pass
67 | chat_id = await get_cmode(message.chat.id)
68 | if chat_id:
69 | try:
70 | got = await app.get_chat(chat_id)
71 | except:
72 | pass
73 | userbot = await get_assistant(chat_id)
74 | try:
75 | if got.username:
76 | await userbot.resolve_peer(got.username)
77 | else:
78 | await userbot.resolve_peer(chat_id)
79 | except:
80 | pass
81 | try:
82 | db[chat_id] = []
83 | await Anony.stop_stream_force(chat_id)
84 | except:
85 | pass
86 | return await mystic.edit_text(_["reload_5"].format(app.mention))
87 |
88 |
89 | @app.on_callback_query(filters.regex("close") & ~BANNED_USERS)
90 | async def close_menu(_, CallbackQuery):
91 | try:
92 | await CallbackQuery.answer()
93 | await CallbackQuery.message.delete()
94 | await CallbackQuery.message.reply_text(
95 | f"Cʟᴏsᴇᴅ ʙʏ : {CallbackQuery.from_user.mention}"
96 | )
97 | except:
98 | pass
99 |
100 |
101 | @app.on_callback_query(filters.regex("stop_downloading") & ~BANNED_USERS)
102 | @ActualAdminCB
103 | async def stop_download(client, CallbackQuery: CallbackQuery, _):
104 | message_id = CallbackQuery.message.id
105 | task = lyrical.get(message_id)
106 | if not task:
107 | return await CallbackQuery.answer(_["tg_4"], show_alert=True)
108 | if task.done() or task.cancelled():
109 | return await CallbackQuery.answer(_["tg_5"], show_alert=True)
110 | if not task.done():
111 | try:
112 | task.cancel()
113 | try:
114 | lyrical.pop(message_id)
115 | except:
116 | pass
117 | await CallbackQuery.answer(_["tg_6"], show_alert=True)
118 | return await CallbackQuery.edit_message_text(
119 | _["tg_7"].format(CallbackQuery.from_user.mention)
120 | )
121 | except:
122 | return await CallbackQuery.answer(_["tg_8"], show_alert=True)
123 | await CallbackQuery.answer(_["tg_9"], show_alert=True)
124 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/gban.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 |
3 | from pyrogram import filters
4 | from pyrogram.errors import FloodWait
5 | from pyrogram.types import Message
6 |
7 | from DeadlineTech import app
8 | from DeadlineTech.misc import SUDOERS
9 | from DeadlineTech.utils import get_readable_time
10 | from DeadlineTech.utils.database import (
11 | add_banned_user,
12 | get_banned_count,
13 | get_banned_users,
14 | get_served_chats,
15 | is_banned_user,
16 | remove_banned_user,
17 | )
18 | from DeadlineTech.utils.decorators.language import language
19 | from DeadlineTech.utils.extraction import extract_user
20 | from config import BANNED_USERS
21 |
22 |
23 | @app.on_message(filters.command(["gban", "globalban"]) & SUDOERS)
24 | @language
25 | async def global_ban(client, message: Message, _):
26 | if not message.reply_to_message:
27 | if len(message.command) != 2:
28 | return await message.reply_text(_["general_1"])
29 | user = await extract_user(message)
30 | if user.id == message.from_user.id:
31 | return await message.reply_text(_["gban_1"])
32 | elif user.id == app.id:
33 | return await message.reply_text(_["gban_2"])
34 | elif user.id in SUDOERS:
35 | return await message.reply_text(_["gban_3"])
36 | is_gbanned = await is_banned_user(user.id)
37 | if is_gbanned:
38 | return await message.reply_text(_["gban_4"].format(user.mention))
39 | if user.id not in BANNED_USERS:
40 | BANNED_USERS.add(user.id)
41 | served_chats = []
42 | chats = await get_served_chats()
43 | for chat in chats:
44 | served_chats.append(int(chat["chat_id"]))
45 | time_expected = get_readable_time(len(served_chats))
46 | mystic = await message.reply_text(_["gban_5"].format(user.mention, time_expected))
47 | number_of_chats = 0
48 | for chat_id in served_chats:
49 | try:
50 | await app.ban_chat_member(chat_id, user.id)
51 | number_of_chats += 1
52 | except FloodWait as fw:
53 | await asyncio.sleep(int(fw.value))
54 | except:
55 | continue
56 | await add_banned_user(user.id)
57 | await message.reply_text(
58 | _["gban_6"].format(
59 | app.mention,
60 | message.chat.title,
61 | message.chat.id,
62 | user.mention,
63 | user.id,
64 | message.from_user.mention,
65 | number_of_chats,
66 | )
67 | )
68 | await mystic.delete()
69 |
70 |
71 | @app.on_message(filters.command(["ungban"]) & SUDOERS)
72 | @language
73 | async def global_un(client, message: Message, _):
74 | if not message.reply_to_message:
75 | if len(message.command) != 2:
76 | return await message.reply_text(_["general_1"])
77 | user = await extract_user(message)
78 | is_gbanned = await is_banned_user(user.id)
79 | if not is_gbanned:
80 | return await message.reply_text(_["gban_7"].format(user.mention))
81 | if user.id in BANNED_USERS:
82 | BANNED_USERS.remove(user.id)
83 | served_chats = []
84 | chats = await get_served_chats()
85 | for chat in chats:
86 | served_chats.append(int(chat["chat_id"]))
87 | time_expected = get_readable_time(len(served_chats))
88 | mystic = await message.reply_text(_["gban_8"].format(user.mention, time_expected))
89 | number_of_chats = 0
90 | for chat_id in served_chats:
91 | try:
92 | await app.unban_chat_member(chat_id, user.id)
93 | number_of_chats += 1
94 | except FloodWait as fw:
95 | await asyncio.sleep(int(fw.value))
96 | except:
97 | continue
98 | await remove_banned_user(user.id)
99 | await message.reply_text(_["gban_9"].format(user.mention, number_of_chats))
100 | await mystic.delete()
101 |
102 |
103 | @app.on_message(filters.command(["gbannedusers", "gbanlist"]) & SUDOERS)
104 | @language
105 | async def gbanned_list(client, message: Message, _):
106 | counts = await get_banned_count()
107 | if counts == 0:
108 | return await message.reply_text(_["gban_10"])
109 | mystic = await message.reply_text(_["gban_11"])
110 | msg = _["gban_12"]
111 | count = 0
112 | users = await get_banned_users()
113 | for user_id in users:
114 | count += 1
115 | try:
116 | user = await app.get_users(user_id)
117 | user = user.first_name if not user.mention else user.mention
118 | msg += f"{count}➤ {user}\n"
119 | except Exception:
120 | msg += f"{count}➤ {user_id}\n"
121 | continue
122 | if count == 0:
123 | return await mystic.edit_text(_["gban_10"])
124 | else:
125 | return await mystic.edit_text(msg)
126 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/misc/clean_assistant.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters
2 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery
3 |
4 | from DeadlineTech import app
5 | from DeadlineTech.misc import SUDOERS
6 | from DeadlineTech.utils.database import get_client, is_active_chat
7 | from config import LOGGER_ID
8 | from pyrogram.enums import ChatType
9 |
10 | from DeadlineTech.core.userbot import assistants
11 |
12 |
13 | async def clean_assistant_chats(client, assistant_num):
14 | total_left = 0
15 | try:
16 | userbot = await get_client(assistant_num)
17 | left = 0
18 | async for dialog in userbot.get_dialogs():
19 | chat = dialog.chat
20 | if chat.type in [ChatType.SUPERGROUP, ChatType.GROUP, ChatType.CHANNEL]:
21 | if chat.id in [LOGGER_ID, -1001686672798, -1001549206010]: # Excluded chats
22 | continue
23 | if not await is_active_chat(chat.id):
24 | try:
25 | await userbot.leave_chat(chat.id)
26 | left += 1
27 | except Exception as e:
28 | print(f"[CleanAssistant Error] Failed to leave {chat.title} ({chat.id}): {e}")
29 | total_left += left
30 | except Exception as e:
31 | print(f"[CleanAssistant Error] Assistant {assistant_num} failed: {e}")
32 |
33 | return total_left
34 |
35 |
36 | @app.on_message(filters.command("cleanassistants") & filters.private & SUDOERS )
37 | async def clean_assistants_command(client, message: Message):
38 | args = message.text.split()
39 | if len(args) == 1:
40 | # No assistant id given, show buttons + clean all
41 | buttons = [
42 | [InlineKeyboardButton(f"Assistant {num}", callback_data=f"clean_assistant:{num}")]
43 | for num in assistants
44 | ]
45 | # Add Clean All button at the bottom
46 | buttons.append([InlineKeyboardButton("Clean All Assistants 🧹", callback_data="clean_assistant:all")])
47 |
48 | reply_markup = InlineKeyboardMarkup(buttons)
49 | await message.reply_text(
50 | "Select the assistant to clean inactive chats, or clean all assistants:",
51 | reply_markup=reply_markup,
52 | )
53 | else:
54 | # assistant id given
55 | arg = args[1].lower()
56 | if arg == "all":
57 | msg = await message.reply_text(f"🧹 Cleaning all assistants... Please wait.")
58 | total_left_all = 0
59 | for assistant_id in assistants:
60 | total_left_all += await clean_assistant_chats(client, assistant_id)
61 | await msg.edit_text(f"✅ Cleaned all assistants.\nTotal chats left: {total_left_all}.")
62 | else:
63 | try:
64 | assistant_id = int(arg)
65 | except ValueError:
66 | return await message.reply_text("Invalid assistant id. Please provide a number or 'all'.")
67 |
68 | if assistant_id not in assistants:
69 | return await message.reply_text("This assistant id is not valid or not available.")
70 |
71 | msg = await message.reply_text(f"🧹 Cleaning inactive chats for assistant {assistant_id}... Please wait.")
72 | total_left = await clean_assistant_chats(client, assistant_id)
73 | await msg.edit_text(f"✅ Cleaned assistant {assistant_id}.\nTotal chats left: {total_left}.")
74 |
75 |
76 | @app.on_callback_query(filters.regex(r"^clean_assistant:(all|\d+)$"))
77 | async def clean_assistant_callback(client, callback_query: CallbackQuery):
78 | if callback_query.from_user.id not in SUDOERS:
79 | return await callback_query.answer("You are not authorized.", show_alert=True)
80 |
81 | arg = callback_query.data.split(":")[1]
82 | if arg == "all":
83 | await callback_query.answer("Cleaning all assistants...")
84 | msg = await callback_query.message.edit_text(f"🧹 Cleaning all assistants... Please wait.")
85 | total_left_all = 0
86 | for assistant_id in assistants:
87 | total_left_all += await clean_assistant_chats(client, assistant_id)
88 | await msg.edit_text(f"✅ Cleaned all assistants.\nTotal chats left: {total_left_all}.")
89 | else:
90 | assistant_id = int(arg)
91 | if assistant_id not in assistants:
92 | return await callback_query.answer("Invalid assistant id.", show_alert=True)
93 |
94 | await callback_query.answer("Cleaning started...")
95 | msg = await callback_query.message.edit_text(f"🧹 Cleaning inactive chats for assistant {assistant_id}... Please wait.")
96 | total_left = await clean_assistant_chats(client, assistant_id)
97 | await msg.edit_text(f"✅ Cleaned assistant {assistant_id}.\nTotal chats left: {total_left}.")
98 |
--------------------------------------------------------------------------------
/DeadlineTech/platforms/Spotify.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team DeadlineTech | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team DeadlineTech
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 |
27 | import re
28 |
29 | import spotipy
30 | from spotipy.oauth2 import SpotifyClientCredentials
31 | from youtubesearchpython.__future__ import VideosSearch
32 |
33 | import config
34 |
35 |
36 | class SpotifyAPI:
37 | def __init__(self):
38 | self.regex = r"^(https:\/\/open.spotify.com\/)(.*)$"
39 | self.client_id = config.SPOTIFY_CLIENT_ID
40 | self.client_secret = config.SPOTIFY_CLIENT_SECRET
41 | if config.SPOTIFY_CLIENT_ID and config.SPOTIFY_CLIENT_SECRET:
42 | self.client_credentials_manager = SpotifyClientCredentials(
43 | self.client_id, self.client_secret
44 | )
45 | self.spotify = spotipy.Spotify(
46 | client_credentials_manager=self.client_credentials_manager
47 | )
48 | else:
49 | self.spotify = None
50 |
51 | async def valid(self, link: str):
52 | if re.search(self.regex, link):
53 | return True
54 | else:
55 | return False
56 |
57 | async def track(self, link: str):
58 | track = self.spotify.track(link)
59 | info = track["name"]
60 | for artist in track["artists"]:
61 | fetched = f' {artist["name"]}'
62 | if "Various Artists" not in fetched:
63 | info += fetched
64 | results = VideosSearch(info, limit=1)
65 | for result in (await results.next())["result"]:
66 | ytlink = result["link"]
67 | title = result["title"]
68 | vidid = result["id"]
69 | duration_min = result["duration"]
70 | thumbnail = result["thumbnails"][0]["url"].split("?")[0]
71 | track_details = {
72 | "title": title,
73 | "link": ytlink,
74 | "vidid": vidid,
75 | "duration_min": duration_min,
76 | "thumb": thumbnail,
77 | }
78 | return track_details, vidid
79 |
80 | async def playlist(self, url):
81 | playlist = self.spotify.playlist(url)
82 | playlist_id = playlist["id"]
83 | results = []
84 | for item in playlist["tracks"]["items"]:
85 | music_track = item["track"]
86 | info = music_track["name"]
87 | for artist in music_track["artists"]:
88 | fetched = f' {artist["name"]}'
89 | if "Various Artists" not in fetched:
90 | info += fetched
91 | results.append(info)
92 | return results, playlist_id
93 |
94 | async def album(self, url):
95 | album = self.spotify.album(url)
96 | album_id = album["id"]
97 | results = []
98 | for item in album["tracks"]["items"]:
99 | info = item["name"]
100 | for artist in item["artists"]:
101 | fetched = f' {artist["name"]}'
102 | if "Various Artists" not in fetched:
103 | info += fetched
104 | results.append(info)
105 |
106 | return (
107 | results,
108 | album_id,
109 | )
110 |
111 | async def artist(self, url):
112 | artistinfo = self.spotify.artist(url)
113 | artist_id = artistinfo["id"]
114 | results = []
115 | artisttoptracks = self.spotify.artist_top_tracks(url)
116 | for item in artisttoptracks["tracks"]:
117 | info = item["name"]
118 | for artist in item["artists"]:
119 | fetched = f' {artist["name"]}'
120 | if "Various Artists" not in fetched:
121 | info += fetched
122 | results.append(info)
123 |
124 | return results, artist_id
125 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/stats.py:
--------------------------------------------------------------------------------
1 | import platform
2 | from sys import version as pyver
3 |
4 | import psutil
5 | from pyrogram import __version__ as pyrover
6 | from pyrogram import filters
7 | from pyrogram.errors import MessageIdInvalid
8 | from pyrogram.types import InputMediaPhoto, Message
9 | from pytgcalls.__version__ import __version__ as pytgver
10 |
11 | import config
12 | from DeadlineTech import app
13 | from DeadlineTech.core.userbot import assistants
14 | from DeadlineTech.misc import SUDOERS, mongodb
15 | from DeadlineTech.plugins import ALL_MODULES
16 | from DeadlineTech.utils.database import get_served_chats, get_served_users, get_sudoers
17 | from DeadlineTech.utils.decorators.language import language, languageCB
18 | from DeadlineTech.utils.inline.stats import back_stats_buttons, stats_buttons
19 | from config import BANNED_USERS
20 |
21 |
22 | @app.on_message(filters.command(["stats", "gstats"]) & filters.group & ~BANNED_USERS)
23 | @language
24 | async def stats_global(client, message: Message, _):
25 | upl = stats_buttons(_, True if message.from_user.id in SUDOERS else False)
26 | await message.reply_photo(
27 | photo=config.STATS_IMG_URL,
28 | caption=_["gstats_2"].format(app.mention),
29 | reply_markup=upl,
30 | )
31 |
32 |
33 | @app.on_callback_query(filters.regex("stats_back") & ~BANNED_USERS)
34 | @languageCB
35 | async def home_stats(client, CallbackQuery, _):
36 | upl = stats_buttons(_, True if CallbackQuery.from_user.id in SUDOERS else False)
37 | await CallbackQuery.edit_message_text(
38 | text=_["gstats_2"].format(app.mention),
39 | reply_markup=upl,
40 | )
41 |
42 |
43 | @app.on_callback_query(filters.regex("TopOverall") & ~BANNED_USERS)
44 | @languageCB
45 | async def overall_stats(client, CallbackQuery, _):
46 | await CallbackQuery.answer()
47 | upl = back_stats_buttons(_)
48 | try:
49 | await CallbackQuery.answer()
50 | except:
51 | pass
52 | await CallbackQuery.edit_message_text(_["gstats_1"].format(app.mention))
53 | served_chats = len(await get_served_chats())
54 | served_users = len(await get_served_users())
55 | text = _["gstats_3"].format(
56 | app.mention,
57 | len(assistants),
58 | len(BANNED_USERS),
59 | served_chats,
60 | served_users,
61 | len(ALL_MODULES),
62 | len(SUDOERS),
63 | config.DURATION_LIMIT_MIN,
64 | )
65 | med = InputMediaPhoto(media=config.STATS_IMG_URL, caption=text)
66 | try:
67 | await CallbackQuery.edit_message_media(media=med, reply_markup=upl)
68 | except MessageIdInvalid:
69 | await CallbackQuery.message.reply_photo(
70 | photo=config.STATS_IMG_URL, caption=text, reply_markup=upl
71 | )
72 |
73 |
74 | @app.on_callback_query(filters.regex("bot_stats_sudo"))
75 | @languageCB
76 | async def bot_stats(client, CallbackQuery, _):
77 | if CallbackQuery.from_user.id not in SUDOERS:
78 | return await CallbackQuery.answer(_["gstats_4"], show_alert=True)
79 | upl = back_stats_buttons(_)
80 | try:
81 | await CallbackQuery.answer()
82 | except:
83 | pass
84 | await CallbackQuery.edit_message_text(_["gstats_1"].format(app.mention))
85 | p_core = psutil.cpu_count(logical=False)
86 | t_core = psutil.cpu_count(logical=True)
87 | ram = str(round(psutil.virtual_memory().total / (1024.0**3))) + " ɢʙ"
88 | try:
89 | cpu_freq = psutil.cpu_freq().current
90 | if cpu_freq >= 1000:
91 | cpu_freq = f"{round(cpu_freq / 1000, 2)}ɢʜᴢ"
92 | else:
93 | cpu_freq = f"{round(cpu_freq, 2)}ᴍʜᴢ"
94 | except:
95 | cpu_freq = "ғᴀɪʟᴇᴅ ᴛᴏ ғᴇᴛᴄʜ"
96 | hdd = psutil.disk_usage("/")
97 | total = hdd.total / (1024.0**3)
98 | used = hdd.used / (1024.0**3)
99 | free = hdd.free / (1024.0**3)
100 | call = await mongodb.command("dbstats")
101 | datasize = call["dataSize"] / 1024
102 | storage = call["storageSize"] / 1024
103 | served_chats = len(await get_served_chats())
104 | served_users = len(await get_served_users())
105 | text = _["gstats_5"].format(
106 | app.mention,
107 | len(ALL_MODULES),
108 | platform.system(),
109 | ram,
110 | p_core,
111 | t_core,
112 | cpu_freq,
113 | pyver.split()[0],
114 | pyrover,
115 | pytgver,
116 | str(total)[:4],
117 | str(used)[:4],
118 | str(free)[:4],
119 | served_chats,
120 | served_users,
121 | len(BANNED_USERS),
122 | len(await get_sudoers()),
123 | str(datasize)[:6],
124 | storage,
125 | call["collections"],
126 | call["objects"],
127 | )
128 | med = InputMediaPhoto(media=config.STATS_IMG_URL, caption=text)
129 | try:
130 | await CallbackQuery.edit_message_media(media=med, reply_markup=upl)
131 | except MessageIdInvalid:
132 | await CallbackQuery.message.reply_photo(
133 | photo=config.STATS_IMG_URL, caption=text, reply_markup=upl
134 | )
135 |
--------------------------------------------------------------------------------
/DeadlineTech/core/userbot.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ==========================================================
4 | # 🎧 Public Open-Source VC Player Music Bot (Cookies Based)
5 | # 🛠️ Maintained by Team Arc | Lead Developer: @Its_damiann
6 | # 🔓 Licensed for Public Use — All Rights Reserved © Team Arc
7 | #
8 | # This file is part of a publicly available and open-source Telegram music bot
9 | # developed by Team DeadlineTech. It offers high-quality streaming in Telegram voice
10 | # chats using YouTube as a source, supported by session-based assistant accounts and
11 | # YouTube cookie integration for improved access and performance.
12 | #
13 | # 💡 This source code is released for educational and community purposes. You're free
14 | # to study, modify, and deploy it under fair and respectful usage. However, any misuse,
15 | # removal of credits, or false ownership claims will be considered a violation of our
16 | # community standards and may lead to denial of support or blacklisting.
17 | #
18 | # 🔗 Looking for powerful performance with stable APIs? Get access to the official
19 | # premium API service: https://DeadlineTech.site or Visit @ApixhubBot
20 | #
21 | # ❤️ Openly built for the community, but proudly protected by the passion of its creators.
22 | # ==========================================================
23 |
24 |
25 |
26 | from pyrogram import Client
27 | import config
28 | from ..logging import LOGGER
29 |
30 | assistants = []
31 | assistantids = []
32 |
33 |
34 | class Userbot(Client):
35 | def __init__(self):
36 | self.one = Client(
37 | name="DeadlineXAss1",
38 | api_id=config.API_ID,
39 | api_hash=config.API_HASH,
40 | session_string=str(config.STRING1),
41 | no_updates=True,
42 | )
43 | self.two = Client(
44 | name="DeadlineXAss2",
45 | api_id=config.API_ID,
46 | api_hash=config.API_HASH,
47 | session_string=str(config.STRING2),
48 | no_updates=True,
49 | )
50 | self.three = Client(
51 | name="DeadlineXAss3",
52 | api_id=config.API_ID,
53 | api_hash=config.API_HASH,
54 | session_string=str(config.STRING3),
55 | no_updates=True,
56 | )
57 | self.four = Client(
58 | name="DeadlineXAss4",
59 | api_id=config.API_ID,
60 | api_hash=config.API_HASH,
61 | session_string=str(config.STRING4),
62 | no_updates=True,
63 | )
64 | self.five = Client(
65 | name="DeadlineXAss5",
66 | api_id=config.API_ID,
67 | api_hash=config.API_HASH,
68 | session_string=str(config.STRING5),
69 | no_updates=True,
70 | )
71 |
72 | async def start(self):
73 | LOGGER(__name__).info("🚀 Starting assistant clients...")
74 |
75 | async def setup_assistant(client, number):
76 | try:
77 | await client.start()
78 | await client.join_chat("ArcBotz")
79 | await client.join_chat("ArcUpdates")
80 | except Exception:
81 | pass
82 |
83 | assistants.append(number)
84 |
85 | try:
86 | await client.send_message(config.LOGGER_ID, f"✅ Assistant {number} is now online.")
87 | except Exception:
88 | LOGGER(__name__).error(
89 | f"❌ Assistant {number} failed to send a message to the log group. "
90 | f"Ensure it's added and promoted to admin in LOGGER group ({config.LOGGER_ID})."
91 | )
92 | exit()
93 |
94 | client.id = client.me.id
95 | client.name = client.me.mention
96 | client.username = client.me.username
97 | assistantids.append(client.id)
98 |
99 | LOGGER(__name__).info(f"🤖 Assistant {number} is active as {client.name}")
100 |
101 | if config.STRING1:
102 | await setup_assistant(self.one, 1)
103 | if config.STRING2:
104 | await setup_assistant(self.two, 2)
105 | if config.STRING3:
106 | await setup_assistant(self.three, 3)
107 | if config.STRING4:
108 | await setup_assistant(self.four, 4)
109 | if config.STRING5:
110 | await setup_assistant(self.five, 5)
111 |
112 | LOGGER(__name__).info("✅ All available assistants are now online.")
113 |
114 | async def stop(self):
115 | LOGGER(__name__).info("🛑 Shutting down assistant clients...")
116 | try:
117 | if config.STRING1:
118 | await self.one.stop()
119 | if config.STRING2:
120 | await self.two.stop()
121 | if config.STRING3:
122 | await self.three.stop()
123 | if config.STRING4:
124 | await self.four.stop()
125 | if config.STRING5:
126 | await self.five.stop()
127 | except Exception as e:
128 | LOGGER(__name__).warning(f"⚠️ Error while stopping assistants: {e}")
129 |
--------------------------------------------------------------------------------
/DeadlineTech/utils/formatters.py:
--------------------------------------------------------------------------------
1 | import json
2 | import subprocess
3 |
4 |
5 | def get_readable_time(seconds: int) -> str:
6 | count = 0
7 | ping_time = ""
8 | time_list = []
9 | time_suffix_list = ["s", "ᴍ", "ʜ", "ᴅᴀʏs"]
10 | while count < 4:
11 | count += 1
12 | if count < 3:
13 | remainder, result = divmod(seconds, 60)
14 | else:
15 | remainder, result = divmod(seconds, 24)
16 | if seconds == 0 and remainder == 0:
17 | break
18 | time_list.append(int(result))
19 | seconds = int(remainder)
20 | for i in range(len(time_list)):
21 | time_list[i] = str(time_list[i]) + time_suffix_list[i]
22 | if len(time_list) == 4:
23 | ping_time += time_list.pop() + ", "
24 | time_list.reverse()
25 | ping_time += ":".join(time_list)
26 | return ping_time
27 |
28 |
29 | def convert_bytes(size: float) -> str:
30 | """humanize size"""
31 | if not size:
32 | return ""
33 | power = 1024
34 | t_n = 0
35 | power_dict = {0: " ", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"}
36 | while size > power:
37 | size /= power
38 | t_n += 1
39 | return "{:.2f} {}B".format(size, power_dict[t_n])
40 |
41 |
42 | async def int_to_alpha(user_id: int) -> str:
43 | alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
44 | text = ""
45 | user_id = str(user_id)
46 | for i in user_id:
47 | text += alphabet[int(i)]
48 | return text
49 |
50 |
51 | async def alpha_to_int(user_id_alphabet: str) -> int:
52 | alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
53 | user_id = ""
54 | for i in user_id_alphabet:
55 | index = alphabet.index(i)
56 | user_id += str(index)
57 | user_id = int(user_id)
58 | return user_id
59 |
60 |
61 | def time_to_seconds(time):
62 | stringt = str(time)
63 | return sum(int(x) * 60**i for i, x in enumerate(reversed(stringt.split(":"))))
64 |
65 |
66 | def seconds_to_min(seconds):
67 | if seconds is not None:
68 | seconds = int(seconds)
69 | d, h, m, s = (
70 | seconds // (3600 * 24),
71 | seconds // 3600 % 24,
72 | seconds % 3600 // 60,
73 | seconds % 3600 % 60,
74 | )
75 | if d > 0:
76 | return "{:02d}:{:02d}:{:02d}:{:02d}".format(d, h, m, s)
77 | elif h > 0:
78 | return "{:02d}:{:02d}:{:02d}".format(h, m, s)
79 | elif m > 0:
80 | return "{:02d}:{:02d}".format(m, s)
81 | elif s > 0:
82 | return "00:{:02d}".format(s)
83 | return "-"
84 |
85 |
86 | def speed_converter(seconds, speed):
87 | if str(speed) == str("0.5"):
88 | seconds = seconds * 2
89 | if str(speed) == str("0.75"):
90 | seconds = seconds + ((50 * seconds) // 100)
91 | if str(speed) == str("1.5"):
92 | seconds = seconds - ((25 * seconds) // 100)
93 | if str(speed) == str("2.0"):
94 | seconds = seconds - ((50 * seconds) // 100)
95 | collect = seconds
96 | if seconds is not None:
97 | seconds = int(seconds)
98 | d, h, m, s = (
99 | seconds // (3600 * 24),
100 | seconds // 3600 % 24,
101 | seconds % 3600 // 60,
102 | seconds % 3600 % 60,
103 | )
104 | if d > 0:
105 | convert = "{:02d}:{:02d}:{:02d}:{:02d}".format(d, h, m, s)
106 | return convert, collect
107 | elif h > 0:
108 | convert = "{:02d}:{:02d}:{:02d}".format(h, m, s)
109 | return convert, collect
110 | elif m > 0:
111 | convert = "{:02d}:{:02d}".format(m, s)
112 | return convert, collect
113 | elif s > 0:
114 | convert = "00:{:02d}".format(s)
115 | return convert, collect
116 | return "-"
117 |
118 |
119 | def check_duration(file_path):
120 | command = [
121 | "ffprobe",
122 | "-loglevel",
123 | "quiet",
124 | "-print_format",
125 | "json",
126 | "-show_format",
127 | "-show_streams",
128 | file_path,
129 | ]
130 |
131 | pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
132 | out, err = pipe.communicate()
133 | _json = json.loads(out)
134 |
135 | if "format" in _json:
136 | if "duration" in _json["format"]:
137 | return float(_json["format"]["duration"])
138 |
139 | if "streams" in _json:
140 | for s in _json["streams"]:
141 | if "duration" in s:
142 | return float(s["duration"])
143 |
144 | return "Unknown"
145 |
146 |
147 | formats = [
148 | "webm",
149 | "mkv",
150 | "flv",
151 | "vob",
152 | "ogv",
153 | "ogg",
154 | "rrc",
155 | "gifv",
156 | "mng",
157 | "mov",
158 | "avi",
159 | "qt",
160 | "wmv",
161 | "yuv",
162 | "rm",
163 | "asf",
164 | "amv",
165 | "mp4",
166 | "m4p",
167 | "m4v",
168 | "mpg",
169 | "mp2",
170 | "mpeg",
171 | "mpe",
172 | "mpv",
173 | "m4v",
174 | "svi",
175 | "3gp",
176 | "3g2",
177 | "mxf",
178 | "roq",
179 | "nsv",
180 | "flv",
181 | "f4v",
182 | "f4p",
183 | "f4a",
184 | "f4b",
185 | ]
186 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/sudo/restart.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import os
3 | import shutil
4 | import socket
5 | from datetime import datetime
6 |
7 | import urllib3
8 | from git import Repo
9 | from git.exc import GitCommandError, InvalidGitRepositoryError
10 | from pyrogram import filters
11 |
12 | import config
13 | from DeadlineTech import app
14 | from DeadlineTech.misc import HAPP, SUDOERS, XCB
15 | from DeadlineTech.utils.database import (
16 | get_active_chats,
17 | remove_active_chat,
18 | remove_active_video_chat,
19 | )
20 | from DeadlineTech.utils.decorators.language import language
21 | from DeadlineTech.utils.pastebin import AnonyBin
22 |
23 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
24 |
25 |
26 | async def is_heroku():
27 | return "heroku" in socket.getfqdn()
28 |
29 |
30 | @app.on_message(filters.command(["getlog", "logs", "getlogs"]) & SUDOERS)
31 | @language
32 | async def log_(client, message, _):
33 | try:
34 | await message.reply_document(document="log.txt")
35 | except:
36 | await message.reply_text(_["server_1"])
37 |
38 |
39 | @app.on_message(filters.command(["update", "gitpull"]) & SUDOERS)
40 | @language
41 | async def update_(client, message, _):
42 | if await is_heroku():
43 | if HAPP is None:
44 | return await message.reply_text(_["server_2"])
45 | response = await message.reply_text(_["server_3"])
46 | try:
47 | repo = Repo()
48 | except GitCommandError:
49 | return await response.edit(_["server_4"])
50 | except InvalidGitRepositoryError:
51 | return await response.edit(_["server_5"])
52 | to_exc = f"git fetch origin {config.UPSTREAM_BRANCH} &> /dev/null"
53 | os.system(to_exc)
54 | await asyncio.sleep(7)
55 | verification = ""
56 | REPO_ = repo.remotes.origin.url.split(".git")[0]
57 | for checks in repo.iter_commits(f"HEAD..origin/{config.UPSTREAM_BRANCH}"):
58 | verification = str(checks.count())
59 | if verification == "":
60 | return await response.edit(_["server_6"])
61 | updates = ""
62 | ordinal = lambda format: "%d%s" % (
63 | format,
64 | "tsnrhtdd"[(format // 10 % 10 != 1) * (format % 10 < 4) * format % 10 :: 4],
65 | )
66 | for info in repo.iter_commits(f"HEAD..origin/{config.UPSTREAM_BRANCH}"):
67 | updates += f"➣ #{info.count()}: {info.summary} ʙʏ -> {info.author}\n\t\t\t\t➥ ᴄᴏᴍᴍɪᴛᴇᴅ ᴏɴ : {ordinal(int(datetime.fromtimestamp(info.committed_date).strftime('%d')))} {datetime.fromtimestamp(info.committed_date).strftime('%b')}, {datetime.fromtimestamp(info.committed_date).strftime('%Y')}\n\n"
68 | _update_response_ = "ᴀ ɴᴇᴡ ᴜᴩᴅᴀᴛᴇ ɪs ᴀᴠᴀɪʟᴀʙʟᴇ ғᴏʀ ᴛʜᴇ ʙᴏᴛ !\n\n➣ ᴩᴜsʜɪɴɢ ᴜᴩᴅᴀᴛᴇs ɴᴏᴡ\n\nᴜᴩᴅᴀᴛᴇs:\n\n"
69 | _final_updates_ = _update_response_ + updates
70 | if len(_final_updates_) > 4096:
71 | url = await AnonyBin(updates)
72 | nrs = await response.edit(
73 | f"ᴀ ɴᴇᴡ ᴜᴩᴅᴀᴛᴇ ɪs ᴀᴠᴀɪʟᴀʙʟᴇ ғᴏʀ ᴛʜᴇ ʙᴏᴛ !\n\n➣ ᴩᴜsʜɪɴɢ ᴜᴩᴅᴀᴛᴇs ɴᴏᴡ\n\nᴜᴩᴅᴀᴛᴇs :\n\nᴄʜᴇᴄᴋ ᴜᴩᴅᴀᴛᴇs"
74 | )
75 | else:
76 | nrs = await response.edit(_final_updates_, disable_web_page_preview=True)
77 | os.system("git stash &> /dev/null && git pull")
78 |
79 | try:
80 | served_chats = await get_active_chats()
81 | for x in served_chats:
82 | try:
83 | await app.send_message(
84 | chat_id=int(x),
85 | text=_["server_8"].format(app.mention),
86 | )
87 | await remove_active_chat(x)
88 | await remove_active_video_chat(x)
89 | except:
90 | pass
91 | await response.edit(f"{nrs.text}\n\n{_['server_7']}")
92 | except:
93 | pass
94 |
95 | if await is_heroku():
96 | try:
97 | os.system(
98 | f"{XCB[5]} {XCB[7]} {XCB[9]}{XCB[4]}{XCB[0]*2}{XCB[6]}{XCB[4]}{XCB[8]}{XCB[1]}{XCB[5]}{XCB[2]}{XCB[6]}{XCB[2]}{XCB[3]}{XCB[0]}{XCB[10]}{XCB[2]}{XCB[5]} {XCB[11]}{XCB[4]}{XCB[12]}"
99 | )
100 | return
101 | except Exception as err:
102 | await response.edit(f"{nrs.text}\n\n{_['server_9']}")
103 | return await app.send_message(
104 | chat_id=config.LOGGER_ID,
105 | text=_["server_10"].format(err),
106 | )
107 | else:
108 | os.system("pip3 install -r requirements.txt")
109 | os.system(f"kill -9 {os.getpid()} && bash start")
110 | exit()
111 |
112 |
113 | @app.on_message(filters.command(["restart"]) & SUDOERS)
114 | async def restart_(_, message):
115 | response = await message.reply_text("ʀᴇsᴛᴀʀᴛɪɴɢ...")
116 | ac_chats = await get_active_chats()
117 | for x in ac_chats:
118 | try:
119 | await app.send_message(
120 | chat_id=int(x),
121 | text=f"{app.mention} ɪs ʀᴇsᴛᴀʀᴛɪɴɢ...\n\nʏᴏᴜ ᴄᴀɴ sᴛᴀʀᴛ ᴩʟᴀʏɪɴɢ ᴀɢᴀɪɴ ᴀғᴛᴇʀ 15-20 sᴇᴄᴏɴᴅs.",
122 | )
123 | await remove_active_chat(x)
124 | await remove_active_video_chat(x)
125 | except:
126 | pass
127 |
128 | try:
129 | shutil.rmtree("downloads")
130 | shutil.rmtree("raw_files")
131 | shutil.rmtree("cache")
132 | except:
133 | pass
134 | await response.edit_text(
135 | "» ʀᴇsᴛᴀʀᴛ ᴘʀᴏᴄᴇss sᴛᴀʀᴛᴇᴅ, ᴘʟᴇᴀsᴇ ᴡᴀɪᴛ ғᴏʀ ғᴇᴡ sᴇᴄᴏɴᴅs ᴜɴᴛɪʟ ᴛʜᴇ ʙᴏᴛ sᴛᴀʀᴛs..."
136 | )
137 | os.system(f"kill -9 {os.getpid()} && bash start")
138 |
--------------------------------------------------------------------------------
/.github/README.md:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
179 | - sᴩᴇᴄɪᴀʟ ᴛʜᴀɴᴋs ᴛᴏ [ᴛᴇᴀᴍ ʏᴜᴋᴋɪ] ғᴏʀ [ʏᴜᴋᴋɪ ᴍᴜsɪᴄ ʙᴏᴛ] 180 |
181 | -------------------------------------------------------------------------------- /DeadlineTech/utils/inline/play.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | from pyrogram.types import InlineKeyboardButton 4 | 5 | from DeadlineTech.utils.formatters import time_to_seconds 6 | 7 | 8 | def track_markup(_, videoid, user_id, channel, fplay): 9 | buttons = [ 10 | [ 11 | InlineKeyboardButton( 12 | text=_["P_B_1"], 13 | callback_data=f"MusicStream {videoid}|{user_id}|a|{channel}|{fplay}", 14 | ), 15 | InlineKeyboardButton( 16 | text=_["P_B_2"], 17 | callback_data=f"MusicStream {videoid}|{user_id}|v|{channel}|{fplay}", 18 | ), 19 | ], 20 | ] 21 | return buttons 22 | 23 | 24 | def stream_markup_timer(_, chat_id, played, dur): 25 | played_sec = time_to_seconds(played) 26 | duration_sec = time_to_seconds(dur) 27 | percentage = (played_sec / duration_sec) * 100 28 | umm = math.floor(percentage) 29 | if 0 < umm <= 10: 30 | bar = "◉—————————" 31 | elif 10 < umm < 20: 32 | bar = "—◉————————" 33 | elif 20 <= umm < 30: 34 | bar = "——◉———————" 35 | elif 30 <= umm < 40: 36 | bar = "———◉——————" 37 | elif 40 <= umm < 50: 38 | bar = "————◉—————" 39 | elif 50 <= umm < 60: 40 | bar = "—————◉————" 41 | elif 60 <= umm < 70: 42 | bar = "——————◉———" 43 | elif 70 <= umm < 80: 44 | bar = "———————◉——" 45 | elif 80 <= umm < 95: 46 | bar = "————————◉—" 47 | else: 48 | bar = "—————————◉" 49 | buttons = [ 50 | [ 51 | InlineKeyboardButton( 52 | text=f"{played} {bar} {dur}", 53 | callback_data="GetTimer", 54 | ) 55 | ], 56 | [ 57 | InlineKeyboardButton(text="▷", callback_data=f"ADMIN Resume|{chat_id}"), 58 | InlineKeyboardButton(text="II", callback_data=f"ADMIN Pause|{chat_id}"), 59 | InlineKeyboardButton(text="↻", callback_data=f"ADMIN Replay|{chat_id}"), 60 | InlineKeyboardButton(text="‣‣I", callback_data=f"ADMIN Skip|{chat_id}"), 61 | InlineKeyboardButton(text="▢", callback_data=f"ADMIN Stop|{chat_id}"), 62 | ], 63 | [InlineKeyboardButton(text=_["CLOSE_BUTTONS"], callback_data="close")], 64 | ] 65 | return buttons 66 | 67 | 68 | def stream_markup(_, chat_id): 69 | buttons = [ 70 | [ 71 | InlineKeyboardButton(text="▷", callback_data=f"ADMIN Resume|{chat_id}"), 72 | InlineKeyboardButton(text="II", callback_data=f"ADMIN Pause|{chat_id}"), 73 | InlineKeyboardButton(text="↻", callback_data=f"ADMIN Replay|{chat_id}"), 74 | InlineKeyboardButton(text="‣‣I", callback_data=f"ADMIN Skip|{chat_id}"), 75 | InlineKeyboardButton(text="▢", callback_data=f"ADMIN Stop|{chat_id}"), 76 | ], 77 | [InlineKeyboardButton(text=_["CLOSE_BUTTON"], callback_data="close")], 78 | ] 79 | return buttons 80 | 81 | 82 | def playlist_markup(_, videoid, user_id, ptype, channel, fplay): 83 | buttons = [ 84 | [ 85 | InlineKeyboardButton( 86 | text=_["P_B_1"], 87 | callback_data=f"AnonyPlaylists {videoid}|{user_id}|{ptype}|a|{channel}|{fplay}", 88 | ), 89 | InlineKeyboardButton( 90 | text=_["P_B_2"], 91 | callback_data=f"AnonyPlaylists {videoid}|{user_id}|{ptype}|v|{channel}|{fplay}", 92 | ), 93 | ], 94 | [ 95 | InlineKeyboardButton( 96 | text=_["CLOSE_BUTTON"], 97 | callback_data=f"forceclose {videoid}|{user_id}", 98 | ), 99 | ], 100 | ] 101 | return buttons 102 | 103 | 104 | def livestream_markup(_, videoid, user_id, mode, channel, fplay): 105 | buttons = [ 106 | [ 107 | InlineKeyboardButton( 108 | text=_["P_B_3"], 109 | callback_data=f"LiveStream {videoid}|{user_id}|{mode}|{channel}|{fplay}", 110 | ), 111 | ], 112 | [ 113 | InlineKeyboardButton( 114 | text=_["CLOSE_BUTTON"], 115 | callback_data=f"forceclose {videoid}|{user_id}", 116 | ), 117 | ], 118 | ] 119 | return buttons 120 | 121 | 122 | def slider_markup(_, videoid, user_id, query, query_type, channel, fplay): 123 | query = f"{query[:20]}" 124 | buttons = [ 125 | [ 126 | InlineKeyboardButton( 127 | text=_["P_B_1"], 128 | callback_data=f"MusicStream {videoid}|{user_id}|a|{channel}|{fplay}", 129 | ), 130 | InlineKeyboardButton( 131 | text=_["P_B_2"], 132 | callback_data=f"MusicStream {videoid}|{user_id}|v|{channel}|{fplay}", 133 | ), 134 | ], 135 | [ 136 | InlineKeyboardButton( 137 | text="◁", 138 | callback_data=f"slider B|{query_type}|{query}|{user_id}|{channel}|{fplay}", 139 | ), 140 | InlineKeyboardButton( 141 | text=_["CLOSE_BUTTON"], 142 | callback_data=f"forceclose {query}|{user_id}", 143 | ), 144 | InlineKeyboardButton( 145 | text="▷", 146 | callback_data=f"slider F|{query_type}|{query}|{user_id}|{channel}|{fplay}", 147 | ), 148 | ], 149 | ] 150 | return buttons 151 | 152 | 153 | def stream_markup2(_, chat_id): 154 | buttons = [ 155 | [ 156 | InlineKeyboardButton( 157 | text=_["S_B_3"], 158 | url=f"https://t.me/{app.username}?startgroup=true", 159 | ), 160 | ], 161 | [ 162 | InlineKeyboardButton(text="▷", callback_data=f"ADMIN Resume|{chat_id}"), 163 | InlineKeyboardButton(text="II", callback_data=f"ADMIN Pause|{chat_id}"), 164 | InlineKeyboardButton(text="↻", callback_data=f"ADMIN Replay|{chat_id}"), 165 | InlineKeyboardButton(text="‣‣I", callback_data=f"ADMIN Skip|{chat_id}"), 166 | InlineKeyboardButton(text="▢", callback_data=f"ADMIN Stop|{chat_id}"), 167 | ], 168 | [ 169 | InlineKeyboardButton(text=_["CLOSEMENU_BUTTON"], callback_data="close"), 170 | ], 171 | ] 172 | return buttons 173 | -------------------------------------------------------------------------------- /DeadlineTech/utils/thumbnails.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import random 4 | import aiohttp 5 | import aiofiles 6 | import traceback 7 | 8 | from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont, ImageOps 9 | from youtubesearchpython.__future__ import VideosSearch 10 | 11 | 12 | def changeImageSize(maxWidth, maxHeight, image): 13 | ratio = min(maxWidth / image.size[0], maxHeight / image.size[1]) 14 | newSize = (int(image.size[0] * ratio), int(image.size[1] * ratio)) 15 | return image.resize(newSize, Image.ANTIALIAS) 16 | 17 | 18 | def truncate(text, max_chars=50): 19 | words = text.split() 20 | text1, text2 = "", "" 21 | for word in words: 22 | if len(text1 + " " + word) <= max_chars and not text2: 23 | text1 += " " + word 24 | else: 25 | text2 += " " + word 26 | return [text1.strip(), text2.strip()] 27 | 28 | 29 | def add_rounded_corners(im, radius): 30 | circle = Image.new('L', (radius * 2, radius * 2), 0) 31 | draw = ImageDraw.Draw(circle) 32 | draw.ellipse((0, 0, radius * 2, radius * 2), fill=255) 33 | alpha = Image.new('L', im.size, 255) 34 | w, h = im.size 35 | alpha.paste(circle.crop((0, 0, radius, radius)), (0, 0)) 36 | alpha.paste(circle.crop((0, radius, radius, radius * 2)), (0, h - radius)) 37 | alpha.paste(circle.crop((radius, 0, radius * 2, radius)), (w - radius, 0)) 38 | alpha.paste(circle.crop((radius, radius, radius * 2, radius * 2)), (w - radius, h - radius)) 39 | im.putalpha(alpha) 40 | return im 41 | 42 | 43 | def fit_text(draw, text, max_width, font_path, start_size, min_size): 44 | size = start_size 45 | while size >= min_size: 46 | font = ImageFont.truetype(font_path, size) 47 | if draw.textlength(text, font=font) <= max_width: 48 | return font 49 | size -= 1 50 | return ImageFont.truetype(font_path, min_size) 51 | 52 | 53 | async def get_thumb(videoid: str): 54 | url = f"https://www.youtube.com/watch?v={videoid}" 55 | try: 56 | results = VideosSearch(url, limit=1) 57 | for result in (await results.next())["result"]: 58 | title = re.sub(r"\W+", " ", result.get("title", "Unsupported Title")).title() 59 | duration = result.get("duration", "Unknown Mins") 60 | thumbnail = result["thumbnails"][0]["url"].split("?")[0] 61 | views = result.get("viewCount", {}).get("short", "Unknown Views") 62 | channel = result.get("channel", {}).get("name", "Unknown Channel") 63 | 64 | async with aiohttp.ClientSession() as session: 65 | async with session.get(thumbnail) as resp: 66 | if resp.status == 200: 67 | f = await aiofiles.open(f"cache/thumb{videoid}.png", mode="wb") 68 | await f.write(await resp.read()) 69 | await f.close() 70 | 71 | icons = Image.open("DeadlineTech/assets/icons.png") 72 | youtube = Image.open(f"cache/thumb{videoid}.png") 73 | image1 = changeImageSize(1280, 720, youtube) 74 | image2 = image1.convert("RGBA") 75 | 76 | gradient = Image.new("RGBA", image2.size, (0, 0, 0, 255)) 77 | enhancer = ImageEnhance.Brightness(image2.filter(ImageFilter.GaussianBlur(15))) 78 | blurred = enhancer.enhance(0.5) 79 | background = Image.alpha_composite(gradient, blurred) 80 | 81 | Xcenter = image2.width / 2 82 | Ycenter = image2.height / 2 83 | logo = youtube.crop((Xcenter - 200, Ycenter - 200, Xcenter + 200, Ycenter + 200)) 84 | logo.thumbnail((340, 340), Image.ANTIALIAS) 85 | 86 | shadow = Image.new("RGBA", logo.size, (0, 0, 0, 0)) 87 | shadow_draw = ImageDraw.Draw(shadow) 88 | shadow_draw.ellipse((0, 0, logo.size[0], logo.size[1]), fill=(0, 0, 0, 100)) 89 | background.paste(shadow, (110, 160), shadow) 90 | 91 | rand = (random.randint(100, 255), random.randint(100, 255), random.randint(100, 255)) 92 | logo = ImageOps.expand(logo, border=15, fill=rand) 93 | background.paste(logo, (100, 150)) 94 | 95 | draw = ImageDraw.Draw(background) 96 | font_info = ImageFont.truetype("DeadlineTech/assets/font2.ttf", 28) 97 | font_time = ImageFont.truetype("DeadlineTech/assets/font2.ttf", 26) 98 | font_path = "DeadlineTech/assets/font3.ttf" 99 | 100 | title_max_width = 540 101 | title_lines = truncate(title, 35) 102 | 103 | title_font1 = fit_text(draw, title_lines[0], title_max_width, font_path, 42, 28) 104 | draw.text((565, 180), title_lines[0], (255, 255, 255), font=title_font1) 105 | 106 | if title_lines[1]: 107 | title_font2 = fit_text(draw, title_lines[1], title_max_width, font_path, 36, 24) 108 | draw.text((565, 225), title_lines[1], (220, 220, 220), font=title_font2) 109 | 110 | draw.text((565, 305), f"{channel} | {views}", (240, 240, 240), font=font_info) 111 | 112 | draw.line([(565, 370), (1130, 370)], fill="white", width=6) 113 | draw.line([(565, 370), (990, 370)], fill=rand, width=6) 114 | draw.ellipse([(990, 362), (1010, 382)], outline=rand, fill=rand, width=12) 115 | 116 | draw.text((565, 385), "00:00", (255, 255, 255), font=font_time) 117 | draw.text((1080, 385), duration, (255, 255, 255), font=font_time) 118 | 119 | picons = icons.resize((580, 62)) 120 | background.paste(picons, (565, 430), picons) 121 | 122 | watermark_font = ImageFont.truetype("DeadlineTech/assets/font2.ttf", 24) 123 | watermark_text = "Team DeadlineTech" 124 | text_size = draw.textsize(watermark_text, font=watermark_font) 125 | x = background.width - text_size[0] - 25 126 | y = background.height - text_size[1] - 25 127 | glow_pos = [(x + dx, y + dy) for dx in (-1, 1) for dy in (-1, 1)] 128 | for pos in glow_pos: 129 | draw.text(pos, watermark_text, font=watermark_font, fill=(0, 0, 0, 180)) 130 | draw.text((x, y), watermark_text, font=watermark_font, fill=(255, 255, 255, 240)) 131 | 132 | background = add_rounded_corners(background, 30) 133 | 134 | try: 135 | os.remove(f"cache/thumb{videoid}.png") 136 | except: 137 | pass 138 | 139 | tpath = f"cache/{videoid}.png" 140 | background.save(tpath) 141 | return tpath 142 | 143 | except: 144 | traceback.print_exc() 145 | return None 146 | -------------------------------------------------------------------------------- /DeadlineTech/plugins/bot/start.py: -------------------------------------------------------------------------------- 1 | # Powered By Team DeadlineTech 2 | 3 | import time 4 | 5 | from pyrogram import filters 6 | from pyrogram.enums import ChatType 7 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message 8 | from youtubesearchpython.__future__ import VideosSearch 9 | 10 | import config 11 | from DeadlineTech import app 12 | from DeadlineTech.misc import _boot_ 13 | from DeadlineTech.plugins.sudo.sudoers import sudoers_list 14 | from DeadlineTech.utils.database import ( 15 | add_served_chat, 16 | add_served_user, 17 | blacklisted_chats, 18 | get_lang, 19 | is_banned_user, 20 | is_on_off, 21 | ) 22 | from DeadlineTech.utils.decorators.language import LanguageStart 23 | from DeadlineTech.utils.formatters import get_readable_time 24 | from DeadlineTech.utils.inline import help_pannel, private_panel, start_panel 25 | from config import BANNED_USERS 26 | from strings import get_string 27 | 28 | 29 | @app.on_message(filters.command(["start"]) & filters.private & ~BANNED_USERS) 30 | @LanguageStart 31 | async def start_pm(client, message: Message, _): 32 | await add_served_user(message.from_user.id) 33 | if len(message.text.split()) > 1: 34 | name = message.text.split(None, 1)[1] 35 | if name[0:4] == "help": 36 | keyboard = help_pannel(_) 37 | return await message.reply_photo( 38 | photo=config.START_IMG_URL, 39 | caption=_["help_1"].format(config.SUPPORT_CHAT), 40 | reply_markup=keyboard, 41 | ) 42 | if name[0:3] == "sud": 43 | await sudoers_list(client=client, message=message, _=_) 44 | if await is_on_off(2): 45 | return await app.send_message( 46 | chat_id=config.LOGGER_ID, 47 | text=f"{message.from_user.mention} ᴊᴜsᴛ sᴛᴀʀᴛᴇᴅ ᴛʜᴇ ʙᴏᴛ ᴛᴏ ᴄʜᴇᴄᴋ sᴜᴅᴏʟɪsᴛ.\n\nᴜsᴇʀ ɪᴅ :{message.from_user.id}\nᴜsᴇʀɴᴀᴍᴇ : @{message.from_user.username}",
48 | )
49 | return
50 | if name[0:3] == "inf":
51 | m = await message.reply_text("🔎")
52 | query = (str(name)).replace("info_", "", 1)
53 | query = f"https://www.youtube.com/watch?v={query}"
54 | results = VideosSearch(query, limit=1)
55 | for result in (await results.next())["result"]:
56 | title = result["title"]
57 | duration = result["duration"]
58 | views = result["viewCount"]["short"]
59 | thumbnail = result["thumbnails"][0]["url"].split("?")[0]
60 | channellink = result["channel"]["link"]
61 | channel = result["channel"]["name"]
62 | link = result["link"]
63 | published = result["publishedTime"]
64 | searched_text = _["start_6"].format(
65 | title, duration, views, published, channellink, channel, app.mention
66 | )
67 | key = InlineKeyboardMarkup(
68 | [
69 | [
70 | InlineKeyboardButton(text=_["S_B_8"], url=link),
71 | InlineKeyboardButton(text=_["S_B_9"], url=config.SUPPORT_CHAT),
72 | ],
73 | ]
74 | )
75 | await m.delete()
76 | await app.send_photo(
77 | chat_id=message.chat.id,
78 | photo=thumbnail,
79 | caption=searched_text,
80 | reply_markup=key,
81 | )
82 | if await is_on_off(2):
83 | return await app.send_message(
84 | chat_id=config.LOGGER_ID,
85 | text=f"{message.from_user.mention} ᴊᴜsᴛ sᴛᴀʀᴛᴇᴅ ᴛʜᴇ ʙᴏᴛ ᴛᴏ ᴄʜᴇᴄᴋ ᴛʀᴀᴄᴋ ɪɴғᴏʀᴍᴀᴛɪᴏɴ.\n\nᴜsᴇʀ ɪᴅ : {message.from_user.id}\nᴜsᴇʀɴᴀᴍᴇ : @{message.from_user.username}",
86 | )
87 | else:
88 | out = private_panel(_)
89 | await message.reply_photo(
90 | photo=config.START_IMG_URL,
91 | caption=_["start_2"].format(message.from_user.mention, app.mention),
92 | reply_markup=InlineKeyboardMarkup(out),
93 | )
94 | if await is_on_off(2):
95 | return await app.send_message(
96 | chat_id=config.LOGGER_ID,
97 | text=f"{message.from_user.mention} ᴊᴜsᴛ sᴛᴀʀᴛᴇᴅ ᴛʜᴇ ʙᴏᴛ.\n\nᴜsᴇʀ ɪᴅ : {message.from_user.id}\nᴜsᴇʀɴᴀᴍᴇ : @{message.from_user.username}",
98 | )
99 |
100 |
101 | @app.on_message(filters.command(["start"]) & filters.group & ~BANNED_USERS)
102 | @LanguageStart
103 | async def start_gp(client, message: Message, _):
104 | out = start_panel(_)
105 | uptime = int(time.time() - _boot_)
106 | await message.reply_photo(
107 | photo=config.START_IMG_URL,
108 | caption=_["start_1"].format(app.mention, get_readable_time(uptime)),
109 | reply_markup=InlineKeyboardMarkup(out),
110 | )
111 | return await add_served_chat(message.chat.id)
112 |
113 |
114 | @app.on_message(filters.new_chat_members, group=-1)
115 | async def welcome(client, message: Message):
116 | for member in message.new_chat_members:
117 | try:
118 | language = await get_lang(message.chat.id)
119 | _ = get_string(language)
120 | if await is_banned_user(member.id):
121 | try:
122 | await message.chat.ban_member(member.id)
123 | except:
124 | pass
125 | if member.id == app.id:
126 | if message.chat.type != ChatType.SUPERGROUP:
127 | await message.reply_text(_["start_4"])
128 | return await app.leave_chat(message.chat.id)
129 | if message.chat.id in await blacklisted_chats():
130 | await message.reply_text(
131 | _["start_5"].format(
132 | app.mention,
133 | f"https://t.me/{app.username}?start=sudolist",
134 | config.SUPPORT_CHAT,
135 | ),
136 | disable_web_page_preview=True,
137 | )
138 | return await app.leave_chat(message.chat.id)
139 |
140 | out = start_panel(_)
141 | await message.reply_photo(
142 | photo=config.START_IMG_URL,
143 | caption=_["start_3"].format(
144 | message.from_user.first_name,
145 | app.mention,
146 | message.chat.title,
147 | app.mention,
148 | ),
149 | reply_markup=InlineKeyboardMarkup(out),
150 | )
151 | await add_served_chat(message.chat.id)
152 | await message.stop_propagation()
153 | except Exception as ex:
154 | print(ex)
155 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/tools/dev.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import subprocess
4 | import sys
5 | import traceback
6 | from inspect import getfullargspec
7 | from io import StringIO
8 | from time import time
9 |
10 | from pyrogram import filters
11 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
12 |
13 | from DeadlineTech import app
14 | from config import OWNER_ID
15 |
16 |
17 | async def aexec(code, client, message):
18 | exec(
19 | "async def __aexec(client, message): "
20 | + "".join(f"\n {a}" for a in code.split("\n"))
21 | )
22 | return await locals()["__aexec"](client, message)
23 |
24 |
25 | async def edit_or_reply(msg: Message, **kwargs):
26 | func = msg.edit_text if msg.from_user.is_self else msg.reply
27 | spec = getfullargspec(func.__wrapped__).args
28 | await func(**{k: v for k, v in kwargs.items() if k in spec})
29 |
30 |
31 | @app.on_edited_message(
32 | filters.command("eval")
33 | & filters.user(OWNER_ID)
34 | & ~filters.forwarded
35 | & ~filters.via_bot
36 | )
37 | @app.on_message(
38 | filters.command("eval")
39 | & filters.user(OWNER_ID)
40 | & ~filters.forwarded
41 | & ~filters.via_bot
42 | )
43 | async def executor(client: app, message: Message):
44 | if len(message.command) < 2:
45 | return await edit_or_reply(message, text="ᴡʜᴀᴛ ʏᴏᴜ ᴡᴀɴɴᴀ ᴇxᴇᴄᴜᴛᴇ ʙᴀʙʏ ?")
46 | try:
47 | cmd = message.text.split(" ", maxsplit=1)[1]
48 | except IndexError:
49 | return await message.delete()
50 | t1 = time()
51 | old_stderr = sys.stderr
52 | old_stdout = sys.stdout
53 | redirected_output = sys.stdout = StringIO()
54 | redirected_error = sys.stderr = StringIO()
55 | stdout, stderr, exc = None, None, None
56 | try:
57 | await aexec(cmd, client, message)
58 | except Exception:
59 | exc = traceback.format_exc()
60 | stdout = redirected_output.getvalue()
61 | stderr = redirected_error.getvalue()
62 | sys.stdout = old_stdout
63 | sys.stderr = old_stderr
64 | evaluation = "\n"
65 | if exc:
66 | evaluation += exc
67 | elif stderr:
68 | evaluation += stderr
69 | elif stdout:
70 | evaluation += stdout
71 | else:
72 | evaluation += "Success"
73 | final_output = f"⥤ ʀᴇsᴜʟᴛ :\n{evaluation}"
74 | if len(final_output) > 4096:
75 | filename = "output.txt"
76 | with open(filename, "w+", encoding="utf8") as out_file:
77 | out_file.write(str(evaluation))
78 | t2 = time()
79 | keyboard = InlineKeyboardMarkup(
80 | [
81 | [
82 | InlineKeyboardButton(
83 | text="⏳",
84 | callback_data=f"runtime {t2-t1} Seconds",
85 | )
86 | ]
87 | ]
88 | )
89 | await message.reply_document(
90 | document=filename,
91 | caption=f"⥤ ᴇᴠᴀʟ :\n{cmd[0:980]}\n\n⥤ ʀᴇsᴜʟᴛ :\nAttached Document",
92 | quote=False,
93 | reply_markup=keyboard,
94 | )
95 | await message.delete()
96 | os.remove(filename)
97 | else:
98 | t2 = time()
99 | keyboard = InlineKeyboardMarkup(
100 | [
101 | [
102 | InlineKeyboardButton(
103 | text="⏳",
104 | callback_data=f"runtime {round(t2-t1, 3)} Seconds",
105 | ),
106 | InlineKeyboardButton(
107 | text="🗑",
108 | callback_data=f"forceclose abc|{message.from_user.id}",
109 | ),
110 | ]
111 | ]
112 | )
113 | await edit_or_reply(message, text=final_output, reply_markup=keyboard)
114 |
115 |
116 | @app.on_callback_query(filters.regex(r"runtime"))
117 | async def runtime_func_cq(_, cq):
118 | runtime = cq.data.split(None, 1)[1]
119 | await cq.answer(runtime, show_alert=True)
120 |
121 |
122 | @app.on_callback_query(filters.regex("forceclose"))
123 | async def forceclose_command(_, CallbackQuery):
124 | callback_data = CallbackQuery.data.strip()
125 | callback_request = callback_data.split(None, 1)[1]
126 | query, user_id = callback_request.split("|")
127 | if CallbackQuery.from_user.id != int(user_id):
128 | try:
129 | return await CallbackQuery.answer(
130 | "» ɪᴛ'ʟʟ ʙᴇ ʙᴇᴛᴛᴇʀ ɪғ ʏᴏᴜ sᴛᴀʏ ɪɴ ʏᴏᴜʀ ʟɪᴍɪᴛs ʙᴀʙʏ.", show_alert=True
131 | )
132 | except:
133 | return
134 | await CallbackQuery.message.delete()
135 | try:
136 | await CallbackQuery.answer()
137 | except:
138 | return
139 |
140 |
141 | @app.on_edited_message(
142 | filters.command("sh")
143 | & filters.user(OWNER_ID)
144 | & ~filters.forwarded
145 | & ~filters.via_bot
146 | )
147 | @app.on_message(
148 | filters.command("sh")
149 | & filters.user(OWNER_ID)
150 | & ~filters.forwarded
151 | & ~filters.via_bot
152 | )
153 | async def shellrunner(_, message: Message):
154 | if len(message.command) < 2:
155 | return await edit_or_reply(message, text="ᴇxᴀᴍᴩʟᴇ :\n/sh git pull")
156 | text = message.text.split(None, 1)[1]
157 | if "\n" in text:
158 | code = text.split("\n")
159 | output = ""
160 | for x in code:
161 | shell = re.split(""" (?=(?:[^'"]|'[^']*'|"[^"]*")*$)""", x)
162 | try:
163 | process = subprocess.Popen(
164 | shell,
165 | stdout=subprocess.PIPE,
166 | stderr=subprocess.PIPE,
167 | )
168 | except Exception as err:
169 | await edit_or_reply(message, text=f"ERROR :\n{err}")
170 | output += f"{code}\n"
171 | output += process.stdout.read()[:-1].decode("utf-8")
172 | output += "\n"
173 | else:
174 | shell = re.split(""" (?=(?:[^'"]|'[^']*'|"[^"]*")*$)""", text)
175 | for a in range(len(shell)):
176 | shell[a] = shell[a].replace('"', "")
177 | try:
178 | process = subprocess.Popen(
179 | shell,
180 | stdout=subprocess.PIPE,
181 | stderr=subprocess.PIPE,
182 | )
183 | except Exception as err:
184 | print(err)
185 | exc_type, exc_obj, exc_tb = sys.exc_info()
186 | errors = traceback.format_exception(
187 | etype=exc_type,
188 | value=exc_obj,
189 | tb=exc_tb,
190 | )
191 | return await edit_or_reply(
192 | message, text=f"ERROR :\n{''.join(errors)}"
193 | )
194 | output = process.stdout.read()[:-1].decode("utf-8")
195 | if str(output) == "\n":
196 | output = None
197 | if output:
198 | if len(output) > 4096:
199 | with open("output.txt", "w+") as file:
200 | file.write(output)
201 | await app.send_document(
202 | message.chat.id,
203 | "output.txt",
204 | reply_to_message_id=message.id,
205 | caption="Output",
206 | )
207 | return os.remove("output.txt")
208 | await edit_or_reply(message, text=f"OUTPUT :\n{output}")
209 | else:
210 | await edit_or_reply(message, text="OUTPUT :\nNone")
211 | await message.stop_propagation()
212 |
--------------------------------------------------------------------------------
/DeadlineTech/plugins/misc/broadcast.py:
--------------------------------------------------------------------------------
1 | # ==========================================================
2 | # 🔒 All Rights Reserved © Team DeadlineTech
3 | # 📁 This file is part of the DeadlineTech Project.
4 | # ==========================================================
5 |
6 | import time
7 | import logging
8 | import asyncio
9 |
10 | from pyrogram import filters
11 | from pyrogram.enums import ChatMembersFilter
12 | from pyrogram.errors import FloodWait, RPCError
13 | from pyrogram.types import Message
14 |
15 | from DeadlineTech import app
16 | from DeadlineTech.misc import SUDOERS
17 | from DeadlineTech.utils.database import (
18 | get_active_chats,
19 | get_authuser_names,
20 | get_client,
21 | get_served_chats,
22 | get_served_users,
23 | )
24 | from DeadlineTech.utils.decorators.language import language
25 | from DeadlineTech.utils.formatters import alpha_to_int
26 | from config import adminlist
27 |
28 | # Logger config
29 | logging.basicConfig(
30 | level=logging.INFO,
31 | format="%(asctime)s - [%(levelname)s] - %(message)s",
32 | datefmt="%Y-%m-%d %H:%M:%S",
33 | )
34 | logger = logging.getLogger("Broadcast")
35 |
36 | SEMAPHORE = asyncio.Semaphore(30) # Increased concurrency
37 |
38 | @app.on_message(filters.command("broadcast") & SUDOERS)
39 | async def broadcast_command(client, message: Message):
40 | try:
41 | logger.info(f"/broadcast triggered by user: {message.from_user.id}")
42 |
43 | command = message.text.lower()
44 | mode = "forward" if "-forward" in command else "copy"
45 |
46 | # Determine targets
47 | if "-all" in command:
48 | users = await get_served_users()
49 | chats = await get_served_chats()
50 | target_users = [u["user_id"] for u in users]
51 | target_chats = [c["chat_id"] for c in chats]
52 | elif "-users" in command:
53 | users = await get_served_users()
54 | target_users = [u["user_id"] for u in users]
55 | target_chats = []
56 | elif "-chats" in command:
57 | chats = await get_served_chats()
58 | target_users = []
59 | target_chats = [c["chat_id"] for c in chats]
60 | else:
61 | logger.warning("Incorrect broadcast format used.")
62 | return await message.reply_text(
63 | "❗ Usage:\n"
64 | "/broadcast -all/-users/-chats [-forward]\n"
65 | "📝 Example: /broadcast -all Hello!"
66 | )
67 |
68 | if not target_users and not target_chats:
69 | logger.info("No target recipients found.")
70 | return await message.reply_text("⚠ No recipients found.")
71 |
72 | # Extract content
73 | if message.reply_to_message:
74 | content = message.reply_to_message
75 | else:
76 | text = message.text
77 | for kw in ["/broadcast", "-forward", "-all", "-users", "-chats"]:
78 | text = text.replace(kw, "")
79 | text = text.strip()
80 |
81 | if not text:
82 | return await message.reply_text("📝 Reply to a message or add content after the command.")
83 | content = text
84 |
85 | # Summary
86 | total = len(target_users + target_chats)
87 | sent_users = 0
88 | sent_chats = 0
89 | failed = 0
90 |
91 | logger.info(f"Broadcast mode: {mode}")
92 | logger.info(f"Targets - Users: {len(target_users)}, Chats: {len(target_chats)}, Total: {total}")
93 |
94 | await message.reply_text(
95 | f"📢 Broadcast Started\n\n"
96 | f"➤ Mode: {mode}\n"
97 | f"👤 Users: {len(target_users)}\n"
98 | f"👥 Chats: {len(target_chats)}\n"
99 | f"📦 Total: {total}\n"
100 | f"⏳ Please wait while messages are being sent..."
101 | )
102 |
103 | # Define delivery function
104 | async def deliver(chat_id, is_user, retries=3):
105 | nonlocal sent_users, sent_chats, failed
106 | async with SEMAPHORE:
107 | try:
108 | if isinstance(content, str):
109 | await app.send_message(chat_id, content)
110 | elif mode == "forward":
111 | await app.forward_messages(chat_id, message.chat.id, [content.id])
112 | else:
113 | try:
114 | await content.copy(chat_id)
115 | except Exception as e:
116 | logger.warning(f"Copy failed to {chat_id}: {e}")
117 | failed += 1
118 | return
119 |
120 | if is_user:
121 | sent_users += 1
122 | else:
123 | sent_chats += 1
124 |
125 | except FloodWait as e:
126 | wait_time = min(e.value, 120)
127 | logger.warning(f"FloodWait {e.value}s in chat {chat_id}, waiting {wait_time}s")
128 | await asyncio.sleep(wait_time)
129 | if retries > 0:
130 | return await deliver(chat_id, is_user, retries - 1)
131 | failed += 1
132 |
133 | except RPCError as e:
134 | logger.warning(f"RPCError in chat {chat_id}: {e}")
135 | failed += 1
136 |
137 | except Exception as e:
138 | logger.error(f"Error delivering to {chat_id}: {e}")
139 | failed += 1
140 |
141 | # Combine all targets
142 | targets = [(uid, True) for uid in target_users] + [(cid, False) for cid in target_chats]
143 |
144 | for i in range(0, len(targets), 100):
145 | batch = targets[i:i + 100]
146 | await asyncio.gather(*[deliver(chat_id, is_user) for chat_id, is_user in batch])
147 | await asyncio.sleep(2.5) # Throttle between batches
148 |
149 | # Final summary
150 | await message.reply_text(
151 | f"✅ Broadcast Completed\n\n"
152 | f"➤ Mode: {mode}\n"
153 | f"👤 Users Sent: {sent_users}\n"
154 | f"👥 Chats Sent: {sent_chats}\n"
155 | f"📦 Total Delivered: {sent_users + sent_chats}\n"
156 | f"❌ Failed: {failed}"
157 | )
158 | logger.info(f"Broadcast finished. Success: {sent_users + sent_chats}, Failed: {failed}")
159 |
160 | except Exception as e:
161 | logger.exception("Unhandled error in broadcast_command")
162 | await message.reply_text(f"🚫 Broadcast failed: {str(e)}")
163 |
164 |
165 | # Adminlist Auto-cleaner
166 | async def auto_clean():
167 | while True:
168 | await asyncio.sleep(10)
169 | try:
170 | chats = await get_active_chats()
171 | for chat_id in chats:
172 | if chat_id not in adminlist:
173 | adminlist[chat_id] = []
174 |
175 | async for member in app.get_chat_members(chat_id, filter=ChatMembersFilter.ADMINISTRATORS):
176 | if getattr(member, "privileges", None) and member.privileges.can_manage_video_chats:
177 | adminlist[chat_id].append(member.user.id)
178 |
179 | for username in await get_authuser_names(chat_id):
180 | user_id = await alpha_to_int(username)
181 | adminlist[chat_id].append(user_id)
182 |
183 | except Exception as e:
184 | logger.warning(f"AutoClean error: {e}")
185 |
--------------------------------------------------------------------------------