fix: preserve plays when skipping tracks
This commit is contained in:
4 files changed
+35
-5
No files matched your search
@@ -50,6 +50,7 @@ class MusicPlayer:
|
||||
self._queues = queues
|
||||
self._states: dict[int, GuildMusicState] = {}
|
||||
self._playback_tokens: dict[int, int] = {}
|
||||
self._interrupted_playbacks: set[int] = set()
|
||||
self.on_state_change: StateChangeHook | None = None
|
||||
|
||||
# --- Stan ---------------------------------------------------------------
|
||||
@@ -94,6 +95,7 @@ class MusicPlayer:
|
||||
|
||||
def clear(self, guild_id: int) -> None:
|
||||
self._playback_tokens[guild_id] = self._playback_tokens.get(guild_id, 0) + 1
|
||||
self._interrupted_playbacks.discard(guild_id)
|
||||
self.state(guild_id).reset()
|
||||
|
||||
def has_saved_queue(self, guild_id: int) -> bool:
|
||||
@@ -121,6 +123,13 @@ class MusicPlayer:
|
||||
if current is state.current:
|
||||
current.plays_left = max(self.plays_left(current, guild_id) - 1, 0)
|
||||
|
||||
def skip(self, guild_id: int) -> None:
|
||||
"""Stop the current source without consuming a play."""
|
||||
voice_client = self.voice_client(guild_id)
|
||||
if voice_client and (voice_client.is_playing() or voice_client.is_paused()):
|
||||
self._interrupted_playbacks.add(guild_id)
|
||||
voice_client.stop()
|
||||
|
||||
async def restore_queue(self, guild_id: int) -> int:
|
||||
if not self._queues:
|
||||
return 0
|
||||
@@ -128,6 +137,7 @@ class MusicPlayer:
|
||||
state = self.state(guild_id)
|
||||
playback_token = self._playback_tokens.get(guild_id, 0) + 1
|
||||
self._playback_tokens[guild_id] = playback_token
|
||||
self._interrupted_playbacks.discard(guild_id)
|
||||
voice_client = self.voice_client(guild_id)
|
||||
if voice_client and (voice_client.is_playing() or voice_client.is_paused()):
|
||||
voice_client.stop()
|
||||
@@ -272,13 +282,20 @@ class MusicPlayer:
|
||||
async def _restart_playback(self, guild_id: int) -> None:
|
||||
voice_client = self.voice_client(guild_id)
|
||||
if voice_client and (voice_client.is_playing() or voice_client.is_paused()):
|
||||
self._interrupted_playbacks.add(guild_id)
|
||||
voice_client.stop() # `after` wywoła play_next, flaga przeskoku zablokuje advance
|
||||
else:
|
||||
await self.play_next(guild_id, advance=False)
|
||||
|
||||
# --- Odtwarzanie --------------------------------------------------------
|
||||
|
||||
async def play_next(self, guild_id: int, advance: bool = True, _failures: int = 0) -> None:
|
||||
async def play_next(
|
||||
self,
|
||||
guild_id: int,
|
||||
advance: bool = True,
|
||||
_failures: int = 0,
|
||||
consume_current: bool = True,
|
||||
) -> None:
|
||||
"""Przechodzi do kolejnego utworu; ``_failures`` chroni przed pętlą pomijania."""
|
||||
state = self.state(guild_id)
|
||||
playback_token = self._playback_tokens.get(guild_id, 0)
|
||||
@@ -290,7 +307,7 @@ class MusicPlayer:
|
||||
if state.consume_jump():
|
||||
advance = False
|
||||
|
||||
if advance:
|
||||
if advance and consume_current:
|
||||
self.finish_current(guild_id)
|
||||
|
||||
# Utwór z ostatnim odtworzeniem musi pozostać w kolejce do chwili
|
||||
@@ -390,9 +407,13 @@ class MusicPlayer:
|
||||
def _schedule_next(self, guild_id: int, error: Exception | None, playback_token: int) -> None:
|
||||
if self._playback_tokens.get(guild_id) != playback_token:
|
||||
return
|
||||
consume_current = guild_id not in self._interrupted_playbacks
|
||||
self._interrupted_playbacks.discard(guild_id)
|
||||
if error:
|
||||
logger.error("Odtwarzanie zakończone błędem na serwerze %s: %s", guild_id, error)
|
||||
asyncio.run_coroutine_threadsafe(self.play_next(guild_id, advance=True), self._bot.loop)
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.play_next(guild_id, advance=True, consume_current=consume_current), self._bot.loop
|
||||
)
|
||||
|
||||
def _record_history(self, guild_id: int, track: YTDLSource) -> None:
|
||||
if not track.title:
|
||||
|
||||
@@ -122,7 +122,7 @@ async def skip(
|
||||
if not player.is_active(guild.id):
|
||||
raise HTTPException(status_code=400, detail="Bot is not playing anything on this server")
|
||||
|
||||
player.voice_client(guild.id).stop()
|
||||
player.skip(guild.id)
|
||||
await broadcaster.broadcast()
|
||||
return {"status": "skipped"}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class ControlCog(MusicCogBase, name="Control"):
|
||||
if not self.player.is_active(guild_id):
|
||||
await interaction.response.send_message("Nic nie jest odtwarzane.", ephemeral=True)
|
||||
return
|
||||
interaction.guild.voice_client.stop()
|
||||
self.player.skip(guild_id)
|
||||
await self.player.trigger_state_change()
|
||||
await interaction.response.send_message("Pominięto aktualny utwór.")
|
||||
|
||||
|
||||
Reference in new issue
Block a user