impr: Voice checks and menu fixes.

This commit is contained in:
Lemon4ksan
2025-01-10 16:19:27 +03:00
parent bcaba81f41
commit a108799e63
4 changed files with 326 additions and 173 deletions

View File

@@ -1,87 +1,80 @@
from math import ceil
from typing import cast
from io import BytesIO
import aiohttp
import discord
import yandex_music
from PIL import Image
from yandex_music import Track, Album, Artist, Label
from discord.ui import View, Button, Item
from discord import ButtonStyle, Interaction
from MusicBot.cogs.utils.voice import VoiceExtension
from MusicBot.database import VoiceGuildsDatabase, BaseUsersDatabase
from MusicBot.cogs.utils.voice import VoiceExtension, get_average_color_from_url
class PlayTrackButton(Button, VoiceExtension):
def __init__(
self,
track: yandex_music.Track,
*,
style: ButtonStyle = ButtonStyle.secondary,
label: str | None = None,
disabled: bool = False,
custom_id: str | None = None,
url: str | None = None,
emoji: str | discord.Emoji | discord.PartialEmoji | None = None,
sku_id: int | None = None,
row: int | None = None
):
Button.__init__(self, style=style, label=label, disabled=disabled, custom_id=custom_id, url=url, emoji=emoji, sku_id=sku_id, row=row)
def __init__(self, track: Track, **kwargs):
Button.__init__(self, **kwargs)
VoiceExtension.__init__(self)
self.track = track
async def callback(self, interaction: Interaction) -> None:
if interaction.channel is None or not isinstance(interaction.channel, discord.VoiceChannel):
await interaction.respond("Вы должны отправить команду в голосовом канале.", ephemeral=True)
if not interaction.guild or not await self.voice_check(interaction):
return
title = await self.play_track(interaction, self.track)
if title:
await interaction.respond(f"Сейчас играет: **{title}**!", delete_after=15)
gid = interaction.guild.id
guild = self.db.get_guild(gid)
if guild['current_track'] is not None:
self.db.modify_track(gid, self.track, 'next', 'append')
if guild['current_player'] is not None and interaction.message:
await interaction.message.delete()
await interaction.respond(f"Трек **{self.track.title}** был добавлен в очередь.", delete_after=15)
else:
title = await self.play_track(interaction, self.track)
if title:
if guild['current_player'] is not None and interaction.message:
await interaction.message.delete()
await interaction.respond(f"Сейчас играет: **{title}**!", delete_after=15)
class PlayAlbumButton(Button, VoiceExtension):
def __init__(
self,
album: yandex_music.Album,
*,
style: ButtonStyle = ButtonStyle.secondary,
label: str | None = None,
disabled: bool = False,
custom_id: str | None = None,
url: str | None = None,
emoji: str | discord.Emoji | discord.PartialEmoji | None = None,
sku_id: int | None = None,
row: int | None = None
):
Button.__init__(self, style=style, label=label, disabled=disabled, custom_id=custom_id, url=url, emoji=emoji, sku_id=sku_id, row=row)
def __init__(self, album: Album, **kwargs):
Button.__init__(self, **kwargs)
VoiceExtension.__init__(self)
self.album = album
async def callback(self, interaction: Interaction) -> None:
if not interaction.guild:
if not interaction.guild or not await self.voice_check(interaction):
return
gid = interaction.guild.id
guild = self.db.get_guild(gid)
album = cast(yandex_music.Album, await self.album.with_tracks_async())
album = await self.album.with_tracks_async()
if not album or not album.volumes:
return
tracks: list[Track] = []
for volume in album.volumes:
for track in volume:
self.db.add_track(interaction.guild.id, track)
track = self.db.pop_track(interaction.guild.id)
ym_track = yandex_music.Track.de_json(track, client=album.client) # type: ignore
title = await self.play_track(interaction, ym_track) # type: ignore
if title:
await interaction.respond(f"Сейчас играет: **{album.title}**!", delete_after=15)
tracks.extend(volume)
if guild['current_track'] is not None:
self.db.modify_track(gid, tracks, 'next', 'extend')
if guild['current_player'] is not None and interaction.message:
await interaction.message.delete()
else:
await interaction.respond(f"Альбом **{album.title}** был добавлен в очередь.", delete_after=15)
else:
await interaction.respond("Добавьте бота в голосовой канал при помощи команды /voice join.", delete_after=15, ephemeral=True)
track = tracks.pop(0)
self.db.modify_track(gid, tracks, 'next', 'extend')
title = await self.play_track(interaction, track)
if title:
if guild['current_player'] is not None and interaction.message:
await interaction.message.delete()
else:
await interaction.respond(f"Сейчас играет: **{album.title}**!", delete_after=15)
class ListenTrack(View):
def __init__(self, track: yandex_music.Track, album_id: int, *items: Item, timeout: float | None = 360, disable_on_timeout: bool = False):
def __init__(self, track: Track, album_id: int, *items: Item, timeout: float | None = 360, disable_on_timeout: bool = True):
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
link_app = f"yandexmusic://album/{album_id}/track/{track.id}"
link_web = f"https://music.yandex.ru/album/{album_id}/track/{track.id}"
@@ -94,7 +87,7 @@ class ListenTrack(View):
class ListenAlbum(View):
def __init__(self, album: yandex_music.Album, *items: Item, timeout: float | None = 360, disable_on_timeout: bool = False):
def __init__(self, album: Album, *items: Item, timeout: float | None = 360, disable_on_timeout: bool = True):
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
link_app = f"yandexmusic://album/{album.id}"
link_web = f"https://music.yandex.ru/album/{album.id}"
@@ -107,7 +100,7 @@ class ListenAlbum(View):
class ListenArtist(View):
def __init__(self, artist_id, *items: Item, timeout: float | None = 360, disable_on_timeout: bool = False):
def __init__(self, artist_id: int, *items: Item, timeout: float | None = 360, disable_on_timeout: bool = True):
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
link_app = f"yandexmusic://artist/{artist_id}"
link_web = f"https://music.yandex.ru/artist/{artist_id}"
@@ -115,45 +108,9 @@ class ListenArtist(View):
self.button2 = Button(label="Слушать в браузере", style=ButtonStyle.gray, url=link_web)
# self.add_item(self.button1) # Discord doesn't allow well formed URLs in buttons for some reason.
self.add_item(self.button2)
async def get_average_color_from_url(url: str) -> int:
"""Get image from url and calculate its average color to use in embeds.
Args:
url (str): Image url.
Returns:
int: RGB Hex code. 0x000 if failed.
"""
try:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
response.raise_for_status()
response = await response.read()
img = Image.open(BytesIO(response))
img = img.convert('RGB')
width, height = img.size
r_total, g_total, b_total = 0, 0, 0
for y in range(height):
for x in range(width):
r, g, b = cast(tuple, img.getpixel((x, y)))
r_total += r
g_total += g
b_total += b
count = width * height
r = r_total // count
g = g_total // count
b = b_total // count
return (r << 16) + (g << 8) + b
except Exception:
return 0x000
async def proccess_album(album: yandex_music.Album) -> discord.Embed:
async def proccess_album(album: Album) -> discord.Embed:
"""Generate album embed.
Args:
@@ -179,8 +136,8 @@ async def proccess_album(album: yandex_music.Album) -> discord.Embed:
cover_url = album.get_cover_url('400x400')
color = await get_average_color_from_url(cover_url)
if isinstance(album.labels[0], yandex_music.Label):
labels = [cast(yandex_music.Label, label).name for label in album.labels]
if isinstance(album.labels[0], Label):
labels = [cast(Label, label).name for label in album.labels]
else:
labels = [cast(str, label) for label in album.labels]
@@ -232,7 +189,7 @@ async def proccess_album(album: yandex_music.Album) -> discord.Embed:
return embed
async def process_track(track: yandex_music.Track) -> discord.Embed:
async def process_track(track: Track) -> discord.Embed:
"""Generate track embed.
Args:
@@ -305,7 +262,7 @@ async def process_track(track: yandex_music.Track) -> discord.Embed:
return embed
async def process_artist(artist: yandex_music.Artist) -> discord.Embed:
async def process_artist(artist: Artist) -> discord.Embed:
"""Generate artist embed.
Args:

View File

@@ -1,5 +1,5 @@
from discord.ui import View, Button, Item
from discord import ButtonStyle, Interaction, ApplicationContext
from discord import InteractionMessage, ButtonStyle, Interaction, ApplicationContext
from MusicBot.cogs.utils.voice import VoiceExtension
@@ -9,14 +9,26 @@ class PlayPauseButton(Button, VoiceExtension):
VoiceExtension.__init__(self)
async def callback(self, interaction: Interaction) -> None:
if not await self.voice_check(interaction):
return
vc = self.get_voice_client(interaction)
if vc is not None:
if not vc.is_paused():
self.pause_playing(interaction)
await interaction.edit(content="Результат паузы.")
vc.pause()
message = interaction.message
if not message:
return
embed = message.embeds[0]
embed.set_footer(text='Приостановлено')
await interaction.edit(embed=embed)
else:
self.resume_playing(interaction)
await interaction.edit(content="Результат возобновления.")
vc.resume()
message = interaction.message
if not message:
return
embed = message.embeds[0]
embed.remove_footer()
await interaction.edit(embed=embed)
class NextTrackButton(Button, VoiceExtension):
def __init__(self, **kwargs):
@@ -24,8 +36,11 @@ class NextTrackButton(Button, VoiceExtension):
VoiceExtension.__init__(self)
async def callback(self, interaction: Interaction) -> None:
await self.next_track(interaction)
await interaction.edit(content='Результат переключения >.')
if not await self.voice_check(interaction):
return
title = await self.next_track(interaction)
if not title:
await interaction.respond(f"Нет треков в очереди.", delete_after=15, ephemeral=True)
class PrevTrackButton(Button, VoiceExtension):
def __init__(self, **kwargs):
@@ -33,23 +48,27 @@ class PrevTrackButton(Button, VoiceExtension):
VoiceExtension.__init__(self)
async def callback(self, interaction: Interaction) -> None:
await self.prev_track(interaction)
await interaction.edit(content='Результат переключения <.')
if not await self.voice_check(interaction):
return
title = await self.prev_track(interaction)
if not title:
await interaction.respond(f"Нет треков в истории.", delete_after=15, ephemeral=True)
class Player(View):
def __init__(self, ctx: ApplicationContext, *items: Item, timeout: float | None = 3600, disable_on_timeout: bool = False):
def __init__(self, ctx: ApplicationContext, *items: Item, timeout: float | None = 3600, disable_on_timeout: bool = True):
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
self.ctx = ctx
self.repeat_button = Button(style=ButtonStyle.secondary, emoji='🔂', row=0)
self.shuffle_button = Button(style=ButtonStyle.secondary, emoji='🔀', row=0)
self.queue_button = Button(style=ButtonStyle.primary, emoji='📋', row=0)
self.play_pause_button = PlayPauseButton(style=ButtonStyle.primary, emoji='', row=0)
self.next_button = NextTrackButton(style=ButtonStyle.primary, emoji='', row=0)
self.prev_button = PrevTrackButton(style=ButtonStyle.primary, emoji='', row=0)
self.queue_button = Button(style=ButtonStyle.primary, emoji='📋', row=1)
self.add_item(self.repeat_button)
self.add_item(self.prev_button)
self.add_item(self.play_pause_button)

View File

@@ -1,6 +1,9 @@
import aiohttp
import asyncio
from math import ceil
from typing import cast
from io import BytesIO
from PIL import Image
from yandex_music import Track, ClientAsync
@@ -9,16 +12,187 @@ from discord import Interaction, ApplicationContext
from MusicBot.database import VoiceGuildsDatabase, BaseUsersDatabase
# This should be in find.py but recursive import is a thing
async def generate_player_embed(track: Track) -> discord.Embed:
"""Generate track embed for player.
Args:
track (yandex_music.Track): Track to be processed.
Returns:
discord.Embed: Track embed.
"""
title = cast(str, track.title) # casted types are always there, blame JS for that
avail = cast(bool, track.available)
artists = track.artists_name()
albums = [cast(str, album.title) for album in track.albums]
lyrics = cast(bool, track.lyrics_available)
duration = cast(int, track.duration_ms)
explicit = track.explicit or track.content_warning
bg_video = track.background_video_uri
metadata = track.meta_data
year = track.albums[0].year
artist = track.artists[0]
cover_url = track.get_cover_url('400x400')
color = await get_average_color_from_url(cover_url)
if explicit:
title += ' <:explicit:1325879701117472869>'
duration_m = duration // 60000
duration_s = ceil(duration / 1000) - duration_m * 60
artist_url = f"https://music.yandex.ru/artist/{artist.id}"
artist_cover = artist.cover
if not artist_cover:
artist_cover_url = artist.get_op_image_url()
else:
artist_cover_url = artist_cover.get_url()
embed = discord.Embed(
title=title,
description=", ".join(albums),
color=color,
)
embed.set_thumbnail(url=cover_url)
embed.set_author(name=", ".join(artists), url=artist_url, icon_url=artist_cover_url)
embed.add_field(name="Текст песни", value="Есть" if lyrics else "Нет")
embed.add_field(name="Длительность", value=f"{duration_m}:{duration_s:02}")
if year:
embed.add_field(name="Год выпуска", value=str(year))
if metadata:
if metadata.year:
embed.add_field(name="Год выхода", value=str(metadata.year))
if metadata.number:
embed.add_field(name="Позиция", value=str(metadata.number))
if metadata.composer:
embed.add_field(name="Композитор", value=metadata.composer)
if metadata.version:
embed.add_field(name="Версия", value=metadata.version)
if bg_video:
embed.add_field(name="Видеофон", value=f"[Ссылка]({bg_video})")
if not avail:
embed.set_footer(text=f"Трек в данный момент недоступен.")
return embed
async def get_average_color_from_url(url: str) -> int:
"""Get image from url and calculate its average color to use in embeds.
Args:
url (str): Image url.
Returns:
int: RGB Hex code. 0x000 if failed.
"""
try:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
response.raise_for_status()
response = await response.read()
img = Image.open(BytesIO(response))
img = img.convert('RGB')
width, height = img.size
r_total, g_total, b_total = 0, 0, 0
for y in range(height):
for x in range(width):
r, g, b = cast(tuple, img.getpixel((x, y)))
r_total += r
g_total += g
b_total += b
count = width * height
r = r_total // count
g = g_total // count
b = b_total // count
return (r << 16) + (g << 8) + b
except Exception:
return 0x000
class VoiceExtension:
def __init__(self) -> None:
self.db = VoiceGuildsDatabase()
self.users_db = BaseUsersDatabase()
def clear_queue(self, ctx: ApplicationContext | Interaction):
if ctx.guild:
self.db.update(ctx.guild.id, {'tracks_list': []})
async def update_player_embed(self, ctx: ApplicationContext | Interaction, player_mid: int) -> None:
"""Update current player message by its id.
Args:
ctx (ApplicationContext | Interaction): Context.
player_mid (int): Id of the player message. There can only be only one player in the guild.
"""
if isinstance(ctx, Interaction):
player = ctx.client.get_message(player_mid)
else:
player = await ctx.fetch_message(player_mid)
if not player:
return
guild = ctx.guild
user = ctx.user
if guild and user:
token = self.users_db.get_ym_token(user.id)
current_track = self.db.get_track(guild.id, 'current')
track = cast(Track, Track.de_json(current_track, client=ClientAsync(token))) # type: ignore
embed = await generate_player_embed(track)
if isinstance(ctx, Interaction) and ctx.message and ctx.message.id == player_mid:
# If interaction from player buttons
await ctx.edit(embed=embed)
else:
# If interaction from other buttons. They should have thair own response.
await player.edit(embed=embed)
async def voice_check(self, ctx: ApplicationContext | Interaction) -> bool:
"""Check if bot can perform voice tasks and respond if failed.
Args:
ctx (discord.ApplicationContext): Command context.
Returns:
bool: Check result.
"""
if not ctx.user:
return False
token = self.users_db.get_ym_token(ctx.user.id)
if not token:
await ctx.respond('❌ Необходимо указать свой токен доступа с помощью комманды /login.', delete_after=15, ephemeral=True)
return False
channel = ctx.channel
if not isinstance(channel, discord.VoiceChannel):
await ctx.respond("❌ Вы должны отправить команду в голосовом канале.", delete_after=15, ephemeral=True)
return False
if isinstance(ctx, Interaction):
channels = ctx.client.voice_clients
else:
channels = ctx.bot.voice_clients
voice_chat = discord.utils.get(channels, guild=ctx.guild)
if not voice_chat:
await ctx.respond("❌ Добавьте бота в голосовой канал при помощи команды /voice join.", delete_after=15, ephemeral=True)
return False
return True
def get_voice_client(self, ctx: ApplicationContext | Interaction) -> discord.VoiceClient | None:
"""Return voice client for the given guild id. Return None if not present.
@@ -61,18 +235,19 @@ class VoiceExtension:
gid = ctx.guild.id
guild = self.db.get_guild(gid)
if guild.get('current_track') is not None:
self.db.add_track(gid, track)
await ctx.respond(f"Трек **{track.title}** был добавлен в очередь.", delete_after=15)
else:
await track.download_async(f'music/{ctx.guild_id}.mp3')
song = discord.FFmpegPCMAudio(f'music/{ctx.guild_id}.mp3', options='-vn -filter:a "volume=0.15"')
await track.download_async(f'music/{ctx.guild_id}.mp3')
song = discord.FFmpegPCMAudio(f'music/{ctx.guild_id}.mp3', options='-vn -filter:a "volume=0.15"')
vc.play(song, after=lambda exc: asyncio.run_coroutine_threadsafe(self.next_track(ctx), loop))
self.db.set_current_track(gid, track)
self.db.update(gid, {'is_stopped': False})
return track.title
vc.play(song, after=lambda exc: asyncio.run_coroutine_threadsafe(self.next_track(ctx), loop))
self.db.set_current_track(gid, track)
self.db.update(gid, {'is_stopped': False})
player = guild['current_player']
if player is not None:
await self.update_player_embed(ctx, player)
return track.title
def pause_playing(self, ctx: ApplicationContext | Interaction) -> None:
vc = self.get_voice_client(ctx)
@@ -115,15 +290,19 @@ class VoiceExtension:
if not self.get_voice_client(ctx): # Silently return if bot got kicked
return
current_track = guild.get('current_track')
tracks_list = guild.get('tracks_list')
if tracks_list and current_track:
self.db.add_previous_track(gid, current_track)
track = self.db.pop_track(gid)
ym_track = Track.de_json(track, client=ClientAsync(token)) # type: ignore
current_track = guild['current_track']
next_track = self.db.get_track(gid, 'next')
if next_track and current_track:
self.db.modify_track(gid, current_track, 'previous', 'insert')
ym_track = Track.de_json(next_track, client=ClientAsync(token)) # type: ignore
self.stop_playing(ctx)
return await self.play_track(ctx, ym_track) # type: ignore
elif next_track:
ym_track = Track.de_json(next_track, client=ClientAsync(token)) # type: ignore
self.stop_playing(ctx)
return await self.play_track(ctx, ym_track) # type: ignore
elif current_track:
self.db.modify_track(gid, current_track, 'previous', 'insert')
self.stop_playing(ctx)
async def prev_track(self, ctx: ApplicationContext | Interaction) -> str | None:
@@ -141,15 +320,14 @@ class VoiceExtension:
return
gid = ctx.guild.id
guild = self.db.get_guild(gid)
token = self.users_db.get_ym_token(ctx.user.id)
current_track = guild.get('current_track')
current_track = self.db.get_track(gid, 'current')
tracks_list = self.db.get_previous_tracks_list(gid)
if tracks_list and current_track:
self.db.insert_track(gid, current_track)
track = self.db.pop_previous_track(gid)
ym_track = Track.de_json(track, client=ClientAsync(token)) # type: ignore
prev_track = self.db.get_track(gid, 'previous')
if prev_track:
if current_track:
self.db.modify_track(gid, current_track, 'next', 'insert')
ym_track = Track.de_json(prev_track, client=ClientAsync(token)) # type: ignore
self.stop_playing(ctx)
return await self.play_track(ctx, ym_track) # type: ignore
elif current_track:
@@ -169,10 +347,9 @@ class VoiceExtension:
return
gid = ctx.guild.id
guild = self.db.get_guild(gid)
token = self.users_db.get_ym_token(ctx.user.id)
current_track = guild.get('current_track')
current_track = self.db.get_track(gid, 'current')
if current_track:
ym_track = Track.de_json(current_track, client=ClientAsync(token)) # type: ignore
self.stop_playing(ctx)

View File

@@ -1,6 +1,11 @@
from typing import cast
import discord
from discord.ext.commands import Cog
from yandex_music import Track, ClientAsync
from MusicBot.cogs.utils.find import process_track
from MusicBot.cogs.utils.voice import VoiceExtension
from MusicBot.cogs.utils.player import Player
@@ -9,66 +14,61 @@ def setup(bot: discord.Bot):
class Voice(Cog, VoiceExtension):
toggle = discord.SlashCommandGroup("toggle", "Команды, связанные с переключением опций.", [1247100229535141899])
voice = discord.SlashCommandGroup("voice", "Команды, связанные с голосовым каналом.", [1247100229535141899])
queue = discord.SlashCommandGroup("queue", "Команды, связанные с очередью треков.", [1247100229535141899])
track = discord.SlashCommandGroup("track", "Команды, связанные с текущим треком.", [1247100229535141899])
async def voice_check(self, ctx: discord.ApplicationContext) -> bool:
"""Check if bot can perform voice tasks and respond if failed.
Args:
ctx (discord.ApplicationContext): Command context.
Returns:
bool: Check result.
"""
channel = ctx.channel
if not isinstance(channel, discord.VoiceChannel):
await ctx.respond("Вы должны отправить команду в голосовом канале.", delete_after=15, ephemeral=True)
return False
channels = ctx.bot.voice_clients
voice_chat = discord.utils.get(channels, guild=ctx.guild)
if not voice_chat:
await ctx.respond("Добавьте бота в голосовой канал при помощи команды /voice join.", delete_after=15, ephemeral=True)
return False
return True
@toggle.command(name="menu", description="Toggle player menu. Available only if you're the only one in the vocie channel.")
@voice.command(name="menu", description="Toggle player menu. Available only if you're the only one in the vocie channel.")
async def menu(self, ctx: discord.ApplicationContext) -> None:
if self.voice_check:
await ctx.respond("Меню", view=Player(ctx), ephemeral=True)
if not await self.voice_check(ctx):
return
current_track = self.db.get_track(ctx.guild.id, 'current')
try:
embed = await process_track(Track.de_json(current_track, client=ClientAsync())) # type: ignore
vc = self.get_voice_client(ctx)
if not vc:
return
if not vc.is_paused():
embed.set_footer(text='Приостановлено')
else:
embed.remove_footer()
except AttributeError:
embed = None
interaction = cast(discord.Interaction, await ctx.respond(view=Player(ctx), embed=embed, delete_after=3600))
response = await interaction.original_response()
self.db.update(ctx.guild.id, {'current_player': response.id})
@voice.command(name="join", description="Join the voice channel you're currently in.")
async def join(self, ctx: discord.ApplicationContext) -> None:
vc = self.get_voice_client(ctx)
if vc is not None and vc.is_playing():
await ctx.respond("Бот уже находится в голосовом канале. Выключите его с помощью команды /voice leave.", delete_after=15, ephemeral=True)
await ctx.respond("Бот уже находится в голосовом канале. Выключите его с помощью команды /voice leave.", delete_after=15, ephemeral=True)
elif ctx.channel is not None and isinstance(ctx.channel, discord.VoiceChannel):
await ctx.channel.connect(timeout=15)
await ctx.respond("Подключение успешно!", delete_after=15, ephemeral=True)
else:
await ctx.respond("Вы должны отправить команду в голосовом канале.", delete_after=15, ephemeral=True)
await ctx.respond("Вы должны отправить команду в голосовом канале.", delete_after=15, ephemeral=True)
@voice.command(description="Force the bot to leave the voice channel.")
async def leave(self, ctx: discord.ApplicationContext) -> None:
vc = self.get_voice_client(ctx)
if await self.voice_check(ctx) and vc is not None:
self.stop_playing(ctx)
self.db.clear_history(ctx.guild.id)
await vc.disconnect(force=True)
await ctx.respond("Отключение успешно!", delete_after=15, ephemeral=True)
@queue.command(description="Clear tracks queue.")
@queue.command(description="Clear tracks queue and history.")
async def clear(self, ctx: discord.ApplicationContext) -> None:
self.clear_queue(ctx)
await ctx.respond("Очередь сброшена.", delete_after=15, ephemeral=True)
if not await self.voice_check(ctx):
return
self.db.clear_history(ctx.guild.id)
await ctx.respond("Очередь и история сброшены.", delete_after=15, ephemeral=True)
@queue.command(description="Get tracks queue.")
async def get(self, ctx: discord.ApplicationContext) -> None:
if await self.voice_check(ctx):
guild = self.db.get_guild(ctx.guild.id)
tracks_list = guild.get('tracks_list')
tracks_list = self.db.get_tracks_list(ctx.guild.id, 'next')
embed = discord.Embed(
title='Список треков',
color=discord.Color.dark_purple()
@@ -99,10 +99,10 @@ class Voice(Cog, VoiceExtension):
else:
await ctx.respond("Воспроизведение не на паузе.", delete_after=15, ephemeral=True)
@track.command(description="Stop the current track and clear the queue.")
@track.command(description="Stop the current track and clear the queue and history.")
async def stop(self, ctx: discord.ApplicationContext) -> None:
if await self.voice_check(ctx):
self.clear_queue(ctx)
self.db.clear_history(ctx.guild.id)
self.stop_playing(ctx)
await ctx.respond("Воспроизведение остановлено.", delete_after=15, ephemeral=True)
@@ -110,7 +110,7 @@ class Voice(Cog, VoiceExtension):
async def next(self, ctx: discord.ApplicationContext) -> None:
if await self.voice_check(ctx):
gid = ctx.guild.id
tracks_list = self.db.get_tracks_list(gid)
tracks_list = self.db.get_tracks_list(gid, 'next')
if not tracks_list:
await ctx.respond("Нет песенен в очереди.", delete_after=15, ephemeral=True)
return