Привет, ребята, я здесь новичок, я пытался создать бот discord.py с музыкальным процессором, который использует сервер nodelink и wavelink. я сам сделал версию кода и почти работал, а потом попросил ИИ переписать ее, вся моя проблема в очереди. на самом деле он никогда не воспроизводит вторую песню в очереди...
@commands.Cog.listener()
async def on_wavelink_track_end(self, payload: wavelink.TrackEndEventPayload):
"""Called when a track finishes playing."""
if not payload.player or not payload.player.guild:
return
guild = payload.player.guild
logging.info(f"on_wavelink_track_end fired - Guild: {guild.id}, Reason: {payload.reason}")
# CRITICAL: Ignore 'REPLACED' to prevent skipping the song that just started
if payload.reason == "REPLACED":
logging.info(f"Ignoring REPLACED event for guild {guild.id}")
return
logging.info(f"Track ended in guild {guild.id}. Reason: {payload.reason}. Triggering play_next...")
# Trigger the next song
await asyncio.sleep(0.5) # Small delay to allow state to settle
await self.play_next(guild, force=True)
@commands.Cog.listener()
async def on_wavelink_track_stuck(self, payload: wavelink.TrackStuckEventPayload):
"""Called when a track gets stuck."""
if not payload.player or not payload.player.guild:
return
logging.warning(f"Track Stuck in guild {payload.player.guild.id}: {payload.threshold}ms")
await asyncio.sleep(0.5)
self.bot.loop.create_task(self.play_next(payload.player.guild, force=True))
async def play_next(self, guild: discord.Guild, force: bool = False, user_skipped: bool = False, recursion: int = 0):
if recursion > 3:
logging.error(f"play_next recursion limit reached for guild {guild.id}")
return
queue = self.get_queue(guild.id)
if queue.disconnect_task:
queue.disconnect_task.cancel()
queue.disconnect_task = None
vc: wavelink.Player = guild.voice_client
if not vc:
logging.warning(f"No voice client for guild {guild.id}")
return
# Safety check: if already playing, don't interfere (prevents double-play from skip + track_end)
# BUT if force=True (from TrackEnd or Skip), we MUST proceed even if it thinks it's playing
if vc.playing and not force and not user_skipped:
logging.info(f"play_next called but already playing for guild {guild.id}, skipping")
return
# CRITICAL FIX: Check if queue has songs BEFORE calling next()
# This ensures manually queued songs always play first
has_queued_songs = len(queue.queue) > 0
track = queue.next(skipped=user_skipped)
logging.info(f"play_next - Guild {guild.id}: track={track.title if track else 'None'}, had_queued={has_queued_songs}, queue_now={len(queue.queue)}, loop_mode={queue.loop_mode}")
# 1. HANDLE EMPTY QUEUE / RADIO / 24-7
# Only generate new tracks if we didn't have any queued songs
if not track and not has_queued_songs:
logging.info(f"No track in queue for guild {guild.id}. Checking radio/247/autoplay modes...")
# 24/7 Mode Logic
if queue.is_24_7_mode:
non_bot_members = [m for m in vc.channel.members if not m.bot]
if not non_bot_members:
if not queue.is_idle:
queue.is_idle = True
await self._clear_vc_status(vc)
# If skipping in 24/7 mode and no members, we should stop playing
if user_skipped and vc.playing:
await vc.stop()
return # Stay connected but idle
if queue.is_idle: queue.is_idle = False
# Fetch random track
random_track_info = await self._get_random_track_general()
if random_track_info:
artist, title = random_track_info
logging.info(f"24/7: Found track {title} by {artist}")
w_track = await self.search_wavelink(f"{artist} - {title}")
if w_track:
track = self._create_track(w_track, self.bot.user, vc.channel.id)
track.provider = "24/7 Radio"
queue.current = track
logging.info(f"24/7: Created track {track.title}")
else:
logging.warning(f"24/7: Failed to search for {artist} - {title}")
else:
logging.warning("24/7: Failed to get random track info")
# Radio Mode Logic
# Radio Mode Logic (with Retry)
elif queue.radio_mode:
logging.info(f"Radio mode active for guild {guild.id}")
# Try up to 3 times to get a valid track
for attempt in range(3):
if queue.radio_artist:
random_track_info = await self._get_random_track_from_artist(queue.radio_artist)
else:
random_track_info = await self._get_random_track_general()
if random_track_info:
artist, title = random_track_info
logging.info(f"Radio: Found track {title} by {artist} (Attempt {attempt+1})")
w_track = await self.search_wavelink(f"{artist} - {title}")
if w_track:
track = self._create_track(w_track, self.bot.user, vc.channel.id)
track.provider = f"Radio ({queue.radio_artist if queue.radio_artist else 'General'})"
queue.current = track
logging.info(f"Radio: Created track {track.title}")
break # Success! Exit the retry loop
else:
logging.warning(f"Radio: Failed to search Wavelink for {artist} - {title}")
else:
logging.warning("Radio: Failed to get track info from LastFM")
# Small delay before retry
await asyncio.sleep(0.5)
# Autoplay Logic
# Autoplay Logic
# Use history[-1] because queue.current is cleared by queue.next()
last_track = queue.history[-1] if queue.history else None
if not track and queue.autoplay and last_track:
artist, title = self._parse_track_info(last_track)
similar = await self._get_similar_track(artist, title)
if similar:
s_artist, s_title = similar
w_track = await self.search_wavelink(f"{s_artist} - {s_title}")
if w_track:
track = self._create_track(w_track, self.bot.user, last_track.channel_id)
track.provider = "Autoplay"
queue.current = track
# 2. FINAL CHECK & PLAY
if not track:
if user_skipped and vc.playing:
await vc.stop()
if not queue.is_24_7_mode:
await self._clear_vc_status(vc)
if not queue.disconnect_task:
queue.disconnect_task = self.bot.loop.create_task(self._scheduled_disconnect(guild))
else:
# In 24/7 mode, if we failed to get a track, retry shortly
await asyncio.sleep(5)
await self.play_next(guild, force=True, recursion=recursion+1)
return
self.cancel_scrobble_task(guild.id)
track.start_time = time.time()
# Check if original_track is valid
if not track.original_track:
logging.error(f"Track {track.title} has no original_track object! Skipping...")
await self.play_next(guild, force=True, recursion=recursion+1)
return
# Add to history
queue.history.append(track)
# Update VC Status (Background Task)
artist, title = self._parse_track_info(track)
status_text = f"🎵 {title} - {artist}"
self.bot.loop.create_task(self._update_vc_status(vc, status_text[:128]))
try:
# Play with Wavelink
logging.info(f"Attempting to play track: {track.title} in guild {guild.id}")
if vc.paused:
await vc.pause(False)
await asyncio.sleep(1)
await vc.play(track.original_track)
# Set volume if saved
if guild.id in self.volumes:
await vc.set_volume(int(self.volumes[guild.id] * 100))
# Scrobble
await self.update_lastfm_for_channel(vc.channel, track)
self.scrobble_tasks[guild.id] = self.bot.loop.create_task(
self.wait_and_scrobble(guild.id, vc.channel, track)
)
# Generate and send NOW PLAYING CARD
channel = self.bot.get_channel(track.channel_id)
if channel:
try:
card = await self._generate_now_playing_card(track, track.requester)
view = MusicControls(self.bot, guild.id)
if card:
# Send beautiful card
file = discord.File(card, filename="nowplaying.png")
await channel.send(file=file, view=view)
else:
# Fallback to embed if card generation fails
embed = discord.Embed(
title="🎵 Now Playing",
description=f"**[{track.title}]({track.url})**",
color=discord.Color.purple()
)
embed.add_field(name="Requested by", value=track.requester.mention)
embed.add_field(name="Source", value=f"**{track.provider}**", inline=True)
duration_str = time.strftime('%M:%S', time.gmtime(track.duration))
embed.add_field(name="Duration", value=f"`{duration_str}`", inline=True)
if track.thumbnail:
embed.set_thumbnail(url=track.thumbnail)
await channel.send(embed=embed, view=view)
except Exception as e:
print(f"Failed to send now playing message: {e}")
pass
except Exception as e:
print(f"Play Error: {e}")
logging.error(f"Play Error in guild {guild.id}: {e}")
await asyncio.sleep(1)
await self.play_next(guild, force=True, recursion=recursion+1)
@commands.Cog.listener()
async def on_wavelink_track_start(self, payload: wavelink.TrackStartEventPayload):
"""Called when a track starts playing - for debugging."""
if not payload.player or not payload.player.guild:
return
logging.info(f"Track STARTED in guild {payload.player.guild.id}: {payload.track.title}")
Я попробовал множество исправлений и в конце концов применил ИИ, но, к сожалению, даже это не помогло.
Привет, ребята, я здесь новичок, я пытался создать бот discord.py с музыкальным процессором, который использует сервер nodelink и wavelink. я сам сделал версию кода и почти работал, а потом попросил ИИ переписать ее, вся моя проблема в очереди. на самом деле он никогда не воспроизводит вторую песню в очереди... [code]@commands.Cog.listener() async def on_wavelink_track_end(self, payload: wavelink.TrackEndEventPayload): """Called when a track finishes playing.""" if not payload.player or not payload.player.guild: return
# CRITICAL: Ignore 'REPLACED' to prevent skipping the song that just started if payload.reason == "REPLACED": logging.info(f"Ignoring REPLACED event for guild {guild.id}") return
logging.info(f"Track ended in guild {guild.id}. Reason: {payload.reason}. Triggering play_next...")
# Trigger the next song await asyncio.sleep(0.5) # Small delay to allow state to settle await self.play_next(guild, force=True)
@commands.Cog.listener() async def on_wavelink_track_stuck(self, payload: wavelink.TrackStuckEventPayload): """Called when a track gets stuck.""" if not payload.player or not payload.player.guild: return logging.warning(f"Track Stuck in guild {payload.player.guild.id}: {payload.threshold}ms") await asyncio.sleep(0.5) self.bot.loop.create_task(self.play_next(payload.player.guild, force=True))
async def play_next(self, guild: discord.Guild, force: bool = False, user_skipped: bool = False, recursion: int = 0): if recursion > 3: logging.error(f"play_next recursion limit reached for guild {guild.id}") return
queue = self.get_queue(guild.id)
if queue.disconnect_task: queue.disconnect_task.cancel() queue.disconnect_task = None
vc: wavelink.Player = guild.voice_client if not vc: logging.warning(f"No voice client for guild {guild.id}") return
# Safety check: if already playing, don't interfere (prevents double-play from skip + track_end) # BUT if force=True (from TrackEnd or Skip), we MUST proceed even if it thinks it's playing if vc.playing and not force and not user_skipped: logging.info(f"play_next called but already playing for guild {guild.id}, skipping") return
# CRITICAL FIX: Check if queue has songs BEFORE calling next() # This ensures manually queued songs always play first has_queued_songs = len(queue.queue) > 0 track = queue.next(skipped=user_skipped)
# 1. HANDLE EMPTY QUEUE / RADIO / 24-7 # Only generate new tracks if we didn't have any queued songs if not track and not has_queued_songs: logging.info(f"No track in queue for guild {guild.id}. Checking radio/247/autoplay modes...") # 24/7 Mode Logic if queue.is_24_7_mode: non_bot_members = [m for m in vc.channel.members if not m.bot] if not non_bot_members: if not queue.is_idle: queue.is_idle = True await self._clear_vc_status(vc) # If skipping in 24/7 mode and no members, we should stop playing if user_skipped and vc.playing: await vc.stop() return # Stay connected but idle
if queue.is_idle: queue.is_idle = False
# Fetch random track random_track_info = await self._get_random_track_general() if random_track_info: artist, title = random_track_info logging.info(f"24/7: Found track {title} by {artist}") w_track = await self.search_wavelink(f"{artist} - {title}") if w_track: track = self._create_track(w_track, self.bot.user, vc.channel.id) track.provider = "24/7 Radio" queue.current = track logging.info(f"24/7: Created track {track.title}") else: logging.warning(f"24/7: Failed to search for {artist} - {title}") else: logging.warning("24/7: Failed to get random track info")
# Radio Mode Logic # Radio Mode Logic (with Retry) elif queue.radio_mode: logging.info(f"Radio mode active for guild {guild.id}")
# Try up to 3 times to get a valid track for attempt in range(3): if queue.radio_artist: random_track_info = await self._get_random_track_from_artist(queue.radio_artist) else: random_track_info = await self._get_random_track_general()
if random_track_info: artist, title = random_track_info logging.info(f"Radio: Found track {title} by {artist} (Attempt {attempt+1})") w_track = await self.search_wavelink(f"{artist} - {title}")
if w_track: track = self._create_track(w_track, self.bot.user, vc.channel.id) track.provider = f"Radio ({queue.radio_artist if queue.radio_artist else 'General'})" queue.current = track logging.info(f"Radio: Created track {track.title}") break # Success! Exit the retry loop else: logging.warning(f"Radio: Failed to search Wavelink for {artist} - {title}") else: logging.warning("Radio: Failed to get track info from LastFM")
# Small delay before retry await asyncio.sleep(0.5)
# Autoplay Logic # Autoplay Logic # Use history[-1] because queue.current is cleared by queue.next() last_track = queue.history[-1] if queue.history else None if not track and queue.autoplay and last_track: artist, title = self._parse_track_info(last_track) similar = await self._get_similar_track(artist, title) if similar: s_artist, s_title = similar w_track = await self.search_wavelink(f"{s_artist} - {s_title}") if w_track: track = self._create_track(w_track, self.bot.user, last_track.channel_id) track.provider = "Autoplay" queue.current = track
# 2. FINAL CHECK & PLAY if not track: if user_skipped and vc.playing: await vc.stop()
if not queue.is_24_7_mode: await self._clear_vc_status(vc) if not queue.disconnect_task: queue.disconnect_task = self.bot.loop.create_task(self._scheduled_disconnect(guild)) else: # In 24/7 mode, if we failed to get a track, retry shortly await asyncio.sleep(5) await self.play_next(guild, force=True, recursion=recursion+1) return
# Check if original_track is valid if not track.original_track: logging.error(f"Track {track.title} has no original_track object! Skipping...") await self.play_next(guild, force=True, recursion=recursion+1) return
# Add to history queue.history.append(track)
# Update VC Status (Background Task) artist, title = self._parse_track_info(track) status_text = f"🎵 {title} - {artist}" self.bot.loop.create_task(self._update_vc_status(vc, status_text[:128]))
try: # Play with Wavelink logging.info(f"Attempting to play track: {track.title} in guild {guild.id}") if vc.paused: await vc.pause(False)
await asyncio.sleep(1)
await vc.play(track.original_track)
# Set volume if saved if guild.id in self.volumes: await vc.set_volume(int(self.volumes[guild.id] * 100))
# Generate and send NOW PLAYING CARD channel = self.bot.get_channel(track.channel_id) if channel: try: card = await self._generate_now_playing_card(track, track.requester) view = MusicControls(self.bot, guild.id)
if card: # Send beautiful card file = discord.File(card, filename="nowplaying.png") await channel.send(file=file, view=view) else: # Fallback to embed if card generation fails embed = discord.Embed( title="🎵 Now Playing", description=f"**[{track.title}]({track.url})**", color=discord.Color.purple() ) embed.add_field(name="Requested by", value=track.requester.mention) embed.add_field(name="Source", value=f"**{track.provider}**", inline=True) duration_str = time.strftime('%M:%S', time.gmtime(track.duration)) embed.add_field(name="Duration", value=f"`{duration_str}`", inline=True) if track.thumbnail: embed.set_thumbnail(url=track.thumbnail) await channel.send(embed=embed, view=view) except Exception as e: print(f"Failed to send now playing message: {e}") pass
except Exception as e: print(f"Play Error: {e}") logging.error(f"Play Error in guild {guild.id}: {e}") await asyncio.sleep(1) await self.play_next(guild, force=True, recursion=recursion+1)
@commands.Cog.listener() async def on_wavelink_track_start(self, payload: wavelink.TrackStartEventPayload): """Called when a track starts playing - for debugging.""" if not payload.player or not payload.player.guild: return logging.info(f"Track STARTED in guild {payload.player.guild.id}: {payload.track.title}") [/code] Я попробовал множество исправлений и в конце концов применил ИИ, но, к сожалению, даже это не помогло.