feat: Add VLC player API endpoints and associated tests
- Implemented VLC player API endpoints for playing and stopping sounds. - Added tests for successful playback, error handling, and authentication scenarios. - Created utility function to get sound file paths based on sound properties. - Refactored player service to utilize shared sound path utility. - Enhanced test coverage for sound file path utility with various sound types. - Introduced tests for VLC player service, including subprocess handling and play count tracking.
This commit is contained in:
@@ -9,15 +9,14 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import vlc # type: ignore[import-untyped]
|
||||
from sqlmodel import select
|
||||
|
||||
from app.core.logging import get_logger
|
||||
from app.models.sound import Sound
|
||||
from app.models.sound_played import SoundPlayed
|
||||
from app.repositories.playlist import PlaylistRepository
|
||||
from app.repositories.sound import SoundRepository
|
||||
from app.repositories.user import UserRepository
|
||||
from app.services.socket import socket_manager
|
||||
from app.utils.audio import get_sound_file_path
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -198,7 +197,7 @@ class PlayerService:
|
||||
return
|
||||
|
||||
# Get sound file path
|
||||
sound_path = self._get_sound_file_path(self.state.current_sound)
|
||||
sound_path = get_sound_file_path(self.state.current_sound)
|
||||
if not sound_path.exists():
|
||||
logger.error("Sound file not found: %s", sound_path)
|
||||
return
|
||||
@@ -344,6 +343,12 @@ class PlayerService:
|
||||
if self.state.status != PlayerStatus.STOPPED:
|
||||
await self._stop_playback()
|
||||
|
||||
# Set first track as current if no current track and playlist has sounds
|
||||
if not self.state.current_sound_id and sounds:
|
||||
self.state.current_sound_index = 0
|
||||
self.state.current_sound = sounds[0]
|
||||
self.state.current_sound_id = sounds[0].id
|
||||
|
||||
logger.info(
|
||||
"Loaded playlist: %s (%s sounds)",
|
||||
current_playlist.name,
|
||||
@@ -360,21 +365,6 @@ class PlayerService:
|
||||
"""Get current player state."""
|
||||
return self.state.to_dict()
|
||||
|
||||
def _get_sound_file_path(self, sound: Sound) -> Path:
|
||||
"""Get the file path for a sound."""
|
||||
# Determine the correct subdirectory based on sound type
|
||||
subdir = "extracted" if sound.type.upper() == "EXT" else sound.type.lower()
|
||||
|
||||
# Use normalized file if available, otherwise original
|
||||
if sound.is_normalized and sound.normalized_filename:
|
||||
return (
|
||||
Path("sounds/normalized")
|
||||
/ subdir
|
||||
/ sound.normalized_filename
|
||||
)
|
||||
return (
|
||||
Path("sounds/originals") / subdir / sound.filename
|
||||
)
|
||||
|
||||
def _get_next_index(self, current_index: int) -> int | None:
|
||||
"""Get next track index based on current mode."""
|
||||
@@ -501,7 +491,6 @@ class PlayerService:
|
||||
session = self.db_session_factory()
|
||||
try:
|
||||
sound_repo = SoundRepository(session)
|
||||
user_repo = UserRepository(session)
|
||||
|
||||
# Update sound play count
|
||||
sound = await sound_repo.get_by_id(sound_id)
|
||||
@@ -519,37 +508,17 @@ class PlayerService:
|
||||
else:
|
||||
logger.warning("Sound %s not found for play count update", sound_id)
|
||||
|
||||
# Record play history for admin user (ID 1) as placeholder
|
||||
# This could be refined to track per-user play history
|
||||
admin_user = await user_repo.get_by_id(1)
|
||||
if admin_user:
|
||||
# Check if already recorded for this user using proper query
|
||||
stmt = select(SoundPlayed).where(
|
||||
SoundPlayed.user_id == admin_user.id,
|
||||
SoundPlayed.sound_id == sound_id,
|
||||
)
|
||||
result = await session.exec(stmt)
|
||||
existing = result.first()
|
||||
|
||||
if not existing:
|
||||
sound_played = SoundPlayed(
|
||||
user_id=admin_user.id,
|
||||
sound_id=sound_id,
|
||||
)
|
||||
session.add(sound_played)
|
||||
logger.info(
|
||||
"Created SoundPlayed record for user %s, sound %s",
|
||||
admin_user.id,
|
||||
sound_id,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"SoundPlayed record already exists for user %s, sound %s",
|
||||
admin_user.id,
|
||||
sound_id,
|
||||
)
|
||||
else:
|
||||
logger.warning("Admin user (ID 1) not found for play history")
|
||||
# Record play history without user_id for player-based plays
|
||||
# Always create a new SoundPlayed record for each play event
|
||||
sound_played = SoundPlayed(
|
||||
user_id=None, # No user_id for player-based plays
|
||||
sound_id=sound_id,
|
||||
)
|
||||
session.add(sound_played)
|
||||
logger.info(
|
||||
"Created SoundPlayed record for player play, sound %s",
|
||||
sound_id,
|
||||
)
|
||||
|
||||
await session.commit()
|
||||
logger.info("Successfully recorded play count for sound %s", sound_id)
|
||||
|
||||
Reference in New Issue
Block a user