feat: add SoundRepository and SoundScannerService for audio file management
- Implemented SoundRepository for database operations related to sounds, including methods for retrieving, creating, updating, and deleting sound records. - Developed SoundScannerService to scan directories for audio files, calculate their metadata, and synchronize with the database. - Added support for various audio file formats and integrated ffmpeg for audio duration extraction. - Created comprehensive tests for sound API endpoints and sound scanner service to ensure functionality and error handling. - Updated dependencies to include ffmpeg-python for audio processing.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.v1 import auth, main, socket
|
||||
from app.api.v1 import auth, main, socket, sounds
|
||||
|
||||
# V1 API router with v1 prefix
|
||||
api_router = APIRouter(prefix="/v1")
|
||||
@@ -11,3 +11,4 @@ api_router = APIRouter(prefix="/v1")
|
||||
api_router.include_router(main.router, tags=["main"])
|
||||
api_router.include_router(auth.router, prefix="/auth", tags=["authentication"])
|
||||
api_router.include_router(socket.router, tags=["socket"])
|
||||
api_router.include_router(sounds.router, tags=["sounds"])
|
||||
|
||||
79
app/api/v1/sounds.py
Normal file
79
app/api/v1/sounds.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""Sound management API endpoints."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.dependencies import get_current_active_user_flexible
|
||||
from app.models.user import User
|
||||
from app.services.sound_scanner import ScanResults, SoundScannerService
|
||||
|
||||
router = APIRouter(prefix="/sounds", tags=["sounds"])
|
||||
|
||||
|
||||
async def get_sound_scanner_service(
|
||||
session: Annotated[AsyncSession, Depends(get_db)],
|
||||
) -> SoundScannerService:
|
||||
"""Get the sound scanner service."""
|
||||
return SoundScannerService(session)
|
||||
|
||||
|
||||
@router.post("/scan")
|
||||
async def scan_sounds(
|
||||
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
|
||||
scanner_service: Annotated[SoundScannerService, Depends(get_sound_scanner_service)],
|
||||
) -> dict[str, ScanResults | str]:
|
||||
"""Sync the soundboard directory (add/update/delete sounds)."""
|
||||
# Only allow admins to scan sounds
|
||||
if current_user.role not in ["admin", "superadmin"]:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Only administrators can sync sounds",
|
||||
)
|
||||
|
||||
try:
|
||||
results = await scanner_service.scan_soundboard_directory()
|
||||
return {
|
||||
"message": "Sound sync completed",
|
||||
"results": results,
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to sync sounds: {e!s}",
|
||||
) from e
|
||||
|
||||
|
||||
@router.post("/scan/custom")
|
||||
async def scan_custom_directory(
|
||||
directory: str,
|
||||
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
|
||||
scanner_service: Annotated[SoundScannerService, Depends(get_sound_scanner_service)],
|
||||
sound_type: str = "SDB",
|
||||
) -> dict[str, ScanResults | str]:
|
||||
"""Sync a custom directory with the database (add/update/delete sounds)."""
|
||||
# Only allow admins to sync sounds
|
||||
if current_user.role not in ["admin", "superadmin"]:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Only administrators can sync sounds",
|
||||
)
|
||||
|
||||
try:
|
||||
results = await scanner_service.scan_directory(directory, sound_type)
|
||||
return {
|
||||
"message": f"Sync of directory '{directory}' completed",
|
||||
"results": results,
|
||||
}
|
||||
except ValueError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=str(e),
|
||||
) from e
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to sync directory: {e!s}",
|
||||
) from e
|
||||
Reference in New Issue
Block a user