fix: race condition in skip/seek/stop losing track state

task.cancel() triggers _play_loop's finally block asynchronously.
When cmd_skip or cmd_seek called _ensure_loop before the finally
block ran, the old task's cleanup would overwrite the new task's
state -- causing !np to report "Nothing playing" while audio
was still streaming.

Now await the cancelled task before restarting the loop, ensuring
the finally block completes first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
user
2026-02-22 05:45:00 +01:00
parent 95981275b5
commit 2cd1d5efb1

View File

@@ -537,9 +537,13 @@ async def cmd_stop(bot, message):
task = ps.get("task")
if task and not task.done():
task.cancel()
try:
await task
except (asyncio.CancelledError, Exception):
pass
else:
ps["current"] = None
ps["task"] = None
ps["done_event"] = None
ps["duck_vol"] = None
await bot.reply(message, "Stopped")
@@ -593,14 +597,15 @@ async def cmd_skip(bot, message):
await bot.reply(message, "Nothing playing")
return
skipped = ps["current"]
task = ps.get("task")
if task and not task.done():
task.cancel()
skipped = ps["current"]
ps["current"] = None
ps["task"] = None
ps["duck_vol"] = None
try:
await task
except (asyncio.CancelledError, Exception):
pass
if ps["queue"]:
_ensure_loop(bot)
@@ -657,13 +662,14 @@ async def cmd_seek(bot, message):
# Re-insert current track at front of queue (local_path intact)
ps["queue"].insert(0, track)
# Cancel the play loop
# Cancel the play loop and wait for cleanup
task = ps.get("task")
if task and not task.done():
task.cancel()
ps["current"] = None
ps["task"] = None
ps["duck_vol"] = None
try:
await task
except (asyncio.CancelledError, Exception):
pass
_ensure_loop(bot, seek=target)
await bot.reply(message, f"Seeking to {_fmt_time(target)}")