├── runtime.txt
├── Procfile
├── Dockerfile
├── requirements.txt
├── shamil
├── stickers.py
├── radio.py
├── song.py
├── commands.py
├── callback.py
└── player.py
├── main.py
├── .gitignore
├── config.py
├── README.md
├── app.json
└── utils.py
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.9.2
2 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: python3 main.py
2 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-slim-buster
2 | WORKDIR /app
3 | COPY requirements.txt requirements.txt
4 | RUN pip3 install -r requirements.txt
5 | RUN apt update && apt upgrade -y
6 | RUN apt install ffmpeg -y
7 | COPY . .
8 |
9 | CMD python3 main.py
10 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Pyrogram==1.2.9
2 | TgCrypto==1.2.2
3 | ffmpeg-python
4 | psutil
5 | pytgcalls
6 | wheel
7 | python-arq
8 | aiohttp==3.6.2
9 | youtube_dl
10 | youtube_search_python
11 | youtube_search
12 | wget
13 | requests
14 | python-decouple
15 | aiofiles
16 | python-dotenv
17 | asyncio
18 | search_engine_parser
19 | Pillow
20 | future
21 | tswift
22 |
--------------------------------------------------------------------------------
/shamil/stickers.py:
--------------------------------------------------------------------------------
1 | import os
2 | from os import error
3 | import logging
4 | import pyrogram
5 | import random
6 | from decouple import config
7 | from pyrogram import Client, filters
8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
9 | from pyrogram.types import User, Message, Sticker, Document
10 |
11 |
12 | @Client.on_message(filters.command(["stickerid"]))
13 | async def stickerid(bot, message):
14 | if message.reply_to_message.sticker:
15 | await message.reply(f"**Sticker ID is** \n `{message.reply_to_message.sticker.file_id}` \n \n ** Unique ID is ** \n\n`{message.reply_to_message.sticker.file_unique_id}`", quote=True)
16 | else:
17 | await message.reply("Oops !! Not a sticker file")
18 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 |
2 | from pyrogram import Client, idle, filters
3 | import os
4 | from threading import Thread
5 | import sys
6 | from config import Config
7 | from utils import mp
8 | import asyncio
9 | from pyrogram.raw import functions, types
10 |
11 |
12 | CHAT=Config.CHAT
13 | bot = Client(
14 | "MwkVC",
15 | Config.API_ID,
16 | Config.API_HASH,
17 | bot_token=Config.BOT_TOKEN,
18 | plugins=dict(root="shamil")
19 | )
20 | if not os.path.isdir("./downloads"):
21 | os.makedirs("./downloads")
22 | async def main():
23 | async with bot:
24 | await mp.start_radio()
25 |
26 | bot.run(main())
27 | bot.start()
28 | @bot.on_message(filters.command("update") & filters.user(Config.ADMINS))
29 | def restart(client, message):
30 | message.reply_text("Updating Bot...")
31 | Thread(
32 | target=stop_and_restart
33 | ).start()
34 |
35 | idle()
36 | bot.stop()
37 |
--------------------------------------------------------------------------------
/shamil/radio.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from pyrogram.types import Message
3 | from utils import mp, RADIO, USERNAME
4 | from config import Config
5 | from config import STREAM
6 |
7 | ADMINS=Config.ADMINS
8 |
9 | @Client.on_message(filters.command(["radio", f"radio@{USERNAME}"]) & filters.user(ADMINS))
10 | async def radio(client, message: Message):
11 | if 1 in RADIO:
12 | await message.reply_text("Kindly stop existing Radio Stream /sr")
13 | return
14 | await mp.start_radio()
15 | await message.reply_text(f"Started Radio: {STREAM}")
16 | await message.delete()
17 |
18 | @Client.on_message(filters.command(['stopradio', f"stopradio@{USERNAME}"]) & filters.user(ADMINS))
19 | async def stop(_, message: Message):
20 | if 0 in RADIO:
21 | await message.reply_text("Kindly start Radio First /r")
22 | return
23 | await mp.stop_radio()
24 | await message.reply_text("Radio stream ended.")
25 | await message.delete()
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #---------------------------------#
2 | # Shamil X MwK Musics - @MwKLinks #
3 | #---------------------------------#
4 |
5 | /PATCH_*.sh
6 |
7 | /app/etc/local.xml
8 |
9 | /media/*
10 | !/media/.htaccess
11 |
12 | !/media/customer
13 | /media/customer/*
14 | !/media/customer/.htaccess
15 |
16 | !/media/dhl
17 | /media/dhl/*
18 | !/media/dhl/logo.jpg
19 |
20 | !/media/downloadable
21 | /media/downloadable/*
22 | !/media/downloadable/.htaccess
23 |
24 | !/media/xmlconnect
25 | /media/xmlconnect/*
26 |
27 | !/media/xmlconnect/custom
28 | /media/xmlconnect/custom/*
29 | !/media/xmlconnect/custom/ok.gif
30 |
31 | !/media/xmlconnect/original
32 | /media/xmlconnect/original/*
33 | !/media/xmlconnect/original/ok.gif
34 |
35 | !/media/xmlconnect/system
36 | /media/xmlconnect/system/*
37 | !/media/xmlconnect/system/ok.gif
38 |
39 | /var/*
40 | !/var/.htaccess
41 |
42 | !/var/package
43 | /var/package/*
44 | !/var/package/*.xml
45 |
46 | *.pyc
47 | *.raw
48 | *.log
49 | *.session
50 | unknown_errors.txt
51 | *.session-journal
52 | .env
53 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 | import re
4 | from youtube_dl import YoutubeDL
5 | ydl_opts = {
6 | "geo-bypass": True,
7 | "nocheckcertificate": True
8 | }
9 | ydl = YoutubeDL(ydl_opts)
10 | links=[]
11 | finalurl=""
12 | STREAM=os.environ.get("STREAM_URL", "http://node-25.zeno.fm/kezsc0y2wwzuv?listening-from-radio-garden=1622271954020&rj-ttl=5&rj-tok=AAABec5bAE4Aj31dmRAEFgcbvw")
13 | regex = r"^(https?\:\/\/)?(www\.youtube\.com|youtu\.?be)\/.+"
14 | match = re.match(regex,STREAM)
15 | if match:
16 | meta = ydl.extract_info(STREAM, download=False)
17 | formats = meta.get('formats', [meta])
18 | for f in formats:
19 | links.append(f['url'])
20 | finalurl=links[0]
21 | else:
22 | finalurl=STREAM
23 |
24 | class Config:
25 | ADMIN = os.environ.get("ADMINS", '')
26 | ADMINS = [int(admin) if re.search('^\d+$', admin) else admin for admin in (ADMIN).split()]
27 | API_ID = int(os.environ.get("API_ID", ''))
28 | CHAT = int(os.environ.get("CHAT", ""))
29 | LOG_GROUP=os.environ.get("LOG_GROUP", "")
30 | if LOG_GROUP:
31 | LOG_GROUP=int(LOG_GROUP)
32 | else:
33 | LOG_GROUP=None
34 | STREAM_URL=finalurl
35 | ADMIN_ONLY=os.environ.get("ADMIN_ONLY", "Y")
36 | DURATION_LIMIT=int(os.environ.get("DUR", 15))
37 | API_HASH = os.environ.get("API_HASH", "")
38 | BOT_TOKEN = os.environ.get("BOT_TOKEN", "")
39 | SESSION = os.environ.get("SESSION_STRING", "SESSION")
40 | DOWNLOAD_LOCATION = os.environ.get("DOWNLOAD_LOCATION", "./DOWNLOADS/")
41 | playlist=[]
42 | msg = {}
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bot To Stream Musics on PyTGcalls with Channel Support.
2 |
3 | A Telegram Bot to Play Audio in Voice Chats With Supports Live streaming from youtube and Mega Radio Fm Streamings
4 |
5 |
6 | ## Deploy to Heroku
7 |
8 | [](https://heroku.com/deploy?template=https://github.com/shamilhabeebnelli/MwK-Musics/tree/main)
9 |
10 | ## Deploy On Railway
11 |
12 | [](https://railway.app/new/template?template=https://github.com/shamilhabeebnelli/mwk-musics/tree/main&envs=API_ID,API_HASH,BOT_TOKEN,SESSION_STRING,CHAT,ADMINS,STREAM_URL,ADMIN_ONLY,DUR,LOG_GROUP&optionalEnvs=LOG_GROUP,ADMIN_ONLY,DUR&API_IDDesc=Your+App+id+and+hash+:get+it+from+my.telegram.org/apps&API_HASHDesc=Your+App+id+and+hash+:get+it+from+my.telegram.org/apps&BOT_TOKENDesc=Your+Bot+Api+Token+Get+it+from+@botfather&SESSION_STRINGDesc=your+pyrogram+session+string+:get+it+from+@gensessionbot&ADMINSDesc=your+telegram+ID+And+ids+of+whom+you+wish+to+controll+this&ADMIN_ONLYDesc=Optional+set+this+Y+or+N&LOG_GROUPDesc=Optional:+ID+of+your+bot+commands+log+group;+only+needed+if+you+are+playing+on+channel&CHATDesc=ID+of+channel/group+were+you+want+the+bot+user+to+play&STREAM_URLDesc=Stream+URL+of+radio+station+or+a+youtube+live+video+to+stream+when+the+bot+starts+or+with+/r+command&ADMIN_ONLYDefault=Y&STREAM_URLDefault=https://bit.ly/MwKradio&ADMINSDefault=749673781&DURDefault=300&CHATDefault=-100)
13 |
14 | # Vars:
15 | 1. `API_ID` : Get From my.telegram.org
16 | 2. `API_HASH` : Get from my.telegram.org
17 | 3. `BOT_TOKEN` : @Botfather
18 | 4. `SESSION_STRING` : Generate From [here](https://t.me/genstr_bot)
19 | 5. `CHAT` : ID of Channel/Group where the bot plays Music.
20 | 6. `LOG_GROUP` : Group to send Playlist, if CHAT is a Group
21 | 7. `ADMINS` : ID of users who can use admin commands.
22 | 8. `STREAM_URL` : Stream URL of radio station or a youtube live video to stream when the bot starts or with /r command.
23 |
24 | #### Disclaimer n Credits
25 | ###### This is Old Version of [subinps/musicplayer](https://github.com/subinps/MusicPlayer) with some Allara Chillara Maattam
26 | ###### Fork [Main Project](https://github.com/subinps/MusicPlayer) for Latest Update
27 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "MwK-Musics PyTGcalls",
3 | "description": "Telegram Bot to Play Audio And Live Streams in PyTGcalls",
4 | "logo": "https://telegra.ph/file/a3937c3ddc19bb3300d89.jpg",
5 | "repository": "https://github.com/shamilhabeebnelli/MwK-Musics",
6 | "keywords": [
7 | "telegram",
8 | "bot",
9 | "voicechat",
10 | "music",
11 | "python",
12 | "pyrogram",
13 | "pytgcalls",
14 | "tgcalls",
15 | "voip"
16 | ],
17 | "env": {
18 | "API_ID": {
19 | "description": "api_id part of your Telegram API Key from my.telegram.org/apps",
20 | "required": true
21 | },
22 | "API_HASH": {
23 | "description": "api_hash part of your Telegram API Key from my.telegram.org/apps",
24 | "required": true
25 | },
26 | "BOT_TOKEN": {
27 | "description": "Bot token of Bot, get from @Botfather",
28 | "required": true
29 | },
30 | "ARQ_API": {
31 | "description": "get it for free from @ARQRobot",
32 | "required": true
33 | },
34 | "SESSION_STRING": {
35 | "description": "Session string, use @genstr_bot",
36 | "required": true
37 | },
38 | "CHAT": {
39 | "description": "ID of Channel or Group where the Bot plays Music",
40 | "value": "-100",
41 | "required": true
42 | },
43 | "LOG_GROUP": {
44 | "description": "ID of the group to send playlist If CHAT is a Group, if channel thenleave blank",
45 | "required": false
46 | },
47 | "ADMINS": {
48 | "description": "ID of Users who can use Admin commands seperated by space)",
49 | "value": "749673781",
50 | "required": true
51 | },
52 | "STREAM_URL": {
53 | "description": "URL of Radio station or Youtube live video url to stream with /r command",
54 | "value": "https://bit.ly/MwKradio",
55 | "required": true
56 | },
57 | "ADMIN_ONLY": {
58 | "description": "Make All Commands Admin Only Usable Y/N",
59 | "value": "Y",
60 | "required": false
61 | },
62 | "DUR": {
63 | "description": "Keep This Blank if you dont now what it is, Maximum duration of song to play.(Optional)",
64 | "value": "300",
65 | "required": false
66 | }
67 | },
68 | "formation": {
69 | "worker": {
70 | "quantity": 1,
71 | "size": "free"
72 | }
73 | },
74 | "buildpacks": [
75 | {
76 | "url": "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest"
77 | },
78 | {
79 | "url": "heroku/python"
80 | }
81 | ]
82 | }
83 |
--------------------------------------------------------------------------------
/shamil/song.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 |
3 | import youtube_dl
4 | from youtube_search import YoutubeSearch
5 | import requests
6 |
7 | import os
8 |
9 | ## Extra Fns -------------------------------
10 |
11 | # Convert hh:mm:ss to seconds
12 | def time_to_seconds(time):
13 | stringt = str(time)
14 | return sum(int(x) * 60 ** i for i, x in enumerate(reversed(stringt.split(':'))))
15 |
16 |
17 | ## Commands --------------------------------
18 |
19 | @Client.on_message(filters.command(['song']))
20 | def a(client, message):
21 | query = ''
22 | for i in message.command[1:]:
23 | query += ' ' + str(i)
24 | print(query)
25 | m = message.reply('`Searching... Please Wait...`')
26 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
27 | try:
28 | results = []
29 | count = 0
30 | while len(results) == 0 and count < 6:
31 | if count>0:
32 | time.sleep(1)
33 | results = YoutubeSearch(query, max_results=1).to_dict()
34 | count += 1
35 | # results = YoutubeSearch(query, max_results=1).to_dict()
36 | try:
37 | link = f"https://youtube.com{results[0]['url_suffix']}"
38 | # print(results)
39 | title = results[0]["title"]
40 | thumbnail = results[0]["thumbnails"][0]
41 | duration = results[0]["duration"]
42 | views = results[0]["views"]
43 |
44 | ## UNCOMMENT THIS IF YOU WANT A LIMIT ON DURATION. CHANGE 1800 TO YOUR OWN PREFFERED DURATION AND EDIT THE MESSAGE (30 minutes cap) LIMIT IN SECONDS
45 | # if time_to_seconds(duration) >= 7000: # duration limit
46 | # m.edit("Exceeded 30mins cap")
47 | # return
48 |
49 | performer = f"[MwK-Musics]"
50 | thumb_name = f'thumb{message.message_id}.jpg'
51 | thumb = requests.get(thumbnail, allow_redirects=True)
52 | open(thumb_name, 'wb').write(thumb.content)
53 |
54 | except Exception as e:
55 | print(e)
56 | m.edit('**👎 Nᴏᴛʜɪɴɢ Tᴏ Bᴇ Fᴏᴜɴᴅ 🥺 Oʀ Cʜᴇᴄᴋ Sᴩᴇʟʟɪɴɢ 🤗!**')
57 | return
58 | except Exception as e:
59 | m.edit(
60 | "**Enter Song Name with /song Command!**"
61 | )
62 | print(str(e))
63 | return
64 | m.edit("`Bruh... Uploading... Please Wait...`")
65 | try:
66 | with youtube_dl.YoutubeDL(ydl_opts) as ydl:
67 | info_dict = ydl.extract_info(link, download=False)
68 | audio_file = ydl.prepare_filename(info_dict)
69 | ydl.process_info(info_dict)
70 | rep = f'🎶 Title: {title}\n⌚ Duration: {duration}\n📻 Uploaded By: [MwK] Musics'
71 | secmul, dur, dur_arr = 1, 0, duration.split(':')
72 | for i in range(len(dur_arr)-1, -1, -1):
73 | dur += (int(dur_arr[i]) * secmul)
74 | secmul *= 60
75 | message.reply_audio(audio_file, caption=rep, parse_mode='HTML',quote=False, title=title, duration=dur, performer=performer, thumb=thumb_name)
76 | m.delete()
77 | message.delete()
78 | except Exception as e:
79 | m.edit('**Sᴇᴇᴍꜱ Lɪᴋᴇ Aɴ Eʀʀᴏʀ Oᴄᴄᴜʀᴇᴅ 🥶 Report This @redbullfed!!**')
80 | print(e)
81 | try:
82 | os.remove(audio_file)
83 | os.remove(thumb_name)
84 | except Exception as e:
85 | print(e)
86 |
87 |
--------------------------------------------------------------------------------
/shamil/commands.py:
--------------------------------------------------------------------------------
1 | # A Subinps Project
2 | # Pyrogram - Telegram MTProto API Client Library for Python
3 | # Copyright (C) 2017-2020 Dan
4 | #
5 | # This file is part of Pyrogram.
6 | #
7 | # Pyrogram is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Lesser General Public License as published
9 | # by the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Pyrogram is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Lesser General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Lesser General Public License
18 | # along with Pyrogram. If not, see .
19 |
20 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
21 | from pyrogram import Client, filters
22 | import signal
23 | from utils import USERNAME, FFMPEG_PROCESSES
24 | from config import Config
25 | import os
26 | import sys
27 | U=USERNAME
28 | CHAT=Config.CHAT
29 |
30 |
31 | HOME_TEXT = "Helo, [{}](tg://user?id={})\n\n• Iam A Bot Project by MwK MusicS\n• I Can Manage Group VC's\n\n• Hit /help to know about available commands."
32 | HELP = """
33 | 🎧 I Can Play Music On VoiceChats 🤪
34 |
35 | 🎶 **Common Commands**:
36 | • `/current` __Show current playing song__
37 | • `/help` __Show help for commands__
38 | • `/mwk` __Shows the playlist__
39 | • `/stickerid` __To Get Id Of Replied Sticker__
40 |
41 | 🎶 **Admin Commands**:
42 | • `/play` __Reply to an audio file or YouTube link to play it or use /p __
43 | • `/dplay` __Play music from Deezer, Use /d __
44 | • `/skip [n]` __...Skip current or n where n >= 2__
45 | • `/join` __Join voice chat__
46 | • `/leave` __Leave current voice chat__
47 | • `/mwk` __Check which VC is joined__
48 | • `/stop` __Stop playing__
49 | • `/radio` __Start Radio__
50 | • `/stopradio` __Stops Radio Stream__
51 | • `/replay` __Play from the beginning__
52 | • `/clear` __Remove unused RAW PCM files__
53 | • `/pause` __Pause playing__
54 | • `/resume` __Resume playing__
55 | • `/mute` __Mute in VC__
56 | • `/unmute` __Unmute in VC__
57 | • `/update` __Update Current Settings n Restarts the Bot__
58 |
59 | © Powered By
60 | [ __@mwkBoTs | @subin_works__ ]
61 | """
62 |
63 |
64 |
65 | @Client.on_message(filters.command('start'))
66 | async def start(client, message):
67 | buttons = [
68 | [
69 | InlineKeyboardButton("❔ How To Use Me ❔", callback_data="help"),
70 | ],[
71 | InlineKeyboardButton('📢 Updates', url='https://t.me/mwklinks'),
72 | InlineKeyboardButton('💬 Support', url='https://t.me/redbullfed')
73 | ],[
74 | InlineKeyboardButton('🤖 Developer', url='t.me/subinps'),
75 | InlineKeyboardButton('Bugs', url='t.me/subin_works')
76 | ],[
77 | InlineKeyboardButton('📜 Source Code 📜', url='https://github.com/shamilhabeebnelli/mwk-musics'),
78 | ]]
79 | reply_markup = InlineKeyboardMarkup(buttons)
80 | await message.reply_photo(photo="https://telegra.ph/file/a3937c3ddc19bb3300d89.jpg", caption=HOME_TEXT.format(message.from_user.first_name, message.from_user.id), reply_markup=reply_markup)
81 | await message.delete()
82 |
83 |
84 | @Client.on_message(filters.command("help"))
85 | async def show_help(client, message):
86 | buttons = [
87 | [
88 | InlineKeyboardButton('📢 Updates', url='https://t.me/mwklinks'),
89 | InlineKeyboardButton('💬 Support', url='https://t.me/redbullfed')
90 | ],[
91 | InlineKeyboardButton('🤖 Developer', url='t.me/subinps'),
92 | InlineKeyboardButton('Bugs', url='t.me/subin_works')
93 | ],[
94 | InlineKeyboardButton('📜 Source Code 📜', url='https://github.com/shamilhabeebnelli/mwk-musics'),
95 | ]
96 | ]
97 | reply_markup = InlineKeyboardMarkup(buttons)
98 | await message.reply_photo(photo="https://telegra.ph/file/a3937c3ddc19bb3300d89.jpg", caption=HELP, reply_markup=reply_markup)
99 | await message.delete()
100 |
--------------------------------------------------------------------------------
/shamil/callback.py:
--------------------------------------------------------------------------------
1 | # A Subinps Project
2 | # Pyrogram - Telegram MTProto API Client Library for Python
3 | # Copyright (C) 2017-2020 Dan
4 | #
5 | # This file is part of Pyrogram.
6 | #
7 | # Pyrogram is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Lesser General Public License as published
9 | # by the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Pyrogram is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Lesser General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Lesser General Public License
18 | # along with Pyrogram. If not, see .
19 |
20 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
21 | from pyrogram import Client, emoji
22 | from utils import mp
23 | from config import Config
24 | playlist=Config.playlist
25 |
26 | HELP = """
27 |
28 | 🎧 I Can Play Music On VoiceChats 🤪
29 |
30 | 🎶 **Common Commands**:
31 | • `/current` __Show current playing song__
32 | • `/help` __Show help for commands__
33 | • `/mwk` __Shows the playlist__
34 | • `/stickerid` __To Get Id Of Replied Sticker__
35 |
36 | 🎶 **Admin Commands**:
37 | • `/play` __Reply to an audio file or YouTube link to play it or use /p __
38 | • `/dplay` __Play music from Deezer, Use /d __
39 | • `/skip [n]` __...Skip current or n where n >= 2__
40 | • `/join` __Join voice chat__
41 | • `/leave` __Leave current voice chat__
42 | • `/mwk` __Check which VC is joined__
43 | • `/stop` __Stop playing__
44 | • `/radio` __Start Radio__
45 | • `/stopradio` __Stops Radio Stream__
46 | • `/replay` __Play from the beginning__
47 | • `/clear` __Remove unused RAW PCM files__
48 | • `/pause` __Pause playing__
49 | • `/resume` __Resume playing__
50 | • `/mute` __Mute in VC__
51 | • `/unmute` __Unmute in VC__
52 | • `/update` __Update Current Settings n Restarts the Bot__
53 |
54 | © Powered By
55 | [ __@mwkBoTs | @subin_works__ ]
56 | """
57 |
58 |
59 | @Client.on_callback_query()
60 | async def cb_handler(client: Client, query: CallbackQuery):
61 | if query.data == "rp":
62 | group_call = mp.group_call
63 | if not playlist:
64 | return
65 | group_call.restart_playout()
66 | if not playlist:
67 | pl = f"😖 Nothing On Que Ser"
68 | else:
69 | pl = f"🎧 **Playlist**:\n" + "\n".join([
70 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
71 | for i, x in enumerate(playlist)
72 | ])
73 | await query.edit_message_text(
74 | f"{pl}",
75 | parse_mode="Markdown",
76 | reply_markup=InlineKeyboardMarkup(
77 | [
78 | [
79 | InlineKeyboardButton("Replay", callback_data="rp"),
80 | InlineKeyboardButton("Pause", callback_data="ps")
81 | ],[
82 | InlineKeyboardButton("Skip", callback_data="sk"),
83 | InlineKeyboardButton("Report Bug", url="subinps_bot")
84 | ]
85 | ]
86 | )
87 | )
88 |
89 | elif query.data == "ps":
90 | if not playlist:
91 | return
92 | else:
93 | mp.group_call.pause_playout()
94 | pl = f"🎧 **Playlist**:\n" + "\n".join([
95 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
96 | for i, x in enumerate(playlist)
97 | ])
98 | await query.edit_message_text(f"{emoji.PLAY_OR_PAUSE_BUTTON} Paused\n\n{pl}",
99 | reply_markup=InlineKeyboardMarkup(
100 | [
101 | [
102 | InlineKeyboardButton("Replay", callback_data="replace"),
103 | InlineKeyboardButton("Resume", callback_data="resume")
104 | ],[
105 | InlineKeyboardButton("Skip", callback_data="skip"),
106 | InlineKeyboardButton("Updates", url='t.me/mwkBoTs')
107 | ],
108 | ]
109 | )
110 | )
111 |
112 |
113 | elif query.data == "rs":
114 | if not playlist:
115 | return
116 | else:
117 | mp.group_call.resume_playout()
118 | pl = f"🎧 **Playlist**:\n" + "\n".join([
119 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
120 | for i, x in enumerate(playlist)
121 | ])
122 | await query.edit_message_text(f"{emoji.PLAY_OR_PAUSE_BUTTON} Resumed\n\n{pl}",
123 | reply_markup=InlineKeyboardMarkup(
124 | [
125 | [
126 | InlineKeyboardButton("Replay", callback_data="rp"),
127 | InlineKeyboardButton("Pause", callback_data="ps")
128 | ],[
129 | InlineKeyboardButton("Skip", callback_data="sk"),
130 | InlineKeyboardButton("Support", url="https://t.me/redbullfed")
131 | ],
132 | ]
133 | )
134 | )
135 |
136 | elif query.data=="sk":
137 | if not playlist:
138 | return
139 | else:
140 | await mp.skip_current_playing()
141 | pl = f"🎧 **Playlist**:\n" + "\n".join([
142 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
143 | for i, x in enumerate(playlist)
144 | ])
145 | try:
146 | await query.edit_message_text(f"{emoji.PLAY_OR_PAUSE_BUTTON} Skipped\n\n{pl}",
147 | reply_markup=InlineKeyboardMarkup(
148 | [
149 | [
150 | InlineKeyboardButton("Replay", callback_data="rp"),
151 | InlineKeyboardButton("Pause", callback_data="ps")
152 | ],[
153 | InlineKeyboardButton("Skip", callback_data="sk"),
154 | InlineKeyboardButton("Updates", url="t.me/subin_works")
155 |
156 | ],
157 | ]
158 | )
159 | )
160 | except:
161 | pass
162 | elif query.data=="help":
163 | buttons = [
164 | [
165 | InlineKeyboardButton('📢 Updates', url='https://t.me/mwklinks'),
166 | InlineKeyboardButton('💬 Support', url='https://t.me/redbullfed')
167 | ],[
168 | InlineKeyboardButton('🤖 Developer', url='t.me/subinps'),
169 | InlineKeyboardButton('Bugs', url='t.me/subin_works')
170 | ],[
171 | InlineKeyboardButton('📜 Source Code 📜', url='https://github.com/shamilhabeebnelli/mwk-musics'),
172 | ]
173 | ]
174 | reply_markup = InlineKeyboardMarkup(buttons)
175 | await query.edit_message_text(
176 | HELP,
177 | reply_markup=reply_markup
178 |
179 | )
180 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | # A Subinps Project
2 | # Pyrogram - Telegram MTProto API Client Library for Python
3 | # Copyright (C) 2017-2020 Dan
4 | #
5 | # This file is part of Pyrogram.
6 | #
7 | # Pyrogram is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Lesser General Public License as published
9 | # by the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Pyrogram is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Lesser General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Lesser General Public License
18 | # along with Pyrogram. If not, see .
19 |
20 |
21 |
22 | import os
23 | from config import Config
24 | import ffmpeg
25 | from pyrogram import emoji
26 | from pyrogram.methods.messages.download_media import DEFAULT_DOWNLOAD_DIR
27 | from pytgcalls import GroupCall
28 | import signal
29 | from pyrogram import Client
30 | from youtube_dl import YoutubeDL
31 | from os import path
32 | bot = Client(
33 | "MwKVC",
34 | Config.API_ID,
35 | Config.API_HASH,
36 | bot_token=Config.BOT_TOKEN
37 | )
38 | bot.start()
39 | e=bot.get_me()
40 | USERNAME=e.username
41 |
42 | from user import USER
43 | STREAM_URL=Config.STREAM_URL
44 | CHAT=Config.CHAT
45 | GROUP_CALLS = {}
46 | FFMPEG_PROCESSES = {}
47 | RADIO={6}
48 | LOG_GROUP=Config.LOG_GROUP
49 | DURATION_LIMIT=Config.DURATION_LIMIT
50 | playlist=Config.playlist
51 | msg=Config.msg
52 |
53 |
54 | ydl_opts = {
55 | "format": "bestaudio[ext=m4a]",
56 | "geo-bypass": True,
57 | "nocheckcertificate": True,
58 | "outtmpl": "downloads/%(id)s.%(ext)s",
59 | }
60 | ydl = YoutubeDL(ydl_opts)
61 | def youtube(url: str) -> str:
62 | info = ydl.extract_info(url, False)
63 | duration = round(info["duration"] / 60)
64 | try:
65 | ydl.download([url])
66 | except Exception as e:
67 | print(e)
68 | pass
69 | return path.join("downloads", f"{info['id']}.{info['ext']}")
70 |
71 | class MusicPlayer(object):
72 | def __init__(self):
73 | self.group_call = GroupCall(USER, path_to_log_file='')
74 | self.chat_id = None
75 |
76 |
77 | async def send_playlist(self):
78 | if not playlist:
79 | pl = f"Playlist is Empty Like Your Brain"
80 | else:
81 | pl = f"🎧 **Playlist**:\n" + "\n".join([
82 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}\n"
83 | for i, x in enumerate(playlist)
84 | ])
85 | if msg.get('playlist') is not None:
86 | await msg['playlist'].delete()
87 | msg['playlist'] = await self.send_text(pl)
88 |
89 | async def skip_current_playing(self):
90 | group_call = self.group_call
91 | if not playlist:
92 | return
93 | if len(playlist) == 1:
94 | await mp.start_radio()
95 | return
96 | client = group_call.client
97 | download_dir = os.path.join(client.workdir, DEFAULT_DOWNLOAD_DIR)
98 | group_call.input_filename = os.path.join(
99 | download_dir,
100 | f"{playlist[1][1]}.raw"
101 | )
102 | # remove old track from playlist
103 | old_track = playlist.pop(0)
104 | print(f"- START PLAYING: {playlist[0][1]}")
105 | if LOG_GROUP:
106 | await self.send_playlist()
107 | os.remove(os.path.join(
108 | download_dir,
109 | f"{old_track[1]}.raw")
110 | )
111 | if len(playlist) == 1:
112 | return
113 | await self.download_audio(playlist[1])
114 |
115 | async def send_text(self, text):
116 | group_call = self.group_call
117 | client = group_call.client
118 | chat_id = LOG_GROUP
119 | message = await bot.send_message(
120 | chat_id,
121 | text,
122 | disable_web_page_preview=True,
123 | disable_notification=True
124 | )
125 | return message
126 |
127 | async def download_audio(self, song):
128 | group_call = self.group_call
129 | client = group_call.client
130 | raw_file = os.path.join(client.workdir, DEFAULT_DOWNLOAD_DIR,
131 | f"{song[1]}.raw")
132 | #if os.path.exists(raw_file):
133 | #os.remove(raw_file)
134 | if not os.path.isfile(raw_file):
135 | # credits: SpechiDe
136 | #os.mkfifo(raw_file)
137 | if song[3] == "telegram":
138 | original_file = await bot.download_media(f"{song[2]}")
139 | elif song[3] == "youtube":
140 | original_file = youtube(song[2])
141 | else:
142 | original_file=wget.download(song[2])
143 | ffmpeg.input(original_file).output(
144 | raw_file,
145 | format='s16le',
146 | acodec='pcm_s16le',
147 | ac=2,
148 | ar='48k',
149 | loglevel='error'
150 | ).overwrite_output().run()
151 | os.remove(original_file)
152 |
153 |
154 | async def start_radio(self):
155 | group_call = mp.group_call
156 | if group_call.is_connected:
157 | playlist.clear()
158 | group_call.input_filename = ''
159 | await group_call.stop()
160 | process = FFMPEG_PROCESSES.get(CHAT)
161 | if process:
162 | process.send_signal(signal.SIGTERM)
163 | station_stream_url = STREAM_URL
164 | group_call.input_filename = f'radio-{CHAT}.raw'
165 | try:
166 | RADIO.remove(0)
167 | except:
168 | pass
169 | try:
170 | RADIO.add(1)
171 | except:
172 | pass
173 | if os.path.exists(group_call.input_filename):
174 | os.remove(group_call.input_filename)
175 | # credits: https://t.me/c/1480232458/6825
176 | #os.mkfifo(group_call.input_filename)
177 | process = ffmpeg.input(station_stream_url).output(
178 | group_call.input_filename,
179 | format='s16le',
180 | acodec='pcm_s16le',
181 | ac=2,
182 | ar='48k'
183 | ).overwrite_output().run_async()
184 | FFMPEG_PROCESSES[CHAT] = process
185 | while True:
186 | if os.path.isfile(group_call.input_filename):
187 | await group_call.start(CHAT)
188 | break
189 | else:
190 | continue
191 |
192 | async def stop_radio(self):
193 | group_call = mp.group_call
194 | if group_call:
195 | playlist.clear()
196 | group_call.input_filename = ''
197 | try:
198 | RADIO.remove(1)
199 | except:
200 | pass
201 | try:
202 | RADIO.add(0)
203 | except:
204 | pass
205 | process = FFMPEG_PROCESSES.get(CHAT)
206 | if process:
207 | process.send_signal(signal.SIGTERM)
208 |
209 | async def start_call(self):
210 | group_call = mp.group_call
211 | await group_call.start(CHAT)
212 |
213 |
214 |
215 |
216 | mp = MusicPlayer()
217 |
218 |
219 | # pytgcalls handlers
220 |
221 | @mp.group_call.on_network_status_changed
222 | async def network_status_changed_handler(gc: GroupCall, is_connected: bool):
223 | if is_connected:
224 | mp.chat_id = int("-100" + str(gc.full_chat.id))
225 | else:
226 | mp.chat_id = None
227 |
228 |
229 | @mp.group_call.on_playout_ended
230 | async def playout_ended_handler(_, __):
231 | if not playlist:
232 | await mp.start_radio()
233 | else:
234 | await mp.skip_current_playing()
235 |
--------------------------------------------------------------------------------
/shamil/player.py:
--------------------------------------------------------------------------------
1 | # A Subinps Project
2 | # Pyrogram - Telegram MTProto API Client Library for Python
3 | # Copyright (C) 2017-2020 Dan
4 | #
5 | # This file is part of Pyrogram.
6 | #
7 | # Pyrogram is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Lesser General Public License as published
9 | # by the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Pyrogram is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Lesser General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Lesser General Public License
18 | # along with Pyrogram. If not, see .
19 |
20 | import os
21 | from youtube_dl import YoutubeDL
22 | from config import Config
23 | from pyrogram import Client, filters, emoji
24 | from pyrogram.methods.messages.download_media import DEFAULT_DOWNLOAD_DIR
25 | from pyrogram.types import Message
26 | from utils import mp, RADIO, USERNAME, FFMPEG_PROCESSES
27 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
28 | from youtube_search import YoutubeSearch
29 | from pyrogram import Client
30 | from aiohttp import ClientSession
31 | import signal
32 | import re
33 | U=USERNAME
34 | LOG_GROUP=Config.LOG_GROUP
35 | ADMIN_ONLY=Config.ADMIN_ONLY
36 | DURATION_LIMIT = Config.DURATION_LIMIT
37 | session = ClientSession()
38 | playlist=Config.playlist
39 |
40 | ADMINS=Config.ADMINS
41 | CHAT=Config.CHAT
42 |
43 | @Client.on_message(filters.command(["play", f"play@{U}"]) | filters.audio & filters.private)
44 | async def yplay(_, message: Message):
45 | if ADMIN_ONLY == "Y":
46 | admins=[626664225]
47 | grpadmins=await _.get_chat_members(chat_id=CHAT, filter="administrators")
48 | for administrator in grpadmins:
49 | admins.append(administrator.user.id)
50 | if message.from_user.id not in admins:
51 | await message.reply_sticker("CAACAgUAAxkBAAIJM2DTpi52NSM-O-KnYcC1IzbJos8HAAK6AQACsm0wVffnRbQlKgeTHwQ")
52 | await message.delete()
53 | return
54 | type=""
55 | yturl=""
56 | ysearch=""
57 | if message.audio:
58 | type="audio"
59 | m_audio = message
60 | elif message.reply_to_message and message.reply_to_message.audio:
61 | type="audio"
62 | m_audio = message.reply_to_message
63 | else:
64 | if message.reply_to_message:
65 | link=message.reply_to_message.text
66 | regex = r"^(https?\:\/\/)?(www\.youtube\.com|youtu\.?be)\/.+"
67 | match = re.match(regex,link)
68 | if match:
69 | type="youtube"
70 | yturl=link
71 | elif " " in message.text:
72 | text = message.text.split(" ", 1)
73 | query = text[1]
74 | regex = r"^(https?\:\/\/)?(www\.youtube\.com|youtu\.?be)\/.+"
75 | match = re.match(regex,query)
76 | if match:
77 | type="youtube"
78 | yturl=query
79 | else:
80 | type="query"
81 | ysearch=query
82 | else:
83 | await message.reply_text("lmao 😇, Lemma Gib Me something to play or reply /p to any audio file.")
84 | return
85 | user=f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})"
86 | group_call = mp.group_call
87 | if type=="audio":
88 | if round(m_audio.audio.duration / 60) > DURATION_LIMIT:
89 | await message.reply_text(f"Oops Its Seems too Lengthy is about {round(m_audio.audio.duration/60)} minute(s) The Limit you can use is {DURATION_LIMIT} minute(s)")
90 | return
91 | if playlist and playlist[-1][2] \
92 | == m_audio.audio.file_id:
93 | await message.reply_text(f"📜 Already Qued Bruh")
94 | return
95 | data={1:m_audio.audio.title, 2:m_audio.audio.file_id, 3:"telegram", 4:user}
96 | playlist.append(data)
97 | if len(playlist) == 1:
98 | m_status = await message.reply_text(
99 | f"fetching data from m.youtube.com"
100 | )
101 | await mp.download_audio(playlist[0])
102 | if 1 in RADIO:
103 | if group_call:
104 | group_call.input_filename = ''
105 | RADIO.remove(1)
106 | RADIO.add(0)
107 | process = FFMPEG_PROCESSES.get(CHAT)
108 | if process:
109 | process.send_signal(signal.SIGTERM)
110 | if not group_call.is_connected:
111 | await mp.start_call()
112 | file=playlist[0][1]
113 | group_call.input_filename = os.path.join(
114 | _.workdir,
115 | DEFAULT_DOWNLOAD_DIR,
116 | f"{file}.raw"
117 | )
118 |
119 | await m_status.delete()
120 | print(f"- START PLAYING: {playlist[0][1]}")
121 | if not playlist:
122 | pl = f"📻 Nothing Is On Que"
123 | else:
124 | pl = f"🎧 **Que**:\n" + "\n".join([
125 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
126 | for i, x in enumerate(playlist)
127 | ])
128 | if LOG_GROUP and message.chat.id != LOG_GROUP:
129 | await message.reply_text(pl)
130 | for track in playlist[:2]:
131 | await mp.download_audio(track)
132 | if LOG_GROUP:
133 | await mp.send_playlist()
134 | else:
135 | await message.reply_text(pl)
136 | if type=="youtube" or type=="query":
137 | if type=="youtube":
138 | msg = await message.reply_text("**Fetching Song Data From YouTube...**")
139 | url=yturl
140 | elif type=="query":
141 | try:
142 | msg = await message.reply_text("**Seems Like Something Found...**")
143 | ytquery=ysearch
144 | results = YoutubeSearch(ytquery, max_results=1).to_dict()
145 | url = f"https://youtube.com{results[0]['url_suffix']}"
146 | title = results[0]["title"][:40]
147 | except Exception as e:
148 | await msg.edit(
149 | "Sed Nothing Is Found For Your Query, Ensure spelling or Try inline"
150 | )
151 | print(str(e))
152 | return
153 | else:
154 | return
155 | ydl_opts = {
156 | "geo-bypass": True,
157 | "nocheckcertificate": True
158 | }
159 | ydl = YoutubeDL(ydl_opts)
160 | info = ydl.extract_info(url, False)
161 | duration = round(info["duration"] / 60)
162 | print(info)
163 | title= info["title"]
164 | if int(duration) > DURATION_LIMIT:
165 | await message.reply_text(f"Oops Its Seems too Lengthy is about {round(m_audio.audio.duration/60)} minute(s) The Limit you can use is {DURATION_LIMIT} minute(s)")
166 | return
167 |
168 | data={1:title, 2:url, 3:"youtube", 4:user}
169 | playlist.append(data)
170 | group_call = mp.group_call
171 | client = group_call.client
172 | if len(playlist) == 1:
173 | m_status = await msg.edit(
174 | f"Im on it bruh..."
175 | )
176 | await mp.download_audio(playlist[0])
177 | if 1 in RADIO:
178 | if group_call:
179 | group_call.input_filename = ''
180 | RADIO.remove(1)
181 | RADIO.add(0)
182 | process = FFMPEG_PROCESSES.get(CHAT)
183 | if process:
184 | process.send_signal(signal.SIGTERM)
185 | if not group_call.is_connected:
186 | await mp.start_call()
187 | file=playlist[0][1]
188 | group_call.input_filename = os.path.join(
189 | client.workdir,
190 | DEFAULT_DOWNLOAD_DIR,
191 | f"{file}.raw"
192 | )
193 |
194 | await m_status.delete()
195 | print(f"- START PLAYING: {playlist[0][1]}")
196 | if not playlist:
197 | pl = f"📻 Nothing Is On Que"
198 | else:
199 | pl = f"🎧 **Que**:\n" + "\n".join([
200 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
201 | for i, x in enumerate(playlist)
202 | ])
203 | if LOG_GROUP and message.chat.id != LOG_GROUP:
204 | await message.reply_text(pl)
205 | for track in playlist[:2]:
206 | await mp.download_audio(track)
207 | if LOG_GROUP:
208 | await mp.send_playlist()
209 | else:
210 | await message.reply_text(pl)
211 | await message.delete()
212 |
213 | @Client.on_message(filters.command(["current", f"current@{U}"]))
214 | async def player(_, m: Message):
215 | if not playlist:
216 | await m.reply_text(f"{emoji.NO_ENTRY} No songs are playing")
217 | return
218 | else:
219 | pl = f"{emoji.PLAY_BUTTON} **Playlist**:\n" + "\n".join([
220 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
221 | for i, x in enumerate(playlist)
222 | ])
223 | await m.reply_text(
224 | pl,
225 | parse_mode="Markdown",
226 | reply_markup=InlineKeyboardMarkup(
227 | [
228 | [
229 | InlineKeyboardButton("Replay", callback_data="rp"),
230 | InlineKeyboardButton("Pause", callback_data="ps"),
231 | InlineKeyboardButton("Skip", callback_data="sk")
232 |
233 | ],
234 |
235 | ]
236 | )
237 | )
238 | await m.delete()
239 |
240 | @Client.on_message(filters.command(["skip", f"skip@{U}"]) & filters.user(ADMINS))
241 | async def skip_track(_, m: Message):
242 | group_call = mp.group_call
243 | if not group_call.is_connected:
244 | await m.reply("Playing, Playlist, and Que is utterly empty like your brain 🤪")
245 | return
246 | if len(m.command) == 1:
247 | await mp.skip_current_playing()
248 | if not playlist:
249 | pl = f"📻 Empty Que, Like Your Brain"
250 | else:
251 | pl = f"{emoji.PLAY_BUTTON} **Playlist**:\n" + "\n".join([
252 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
253 | for i, x in enumerate(playlist)
254 | ])
255 | if LOG_GROUP and m.chat.id != LOG_GROUP:
256 | await m.reply_text(pl)
257 | if LOG_GROUP:
258 | await mp.send_playlist()
259 | else:
260 | await m.reply_text(pl)
261 | else:
262 | try:
263 | items = list(dict.fromkeys(m.command[1:]))
264 | items = [int(x) for x in items if x.isdigit()]
265 | items.sort(reverse=True)
266 | text = []
267 | for i in items:
268 | if 2 <= i <= (len(playlist) - 1):
269 | audio = f"{playlist[i].audio.title}"
270 | playlist.pop(i)
271 | text.append(f"{emoji.WASTEBASKET} {i}. **{audio}**")
272 | else:
273 | text.append(f"{emoji.CROSS_MARK} {i}")
274 | await m.reply_text("\n".join(text))
275 | if not playlist:
276 | pl = f"📻 Empty Que, Like your Brain"
277 | else:
278 | pl = f"{emoji.PLAY_BUTTON} **Playlist**:\n" + "\n".join([
279 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
280 | for i, x in enumerate(playlist)
281 | ])
282 | if LOG_GROUP and m.chat.id != LOG_GROUP:
283 | await m.reply_text(pl)
284 | if LOG_GROUP:
285 | await mp.send_playlist()
286 | else:
287 | await m.reply_text(pl)
288 | except (ValueError, TypeError):
289 | await m.reply_text(f"{emoji.NO_ENTRY} Invalid input",
290 | disable_web_page_preview=True)
291 | await m.delete()
292 |
293 |
294 | @Client.on_message(filters.command(["join", f"join@{U}"]) & filters.user(ADMINS))
295 | async def join_group_call(client, m: Message):
296 | group_call = mp.group_call
297 | if group_call.is_connected:
298 | await m.reply_text(f"{emoji.ROBOT} Already joined VC")
299 | return
300 | await mp.start_call()
301 | chat = await client.get_chat(CHAT)
302 | await m.reply_text(f"Succesfully Joined Voice Chat in {chat.title}")
303 | await m.delete()
304 |
305 |
306 | @Client.on_message(filters.command("leave") & filters.user(ADMINS))
307 | async def leave_voice_chat(_, m: Message):
308 | group_call = mp.group_call
309 | if not group_call.is_connected:
310 | await m.reply_text("Not joined any Alive VCs yet.")
311 | return
312 | playlist.clear()
313 | if 1 in RADIO:
314 | await mp.stop_radio()
315 | group_call.input_filename = ''
316 | await group_call.stop()
317 | await m.reply_text("Left the VoiceChat")
318 | await m.delete()
319 |
320 |
321 | @Client.on_message(filters.command(["mwk", f"mwk@{U}"]) & filters.user(ADMINS))
322 | async def list_voice_chat(client, m: Message):
323 | group_call = mp.group_call
324 | if group_call.is_connected:
325 | chat_id = int("-100" + str(group_call.full_chat.id))
326 | chat = await client.get_chat(chat_id)
327 | await m.reply_text(
328 | f"{emoji.MUSICAL_NOTES} **Currently in the voice chat**:\n"
329 | f"- **{chat.title}**"
330 | )
331 | else:
332 | await m.reply_text(emoji.NO_ENTRY
333 | + "Didn't join any VCs yet")
334 | await m.delete()
335 |
336 |
337 | @Client.on_message(filters.command(["stop", f"stop@{U}"]) & filters.user(ADMINS))
338 | async def stop_playing(_, m: Message):
339 | group_call = mp.group_call
340 | if not group_call.is_connected:
341 | await m.reply_text("Nothing playing to stop.")
342 | return
343 | if 1 in RADIO:
344 | await mp.stop_radio()
345 | group_call.stop_playout()
346 | await m.reply_text(f"{emoji.STOP_BUTTON} Stopped playing")
347 | playlist.clear()
348 | await m.delete()
349 |
350 |
351 | @Client.on_message(filters.command(["replay", f"replay@{U}"]) & filters.user(ADMINS))
352 | async def restart_playing(_, m: Message):
353 | group_call = mp.group_call
354 | if not group_call.is_connected:
355 | await m.reply_text("Nothing playing to replay.")
356 | return
357 | if not playlist:
358 | await m.reply_text("Empty Que, Like your brain.")
359 | return
360 | group_call.restart_playout()
361 | await m.reply_text(
362 | f"{emoji.COUNTERCLOCKWISE_ARROWS_BUTTON} "
363 | "Playing from the beginning..."
364 | )
365 | await m.delete()
366 |
367 |
368 | @Client.on_message(filters.command(["pause", f"pause@{U}"]) & filters.user(ADMINS))
369 | async def pause_playing(_, m: Message):
370 | group_call = mp.group_call
371 | if not group_call.is_connected:
372 | await m.reply_text("Nothing playing to pause.")
373 | return
374 | mp.group_call.pause_playout()
375 | await m.reply_text(f"{emoji.PLAY_OR_PAUSE_BUTTON} Paused",
376 | quote=False)
377 | await m.delete()
378 |
379 |
380 |
381 | @Client.on_message(filters.command(["resume", f"resume@{U}"]) & filters.user(ADMINS))
382 | async def resume_playing(_, m: Message):
383 | if not mp.group_call.is_connected:
384 | await m.reply_text("Nothing paused to resume.")
385 | return
386 | mp.group_call.resume_playout()
387 | await m.reply_text(f"{emoji.PLAY_OR_PAUSE_BUTTON} Resumed",
388 | quote=False)
389 |
390 | @Client.on_message(filters.command(["clear", f"clear@{U}"]) & filters.user(ADMINS))
391 | async def clean_raw_pcm(client, m: Message):
392 | download_dir = os.path.join(client.workdir, DEFAULT_DOWNLOAD_DIR)
393 | all_fn: list[str] = os.listdir(download_dir)
394 | for track in playlist[:2]:
395 | track_fn = f"{track[1]}.raw"
396 | if track_fn in all_fn:
397 | all_fn.remove(track_fn)
398 | count = 0
399 | if all_fn:
400 | for fn in all_fn:
401 | if fn.endswith(".raw"):
402 | count += 1
403 | os.remove(os.path.join(download_dir, fn))
404 | await m.reply_text(f"{emoji.WASTEBASKET} Cleaned {count} files")
405 | await m.delete()
406 |
407 |
408 | @Client.on_message(filters.command(["mute", f"mute@{U}"]) & filters.user(ADMINS))
409 | async def mute(_, m: Message):
410 | group_call = mp.group_call
411 | if not group_call.is_connected:
412 | await m.reply_text("Nothing playing to mute.")
413 | return
414 | group_call.set_is_mute(True)
415 | await m.reply_text(f"🤐 Muted")
416 | await m.delete()
417 |
418 | @Client.on_message(filters.command(["unmute", f"unmute@{U}"]) & filters.user(ADMINS))
419 | async def unmute(_, m: Message):
420 | group_call = mp.group_call
421 | if not group_call.is_connected:
422 | await m.reply_text("Nothing playing to mute.")
423 | return
424 | group_call.set_is_mute(False)
425 | await m.reply_text(f"{emoji.SPEAKER_MEDIUM_VOLUME} Unmuted")
426 | await m.delete()
427 |
428 | @Client.on_message(filters.command(["playlist", f"playlist@{U}"]))
429 | async def show_playlist(_, m: Message):
430 | group_call = mp.group_call
431 | if not group_call.is_connected:
432 | await m.reply_text("No active VC.")
433 | return
434 | if not playlist:
435 | pl = f"📜 Empty Playlist."
436 | else:
437 | pl = f"{emoji.PLAY_BUTTON} **Playlist**:\n" + "\n".join([
438 | f"**{i}**. **📻{x[1]}**\n 👤**Requested by:** {x[4]}"
439 | for i, x in enumerate(playlist)
440 | ])
441 | await m.reply_text(pl)
442 | await m.delete()
443 |
444 | admincmds=["join", "unmute", "mute", "leave", "clear", "mwk", "pause", "resume", "skip", "radio", "stopradio", "replay", "update", f"join@{U}", f"unmute@{U}", f"mute@{U}", f"leave@{U}", f"clear@{U}", f"mwk@{U}", f"pause@{U}", f"resume@{U}", f"skip@{U}", f"radio@{U}", f"stopradio@{U}", f"replay@{U}", f"update@{U}"]
445 |
446 | @Client.on_message(filters.command(admincmds) & ~filters.user(ADMINS))
447 | async def notforu(_, m: Message):
448 | await m.reply_sticker("CAACAgUAAxkBAAIJM2DTpi52NSM-O-KnYcC1IzbJos8HAAK6AQACsm0wVffnRbQlKgeTHwQ")
449 |
--------------------------------------------------------------------------------