Refactor player service to diminish play complexity
All checks were successful
Backend CI / test (push) Successful in 4m53s
All checks were successful
Backend CI / test (push) Successful in 4m53s
This commit is contained in:
@@ -166,20 +166,39 @@ class PlayerService:
|
|||||||
|
|
||||||
async def play(self, index: int | None = None) -> None:
|
async def play(self, index: int | None = None) -> None:
|
||||||
"""Play audio at specified index or current position."""
|
"""Play audio at specified index or current position."""
|
||||||
# Check if we're resuming from pause
|
if self._should_resume_playback(index):
|
||||||
is_resuming = (
|
await self._resume_playback()
|
||||||
|
return
|
||||||
|
|
||||||
|
await self._start_new_track(index)
|
||||||
|
|
||||||
|
def _should_resume_playback(self, index: int | None) -> bool:
|
||||||
|
"""Check if we should resume paused playback."""
|
||||||
|
return (
|
||||||
index is None
|
index is None
|
||||||
and self.state.status == PlayerStatus.PAUSED
|
and self.state.status == PlayerStatus.PAUSED
|
||||||
and self.state.current_sound is not None
|
and self.state.current_sound is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_resuming:
|
async def _resume_playback(self) -> None:
|
||||||
# Simply resume playback
|
"""Resume paused playback."""
|
||||||
result = self._player.play()
|
result = self._player.play()
|
||||||
if result == 0: # VLC returns 0 on success
|
if result == 0: # VLC returns 0 on success
|
||||||
self.state.status = PlayerStatus.PLAYING
|
self.state.status = PlayerStatus.PLAYING
|
||||||
|
self._ensure_play_time_tracking_for_resume()
|
||||||
|
await self._broadcast_state()
|
||||||
|
|
||||||
# Ensure play time tracking is initialized for resumed track
|
sound_name = (
|
||||||
|
self.state.current_sound.name
|
||||||
|
if self.state.current_sound
|
||||||
|
else "Unknown"
|
||||||
|
)
|
||||||
|
logger.info("Resumed playing sound: %s", sound_name)
|
||||||
|
else:
|
||||||
|
logger.error("Failed to resume playback: VLC error code %s", result)
|
||||||
|
|
||||||
|
def _ensure_play_time_tracking_for_resume(self) -> None:
|
||||||
|
"""Ensure play time tracking is initialized for resumed track."""
|
||||||
if (
|
if (
|
||||||
self.state.current_sound_id
|
self.state.current_sound_id
|
||||||
and self.state.current_sound_id not in self._play_time_tracking
|
and self.state.current_sound_id not in self._play_time_tracking
|
||||||
@@ -191,52 +210,85 @@ class PlayerService:
|
|||||||
"threshold_reached": False,
|
"threshold_reached": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
await self._broadcast_state()
|
async def _start_new_track(self, index: int | None) -> None:
|
||||||
logger.info(
|
"""Start playing a new track."""
|
||||||
"Resumed playing sound: %s",
|
if not self._prepare_sound_for_playback(index):
|
||||||
(
|
|
||||||
self.state.current_sound.name
|
|
||||||
if self.state.current_sound
|
|
||||||
else "Unknown"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.error("Failed to resume playback: VLC error code %s", result)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Starting new track or changing track
|
if not self._load_and_play_media():
|
||||||
if index is not None:
|
return
|
||||||
if index < 0 or index >= len(self.state.playlist_sounds):
|
|
||||||
msg = "Invalid sound index"
|
await self._handle_successful_playback()
|
||||||
raise ValueError(msg)
|
|
||||||
self.state.current_sound_index = index
|
def _prepare_sound_for_playback(self, index: int | None) -> bool:
|
||||||
self.state.current_sound = self.state.playlist_sounds[index]
|
"""Prepare sound for playback, return True if ready."""
|
||||||
self.state.current_sound_id = self.state.current_sound.id
|
if index is not None and not self._set_sound_by_index(index):
|
||||||
|
return False
|
||||||
|
|
||||||
if not self.state.current_sound:
|
if not self.state.current_sound:
|
||||||
logger.warning("No sound to play")
|
logger.warning("No sound to play")
|
||||||
return
|
return False
|
||||||
|
|
||||||
|
return self._validate_sound_file()
|
||||||
|
|
||||||
|
def _set_sound_by_index(self, index: int) -> bool:
|
||||||
|
"""Set current sound by index, return True if valid."""
|
||||||
|
if index < 0 or index >= len(self.state.playlist_sounds):
|
||||||
|
msg = "Invalid sound index"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
self.state.current_sound_index = index
|
||||||
|
self.state.current_sound = self.state.playlist_sounds[index]
|
||||||
|
self.state.current_sound_id = self.state.current_sound.id
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _validate_sound_file(self) -> bool:
|
||||||
|
"""Validate sound file exists, return True if valid."""
|
||||||
|
if not self.state.current_sound:
|
||||||
|
return False
|
||||||
|
|
||||||
# Get sound file path
|
|
||||||
sound_path = get_sound_file_path(self.state.current_sound)
|
sound_path = get_sound_file_path(self.state.current_sound)
|
||||||
if not sound_path.exists():
|
if not sound_path.exists():
|
||||||
logger.error("Sound file not found: %s", sound_path)
|
logger.error("Sound file not found: %s", sound_path)
|
||||||
return
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
# Load and play media (new track)
|
def _load_and_play_media(self) -> bool:
|
||||||
|
"""Load media and start playback, return True if successful."""
|
||||||
if self._vlc_instance is None:
|
if self._vlc_instance is None:
|
||||||
logger.error("VLC instance is not initialized. Cannot play media.")
|
logger.error("VLC instance is not initialized. Cannot play media.")
|
||||||
return
|
return False
|
||||||
|
|
||||||
|
if not self.state.current_sound:
|
||||||
|
logger.error("No current sound to play")
|
||||||
|
return False
|
||||||
|
|
||||||
|
sound_path = get_sound_file_path(self.state.current_sound)
|
||||||
media = self._vlc_instance.media_new(str(sound_path))
|
media = self._vlc_instance.media_new(str(sound_path))
|
||||||
self._player.set_media(media)
|
self._player.set_media(media)
|
||||||
|
|
||||||
result = self._player.play()
|
result = self._player.play()
|
||||||
if result == 0: # VLC returns 0 on success
|
if result != 0: # VLC returns 0 on success
|
||||||
|
logger.error("Failed to start playback: VLC error code %s", result)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def _handle_successful_playback(self) -> None:
|
||||||
|
"""Handle successful playback start."""
|
||||||
|
if not self.state.current_sound:
|
||||||
|
logger.error("No current sound for successful playback")
|
||||||
|
return
|
||||||
|
|
||||||
self.state.status = PlayerStatus.PLAYING
|
self.state.status = PlayerStatus.PLAYING
|
||||||
self.state.current_sound_duration = self.state.current_sound.duration or 0
|
self.state.current_sound_duration = self.state.current_sound.duration or 0
|
||||||
|
|
||||||
# Initialize play time tracking for new track
|
self._initialize_play_time_tracking()
|
||||||
|
await self._broadcast_state()
|
||||||
|
logger.info("Started playing sound: %s", self.state.current_sound.name)
|
||||||
|
|
||||||
|
def _initialize_play_time_tracking(self) -> None:
|
||||||
|
"""Initialize play time tracking for new track."""
|
||||||
if self.state.current_sound_id:
|
if self.state.current_sound_id:
|
||||||
self._play_time_tracking[self.state.current_sound_id] = {
|
self._play_time_tracking[self.state.current_sound_id] = {
|
||||||
"total_time": 0,
|
"total_time": 0,
|
||||||
@@ -250,11 +302,6 @@ class PlayerService:
|
|||||||
self.state.current_sound_duration,
|
self.state.current_sound_duration,
|
||||||
)
|
)
|
||||||
|
|
||||||
await self._broadcast_state()
|
|
||||||
logger.info("Started playing sound: %s", self.state.current_sound.name)
|
|
||||||
else:
|
|
||||||
logger.error("Failed to start playback: VLC error code %s", result)
|
|
||||||
|
|
||||||
async def pause(self) -> None:
|
async def pause(self) -> None:
|
||||||
"""Pause playback."""
|
"""Pause playback."""
|
||||||
if self.state.status == PlayerStatus.PLAYING:
|
if self.state.status == PlayerStatus.PLAYING:
|
||||||
|
|||||||
Reference in New Issue
Block a user