From 2e464dc977b0ea20459f4b84b22bd51cff671565 Mon Sep 17 00:00:00 2001 From: JSC Date: Tue, 8 Jul 2025 13:36:51 +0200 Subject: [PATCH] feat: Enhance track ending detection and handling in MusicPlayerService --- app/services/music_player_service.py | 60 ++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/app/services/music_player_service.py b/app/services/music_player_service.py index 333ad0a..f3f9bf5 100644 --- a/app/services/music_player_service.py +++ b/app/services/music_player_service.py @@ -38,10 +38,11 @@ class MusicPlayerService: self.current_time = 0 self.duration = 0 self.last_sync_time = 0 - self.sync_interval = 1.0 # seconds + self.sync_interval = 0.5 # seconds (increased frequency to catch track endings) self.lock = threading.Lock() self._sync_thread = None self._stop_sync = False + self._track_ending_handled = False # Flag to prevent duplicate ending triggers def start_vlc_instance(self) -> bool: """Start a VLC instance with Python bindings.""" @@ -183,6 +184,8 @@ class MusicPlayerService: if media: self.player.set_media(media) self.current_track_index = index + # Reset track ending flag when loading a new track + self._track_ending_handled = False return True return False except Exception as e: @@ -229,6 +232,9 @@ class MusicPlayerService: if not self.player: return False + # Reset track ending flag when starting playback + self._track_ending_handled = False + result = self.player.play() if result == 0: # Success self.is_playing = True @@ -521,17 +527,47 @@ class MusicPlayerService: # Get volume self.volume = self.player.audio_get_volume() - # Check if track ended and handle auto-advance - if state == vlc.State.Ended and self.play_mode in [ - "continuous", - "loop-playlist", - "random", - ]: - self.next_track() - elif state == vlc.State.Ended and self.play_mode == "loop-one": - # Restart the same track - self.player.set_position(0) - self.play() + # Enhanced track ending detection + track_ended = False + + # Check for ended state + if state == vlc.State.Ended: + track_ended = True + logger.info(f"Track ended via VLC State.Ended, mode: {self.play_mode}") + + # Also check if we're very close to the end (within 500ms) and not playing + elif (self.duration > 0 and self.current_time > 0 and + self.current_time >= (self.duration - 500) and + not self.is_playing and old_playing): + track_ended = True + logger.info(f"Track ended via time check, mode: {self.play_mode}") + + # Handle track ending based on play mode (only if not already handled) + if track_ended and not self._track_ending_handled: + self._track_ending_handled = True + + if self.play_mode == "loop-one": + logger.info("Restarting track for loop-one mode") + # Stop first, then reload and play + self.player.stop() + # Reload the current track + if (self.current_track_index < len(self.playlist_files)): + media = self.instance.media_new( + self.playlist_files[self.current_track_index] + ) + self.player.set_media(media) + self.player.play() + # Reset the flag after a short delay to allow for new track + self._track_ending_handled = False + elif self.play_mode in ["continuous", "loop-playlist", "random"]: + logger.info(f"Advancing to next track for {self.play_mode} mode") + self.next_track() + # Reset the flag after track change + self._track_ending_handled = False + + # Reset the flag if we're playing again (new track started) + elif self.is_playing and not old_playing: + self._track_ending_handled = False # Emit updates if state changed significantly or periodically state_changed = (