Files
Vocard/web/ipc/methods.py
2023-05-31 12:23:30 +08:00

408 lines
14 KiB
Python

import json, function as func
from typing import List
from discord import Member, VoiceChannel
from discord.ext import commands
from voicelink import Player, Track, Playlist, NodePool, connect_channel, decode
class TempCtx():
def __init__(self, author: Member, channel: VoiceChannel) -> None:
self.author = author
self.channel = channel
self.guild = channel.guild
def missingPermission(user_id:int):
payload = {"op": "errorMsg", "level": "info", "msg": "Only the DJ or admins may use this funciton!"}
payload["user_id"] = user_id
return payload
def error_msg(msg: str, *, user_id: int = None, guild_id: int = None, level: str = "info"):
payload = {"op": "errorMsg", "level": level, "msg": msg}
if user_id:
payload["user_id"] = user_id
if guild_id:
payload["guild_id"] = guild_id
return payload
async def connect_channel(member: Member, bot: commands.Bot):
if not member.voice:
return
channel = member.voice.channel
try:
player: Player = await channel.connect(cls=Player(bot, channel, TempCtx(member, channel)))
await player.send_ws({"op": "createPlayer", "members_id": [member.id for member in channel.members]})
return player
except:
return
async def initPlayer(player: Player, member: Member, data: dict):
player._ipc_connection = True
return {
"op": "initPlayer",
"guild_id": player.guild.id,
"user_id": data.get("user_id"),
"users": [{
"user_id": member.id,
"avatar_url": member.display_avatar.url,
"name": member.name
} for member in player.channel.members ],
"tracks": [ track.track_id for track in player.queue._queue ],
"repeat_mode": player.queue.repeat.lower(),
"channel_name": player.channel.name,
"current_queue_position": player.queue._position if player.is_playing else player.queue._position + 1,
"current_position": 0 or player.position if player.is_playing else 0,
"is_playing": player.is_playing,
"is_paused": player.is_paused,
"is_dj": player.is_privileged(member, check_user_join=False),
"autoplay": player.settings.get("autoplay", False)
}
async def skipTo(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
if player.current and member == player.current.requester:
pass
elif member in player.skip_votes:
return error_msg(player.get_msg('voted', 'EN'), user_id=member.id)
else:
player.skip_votes.add(member)
if len(player.skip_votes) >= (required := player.required()):
pass
else:
return error_msg(player.get_msg('skipVote', 'EN').format(member, len(player.skip_votes), required), guild_id=player.guild.id)
index = data.get("index", 1)
if index > 1:
player.queue.skipto(index)
if player.queue._repeat == 1:
await player.set_repeat("off")
await player.stop()
async def backTo(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
if player.current and member == player.current.requester:
pass
elif member in player.skip_votes:
return error_msg(player.get_msg('voted', 'EN'), user_id=member.id)
else:
player.skip_votes.add(member)
if len(player.skip_votes) >= (required := player.required()):
pass
else:
return error_msg(player.get_msg('backVote', 'EN').format(member, len(player.skip_votes), required), guild_id=player.guild.id)
index = data.get("index", 1)
if not player.is_playing:
player.queue.backto(index)
await player.do_next()
else:
player.queue.backto(index + 1)
await player.stop()
async def moveTrack(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
return missingPermission(member.id)
c = player.queue._position - 1
position = data.get("position")
new_position = data.get("newPosition")
moveItem = player.queue._queue[position]
player.queue._queue.remove(moveItem)
player.queue._queue.insert(new_position, moveItem)
if position > c and new_position <= c:
player.queue._position += 1
elif position < c and new_position >= c:
player.queue._position -= 1
elif position == c:
player.queue._position = new_position + 1
return {
"op": "moveTrack",
"position": {
"index": position - c,
"track_id": moveItem.track_id
},
"newPosition": {
"index": new_position - c
},
"guild_id": player.guild.id,
"requester_id": member.id,
"skip_users": [member.id]
}
async def addTracks(player: Player, member: Member, data: dict):
raw_tracks = data.get("tracks", [])
tracks = [Track(
track_id=track_id,
info=decode(track_id),
requester=member
) for track_id in raw_tracks]
await player.add_track(tracks)
if not player.is_playing:
await player.do_next()
async def getTracks(player: Player, member: Member, data: dict):
query = data.get("query", None)
if query:
payload = {"op": "getTracks", "user_id": member.id}
tracks = await player.get_tracks(query, requester=member)
if not tracks:
return payload
if isinstance(tracks, Playlist):
tracks = [ track for track in tracks.tracks[:50] ]
payload["tracks"] = [ track.track_id for track in tracks ]
return payload
async def shuffleTrack(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
if member in player.shuffle_votes:
return error_msg(player.get_msg('voted'), user_id=member.id)
else:
player.shuffle_votes.add(member)
if len(player.shuffle_votes) >= (required := player.required()):
pass
else:
return error_msg(player.get_msg('shuffleVote').format(member, len(player.skip_votes), required), guild_id=player.guild.id)
await player.shuffle(data.get("type", "queue"), member)
async def repeatTrack(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
return missingPermission(member.id)
await player.set_repeat()
async def removeTrack(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
return missingPermission(member.id)
position = data.get("position")
verify_id = data.get("track_id")
track = player.queue._queue[position]
if track.track_id == verify_id:
player.queue._queue.remove(track)
if position < player.queue._position:
player.queue._position -= 1
return {
"op": "removeTrack",
"positions": [position],
"track_ids": [track.track_id],
"current_queue_position": player.queue._position,
"requester_id": member.id,
"guild_id": player.guild.id
}
async def updatePause(player: Player, member: Member, data: dict):
pause = data.get("pause", True)
if not player.is_privileged(member):
if pause:
if member in player.pause_votes:
return error_msg(player.get_msg('voted'), user_id=member.id)
else:
player.pause_votes.add(member)
if len(player.pause_votes) >= (required := player.required()):
pass
else:
return error_msg(player.get_msg('pauseVote').format(member, len(player.pause_votes), required), guild_id=player.guild.id)
else:
if member in player.resume_votes:
return error_msg(player.get_msg('voted'), user_id=member.id)
else:
player.resume_votes.add(member)
if len(player.resume_votes) >= (required := player.required()):
pass
else:
return error_msg(player.get_msg('resumeVote').format(member, len(player.resume_votes), required), guild_id=player.guild.id)
if pause:
player.pause_votes.clear()
else:
player.resume_votes.clear()
await player.set_pause(pause, member)
async def updatePosition(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
return missingPermission(member.id)
position = data.get("position");
await player.seek(position, member);
async def toggleAutoplay(player: Player, member: Member, data: dict):
if not player.is_privileged(member):
return error_msg(player.get_msg('missingPerms_autoplay'))
check = data.get("status", False)
player.settings['autoplay'] = check
if not player.is_playing:
await player.do_next()
return {
"op": "toggleAutoplay",
"status": check,
"requester_id": member.id
}
async def closeConnection(player: Player, member: Member, data: dict):
player._ipc_connection = False
async def getPlaylists(member: Member, data: dict):
playlists: dict = await func.get_playlist(member.id, "playlist")
if not playlists:
return
for pId, pList in playlists.copy().items():
if "type" in pList:
if pList["type"] == "link":
tracks: Playlist = await NodePool.get_node().get_tracks(pList["uri"], requester=member)
if tracks:
playlists[pId]["tracks"] = [ track.track_id for track in tracks.tracks ]
elif pList["type"] == "share":
playlist = await func.get_playlist(pList["user"], "playlist", pList["referId"])
if playlist:
if member.id not in playlist["perms"]["read"]:
await func.update_playlist(member.id, {f"playlist.{pId}": 1}, mode=False)
del playlists[pId]
continue
playlists[pId]["tracks"] = playlist["tracks"]
return {
"op": "getPlaylists",
"playlists": playlists,
"user_id": member.id
}
async def removePlaylist(member: Member, data:dict):
pId = data.get("pId")
isShare = data.get("isShare", False)
if pId == 200:
return
if isShare:
refer_user = data.get("refer_user")
await func.update_playlist(refer_user, {f"playlist.{pId}.perms.read": member.id}, pull=True, mode=False)
await func.update_playlist(member.id, {f'playlist.{pId}': 1}, mode=False)
async def addPlaylistTrack(member: Member, data: dict):
track_id = data.get("track")
pId = data.get("pId")
if not track_id or not pId:
return
playlist: dict = await func.get_playlist(member.id, 'playlist', pId)
if not playlist:
return
rank, max_p, max_t = await func.checkroles(member.id)
if len(playlist["tracks"]) >= max_t:
return error_msg(func.get_lang(member.guild.id, "playlistlimited").format(max_t), user_id=member.id)
if track_id in playlist['tracks']:
return error_msg(func.get_lang(member.guild.id, "playlistrepeated"), user_id=member.id)
await func.update_playlist(member.id, {f'playlist.{pId}.tracks': track_id}, push=True)
async def removePlaylistTrack(member: Member, data: dict):
track_id = data.get("track")
pId = data.get("pId")
if not track_id or not pId:
return
await func.update_playlist(member.id, {f'playlist.{pId}.tracks': track_id }, pull=True, mode=False)
methods = {
"initPlayer": [initPlayer, False],
"skipTo": [skipTo, False],
"backTo": [backTo, False],
"moveTrack": [moveTrack, False],
"addTracks": [addTracks, True],
"getTracks": [getTracks, True],
"shuffleTrack": [shuffleTrack, False],
"repeatTrack": [repeatTrack, False],
"removeTrack": [removeTrack, False],
"updatePause": [updatePause, False],
"updatePosition": [updatePosition, False],
"toggleAutoplay": [toggleAutoplay, False],
"getPlaylists": [getPlaylists, False],
"removePlaylist": [removePlaylist, False],
"addPlaylistTrack": [addPlaylistTrack, False],
"removePlaylistTrack": [removePlaylistTrack, False]
}
async def process_methods(websocket, bot: commands.Bot, data: dict) -> None:
method = methods.get(data.get("op", ""), None)
if not method:
return
guild, member = None, None
guild_id = data.get("guild_id", None)
user_id = data.get("user_id", None)
if not user_id:
return
if guild_id is None:
user = bot.get_user(user_id)
if not user:
return
for g in user.mutual_guilds:
m = g.get_member(user.id)
if m.voice and m.voice.channel:
guild = g
member = m
break
else:
guild = bot.get_guild(guild_id)
member = guild.get_member(user_id)
if not member:
return
try:
if 'player' in method[0].__code__.co_varnames:
if not guild:
return
player: Player = guild.voice_client
if not player:
if not method[1]:
return
player: Player = await connect_channel(member, bot)
resp: dict = await method[0](player, member, data)
else:
resp: dict = await method[0](member, data)
if resp:
await websocket.send(json.dumps(resp))
except Exception as e:
payload = {
"op": "errorMsg",
"level": "error",
"msg": str(e),
"user_id": member.id
}
await websocket.send(json.dumps(payload))