from math import ceil from typing import cast import discord from discord.ext.commands import Cog from yandex_music import Track, ClientAsync from MusicBot.cogs.utils.voice import VoiceExtension, generate_player_embed from MusicBot.cogs.utils.player import Player from MusicBot.cogs.utils.misc import QueueView, generate_queue_embed def setup(bot: discord.Bot): bot.add_cog(Voice()) class Voice(Cog, VoiceExtension): voice = discord.SlashCommandGroup("voice", "Команды, связанные с голосовым каналом.") queue = discord.SlashCommandGroup("queue", "Команды, связанные с очередью треков.") track = discord.SlashCommandGroup("track", "Команды, связанные с текущим треком.") @voice.command(name="menu", description="Создать меню проигрывателя. Доступно только если вы единственный в голосовом канале.") async def menu(self, ctx: discord.ApplicationContext) -> None: if not await self.voice_check(ctx): return guild = self.db.get_guild(ctx.guild.id) embed = None if guild['current_track']: embed = await generate_player_embed(Track.de_json(guild['current_track'], client=ClientAsync())) # type: ignore vc = self.get_voice_client(ctx) if vc and vc.is_paused(): embed.set_footer(text='Приостановлено') else: embed.remove_footer() if guild['current_player']: message = await ctx.fetch_message(guild['current_player']) await message.delete() 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="Подключиться к голосовому каналу, в котором вы сейчас находитесь.") async def join(self, ctx: discord.ApplicationContext) -> None: vc = self.get_voice_client(ctx) if vc and vc.is_playing(): response_message = "❌ Бот уже находится в голосовом канале. Выключите его с помощью команды /voice leave." elif isinstance(ctx.channel, discord.VoiceChannel): await ctx.channel.connect(timeout=15) response_message = "Подключение успешно!" else: response_message = "❌ Вы должны отправить команду в голосовом канале." await ctx.respond(response_message, delete_after=15, ephemeral=True) @voice.command(description="Заставить бота покинуть голосовой канал.") async def leave(self, ctx: discord.ApplicationContext) -> None: vc = self.get_voice_client(ctx) if vc and await self.voice_check(ctx): 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="Очистить очередь треков и историю прослушивания.") async def clear(self, ctx: discord.ApplicationContext) -> None: 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="Получить очередь треков.") async def get(self, ctx: discord.ApplicationContext) -> None: if not await self.voice_check(ctx): return tracks = self.db.get_tracks_list(ctx.guild.id, 'next') self.users_db.update(ctx.user.id, {'queue_page': 0}) embed = generate_queue_embed(0, tracks) await ctx.respond(embed=embed, view=QueueView(ctx), ephemeral=True) @track.command(description="Приостановить текущий трек.") async def pause(self, ctx: discord.ApplicationContext) -> None: vc = self.get_voice_client(ctx) if await self.voice_check(ctx) and vc is not None: if not vc.is_paused(): vc.pause() await ctx.respond("Воспроизведение приостановлено.", delete_after=15, ephemeral=True) else: await ctx.respond("Воспроизведение уже приостановлено.", delete_after=15, ephemeral=True) @track.command(description="Возобновить текущий трек.") async def resume(self, ctx: discord.ApplicationContext) -> None: vc = self.get_voice_client(ctx) if await self.voice_check(ctx) and vc is not None: if vc.is_paused(): vc.resume() await ctx.respond("Воспроизведение восстановлено.", delete_after=15, ephemeral=True) else: await ctx.respond("Воспроизведение не на паузе.", delete_after=15, ephemeral=True) @track.command(description="Прервать проигрывание, удалить историю, очередь и текущий плеер.") async def stop(self, ctx: discord.ApplicationContext) -> None: if await self.voice_check(ctx): self.db.clear_history(ctx.guild.id) self.stop_playing(ctx) current_player = self.db.get_guild(ctx.guild.id)['current_player'] if current_player is not None: self.db.update(ctx.guild.id, {'current_player': None, 'repeat': False, 'shuffle': False}) message = await ctx.fetch_message(current_player) await message.delete() await ctx.respond("Воспроизведение остановлено.", delete_after=15, ephemeral=True) @track.command(description="Переключиться на следующую песню в очереди.") 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, 'next') if not tracks_list: await ctx.respond("Нет песенен в очереди.", delete_after=15, ephemeral=True) return self.db.update(gid, {'is_stopped': False}) title = await self.next_track(ctx) if title is not None: await ctx.respond(f"Сейчас играет: **{title}**!", delete_after=15) else: await ctx.respond(f"Нет треков в очереди.", delete_after=15, ephemeral=True) @voice.command(description="Добавить трек в избранное.") async def like(self, ctx: discord.ApplicationContext) -> None: if await self.voice_check(ctx): vc = self.get_voice_client(ctx) if not vc or not vc.is_playing: await ctx.respond("Нет воспроизводимого трека.", delete_after=15, ephemeral=True) result = await self.like_track(ctx) if not result: await ctx.respond("Трек уже добавлен в избранное.", delete_after=15, ephemeral=True) else: await ctx.respond(f"Трек **{result}** был добавлен в избранное.", delete_after=15, ephemeral=True)