fix: delegate !similar playback to music bot, not calling bot
When merlin ran !similar, music operations (fade, queue, play loop) targeted merlin instead of derp, causing audio to play over derp's stream. New _music_bot() helper resolves the DJ bot via active state or plugin filter config, so playback always routes to derp. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -105,26 +105,41 @@ def _parse_title(raw_title: str) -> tuple[str, str]:
|
||||
return ("", raw_title)
|
||||
|
||||
|
||||
def _current_meta(bot) -> tuple[str, str]:
|
||||
"""Extract artist and title from the currently playing track.
|
||||
def _music_bot(bot):
|
||||
"""Return the bot instance that owns music playback.
|
||||
|
||||
Returns (artist, title). Either or both may be empty.
|
||||
Tries the music plugin's current track metadata on this bot first,
|
||||
then checks peer bots (shared registry) so extra bots can see what
|
||||
the music bot is playing.
|
||||
Checks the calling bot first, then peer bots via the shared registry.
|
||||
Returns the first bot with an active music state, or ``bot`` as fallback.
|
||||
"""
|
||||
# Check this bot first, then peers
|
||||
candidates = [bot]
|
||||
for peer in getattr(getattr(bot, "registry", None), "_bots", {}).values():
|
||||
if peer is not bot:
|
||||
candidates.append(peer)
|
||||
for b in candidates:
|
||||
music_ps = getattr(b, "_pstate", {}).get("music", {})
|
||||
current = music_ps.get("current")
|
||||
if current is not None:
|
||||
raw_title = current.title or ""
|
||||
if raw_title:
|
||||
return _parse_title(raw_title)
|
||||
if music_ps.get("current") is not None or music_ps.get("queue"):
|
||||
return b
|
||||
# No active music state -- prefer a bot that allows the music plugin
|
||||
for b in candidates:
|
||||
only = getattr(b, "_only_plugins", None)
|
||||
if only is not None and "music" in only:
|
||||
return b
|
||||
return bot
|
||||
|
||||
|
||||
def _current_meta(bot) -> tuple[str, str]:
|
||||
"""Extract artist and title from the currently playing track.
|
||||
|
||||
Returns (artist, title). Either or both may be empty.
|
||||
Checks the music bot (via ``_music_bot``) for now-playing metadata.
|
||||
"""
|
||||
mb = _music_bot(bot)
|
||||
music_ps = getattr(mb, "_pstate", {}).get("music", {})
|
||||
current = music_ps.get("current")
|
||||
if current is not None:
|
||||
raw_title = current.title or ""
|
||||
if raw_title:
|
||||
return _parse_title(raw_title)
|
||||
return ("", "")
|
||||
|
||||
|
||||
@@ -410,13 +425,14 @@ async def cmd_similar(bot, message):
|
||||
await bot.reply(message, "No playable tracks resolved")
|
||||
return
|
||||
|
||||
# Transition: fade out current, load new playlist
|
||||
ps = music_mod._ps(bot)
|
||||
await music_mod._fade_and_cancel(bot, duration=3.0)
|
||||
# Transition on the music bot (derp), not the calling bot (may be merlin)
|
||||
dj = _music_bot(bot)
|
||||
ps = music_mod._ps(dj)
|
||||
await music_mod._fade_and_cancel(dj, duration=3.0)
|
||||
ps["queue"].clear()
|
||||
ps["current"] = None
|
||||
ps["queue"] = list(tracks)
|
||||
music_mod._ensure_loop(bot, fade_in=True)
|
||||
music_mod._ensure_loop(dj, fade_in=True)
|
||||
await bot.reply(message, f"Playing {len(tracks)} similar tracks for {search_artist}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user