refactor: make players and songs object-oriented
This commit is contained in:
parent
db355e8ade
commit
dc795f7ffe
@ -32,7 +32,7 @@ def match_token(token: str) -> list[Command]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def match(command: str) -> None | list[Command]:
|
def match(command: str) -> list[Command] | None:
|
||||||
if tokens := tokenize(command):
|
if tokens := tokenize(command):
|
||||||
return match_token(tokens[0])
|
return match_token(tokens[0])
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import arguments
|
|||||||
import commands
|
import commands
|
||||||
import utils
|
import utils
|
||||||
import youtubedl
|
import youtubedl
|
||||||
from state import client, player_current, player_queue
|
from state import client, players
|
||||||
|
|
||||||
|
|
||||||
async def queue_or_play(message):
|
async def queue_or_play(message):
|
||||||
@ -12,8 +12,8 @@ async def queue_or_play(message):
|
|||||||
if not command_allowed(message):
|
if not command_allowed(message):
|
||||||
return
|
return
|
||||||
|
|
||||||
if message.guild.id not in player_queue:
|
if message.guild.id not in players:
|
||||||
player_queue[message.guild.id] = []
|
players[message.guild.id] = youtubedl.QueuedPlayer()
|
||||||
|
|
||||||
tokens = commands.tokenize(message.content)
|
tokens = commands.tokenize(message.content)
|
||||||
parser = arguments.ArgumentParser(
|
parser = arguments.ArgumentParser(
|
||||||
@ -62,30 +62,31 @@ async def queue_or_play(message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if args.clear:
|
if args.clear:
|
||||||
player_queue[message.guild.id] = []
|
players[message.guild.id].queue.clear()
|
||||||
await utils.add_check_reaction(message)
|
await utils.add_check_reaction(message)
|
||||||
return
|
return
|
||||||
elif i := args.remove_index:
|
elif i := args.remove_index:
|
||||||
try:
|
try:
|
||||||
queued = player_queue[message.guild.id][i - 1]
|
queued = players[message.guild.id].queue[i - 1]
|
||||||
del player_queue[message.guild.id][i - 1]
|
del players[message.guild.id].queue[i - 1]
|
||||||
await utils.reply(message, f"**x** `{queued['player'].title}`")
|
await utils.reply(message, f"**x** {queued.format()}")
|
||||||
except:
|
except:
|
||||||
await utils.reply(message, "invalid index!")
|
await utils.reply(message, "invalid index!")
|
||||||
elif args.remove_title or args.remove_queuer:
|
elif args.remove_title or args.remove_queuer:
|
||||||
targets = []
|
targets = []
|
||||||
for queued in player_queue[message.guild.id]:
|
for queued in players[message.guild.id].queue:
|
||||||
if t := args.remove_title:
|
if t := args.remove_title:
|
||||||
if t in queued["player"].title:
|
if t in queued.player.title:
|
||||||
targets.append(queued)
|
targets.append(queued)
|
||||||
|
continue
|
||||||
if q := args.remove_queuer:
|
if q := args.remove_queuer:
|
||||||
if q == queued["queuer"]:
|
if q == queued.queuer:
|
||||||
targets.append(queued)
|
targets.append(queued)
|
||||||
if not args.remove_multiple:
|
if args.remove_multiple:
|
||||||
targets = targets[:1]
|
targets = targets[:1]
|
||||||
|
|
||||||
for target in targets:
|
for target in targets:
|
||||||
if target in player_queue[message.guild.id]:
|
players[message.guild.id].queue.remove(target)
|
||||||
player_queue[message.guild.id].remove(target)
|
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
f"removed **{len(targets)}** queued {'song' if len(targets) == 1 else 'songs'}",
|
f"removed **{len(targets)}** queued {'song' if len(targets) == 1 else 'songs'}",
|
||||||
@ -104,67 +105,64 @@ async def queue_or_play(message):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
player_queue[message.guild.id].insert(
|
queued = youtubedl.QueuedSong(player, message.author.id)
|
||||||
0, {"player": player, "queuer": message.author.id}
|
players[message.guild.id].queue_add(queued)
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not message.guild.voice_client.is_playing()
|
not message.guild.voice_client.is_playing()
|
||||||
and not message.guild.voice_client.is_paused()
|
and not message.guild.voice_client.is_paused()
|
||||||
):
|
):
|
||||||
await utils.reply(message, f"**0.** `{player.title}`")
|
await utils.reply(message, f"**0.** {queued.format()}")
|
||||||
play_next(message)
|
play_next(message)
|
||||||
else:
|
else:
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
f"**+** `{player.title}`",
|
f"**+** {queued.format()}",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if message.guild.voice_client:
|
if tokens[0].lower() == "play":
|
||||||
if tokens[0].lower() == "play":
|
message.guild.voice_client.resume()
|
||||||
message.guild.voice_client.resume()
|
|
||||||
await utils.reply(
|
|
||||||
message,
|
|
||||||
"resumed!",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
generate_currently_playing = (
|
|
||||||
lambda: f"**0.** {'(paused) ' if message.guild.voice_client.is_paused() else ''}`{message.guild.voice_client.source.title}` (<@{player_current[message.guild.id]['queuer']}>)"
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
not player_queue[message.guild.id]
|
|
||||||
and not message.guild.voice_client.source
|
|
||||||
):
|
|
||||||
await utils.reply(
|
|
||||||
message,
|
|
||||||
"nothing is playing or queued!",
|
|
||||||
)
|
|
||||||
elif not player_queue[message.guild.id]:
|
|
||||||
await utils.reply(message, generate_currently_playing())
|
|
||||||
elif not message.guild.voice_client.source:
|
|
||||||
await utils.reply(
|
|
||||||
message,
|
|
||||||
generate_queue_list(player_queue[message.guild.id]),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await utils.reply(
|
|
||||||
message,
|
|
||||||
generate_currently_playing()
|
|
||||||
+ "\n"
|
|
||||||
+ generate_queue_list(player_queue[message.guild.id]),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
"nothing is currently queued!",
|
"resumed!",
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
currently_playing = (
|
||||||
|
lambda: f"**0.** {'(paused) ' if message.guild.voice_client.is_paused() else ''} {players[message.guild.id].current.format(with_queuer=True)}"
|
||||||
|
)
|
||||||
|
queue_list = lambda: "\n".join(
|
||||||
|
[
|
||||||
|
f"**{i + 1}.** {queued.format(with_queuer=True, hide_preview=True)}"
|
||||||
|
for i, queued in enumerate(players[message.guild.id].queue)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
not players[message.guild.id].queue
|
||||||
|
and not message.guild.voice_client.source
|
||||||
|
):
|
||||||
|
await utils.reply(
|
||||||
|
message,
|
||||||
|
"nothing is playing or queued!",
|
||||||
|
)
|
||||||
|
elif not players[message.guild.id].queue:
|
||||||
|
await utils.reply(message, currently_playing())
|
||||||
|
elif not message.guild.voice_client.source:
|
||||||
|
await utils.reply(
|
||||||
|
message,
|
||||||
|
queue_list(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await utils.reply(
|
||||||
|
message,
|
||||||
|
currently_playing() + "\n" + queue_list(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def skip(message):
|
async def skip(message):
|
||||||
if not command_allowed(message):
|
if not command_allowed(message):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not player_queue[message.guild.id]:
|
if not players[message.guild.id].queue:
|
||||||
message.guild.voice_client.stop()
|
message.guild.voice_client.stop()
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
@ -193,22 +191,28 @@ async def resume(message):
|
|||||||
if not command_allowed(message):
|
if not command_allowed(message):
|
||||||
return
|
return
|
||||||
|
|
||||||
message.guild.voice_client.resume()
|
if message.guild.voice_client.is_paused():
|
||||||
await utils.reply(
|
message.guild.voice_client.resume()
|
||||||
message,
|
await utils.add_check_reaction(message)
|
||||||
"resumed!",
|
else:
|
||||||
)
|
await utils.reply(
|
||||||
|
message,
|
||||||
|
"nothing is paused!",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def pause(message):
|
async def pause(message):
|
||||||
if not command_allowed(message):
|
if not command_allowed(message):
|
||||||
return
|
return
|
||||||
|
|
||||||
message.guild.voice_client.pause()
|
if message.guild.voice_client.is_playing():
|
||||||
await utils.reply(
|
message.guild.voice_client.pause()
|
||||||
message,
|
await utils.add_check_reaction(message)
|
||||||
"paused!",
|
else:
|
||||||
)
|
await utils.reply(
|
||||||
|
message,
|
||||||
|
"nothing is playing!",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def volume(message):
|
async def volume(message):
|
||||||
@ -233,7 +237,7 @@ async def volume(message):
|
|||||||
if not message.guild.voice_client.source:
|
if not message.guild.voice_client.source:
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
f"there is no player currently active!",
|
f"nothing is playing!",
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -247,14 +251,19 @@ async def volume(message):
|
|||||||
await utils.add_check_reaction(message)
|
await utils.add_check_reaction(message)
|
||||||
|
|
||||||
|
|
||||||
|
def play_after_callback(e, message, once):
|
||||||
|
if e:
|
||||||
|
print(f"player error: {e}")
|
||||||
|
if not once:
|
||||||
|
play_next(message)
|
||||||
|
|
||||||
|
|
||||||
def play_next(message, once=False):
|
def play_next(message, once=False):
|
||||||
message.guild.voice_client.stop()
|
message.guild.voice_client.stop()
|
||||||
if player_queue[message.guild.id]:
|
if players[message.guild.id].queue:
|
||||||
queued = player_queue[message.guild.id][0]
|
queued = players[message.guild.id].queue_pop()
|
||||||
del player_queue[message.guild.id][0]
|
|
||||||
player_current[message.guild.id] = queued
|
|
||||||
message.guild.voice_client.play(
|
message.guild.voice_client.play(
|
||||||
queued["player"], after=lambda _: play_next(message) if not once else None
|
queued.player, after=lambda e: play_after_callback(e, message, once)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -270,12 +279,3 @@ def command_allowed(message):
|
|||||||
if not message.guild.voice_client:
|
if not message.guild.voice_client:
|
||||||
return False
|
return False
|
||||||
return message.author.voice.channel.id == message.guild.voice_client.channel.id
|
return message.author.voice.channel.id == message.guild.voice_client.channel.id
|
||||||
|
|
||||||
|
|
||||||
def generate_queue_list(queue: list):
|
|
||||||
return "\n".join(
|
|
||||||
[
|
|
||||||
f"**{i + 1}.** `{queued['player'].title}` (<@{queued['queuer']}>)"
|
|
||||||
for i, queued in enumerate(queue)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
@ -13,6 +13,7 @@ RELOADABLE_MODULES = [
|
|||||||
"constants",
|
"constants",
|
||||||
"core",
|
"core",
|
||||||
"events",
|
"events",
|
||||||
|
"player",
|
||||||
"utils",
|
"utils",
|
||||||
"voice",
|
"voice",
|
||||||
"youtubedl",
|
"youtubedl",
|
||||||
|
5
core.py
5
core.py
@ -30,6 +30,9 @@ async def on_message(message):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if message.guild.id not in command_locks:
|
||||||
|
command_locks[message.guild.id] = asyncio.Lock()
|
||||||
|
|
||||||
C = commands.Command
|
C = commands.Command
|
||||||
try:
|
try:
|
||||||
match matched[0]:
|
match matched[0]:
|
||||||
@ -95,8 +98,6 @@ async def on_message(message):
|
|||||||
case C.LEAVE:
|
case C.LEAVE:
|
||||||
await commands.voice.leave(message)
|
await commands.voice.leave(message)
|
||||||
case C.QUEUE | C.PLAY:
|
case C.QUEUE | C.PLAY:
|
||||||
if message.guild.id not in command_locks:
|
|
||||||
command_locks[message.guild.id] = asyncio.Lock()
|
|
||||||
async with command_locks[message.guild.id]:
|
async with command_locks[message.guild.id]:
|
||||||
await commands.voice.queue_or_play(message)
|
await commands.voice.queue_or_play(message)
|
||||||
case C.SKIP:
|
case C.SKIP:
|
||||||
|
3
state.py
3
state.py
@ -2,8 +2,7 @@ import time
|
|||||||
|
|
||||||
import disnake
|
import disnake
|
||||||
|
|
||||||
player_queue = {}
|
players = {}
|
||||||
player_current = {}
|
|
||||||
command_locks = {}
|
command_locks = {}
|
||||||
|
|
||||||
intents = disnake.Intents.default()
|
intents = disnake.Intents.default()
|
||||||
|
29
youtubedl.py
29
youtubedl.py
@ -14,7 +14,9 @@ class YTDLSource(disnake.PCMVolumeTransformer):
|
|||||||
self, source: disnake.AudioSource, *, data: dict[str, Any], volume: float = 0.5
|
self, source: disnake.AudioSource, *, data: dict[str, Any], volume: float = 0.5
|
||||||
):
|
):
|
||||||
super().__init__(source, volume)
|
super().__init__(source, volume)
|
||||||
|
print(data)
|
||||||
self.title = data.get("title")
|
self.title = data.get("title")
|
||||||
|
self.original_url = data.get("original_url")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def from_url(
|
async def from_url(
|
||||||
@ -41,6 +43,33 @@ class YTDLSource(disnake.PCMVolumeTransformer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class QueuedPlayer:
|
||||||
|
def __init__(self):
|
||||||
|
self.queue = []
|
||||||
|
self.current = None
|
||||||
|
|
||||||
|
def queue_pop(self):
|
||||||
|
popped = self.queue[0]
|
||||||
|
del self.queue[0]
|
||||||
|
self.current = popped
|
||||||
|
return popped
|
||||||
|
|
||||||
|
def queue_add(self, item):
|
||||||
|
self.queue.append(item)
|
||||||
|
|
||||||
|
|
||||||
|
class QueuedSong:
|
||||||
|
def __init__(self, player, queuer):
|
||||||
|
self.player = player
|
||||||
|
self.queuer = queuer
|
||||||
|
|
||||||
|
def format(self, with_queuer=False, hide_preview=False):
|
||||||
|
return (
|
||||||
|
f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''})"
|
||||||
|
+ (f" (<@{self.queuer}>)" if with_queuer else "")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def __reload_module__():
|
def __reload_module__():
|
||||||
global ytdl
|
global ytdl
|
||||||
ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS)
|
ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user