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