Compare commits

..

3 Commits

3 changed files with 66 additions and 31 deletions

View File

@ -153,11 +153,8 @@ async def queue_or_play(message, edited=False):
else: else:
players[message.guild.id].queue_add(queued) players[message.guild.id].queue_add(queued)
if ( if not message.guild.voice_client.source:
not message.guild.voice_client.is_playing() play_next(message, first=True)
and not message.guild.voice_client.is_paused()
):
play_next(message)
elif args.now: elif args.now:
message.guild.voice_client.stop() message.guild.voice_client.stop()
else: else:
@ -219,10 +216,29 @@ async def playing(message):
if not command_allowed(message): if not command_allowed(message):
return return
if message.guild.voice_client.source: if source := message.guild.voice_client.source:
bar_length = 35
progress = source.original.progress / source.duration
embed = disnake.Embed(
color=constants.EMBED_COLOR,
title=source.title,
description=f"{'⏸️ ' if message.guild.voice_client.is_paused() else ''}"
f"`[{'#'*int(progress * bar_length)}{'-'*int((1 - progress) * bar_length)}]`"
f"{youtubedl.format_duration(int(source.original.progress))} / {youtubedl.format_duration(source.duration)}",
url=source.original_url,
)
embed.add_field(name="Volume", value=f"{int(source.volume*100)}%")
embed.add_field(name="Views", value=f"{source.view_count:,}")
embed.add_field(
name="Queuer",
value=players[message.guild.id].current.trigger_message.author.mention,
)
embed.set_image(source.thumbnail_url)
await utils.reply( await utils.reply(
message, message,
f"{'(paused) ' if message.guild.voice_client.is_paused() else ''} {players[message.guild.id].current.format(show_queuer=True)}", embed=embed,
) )
else: else:
await utils.reply( await utils.reply(
@ -244,10 +260,7 @@ async def skip(message):
else: else:
message.guild.voice_client.stop() message.guild.voice_client.stop()
await utils.add_check_reaction(message) await utils.add_check_reaction(message)
if ( if not message.guild.voice_client.source:
not message.guild.voice_client.is_playing()
and not message.guild.voice_client.is_paused()
):
play_next(message) play_next(message)
@ -347,7 +360,7 @@ def play_after_callback(e, message, once):
play_next(message) play_next(message)
def play_next(message, once=False): def play_next(message, once=False, first=False):
message.guild.voice_client.stop() message.guild.voice_client.stop()
if players[message.guild.id].queue: if players[message.guild.id].queue:
queued = players[message.guild.id].queue_pop() queued = players[message.guild.id].queue_pop()
@ -361,7 +374,7 @@ def play_next(message, once=False):
) )
return return
client.loop.create_task( client.loop.create_task(
utils.channel_send(message, f"**0.** {queued.format(show_queuer=True)}") utils.channel_send(message, queued.format(show_queuer=not first))
) )

View File

@ -11,9 +11,9 @@ async def cleanup():
await asyncio.sleep(3600) await asyncio.sleep(3600)
targets = [] targets = []
for id, player in players: for guild_id, player in players.items():
if len(player.queue) == 0: if len(player.queue) == 0:
targets.append(id) targets.append(guild_id)
for target in targets: for target in targets:
del players[target] del players[target]

View File

@ -11,14 +11,33 @@ import constants
ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS) ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS)
class TrackedAudioSource(disnake.AudioSource):
def __init__(self, source):
self._source = source
self.count = 0
def read(self) -> bytes:
data = self._source.read()
if data:
self.count += 1
return data
@property
def progress(self) -> float:
return self.count * 0.02
class YTDLSource(disnake.PCMVolumeTransformer): class YTDLSource(disnake.PCMVolumeTransformer):
def __init__( def __init__(
self, source: disnake.AudioSource, *, data: dict[str, Any], volume: float = 0.5 self, source: TrackedAudioSource, *, data: dict[str, Any], volume: float = 0.5
): ):
super().__init__(source, volume) super().__init__(source, volume)
self.title = data.get("title")
self.original_url = data.get("original_url")
self.duration = data.get("duration") self.duration = data.get("duration")
self.original_url = data.get("original_url")
self.thumbnail_url = data.get("thumbnail")
self.title = data.get("title")
self.view_count = data.get("view_count")
@classmethod @classmethod
async def from_url( async def from_url(
@ -37,9 +56,11 @@ class YTDLSource(disnake.PCMVolumeTransformer):
data = data["entries"][0] data = data["entries"][0]
return cls( return cls(
TrackedAudioSource(
disnake.FFmpegPCMAudio( disnake.FFmpegPCMAudio(
data["url"] if stream else ytdl.prepare_filename(data), data["url"] if stream else ytdl.prepare_filename(data),
before_options="-vn -reconnect 1", before_options="-vn -reconnect 1",
)
), ),
data=data, data=data,
) )
@ -59,7 +80,7 @@ class QueuedSong:
def format(self, show_queuer=False, hide_preview=False, multiline=False) -> str: def format(self, show_queuer=False, hide_preview=False, multiline=False) -> str:
if multiline: if multiline:
return ( return (
f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''})\n**duration:** {self.format_duration(self.player.duration) if self.player.duration else '[live]'}" f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''})\n**duration:** {format_duration(self.player.duration) if self.player.duration else '[live]'}"
+ ( + (
f", **queuer:** <@{self.trigger_message.author.id}>" f", **queuer:** <@{self.trigger_message.author.id}>"
if show_queuer if show_queuer
@ -68,18 +89,10 @@ class QueuedSong:
) )
else: else:
return ( return (
f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''}) **[{self.format_duration(self.player.duration) if self.player.duration else 'live'}]**" f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''}) **[{format_duration(self.player.duration) if self.player.duration else 'live'}]**"
+ (f" (<@{self.trigger_message.author.id}>)" if show_queuer else "") + (f" (<@{self.trigger_message.author.id}>)" if show_queuer else "")
) )
def format_duration(self, duration: int) -> str:
hours, duration = divmod(duration, 3600)
minutes, duration = divmod(duration, 60)
segments = [hours, minutes, duration]
if len(segments) == 3 and segments[0] == 0:
del segments[0]
return f"{':'.join(f'{s:0>2}' for s in segments)}"
def __str__(self): def __str__(self):
return self.__repr__() return self.__repr__()
@ -104,6 +117,15 @@ class QueuedPlayer:
return self.__repr__() return self.__repr__()
def format_duration(duration: int) -> str:
hours, duration = divmod(duration, 3600)
minutes, duration = divmod(duration, 60)
segments = [hours, minutes, duration]
if len(segments) == 3 and segments[0] == 0:
del segments[0]
return f"{':'.join(f'{s:0>2}' for s in segments)}"
def __reload_module__(): def __reload_module__():
global ytdl global ytdl
ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS) ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS)