diff --git a/plugins/xplayer.py b/plugins/xplayer.py index 83592b7..c6d2cc0 100644 --- a/plugins/xplayer.py +++ b/plugins/xplayer.py @@ -1,3 +1,5 @@ +"""X - MUSIC PLAYER""" + # Copyright (C) 2021 USERGE-X # # Author : github.com/code-rgb [TG : @deleteduser420] @@ -24,17 +26,24 @@ from math import floor from random import shuffle from signal import SIGTERM -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Set, Union import youtube_dl from pyrogram import filters +from pyrogram.errors import UserNotParticipant from pyrogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from userge import Config, Message, get_collection, pool, userge from userge.plugins.bot.alive import _parse_arg from userge.plugins.bot.utube_inline import BASE_YT_URL, get_yt_video_id, get_ytthumb from userge.plugins.misc.upload import check_thumb from userge.plugins.utils.songlink import find_url_from_msg, get_song_link -from userge.utils import escape_markdown, time_formatter +from userge.utils import ( + check_owner, + escape_markdown, + rand_key, + safe_filename, + time_formatter, +) from wget import download from youtube_dl.utils import DownloadError, ExtractorError, GeoRestrictedError from youtubesearchpython.__future__ import VideosSearch @@ -47,21 +56,19 @@ import ffmpeg from pytgcalls import GroupCall, GroupCallAction -from userge.utils import check_owner, rand_key, safe_filename LOG = userge.getLogger(__name__) +SAVED_SETTINGS = get_collection("CONFIGS") STREAM_LINK = re.compile(r"https?://[\S]+\.(?:m3u8?|audio|mp3|aac|[a-z]{1,4}:[0-9]+)") FFMPEG_PROCESSES = {} MAX_DURATION = int(os.environ.get("VC_SONG_MAX_DURATION", 600)) -LOG.debug(MAX_DURATION) -SAVED_SETTINGS = get_collection("CONFIGS") +VC_GROUP_MODE_CHATS: Set[int] = set() async def _init() -> None: - if vc_g_m := await SAVED_SETTINGS.find_one({"_id": "VC_GROUP_MODE"}): - if not hasattr(Config, "VC_GROUP_MODE"): - setattr(Config, "VC_GROUP_MODE", False) - Config.VC_GROUP_MODE = vc_g_m["data"] + global VC_GROUP_MODE_CHATS + if gm_chats := await SAVED_SETTINGS.find_one({"_id": "VC_GROUP_MODE_CHAT"}): + VC_GROUP_MODE_CHATS = set(gm_chats["chat_ids"]) class XPlayer(GroupCall): @@ -76,7 +83,6 @@ def __init__(self, chat_id: int): ) def start_playout(self, key: str): - LOG.debug(f"{keypath(key)} is now playing") self.input_filename = keypath(key) def replay(self) -> bool: @@ -89,11 +95,11 @@ def get_playlist(self) -> str: out += "`[ Empty ]`" else: current = self.playlist[0] - out += f"**Now Playing : šµ [{escape_markdown(current['title'])}]({current['msg'].link})**\n" + out += f"**Now Playing : šµ [{escape_markdown(current['title'])}]({(BASE_YT_URL + current['id']) if current['yt_url'] else current['msg'].link})**\n" if len(self.playlist) > 1: out += "\n".join( [ - f"⢠**{x}.** [{escape_markdown(y['title'])}]({y['msg'].link})" + f"⢠**{x}.** [{escape_markdown(y['title'])}]({(BASE_YT_URL + y['id']) if y['yt_url'] else y['msg'].link})" for x, y in enumerate(self.playlist[1:], start=1) ] ) @@ -110,7 +116,7 @@ async def leave(self): try: await super().stop() except AttributeError: - LOG.debug("No Group call found to leave") + pass vc_chats: Dict[int, XPlayer] = {} @@ -125,14 +131,10 @@ async def get_groupcall(chat_id: int) -> XPlayer: group_call.add_handler(playout_ended_handler, GroupCallAction.PLAYOUT_ENDED) if userge.has_bot: try: - await (await userge.get_chat(chat_id)).get_member( - (await userge.bot.get_me()).id - ) - except Exception: + await userge.get_chat_member(chat_id, (await userge.bot.get_me()).id) + except UserNotParticipant: pass - # LOG.info("Bot is not in the group") else: - # LOG.info("Bot is in the group") group_call.chat_has_bot = True return vc_chats[chat_id] @@ -145,10 +147,8 @@ async def network_status_changed_handler(gc: XPlayer, is_connected: bool) -> Non async def playout_ended_handler(gc, filename) -> None: - LOG.debug("song ended") + LOG.info(f"song ended in {gc.chat_id}") if len(gc.playlist) > 1: - LOG.debug(filename) - LOG.debug("play_now triggered") # deleting the raw file only when the next song has started to_del = keypath(gc.playlist.pop(0)["id"]) await play_now(gc) @@ -159,8 +159,9 @@ async def playout_ended_handler(gc, filename) -> None: def add_groupcall(func): @wraps(func) async def gc_from_chat(m: Message): - gc = await get_groupcall(m.chat.id) - await func(m, gc) + if m.chat.type in ("group", "supergroup", "channel"): + gc = await get_groupcall(m.chat.id) + await func(m, gc) return gc_from_chat @@ -172,12 +173,10 @@ def keypath(key: str, thumb: bool = False) -> Union[str, tuple]: async def play_now(gc: XPlayer) -> None: r = gc.playlist[0] - LOG.debug(str(r)) key = r["id"] client = userge.bot if r["has_bot"] else userge rawfile, thumb = keypath(key, thumb=True) if not os.path.exists(rawfile): - LOG.debug("No .raw file now downloading ...") if not (rawdata := await get_rawaudio_thumb(r)): await client.send_message( gc.chat_id, f"Skipped 1 Invalid Track: `{r['title']}`" @@ -187,11 +186,12 @@ async def play_now(gc: XPlayer) -> None: if len(gc.playlist) > 0: await play_now(gc) return - LOG.debug(str(rawdata)) rawfile, thumb = rawdata gc.start_playout(key) if (msg_ := r["msg"]) and isinstance(msg_, Message): - atitle = f"[{r['title']}]({msg_.link})" + atitle = ( + f"[{r['title']}]({(BASE_YT_URL + r['id']) if r['yt_url'] else msg_.link})" + ) else: atitle = r["title"] text = f'šµ **{atitle}**\nš Duration : `{time_formatter(r["duration"])}`' @@ -254,7 +254,6 @@ def convert_raw(audio_path: str, key: str = None) -> Optional[str]: def check_audio(duration: int, audio_key: str, playlist: List) -> Optional[str]: # Duration - LOG.debug(duration) if (invalid := (duration > MAX_DURATION or duration == 0)) : return f"Song Duration is {'invalid' if duration == 0 else 'too long'}" # check if already in Playlist @@ -334,9 +333,12 @@ def voice_chat_helpers_buttons(): ], [ InlineKeyboardButton("šµ Player", callback_data="vcbtn_player"), - InlineKeyboardButton("š¤ Recorder", callback_data="vcbtn_rec"), InlineKeyboardButton("š Volume", callback_data="vcbtn_vol"), ], + [ + InlineKeyboardButton("š¤ Recorder", callback_data="vcbtn_rec"), + InlineKeyboardButton("š„ Group Mode", callback_data="vcbtn_groupm"), + ], [ InlineKeyboardButton("š Debug", callback_data="vcbtn_debug"), InlineKeyboardButton("āļø Close", callback_data="vcbtn_delete"), @@ -352,8 +354,8 @@ def volume_pannel(): InlineKeyboardButton("ā", callback_data="vc_vol_+"), ], [ - InlineKeyboardButton("š UnMute", callback_data="vc_vol_unmute"), InlineKeyboardButton("š Mute", callback_data="vc_vol_mute"), + InlineKeyboardButton("š UnMute", callback_data="vc_vol_unmute"), ], ] return "š **VOLUME**", buttons @@ -403,22 +405,6 @@ def get_progress_string(current: int, total: int = 200) -> str: ) -# async def get_lyrics(search: str) -> Optional[str]: -# async with get_response.get_session() as session: -# async with session.post( -# "http://www.glyrics.xyz/search", -# json={"searchTerm": search}, -# headers={"content-type": "application/json"}, -# ) as resp: -# if not resp.status == 200: -# return -# result = await resp.json() -# if lyrics := result.get("lyrics"): -# nl = "\n" -# return post_to_telegraph(search, f'
{lyrics.replace(nl,
-# "
")}')
-
-
async def kill_radio(chat_id: int) -> None:
if process := FFMPEG_PROCESSES.get(chat_id):
process.send_signal(SIGTERM)
@@ -427,21 +413,68 @@ async def kill_radio(chat_id: int) -> None:
os.remove(radioraw)
+async def set_group_mode(chat_id: int, clearall: bool = False) -> str:
+ global VC_GROUP_MODE_CHATS
+ if clearall:
+ out = f"playvc **disabled** for `All Chats` (**{len(VC_GROUP_MODE_CHATS)}**)"
+ VC_GROUP_MODE_CHATS.clear()
+ else:
+ if chat_id in VC_GROUP_MODE_CHATS:
+ VC_GROUP_MODE_CHATS.remove(chat_id)
+ out = f"ā playvc **disabled** for __Chat ID__: `{chat_id}`"
+ else:
+ VC_GROUP_MODE_CHATS.add(chat_id)
+ out = f"ā
playvc **enabled** for __Chat ID__: `{chat_id}`"
+ await SAVED_SETTINGS.update_one(
+ {"_id": "VC_GROUP_MODE_CHAT"},
+ {"$set": {"chat_ids": list(VC_GROUP_MODE_CHATS)}},
+ upsert=True,
+ )
+ return out
+
+
+async def append_playlist(gc: XPlayer, m: Message, media_grp: bool, **kwargs) -> None:
+ thumb = kwargs["thumb"]
+ title = kwargs["title"]
+ gc.playlist.append(
+ {
+ "id": kwargs["audio_key"],
+ "title": title,
+ "thumb": thumb,
+ "duration": kwargs["duration"],
+ "has_bot": m.client.is_bot,
+ "msg": kwargs["audio_msg"],
+ "yt_url": kwargs["yt_id"],
+ "by_user": (await userge.get_user_dict(m.from_user, attr_dict=True)).mention
+ if m.from_user
+ else None,
+ }
+ )
+
+ if (pl_length := len(gc.playlist)) == 1:
+ await play_now(gc)
+ await m.delete()
+ elif not media_grp:
+ text = f"Added to Queue at **#{pl_length}\nSONG :** `{title}`"
+ await m.edit((f"[\u200c]({thumb})" + text) if thumb else text)
+
+
if userge.has_bot:
@userge.bot.on_callback_query(filters.regex(pattern=r"^vcbtn_([a-z]+)$"))
@check_owner
async def manage_vc_settings(c_q: CallbackQuery):
- await c_q.answer()
setting = c_q.matches[0].group(1)
chat_id = c_q.message.chat.id
gc = await get_groupcall(chat_id)
if setting == "back":
+ await c_q.answer()
text, buttons = voice_chat_helpers_buttons()
else:
if setting == "delete":
return await c_q.message.delete()
if setting == "debug":
+ await c_q.answer("Debugging ...")
gc.input_filename = ""
await gc.leave()
gc = await get_groupcall(chat_id)
@@ -453,6 +486,13 @@ async def manage_vc_settings(c_q: CallbackQuery):
pass
await play_now(gc)
return await gc.join()
+ if setting == "groupm":
+ if c_q.message.chat.type == "channel":
+ out_ = "Not Permitted for Chat Type: CHANNEL"
+ else:
+ out_ = f"š„ Group Mode : {_parse_arg(bool('enabled' in await set_group_mode(chat_id)))}"
+ return await c_q.answer(out_)
+ await c_q.answer()
if setting == "player":
text, buttons = control_pannel()
elif setting == "vol":
@@ -576,6 +616,8 @@ async def gc_toggles(c_q: CallbackQuery):
"header": "Join voice chat",
"description": "Join voice chat in current group.",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def join_voice_chat(m: Message, gc: XPlayer):
@@ -598,11 +640,13 @@ async def join_voice_chat(m: Message, gc: XPlayer):
"usage": "{tr}skipvc [number of songs to skip]",
"examples": "{tr}skipvc or {tr}skipvc 5",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def skip_song_voice_chat(m: Message, gc: XPlayer):
"""Skip Current playing song."""
- if not gc.playlist:
+ if len(gc.playlist) == 0:
await m.edit("No Songs to Skip", del_in=5)
return
sk_e = "Provide a valid number of songs to skip"
@@ -616,7 +660,8 @@ async def skip_song_voice_chat(m: Message, gc: XPlayer):
if 0 < num <= len(gc.playlist):
gc.playlist = gc.playlist[num:]
await m.edit(f"Skipped **{num}** songs.")
- await play_now(gc)
+ if len(gc.playlist) > 0:
+ await play_now(gc)
else:
await m.err(sk_e, del_in=5)
@@ -630,12 +675,23 @@ async def skip_song_voice_chat(m: Message, gc: XPlayer):
"usage": "{tr}playvc [reply to audio msg / Media group | song name | URL]",
"examples": "{tr}playvc Beliver OR {tr}playvc [reply to audio file]",
},
- filter_me=Config.VC_GROUP_MODE,
+ filter_me=False,
check_client=True,
+ allow_private=False,
+ allow_bots=False,
+ check_downpath=True,
)
@add_groupcall
async def play_voice_chat(m: Message, gc: XPlayer):
"""Play songs..."""
+ if (
+ m.from_user
+ and not (
+ m.from_user.id in Config.OWNER_ID or m.from_user.id in Config.SUDO_USERS
+ )
+ and m.chat.id not in VC_GROUP_MODE_CHATS
+ ):
+ return
await m.edit("`Processing ...`")
reply = m.reply_to_message
playlist = gc.playlist
@@ -727,32 +783,6 @@ async def play_voice_chat(m: Message, gc: XPlayer):
)
-async def append_playlist(gc: XPlayer, m: Message, media_grp: bool, **kwargs) -> None:
- thumb = kwargs["thumb"]
- title = kwargs["title"]
- gc.playlist.append(
- {
- "id": kwargs["audio_key"],
- "title": title,
- "thumb": thumb,
- "duration": kwargs["duration"],
- "has_bot": m.client.is_bot,
- "msg": kwargs["audio_msg"],
- "yt_url": kwargs["yt_id"],
- "by_user": (await userge.get_user_dict(m.from_user, attr_dict=True)).mention
- if m.from_user
- else None,
- }
- )
-
- if (pl_length := len(gc.playlist)) == 1:
- await play_now(gc)
- await m.delete()
- elif not media_grp:
- text = f"Added to Queue at **#{pl_length}\nSONG :** `{title}`"
- await m.edit((f"[\u200c]({thumb})" + text) if thumb else text)
-
-
@userge.on_cmd(
"stopvc",
about={
@@ -762,6 +792,8 @@ async def append_playlist(gc: XPlayer, m: Message, media_grp: bool, **kwargs) ->
"flags": {"-all": "stop all active voice chats"},
"examples": "{tr}stopvc",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def stop_voice_chat(m: Message, gc: XPlayer):
@@ -791,6 +823,8 @@ async def stop_voice_chat(m: Message, gc: XPlayer):
"usage": "{tr}pausevc just use it.",
"examples": "{tr}pausevc",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def pause_voice_chat(m: Message, gc: XPlayer):
@@ -807,6 +841,8 @@ async def pause_voice_chat(m: Message, gc: XPlayer):
"usage": "{tr}pausevc just use it.",
"examples": "{tr}pausevc",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def resume_voice_chat(m: Message, gc: XPlayer):
@@ -823,6 +859,8 @@ async def resume_voice_chat(m: Message, gc: XPlayer):
"usage": "{tr}mutevc just use it.",
"examples": "{tr}mutevc",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def mute_voice_chat(m: Message, gc: XPlayer):
@@ -839,6 +877,8 @@ async def mute_voice_chat(m: Message, gc: XPlayer):
"usage": "{tr}unmutevc just use it.",
"examples": "{tr}unmutevc",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def unmute_voice_chat(m: Message, gc: XPlayer):
@@ -855,6 +895,8 @@ async def unmute_voice_chat(m: Message, gc: XPlayer):
"usage": "Use {tr}volume and setup volume interactively.",
"examples": "{tr}volume",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def change_vol(m: Message, gc: XPlayer):
@@ -874,6 +916,8 @@ async def change_vol(m: Message, gc: XPlayer):
"usage": "Use {tr}managevc and manage !",
"examples": "{tr}managevc",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def manage_voice_chat(m: Message, gc: XPlayer):
@@ -896,29 +940,6 @@ async def manage_voice_chat(m: Message, gc: XPlayer):
)
-# @userge.on_cmd(
-# "lyricvc",
-# about={
-# "header": "Do you find your songs hard to understand ?",
-# "description": "Get lyrics of current playing songs.",
-# "usage": "Use {tr}lyricvc and get lyrics !",
-# "examples": "{tr}lyricvc",
-# },
-# )
-# @add_groupcall
-# async def search_lyrics(m: Message, gc: XPlayer):
-# """Get lyrics for current playing songs."""
-# if len(gc.playlist) == 0:
-# await m.edit("No Song is Playing in voice chat")
-# else:
-# song = gc.playlist[0]["title"]
-# await m.edit(f"Finding Lyrics for - šµ `{song}`")
-# if lyrics_url := await get_lyrics(song):
-# await m.edit(f"šµ **[{song}]({lyrics_url})**")
-# else:
-# await m.edit("No result found !", del_in=5)
-
-
@userge.on_cmd(
"radio",
about={
@@ -927,6 +948,8 @@ async def manage_voice_chat(m: Message, gc: XPlayer):
"usage": "Use {tr}radio [link]",
"examples": "{tr}radio (yet to add example here)",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def start_radio(m: Message, gc: XPlayer):
@@ -946,8 +969,6 @@ async def start_radio(m: Message, gc: XPlayer):
radioraw = keypath(f"radio_{m.chat.id}")
await kill_radio(m.chat.id)
station_stream_url = match.group(0)
- LOG.info(station_stream_url)
- LOG.info(f"radio_{m.chat.id}")
process = (
ffmpeg.input(station_stream_url)
.output(radioraw, format="s16le", acodec="pcm_s16le", ac=2, ar="48k")
@@ -965,6 +986,8 @@ async def start_radio(m: Message, gc: XPlayer):
"header": "Get Song Playlist in current voive chat",
"usage": "use {tr}playlist",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def playlist_voice_chat(m: Message, gc: XPlayer):
@@ -974,22 +997,17 @@ async def playlist_voice_chat(m: Message, gc: XPlayer):
@userge.on_cmd(
"vcgroupmode",
- about={"header": "Allow group members to use playvc command without sudo"},
+ about={
+ "header": "Allow current group members to use .playvc to play songs in voice chat",
+ "flags": {"-d": "disable for all chats"},
+ },
allow_channels=False,
+ allow_private=False,
+ allow_bots=False,
)
-async def groupmode_voice_chat(message: Message):
+async def groupmode_voice_chat(m: Message):
""" enable / disable playvc for group members """
- if Config.VC_GROUP_MODE:
- await message.edit(
- "ā `playvc disabled for everyone (only owner and sudo users can use)`",
- del_in=3,
- )
- else:
- await message.edit("ā
`playvc enabled for everyone`", del_in=3)
- Config.VC_GROUP_MODE = not Config.VC_GROUP_MODE
- await SAVED_SETTINGS.update_one(
- {"_id": "VC_GROUP_MODE"}, {"$set": {"data": Config.VC_GROUP_MODE}}, upsert=True
- )
+ await m.edit(await set_group_mode(m.chat.id, bool("-d" in m.flags)), del_in=5)
@userge.on_cmd(
@@ -998,6 +1016,8 @@ async def groupmode_voice_chat(message: Message):
"header": "Repeat song",
"description": "turn on repeat for the last song in queue",
},
+ allow_private=False,
+ allow_bots=False,
)
@add_groupcall
async def replay_voice_chat(m: Message, gc: XPlayer):