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:
@@ -537,10 +537,14 @@ async def cmd_stop(bot, message):
|
||||
task = ps.get("task")
|
||||
if task and not task.done():
|
||||
task.cancel()
|
||||
ps["current"] = None
|
||||
ps["task"] = None
|
||||
ps["done_event"] = None
|
||||
ps["duck_vol"] = None
|
||||
try:
|
||||
await task
|
||||
except (asyncio.CancelledError, Exception):
|
||||
pass
|
||||
else:
|
||||
ps["current"] = None
|
||||
ps["task"] = 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)}")
|
||||
|
||||
Reference in New Issue
Block a user