Бот не должен работать когда какая либо команда не воспроизводится, его задача - проиграть музыку и выполнять команды по типу стоп и пропустить песню. Из за того что концепция бота странная, после суток работы он просто заходит канал и не воспроизводит музыку. Я хочу что бы после воспроизведения музыки, бот можно скачать самоочищался и не вызывал ошибок, редь ранее он мог играть музыку а сейчас нет. Так вот, ты бы мог сделать так что бы бот перестал вызывать проблемы после нескольких выполнений команд?

import asyncio
import disnake
from disnake.ext import commands
import yt_dlp
import logging

# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Настройки FFmpeg
ffmpeg_options = {
    'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -nostdin',  # Добавлена опция -nostdin
    'options': '-vn -loglevel warning'  # Можно изменить на '-loglevel debug' для более подробного логирования
}

# Настройки yt_dlp для извлечения аудио
ytdl_opts = {
    'format': 'bestaudio/best',
    'noplaylist': True,            # Отключаем обработку плейлистов
    'quiet': True,
    'no_warnings': True,
    'default_search': 'auto',
    'cachedir': False,             # Отключаем кеширование
    'extract_flat': 'in_playlist'  # Предотвращает извлечение плейлистов
}

ytdl = yt_dlp.YoutubeDL(ytdl_opts)


class Song:
    """Класс для хранения информации о песне."""
    def __init__(self, title: str, url: str, thumbnail: str):
        self.title = title
        self.url = url
        self.thumbnail = thumbnail


class YTDLSource(disnake.PCMVolumeTransformer):
    """
    Класс для обработки аудио источника с YouTube.
    """
    def __init__(self, source, *, data, volume=0.5):
        super().__init__(source, volume)
        self.data = data
        self.title = data.get('title', 'Unknown Title')
        self.url = data.get('url')
        self.thumbnail = data.get('thumbnail', '')

    @classmethod
    async def from_song(cls, song: Song, *, loop, stream=True):
        """
        Извлекает информацию о песне и создает аудио источник.
        """
        try:
            logger.info(f"Извлечение информации о треке: {song.title}")
            # Извлекаем полную информацию о записи с помощью yt_dlp
            data = await loop.run_in_executor(None, lambda: ytdl.extract_info(song.url, download=not stream))
            if data is None:
                logger.error("Не удалось извлечь информацию о записи.")
                return None

            # Получаем URL аудио
            audio_url = data.get('url')
            title = data.get('title', song.title)
            thumbnail = data.get('thumbnail', song.thumbnail)

            logger.info(f"Извлечено видео: {title}")
            logger.info(f"Thumbnail URL: {thumbnail}")
            logger.debug(f"Audio URL: {audio_url}")  # Для отладки

            # Создаём источник для FFmpeg
            return cls(disnake.FFmpegPCMAudio(audio_url, **ffmpeg_options), data=data)
        except Exception as e:
            logger.error(f"Ошибка при извлечении записи: {e}")
            return None


class MusicBot(commands.Cog):
    """
    Cog для управления музыкальным воспроизведением.
    """
    def __init__(self, bot: commands.Bot):
        self.bot = bot
        self.playlist = []  # Список песен
        self.current_index = -1  # Индекс текущей песни
        self.current_embed_message = None
        self.loop_album = False
        self.loop_single = False
        self.voice_client = None
        self.current_text_channel = None
        self.play_lock = asyncio.Lock()  # Блокировка для управления воспроизведением
        self.idle_timeout_task = None  # Задача для таймера бездействия

        # Статический плейлист: добавьте сюда свои 18 песен
        self.song_urls = [
            "https://www.youtube.com/watch?v=Vr-DOV-TP5s",
            "https://www.youtube.com/watch?v=apWlgn-nrEE",
            "https://www.youtube.com/watch?v=RGF6nj6tZKA",
            "https://www.youtube.com/watch?v=OQGdrezi0Y4",
            "https://www.youtube.com/watch?v=ocRN6Hz3LrI",
            "https://www.youtube.com/watch?v=FGeaG4eL4OY",
            "https://www.youtube.com/watch?v=ioiG_BNTuOA",
            "https://www.youtube.com/watch?v=T2aNrTrnFAw",
            "https://www.youtube.com/watch?v=3e1fUvqozAM",
            "https://www.youtube.com/watch?v=k13LlCabKdQ",
            "https://www.youtube.com/watch?v=UrJMZfMELVQ",
            "https://www.youtube.com/watch?v=u7un-AAd3Z0",
            "https://www.youtube.com/watch?v=6X-G4sgzHiA",
            "https://www.youtube.com/watch?v=jirQpN2wr9A",
            "https://www.youtube.com/watch?v=KxpGxVQOkG0",
            "https://www.youtube.com/watch?v=oghlaYD2_FQ",
            "https://www.youtube.com/watch?v=HX6NAxBgfKM",
        ]

    @commands.slash_command(name="серегапират", description="Начать воспроизведение музыки.")
    async def play_command(self, inter: disnake.ApplicationCommandInteraction):
        """
        Команда для запуска воспроизведения музыки.
        """
        # Проверяем, находится ли пользователь в голосовом канале
        if not inter.author.voice or not inter.author.voice.channel:
            await inter.response.send_message(
                "Войдите в голосовой канал, прежде чем использовать эту команду.",
                ephemeral=True
            )
            return

        voice_channel = inter.author.voice.channel

        # Подключаемся или перемещаемся в голосовой канал
        if inter.guild.voice_client is None:
            try:
                self.voice_client = await voice_channel.connect()
                logger.info(f"Подключился к голосовому каналу: {voice_channel.name}")
            except Exception as e:
                logger.error(f"Не удалось подключиться к голосовому каналу: {e}")
                await inter.response.send_message(
                    "Не удалось подключиться к голосовому каналу.",
                    ephemeral=True
                )
                return
        else:
            self.voice_client = inter.guild.voice_client
            if self.voice_client.channel != voice_channel:
                try:
                    await self.voice_client.move_to(voice_channel)
                    logger.info(f"Перемещён в голосовой канал: {voice_channel.name}")
                except Exception as e:
                    logger.error(f"Не удалось переместиться в голосовой канал: {e}")
                    await inter.response.send_message(
                        "Не удалось переместиться в голосовой канал.",
                        ephemeral=True
                    )
                    return

        self.current_text_channel = inter.channel

        # Отложенный ответ, чтобы избежать таймаута
        await inter.response.defer()

        if self.current_embed_message:
            try:
                await self.current_embed_message.delete()
            except disnake.NotFound:
                pass
            self.current_embed_message = None

        # Загрузка плейлиста и начало воспроизведения
        await self.load_playlist()

        # Начинаем воспроизведение первой песни, если не воспроизводится
        async with self.play_lock:
            if not self.voice_client.is_playing() and not self.voice_client.is_paused():
                if self.playlist:
                    self.current_index = 0
                    await self.play_current_song()
                else:
                    await self.current_text_channel.send("Плейлист пуст.")

    async def load_playlist(self):
        """
        Загружает информацию о песнях из статического списка URL и добавляет их в плейлист.
        После загрузки первой песни начинает её воспроизведение, а остальные загружает асинхронно.
        """
        try:
            logger.info("Загрузка плейлиста...")

            # Очистка текущего плейлиста перед загрузкой
            self.playlist.clear()
            logger.debug("Текущий плейлист очищен.")

            # Загрузка первой песни
            if self.song_urls:
                first_url = self.song_urls[0]
                try:
                    info = await self.bot.loop.run_in_executor(None, lambda: ytdl.extract_info(first_url, download=False))
                    if info is None:
                        logger.warning(f"Не удалось извлечь информацию для URL: {first_url}")
                    else:
                        # Проверка, что это не плейлист
                        if 'entries' in info:
                            logger.warning(f"URL содержит плейлист, а не отдельную песню: {first_url}")
                        else:
                            title = info.get('title', 'Unknown Title')
                            thumbnail = info.get('thumbnail', '')

                            song = Song(title=title, url=first_url, thumbnail=thumbnail)
                            self.playlist.append(song)
                            logger.info(f"Добавлена песня: {song.title}")
                except Exception as e:
                    logger.error(f"Ошибка при обработке URL {first_url}: {e}")

                # Асинхронная загрузка остальных песен
                asyncio.create_task(self.async_load_rest_songs())
            else:
                logger.warning("Список песен пуст.")
        except Exception as e:
            logger.error(f"Ошибка при загрузке плейлиста: {e}")
            if self.current_text_channel:
                await self.current_text_channel.send(f"Произошла ошибка при загрузке плейлиста: {e}")

    async def async_load_rest_songs(self):
        """
        Асинхронно загружает остальные песни и добавляет их в плейлист.
        """
        try:
            for url in self.song_urls[1:]:
                try:
                    info = await self.bot.loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=False))
                    if info is None:
                        logger.warning(f"Не удалось извлечь информацию для URL: {url}")
                        continue

                    # Если это плейлист, пропускаем (на случай ошибок)
                    if 'entries' in info:
                        logger.warning(f"URL содержит плейлист, а не отдельную песню: {url}")
                        continue

                    title = info.get('title', 'Unknown Title')
                    thumbnail = info.get('thumbnail', '')

                    song = Song(title=title, url=url, thumbnail=thumbnail)
                    self.playlist.append(song)
                    logger.info(f"Добавлена песня: {song.title}")
                except Exception as e:
                    logger.error(f"Ошибка при обработке URL {url}: {e}")
        except Exception as e:
            logger.error(f"Ошибка при асинхронной загрузке песен: {e}")

    async def play_current_song(self):
        """
        Воспроизводит текущую песню по self.current_index.
        """
        logger.debug(f"play_current_song: current_index={self.current_index}, len(playlist)={len(self.playlist)}")
        if not (0 <= self.current_index < len(self.playlist)):
            logger.error("Индекс текущей песни вне диапазона.")
            # Запуск таймера бездействия, так как нет песни для воспроизведения
            await self.start_idle_timer()
            return

        song = self.playlist[self.current_index]
        source = await YTDLSource.from_song(song, loop=self.bot.loop, stream=True)
        if source is None:
            logger.error(f"Не удалось создать источник для песни: {song.title}")
            await self.next_song(auto=True)
            return

        # Проверяем наличие аудио URL
        if not source.url:
            logger.error(f"Отсутствует audio_url для песни: {song.title}")
            await self.next_song(auto=True)
            return

        # Останавливаем текущую песню, если она играет или на паузе
        if self.voice_client.is_playing() or self.voice_client.is_paused():
            self.voice_client.stop()

        # Отменяем таймер бездействия, так как начинается воспроизведение
        await self.cancel_idle_timer()

        # Запускаем воспроизведение
        self.voice_client.play(source, after=self.after_song)

        logger.info(f"Сейчас играет: {song.title}")

        # Создание или обновление embed-сообщения
        embed = disnake.Embed(
            title=f"Сейчас играет: {song.title}",
            description="Музыка с YouTube",
            color=disnake.Color.blue()
        )
        if song.thumbnail:
            embed.set_thumbnail(url=song.thumbnail)
        else:
            embed.description += "\n[Миниатюра недоступна]"

        components = disnake.ui.ActionRow(
            disnake.ui.Button(emoji="⏸", custom_id="pause", style=disnake.ButtonStyle.secondary),
            disnake.ui.Button(emoji="⏭", custom_id="next", style=disnake.ButtonStyle.secondary),
            disnake.ui.Button(
                emoji="🔁",
                custom_id="loop_album",
                style=disnake.ButtonStyle.green if self.loop_album else disnake.ButtonStyle.gray
            ),
            disnake.ui.Button(
                emoji="🔂",
                custom_id="loop_single",
                style=disnake.ButtonStyle.green if self.loop_single else disnake.ButtonStyle.gray
            )
        )

        if self.current_embed_message:
            try:
                await self.current_embed_message.edit(embed=embed, components=components)
            except disnake.NotFound:
                # Если сообщение было удалено, отправляем новое
                self.current_embed_message = await self.current_text_channel.send(embed=embed, components=components)
        else:
            self.current_embed_message = await self.current_text_channel.send(embed=embed, components=components)

    def after_song(self, error):
        """
        Обратный вызов после завершения песни.
        """
        if error:
            logger.error(f"Ошибка при воспроизведении песни: {error}")
            # Отправляем сообщение об ошибке в канал
            if self.current_text_channel:
                asyncio.run_coroutine_threadsafe(
                    self.current_text_channel.send(f"Ошибка при воспроизведении песни: {error}"),
                    self.bot.loop
                )
        # Планируем воспроизведение следующей песни
        asyncio.run_coroutine_threadsafe(self.next_song(auto=True), self.bot.loop)

    async def next_song(self, auto=False):
        """
        Воспроизводит следующую песню.
        Если auto=True, это вызов из after_song, иначе из взаимодействия пользователя.
        """
        async with self.play_lock:
            if self.loop_single:
                # Повторяем текущую песню
                await self.play_current_song()
                return

            self.current_index += 1
            logger.debug(f"next_song: увеличен current_index до {self.current_index}")

            if self.current_index >= len(self.playlist):
                if self.loop_album:
                    self.current_index = 0
                    logger.info("Зацикливание альбома включено. Переходим к первой песне.")
                else:
                    await self.current_text_channel.send("Достигнут конец плейлиста.")
                    self.current_index = -1  # Сброс индекса
                    logger.info("Плейлист завершён. Индекс сброшен.")

                    # Запускаем таймер бездействия, так как воспроизведение завершено
                    await self.start_idle_timer()
                    return

            await self.play_current_song()

            if not auto and self.current_index != -1:
                await self.current_text_channel.send(f"Следующая песня: {self.playlist[self.current_index].title}")

    async def pause_resume_song(self):
        """
        Приостанавливает или возобновляет воспроизведение.
        """
        if self.voice_client.is_playing():
            self.voice_client.pause()
            await self.update_embed(content="Музыка на паузе.")
            logger.info("Музыка приостановлена.")
        elif self.voice_client.is_paused():
            self.voice_client.resume()
            await self.update_embed(content="Музыка продолжена.")
            logger.info("Музыка продолжена.")
        else:
            await self.current_text_channel.send("Музыка не воспроизводится.")

    async def update_embed(self, content: str):
        """
        Обновляет embed-сообщение с дополнительным контентом.
        """
        if self.current_embed_message:
            try:
                await self.current_embed_message.edit(content=content)
            except disnake.NotFound:
                pass

    @commands.Cog.listener()
    async def on_interaction(self, inter: disnake.Interaction):
        """
        Обработка нажатия на кнопки управления.
        """
        if not isinstance(inter, disnake.MessageInteraction):
            return

        if inter.message != self.current_embed_message:
            # Игнорируем взаимодействия с другими сообщениями
            return
        
        custom_id = inter.data.custom_id

        if custom_id == "pause":
            await self.pause_resume_song()
            await inter.response.defer()  # Отложенный ответ, так как мы уже обновили сообщение

        elif custom_id == "next":
            if self.voice_client.is_playing() or self.voice_client.is_paused():
                self.voice_client.stop()
                # Воспроизведение следующей песни будет вызвано `after_song`
                await inter.response.send_message("Следующая песня.", ephemeral=True)
                logger.info("Пользователь запросил следующую песню.")
            else:
                await inter.response.send_message("Музыка не воспроизводится.", ephemeral=True)

        elif custom_id == "loop_album":
            self.loop_album = not self.loop_album
            state = "включено" if self.loop_album else "выключено"
            await inter.response.send_message(f"Зацикливание альбома {state}.", ephemeral=True)
            logger.info(f"Зацикливание альбома {'включено' if self.loop_album else 'выключено'}.")

            # Обновляем стиль кнопки
            if self.current_embed_message:
                try:
                    new_style = disnake.ButtonStyle.green if self.loop_album else disnake.ButtonStyle.gray
                    components = disnake.ui.ActionRow(
                        disnake.ui.Button(emoji="⏸", custom_id="pause", style=disnake.ButtonStyle.secondary),
                        disnake.ui.Button(emoji="⏭", custom_id="next", style=disnake.ButtonStyle.secondary),
                        disnake.ui.Button(
                            emoji="🔁",
                            custom_id="loop_album",
                            style=new_style
                        ),
                        disnake.ui.Button(
                            emoji="🔂",
                            custom_id="loop_single",
                            style=disnake.ButtonStyle.green if self.loop_single else disnake.ButtonStyle.gray
                        )
                    )
                    await self.current_embed_message.edit(components=components)
                except disnake.NotFound:
                    pass

        elif custom_id == "loop_single":
            self.loop_single = not self.loop_single
            state = "включено" if self.loop_single else "выключено"
            await inter.response.send_message(f"Зацикливание текущей песни {state}.", ephemeral=True)
            logger.info(f"Зацикливание текущей песни {'включено' if self.loop_single else 'выключено'}.")

            # Обновляем стиль кнопки
            if self.current_embed_message:
                try:
                    new_style = disnake.ButtonStyle.green if self.loop_single else disnake.ButtonStyle.gray
                    components = disnake.ui.ActionRow(
                        disnake.ui.Button(emoji="⏸", custom_id="pause", style=disnake.ButtonStyle.secondary),
                        disnake.ui.Button(emoji="⏭", custom_id="next", style=disnake.ButtonStyle.secondary),
                        disnake.ui.Button(
                            emoji="🔁",
                            custom_id="loop_album",
                            style=disnake.ButtonStyle.green if self.loop_album else disnake.ButtonStyle.gray
                        ),
                        disnake.ui.Button(
                            emoji="🔂",
                            custom_id="loop_single",
                            style=new_style
                        )
                    )
                    await self.current_embed_message.edit(components=components)
                except disnake.NotFound:
                    pass

    async def cog_unload(self):
        """
        Корректное завершение работы Cog.
        """
        if self.voice_client:
            await self.voice_client.disconnect()

    @commands.Cog.listener()
    async def on_disconnect(self):
        """
        Обработка отключения от Discord-сервера.
        """
        if self.voice_client:
            try:
                await self.voice_client.disconnect()
            except ConnectionResetError:
                logger.warning("Не удалось отключиться от голосового канала: транспорт уже закрывается.")
            except Exception as e:
                logger.error(f"Ошибка при отключении от голосового канала: {e}")

    # Дополнительные методы для таймера
    async def start_idle_timer(self):
        """
        Запускает таймер бездействия на 10 минут.
        Если бот не будет воспроизводить музыку в течение этого времени, он отключится из голосового канала.
        """
        if self.idle_timeout_task and not self.idle_timeout_task.done():
            # Таймер уже запущен
            logger.debug("Таймер бездействия уже запущен.")
            return

        self.idle_timeout_task = self.bot.loop.create_task(self.idle_timeout())
        logger.debug("Таймер бездействия запущен.")

    async def idle_timeout(self):
        """
        Ждёт 10 минут и отключается от голосового канала, если музыка не начала воспроизводиться.
        """
        try:
            await asyncio.sleep(600)  # 10 минут
            if self.voice_client and not self.voice_client.is_playing() and not self.voice_client.is_paused():
                logger.info("Таймер бездействия завершился. Отключение от голосового канала.")
                await self.disconnect_voice()
        except asyncio.CancelledError:
            # Таймер был отменён
            logger.info("Таймер бездействия отменён.")
            pass

    async def cancel_idle_timer(self):
        """
        Отменяет запущенный таймер бездействия.
        """
        if self.idle_timeout_task and not self.idle_timeout_task.done():
            self.idle_timeout_task.cancel()
            try:
                await self.idle_timeout_task
            except asyncio.CancelledError:
                pass
            self.idle_timeout_task = None
            logger.debug("Таймер бездействия отменён.")

    async def disconnect_voice(self):
        """
        Отключает бота из голосового канала и очищает внутреннее состояние.
        """
        if self.voice_client:
            try:
                await self.voice_client.disconnect()
                logger.info("Бот отключился от голосового канала из-за бездействия.")
            except Exception as e:
                logger.error(f"Ошибка при отключении от голосового канала: {e}")
            finally:
                self.voice_client = None
                self.playlist.clear()
                self.current_index = -1
                if self.current_embed_message:
                    try:
                        await self.current_embed_message.delete()
                        logger.debug("Embed-сообщение удалено.")
                    except disnake.NotFound:
                        pass
                    self.current_embed_message = None
                self.current_text_channel = None

    # Добавление команды для остановки музыки и отключения
    @commands.slash_command(name="стоп", description="Остановить воспроизведение и отключить бота.")
    async def stop_command(self, inter: disnake.ApplicationCommandInteraction):
        """
        Команда для остановки воспроизведения и отключения бота из голосового канала.
        """
        if not self.voice_client or not self.voice_client.is_connected():
            await inter.response.send_message("Бот не подключен к голосовому каналу.", ephemeral=True)
            return

        # Останавливаем воспроизведение и очищаем плейлист
        self.voice_client.stop()
        self.playlist.clear()
        self.current_index = -1
        logger.info("Воспроизведение остановлено и плейлист очищен.")

        # Отменяем таймер бездействия, если он запущен
        await self.cancel_idle_timer()

        # Отключаемся из голосового канала
        await self.disconnect_voice()

        await inter.response.send_message("Воспроизведение остановлено и бот отключился из голосового канала.", ephemeral=True)

    @commands.Cog.listener()
    async def on_voice_state_update(self, member, before, after):
        if member == self.bot.user and after.channel is None:
            # Бот был отключен от голосового канала
            self.stop()



# Настройка и запуск бота
intents = disnake.Intents.default()
intents.message_content = True
intents.guilds = True
intents.voice_states = True

bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    print(f"Бот {bot.user} подключился и готов к работе!")

# Добавляем Cog в бота
bot.add_cog(MusicBot(bot))
if __name__ == "__main__":