diff --git a/app/api/v1/player.py b/app/api/v1/player.py index fed1fc1..9780448 100644 --- a/app/api/v1/player.py +++ b/app/api/v1/player.py @@ -165,6 +165,40 @@ async def set_volume( ) from e +@router.post("/mute") +async def mute( + current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001 +) -> MessageResponse: + """Mute playback.""" + try: + player = get_player_service() + await player.mute() + return MessageResponse(message="Playback muted") + except Exception as e: + logger.exception("Error muting playback") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to mute playback", + ) from e + + +@router.post("/unmute") +async def unmute( + current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001 +) -> MessageResponse: + """Unmute playback.""" + try: + player = get_player_service() + await player.unmute() + return MessageResponse(message="Playback unmuted") + except Exception as e: + logger.exception("Error unmuting playback") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to unmute playback", + ) from e + + @router.post("/mode") async def set_mode( request: PlayerModeRequest, diff --git a/app/schemas/player.py b/app/schemas/player.py index e1bce17..6c3c3ae 100644 --- a/app/schemas/player.py +++ b/app/schemas/player.py @@ -43,6 +43,7 @@ class PlayerStateResponse(BaseModel): description="Total duration in milliseconds", ) volume: int = Field(description="Current volume (0-100)") + previous_volume: int = Field(description="Previous volume for unmuting (0-100)") mode: str = Field(description="Current playback mode") index: int | None = Field( None, diff --git a/app/services/player.py b/app/services/player.py index ae58877..8fd95dd 100644 --- a/app/services/player.py +++ b/app/services/player.py @@ -47,6 +47,7 @@ class PlayerState: self.status: PlayerStatus = PlayerStatus.STOPPED self.mode: PlayerMode = PlayerMode.CONTINUOUS self.volume: int = 50 + self.previous_volume: int = 50 self.current_sound_id: int | None = None self.current_sound_index: int | None = None self.current_sound_position: int = 0 @@ -64,6 +65,7 @@ class PlayerState: "status": self.status.value, "mode": self.mode.value, "volume": self.volume, + "previous_volume": self.previous_volume, "position": self.current_sound_position or 0, "duration": self.current_sound_duration, "index": self.current_sound_index, @@ -378,12 +380,27 @@ class PlayerService: async def set_volume(self, volume: int) -> None: """Set playback volume (0-100).""" volume = max(0, min(100, volume)) # Clamp to valid range + + # Store previous volume when muting (going from >0 to 0) + if self.state.volume > 0 and volume == 0: + self.state.previous_volume = self.state.volume + self.state.volume = volume self._player.audio_set_volume(volume) await self._broadcast_state() logger.debug("Volume set to: %s", volume) + async def mute(self) -> None: + """Mute the player (stores current volume as previous_volume).""" + if self.state.volume > 0: + await self.set_volume(0) + + async def unmute(self) -> None: + """Unmute the player (restores previous_volume).""" + if self.state.volume == 0 and self.state.previous_volume > 0: + await self.set_volume(self.state.previous_volume) + async def set_mode(self, mode: PlayerMode) -> None: """Set playback mode.""" self.state.mode = mode