Files
musicseerr/backend/api/v1/routes/local_library.py
T
2026-04-03 15:53:00 +01:00

102 lines
3.6 KiB
Python

import logging
from typing import Literal
from fastapi import APIRouter, Depends, HTTPException, Query
from api.v1.schemas.local_files import (
LocalAlbumMatch,
LocalAlbumSummary,
LocalPaginatedResponse,
LocalStorageStats,
LocalTrackInfo,
)
from core.dependencies import get_local_files_service
from core.exceptions import ExternalServiceError
from infrastructure.msgspec_fastapi import MsgSpecRoute
from services.local_files_service import LocalFilesService
logger = logging.getLogger(__name__)
router = APIRouter(route_class=MsgSpecRoute, prefix="/local", tags=["local-files"])
@router.get("/albums", response_model=LocalPaginatedResponse)
async def get_local_albums(
limit: int = Query(default=50, ge=1, le=200),
offset: int = Query(default=0, ge=0),
sort_by: Literal["name", "date_added", "year"] = "name",
sort_order: Literal["asc", "desc"] = Query(default="asc"),
q: str | None = Query(default=None, min_length=1),
service: LocalFilesService = Depends(get_local_files_service),
) -> LocalPaginatedResponse:
try:
return await service.get_albums(
limit=limit, offset=offset, sort_by=sort_by, sort_order=sort_order, search_query=q
)
except ExternalServiceError as e:
logger.error("Failed to get local albums: %s", e)
raise HTTPException(status_code=502, detail="Failed to get local albums")
@router.get("/albums/match/{musicbrainz_id}", response_model=LocalAlbumMatch)
async def match_local_album(
musicbrainz_id: str,
service: LocalFilesService = Depends(get_local_files_service),
) -> LocalAlbumMatch:
try:
return await service.match_album_by_mbid(musicbrainz_id)
except ExternalServiceError as e:
logger.error("Failed to match local album %s: %s", musicbrainz_id, e)
raise HTTPException(status_code=502, detail="Failed to match local album")
@router.get(
"/albums/{album_id}/tracks", response_model=list[LocalTrackInfo]
)
async def get_local_album_tracks(
album_id: int,
service: LocalFilesService = Depends(get_local_files_service),
) -> list[LocalTrackInfo]:
try:
return await service.get_album_tracks_by_id(album_id)
except ExternalServiceError as e:
logger.error("Failed to get local album tracks %d: %s", album_id, e)
raise HTTPException(
status_code=502, detail="Failed to get local album tracks"
)
@router.get("/search", response_model=list[LocalAlbumSummary])
async def search_local(
q: str = Query(min_length=1),
service: LocalFilesService = Depends(get_local_files_service),
) -> list[LocalAlbumSummary]:
try:
return await service.search(q)
except ExternalServiceError as e:
logger.error("Failed to search local files: %s", e)
raise HTTPException(
status_code=502, detail="Failed to search local files"
)
@router.get("/recent", response_model=list[LocalAlbumSummary])
async def get_local_recent(
limit: int = Query(default=20, ge=1, le=50),
service: LocalFilesService = Depends(get_local_files_service),
) -> list[LocalAlbumSummary]:
try:
return await service.get_recently_added(limit=limit)
except ExternalServiceError as e:
logger.error("Failed to get recent local albums: %s", e)
raise HTTPException(
status_code=502, detail="Failed to get recent local albums"
)
@router.get("/stats", response_model=LocalStorageStats)
async def get_local_stats(
service: LocalFilesService = Depends(get_local_files_service),
) -> LocalStorageStats:
return await service.get_storage_stats()