feat: Implement sound playback with credit validation in VLCPlayerService and update WebSocket handling
This commit is contained in:
@@ -111,20 +111,28 @@ class SocketManager:
|
||||
sound_id = data.get("sound_id")
|
||||
if not sound_id:
|
||||
logger.warning(
|
||||
"Play sound request missing sound_id from user %s", user_id,
|
||||
"Play sound request missing sound_id from user %s",
|
||||
user_id,
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
# Import here to avoid circular imports
|
||||
from app.api.v1.sounds import play_sound_internal
|
||||
from app.services.vlc_player import get_vlc_player_service
|
||||
from app.core.database import get_session_factory
|
||||
|
||||
# Call the internal play sound function
|
||||
await play_sound_internal(int(sound_id), user_id)
|
||||
# Get VLC player service with database factory
|
||||
vlc_player = get_vlc_player_service(get_session_factory())
|
||||
|
||||
# Call the service method
|
||||
await vlc_player.play_sound_with_credits(int(sound_id), int(user_id))
|
||||
logger.info("User %s played sound %s via WebSocket", user_id, sound_id)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
"Error playing sound %s for user %s: %s", sound_id, user_id, e,
|
||||
"Error playing sound %s for user %s: %s",
|
||||
sound_id,
|
||||
user_id,
|
||||
e,
|
||||
)
|
||||
# Emit error back to user
|
||||
await self.sio.emit(
|
||||
|
||||
@@ -9,6 +9,7 @@ from typing import Any
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from app.core.logging import get_logger
|
||||
from app.models.credit_action import CreditActionType
|
||||
from app.models.sound import Sound
|
||||
from app.models.sound_played import SoundPlayed
|
||||
from app.repositories.sound import SoundRepository
|
||||
@@ -307,6 +308,89 @@ class VLCPlayerService:
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
async def play_sound_with_credits(
|
||||
self, sound_id: int, user_id: int
|
||||
) -> dict[str, str | int | bool]:
|
||||
"""Play sound with VLC with credit validation and deduction.
|
||||
|
||||
This method combines credit checking, sound playing, and credit deduction
|
||||
in a single operation. Used by both HTTP and WebSocket endpoints.
|
||||
|
||||
Args:
|
||||
sound_id: ID of the sound to play
|
||||
user_id: ID of the user playing the sound
|
||||
|
||||
Returns:
|
||||
dict: Result information including success status and message
|
||||
|
||||
Raises:
|
||||
HTTPException: For various error conditions (sound not found,
|
||||
insufficient credits, VLC failure)
|
||||
"""
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
from app.services.credit import CreditService, InsufficientCreditsError
|
||||
|
||||
if not self.db_session_factory:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Database session factory not configured",
|
||||
)
|
||||
|
||||
async with self.db_session_factory() as session:
|
||||
sound_repo = SoundRepository(session)
|
||||
|
||||
# Get the sound
|
||||
sound = await sound_repo.get_by_id(sound_id)
|
||||
if not sound:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Sound with ID {sound_id} not found",
|
||||
)
|
||||
|
||||
# Get credit service
|
||||
credit_service = CreditService(self.db_session_factory)
|
||||
|
||||
# Check and validate credits before playing
|
||||
try:
|
||||
await credit_service.validate_and_reserve_credits(
|
||||
user_id,
|
||||
CreditActionType.VLC_PLAY_SOUND,
|
||||
)
|
||||
except InsufficientCreditsError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_402_PAYMENT_REQUIRED,
|
||||
detail=(
|
||||
f"Insufficient credits: {e.required} required, "
|
||||
f"{e.available} available"
|
||||
),
|
||||
) from e
|
||||
|
||||
# Play the sound using VLC
|
||||
success = await self.play_sound(sound)
|
||||
|
||||
# Deduct credits based on success
|
||||
await credit_service.deduct_credits(
|
||||
user_id,
|
||||
CreditActionType.VLC_PLAY_SOUND,
|
||||
success=success,
|
||||
metadata={"sound_id": sound_id, "sound_name": sound.name},
|
||||
)
|
||||
|
||||
if not success:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to launch VLC for sound playback",
|
||||
)
|
||||
|
||||
return {
|
||||
"message": f"Sound '{sound.name}' is now playing via VLC",
|
||||
"sound_id": sound_id,
|
||||
"sound_name": sound.name,
|
||||
"success": True,
|
||||
"credits_deducted": 1,
|
||||
}
|
||||
|
||||
|
||||
# Global VLC player service instance
|
||||
vlc_player_service: VLCPlayerService | None = None
|
||||
|
||||
Reference in New Issue
Block a user