import asyncio import os from datetime import datetime, timedelta from typing import Union from pyrogram import Client from pyrogram.types import InlineKeyboardMarkup from ntgcalls import TelegramServerError from pytgcalls import PyTgCalls from pytgcalls.exceptions import ( AlreadyJoinedError, NoActiveGroupCall, ) from pytgcalls.types import ( MediaStream, AudioQuality, VideoQuality, Update, ) from pytgcalls.types.stream import StreamAudioEnded import config from DragMusic import LOGGER, YouTube, app from DragMusic.misc import db from DragMusic.utils.database import ( add_active_chat, add_active_video_chat, get_lang, get_loop, group_assistant, is_autoend, music_on, remove_active_chat, remove_active_video_chat, set_loop, ) from DragMusic.utils.exceptions import AssistantErr from DragMusic.utils.formatters import check_duration, seconds_to_min, speed_converter from DragMusic.utils.inline.play import stream_markup from DragMusic.utils.stream.autoclear import auto_clean from DragMusic.utils.thumbnails import gen_thumb from strings import get_string autoend = {} counter = {} loop = asyncio.get_event_loop_policy().get_event_loop() async def _clear_(chat_id): db[chat_id] = [] await remove_active_video_chat(chat_id) await remove_active_chat(chat_id) class Call(PyTgCalls): def __init__(self): self.userbot1 = Client( name="AnonXAss1", api_id=config.API_ID, api_hash=config.API_HASH, session_string=str(config.STRING1), ) self.one = PyTgCalls( self.userbot1, cache_duration=100, ) self.userbot2 = Client( name="AnonXAss2", api_id=config.API_ID, api_hash=config.API_HASH, session_string=str(config.STRING2), ) self.two = PyTgCalls( self.userbot2, cache_duration=100, ) self.userbot3 = Client( name="AnonXAss3", api_id=config.API_ID, api_hash=config.API_HASH, session_string=str(config.STRING3), ) self.three = PyTgCalls( self.userbot3, cache_duration=100, ) self.userbot4 = Client( name="AnonXAss4", api_id=config.API_ID, api_hash=config.API_HASH, session_string=str(config.STRING4), ) self.four = PyTgCalls( self.userbot4, cache_duration=100, ) self.userbot5 = Client( name="AnonXAss5", api_id=config.API_ID, api_hash=config.API_HASH, session_string=str(config.STRING5), ) self.five = PyTgCalls( self.userbot5, cache_duration=100, ) async def pause_stream(self, chat_id: int): assistant = await group_assistant(self, chat_id) await assistant.pause_stream(chat_id) async def mute_stream(self, chat_id: int): assistant = await group_assistant(self, chat_id) await assistant.mute_stream(chat_id) async def unmute_stream(self, chat_id: int): assistant = await group_assistant(self, chat_id) await assistant.unmute_stream(chat_id) async def get_participant(self, chat_id: int): assistant = await group_assistant(self, chat_id) participant = await assistant.get_participants(chat_id) return participant async def resume_stream(self, chat_id: int): assistant = await group_assistant(self, chat_id) await assistant.resume_stream(chat_id) async def stop_stream(self, chat_id: int): assistant = await group_assistant(self, chat_id) try: await _clear_(chat_id) await assistant.leave_group_call(chat_id) except: pass async def stop_stream_force(self, chat_id: int): try: if config.STRING1: await self.one.leave_group_call(chat_id) except: pass try: if config.STRING2: await self.two.leave_group_call(chat_id) except: pass try: if config.STRING3: await self.three.leave_group_call(chat_id) except: pass try: if config.STRING4: await self.four.leave_group_call(chat_id) except: pass try: if config.STRING5: await self.five.leave_group_call(chat_id) except: pass try: await _clear_(chat_id) except: pass async def speedup_stream(self, chat_id: int, file_path, speed, playing): assistant = await group_assistant(self, chat_id) if str(speed) != "1.0": base = os.path.basename(file_path) chatdir = os.path.join(os.getcwd(), "playback", str(speed)) if not os.path.isdir(chatdir): os.makedirs(chatdir) out = os.path.join(chatdir, base) if not os.path.isfile(out): if str(speed) == "0.5": vs = 2.0 if str(speed) == "0.75": vs = 1.35 if str(speed) == "1.5": vs = 0.68 if str(speed) == "2.0": vs = 0.5 proc = await asyncio.create_subprocess_shell( cmd=( "ffmpeg " "-i " f"{file_path} " "-filter:v " f"setpts={vs}*PTS " "-filter:a " f"atempo={speed} " f"{out}" ), stdin=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) await proc.communicate() else: out = file_path dur = await loop.run_in_executor(None, check_duration, out) dur = int(dur) played, con_seconds = speed_converter(playing[0]["played"], speed) duration = seconds_to_min(dur) stream = ( MediaStream( out, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ffmpeg_parameters=f"-ss {played} -to {duration}", ) if playing[0]["streamtype"] == "video" else MediaStream( out, audio_parameters=AudioQuality.HIGH, ffmpeg_parameters=f"-ss {played} -to {duration}", video_flags=MediaStream.IGNORE, ) ) if str(db[chat_id][0]["file"]) == str(file_path): await assistant.change_stream(chat_id, stream) else: raise AssistantErr("Umm") if str(db[chat_id][0]["file"]) == str(file_path): exis = (playing[0]).get("old_dur") if not exis: db[chat_id][0]["old_dur"] = db[chat_id][0]["dur"] db[chat_id][0]["old_second"] = db[chat_id][0]["seconds"] db[chat_id][0]["played"] = con_seconds db[chat_id][0]["dur"] = duration db[chat_id][0]["seconds"] = dur db[chat_id][0]["speed_path"] = out db[chat_id][0]["speed"] = speed async def force_stop_stream(self, chat_id: int): assistant = await group_assistant(self, chat_id) try: check = db.get(chat_id) check.pop(0) except: pass await remove_active_video_chat(chat_id) await remove_active_chat(chat_id) try: await assistant.leave_group_call(chat_id) except: pass async def skip_stream( self, chat_id: int, link: str, video: Union[bool, str] = None, image: Union[bool, str] = None, ): assistant = await group_assistant(self, chat_id) if video: stream = MediaStream( link, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) else: stream = MediaStream( link, audio_parameters=AudioQuality.HIGH, video_flags=MediaStream.IGNORE, ) await assistant.change_stream( chat_id, stream, ) async def seek_stream(self, chat_id, file_path, to_seek, duration, mode): assistant = await group_assistant(self, chat_id) stream = ( MediaStream( file_path, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ffmpeg_parameters=f"-ss {to_seek} -to {duration}", ) if mode == "video" else MediaStream( file_path, audio_parameters=AudioQuality.HIGH, ffmpeg_parameters=f"-ss {to_seek} -to {duration}", video_flags=MediaStream.IGNORE, ) ) await assistant.change_stream(chat_id, stream) async def stream_call(self, link): assistant = await group_assistant(self, config.LOGGER_ID) await assistant.join_group_call( config.LOGGER_ID, MediaStream(link), ) await asyncio.sleep(0.2) await assistant.leave_group_call(config.LOGGER_ID) async def join_call( self, chat_id: int, original_chat_id: int, link, video: Union[bool, str] = None, image: Union[bool, str] = None, ): assistant = await group_assistant(self, chat_id) language = await get_lang(chat_id) _ = get_string(language) if video: stream = MediaStream( link, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) else: stream = ( MediaStream( link, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) if video else MediaStream( link, audio_parameters=AudioQuality.HIGH, video_flags=MediaStream.IGNORE, ) ) try: await assistant.join_group_call( chat_id, stream, ) except NoActiveGroupCall: raise AssistantErr(_["call_8"]) except AlreadyJoinedError: raise AssistantErr(_["call_9"]) except TelegramServerError: raise AssistantErr(_["call_10"]) except Exception as e: if "phone.CreateGroupCall" in str(e): raise AssistantErr(_["call_8"]) await add_active_chat(chat_id) await music_on(chat_id) if video: await add_active_video_chat(chat_id) if await is_autoend(): counter[chat_id] = {} users = len(await assistant.get_participants(chat_id)) if users == 1: autoend[chat_id] = datetime.now() + timedelta(minutes=1) async def change_stream(self, client, chat_id): check = db.get(chat_id) popped = None loop = await get_loop(chat_id) try: if loop == 0: popped = check.pop(0) else: loop = loop - 1 await set_loop(chat_id, loop) await auto_clean(popped) if not check: await _clear_(chat_id) return await client.leave_group_call(chat_id) except: try: await _clear_(chat_id) return await client.leave_group_call(chat_id) except: return else: queued = check[0]["file"] language = await get_lang(chat_id) _ = get_string(language) title = (check[0]["title"]).title() user = check[0]["by"] original_chat_id = check[0]["chat_id"] streamtype = check[0]["streamtype"] videoid = check[0]["vidid"] db[chat_id][0]["played"] = 0 if exis := (check[0]).get("old_dur"): db[chat_id][0]["dur"] = exis db[chat_id][0]["seconds"] = check[0]["old_second"] db[chat_id][0]["speed_path"] = None db[chat_id][0]["speed"] = 1.0 video = str(streamtype) == "video" if "live_" in queued: n, link = await YouTube.video(videoid, True) if n == 0: return await app.send_message( original_chat_id, text=_["call_6"], ) if video: stream = MediaStream( link, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) else: stream = MediaStream( link, audio_parameters=AudioQuality.HIGH, video_flags=MediaStream.IGNORE, ) try: await client.change_stream(chat_id, stream) except Exception: return await app.send_message( original_chat_id, text=_["call_6"], ) img = await gen_thumb(videoid) button = stream_markup2(_, chat_id) run = await app.send_photo( chat_id=original_chat_id, photo=img, caption=_["stream_1"].format( f"https://t.me/{app.username}?start=info_{videoid}", title[:23], check[0]["dur"], user, ), reply_markup=InlineKeyboardMarkup(button), ) db[chat_id][0]["mystic"] = run db[chat_id][0]["markup"] = "tg" elif "vid_" in queued: mystic = await app.send_message(original_chat_id, _["call_7"]) try: file_path, direct = await YouTube.download( videoid, mystic, videoid=True, video=str(streamtype) == "video", ) except: return await mystic.edit_text( _["call_6"], disable_web_page_preview=True ) if video: stream = MediaStream( file_path, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) else: stream = MediaStream( file_path, audio_parameters=AudioQuality.HIGH, video_flags=MediaStream.IGNORE, ) try: await client.change_stream(chat_id, stream) except: return await app.send_message( original_chat_id, text=_["call_6"], ) img = await gen_thumb(videoid) button = stream_markup(_, videoid, chat_id) await mystic.delete() run = await app.send_photo( chat_id=original_chat_id, photo=img, caption=_["stream_1"].format( f"https://t.me/{app.username}?start=info_{videoid}", title[:23], check[0]["dur"], user, ), reply_markup=InlineKeyboardMarkup(button), ) db[chat_id][0]["mystic"] = run db[chat_id][0]["markup"] = "stream" elif "index_" in queued: stream = ( MediaStream( videoid, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) if str(streamtype) == "video" else MediaStream( videoid, audio_parameters=AudioQuality.HIGH, video_flags=MediaStream.IGNORE, ) ) try: await client.change_stream(chat_id, stream) except: return await app.send_message( original_chat_id, text=_["call_6"], ) button = stream_markup2(_, chat_id) run = await app.send_photo( chat_id=original_chat_id, photo=config.STREAM_IMG_URL, caption=_["stream_2"].format(user), reply_markup=InlineKeyboardMarkup(button), ) db[chat_id][0]["mystic"] = run db[chat_id][0]["markup"] = "tg" else: if video: stream = MediaStream( queued, audio_parameters=AudioQuality.HIGH, video_parameters=VideoQuality.SD_480p, ) else: stream = MediaStream( queued, audio_parameters=AudioQuality.HIGH, video_flags=MediaStream.IGNORE, ) try: await client.change_stream(chat_id, stream) except: return await app.send_message( original_chat_id, text=_["call_6"], ) if videoid == "telegram": button = stream_markup2(_, chat_id) run = await app.send_photo( chat_id=original_chat_id, photo=( config.TELEGRAM_AUDIO_URL if str(streamtype) == "audio" else config.TELEGRAM_VIDEO_URL ), caption=_["stream_1"].format( config.SUPPORT_CHAT, title[:23], check[0]["dur"], user ), reply_markup=InlineKeyboardMarkup(button), ) db[chat_id][0]["mystic"] = run db[chat_id][0]["markup"] = "tg" elif videoid == "soundcloud": button = stream_markup2(_, chat_id) run = await app.send_photo( chat_id=original_chat_id, photo=config.SOUNCLOUD_IMG_URL, caption=_["stream_1"].format( config.SUPPORT_CHAT, title[:23], check[0]["dur"], user ), reply_markup=InlineKeyboardMarkup(button), ) db[chat_id][0]["mystic"] = run db[chat_id][0]["markup"] = "tg" else: img = await gen_thumb(videoid) button = stream_markup(_, videoid, chat_id) run = await app.send_photo( chat_id=original_chat_id, photo=img, caption=_["stream_1"].format( f"https://t.me/{app.username}?start=info_{videoid}", title[:23], check[0]["dur"], user, ), reply_markup=InlineKeyboardMarkup(button), ) db[chat_id][0]["mystic"] = run db[chat_id][0]["markup"] = "stream" async def ping(self): pings = [] if config.STRING1: pings.append(await self.one.ping) if config.STRING2: pings.append(await self.two.ping) if config.STRING3: pings.append(await self.three.ping) if config.STRING4: pings.append(await self.four.ping) if config.STRING5: pings.append(await self.five.ping) return str(round(sum(pings) / len(pings), 3)) async def start(self): LOGGER(__name__).info("Starting PyTgCalls Client...\n") if config.STRING1: await self.one.start() if config.STRING2: await self.two.start() if config.STRING3: await self.three.start() if config.STRING4: await self.four.start() if config.STRING5: await self.five.start() async def decorators(self): @self.one.on_kicked() @self.two.on_kicked() @self.three.on_kicked() @self.four.on_kicked() @self.five.on_kicked() @self.one.on_closed_voice_chat() @self.two.on_closed_voice_chat() @self.three.on_closed_voice_chat() @self.four.on_closed_voice_chat() @self.five.on_closed_voice_chat() @self.one.on_left() @self.two.on_left() @self.three.on_left() @self.four.on_left() @self.five.on_left() async def stream_services_handler(_, chat_id: int): await self.stop_stream(chat_id) @self.one.on_stream_end() @self.two.on_stream_end() @self.three.on_stream_end() @self.four.on_stream_end() @self.five.on_stream_end() async def stream_end_handler(client, update: Update): if not isinstance(update, StreamAudioEnded): return await self.change_stream(client, update.chat_id) Drag= Call()