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

135 lines
5.0 KiB
Python

import logging
from typing import Literal
from fastapi import APIRouter, Depends, HTTPException, Query
from api.v1.schemas.jellyfin import (
JellyfinAlbumDetail,
JellyfinAlbumMatch,
JellyfinAlbumSummary,
JellyfinArtistSummary,
JellyfinLibraryStats,
JellyfinPaginatedResponse,
JellyfinSearchResponse,
JellyfinTrackInfo,
)
from core.dependencies import get_jellyfin_library_service
from core.exceptions import ExternalServiceError
from infrastructure.msgspec_fastapi import MsgSpecRoute
from services.jellyfin_library_service import JellyfinLibraryService
logger = logging.getLogger(__name__)
router = APIRouter(route_class=MsgSpecRoute, prefix="/jellyfin", tags=["jellyfin-library"])
@router.get("/albums", response_model=JellyfinPaginatedResponse)
async def get_jellyfin_albums(
limit: int = Query(default=50, ge=1, le=200),
offset: int = Query(default=0, ge=0),
sort_by: Literal["SortName", "DateCreated", "PlayCount", "ProductionYear"] = Query(default="SortName"),
sort_order: Literal["Ascending", "Descending"] = Query(default="Ascending"),
genre: str | None = Query(default=None),
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> JellyfinPaginatedResponse:
try:
items, total = await service.get_albums(
limit=limit, offset=offset, sort_by=sort_by, sort_order=sort_order, genre=genre
)
return JellyfinPaginatedResponse(
items=items, total=total, offset=offset, limit=limit
)
except ExternalServiceError as e:
logger.error("Jellyfin service error getting albums: %s", e)
raise HTTPException(status_code=502, detail="Failed to communicate with Jellyfin")
@router.get("/albums/{album_id}", response_model=JellyfinAlbumDetail)
async def get_jellyfin_album_detail(
album_id: str,
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> JellyfinAlbumDetail:
result = await service.get_album_detail(album_id)
if not result:
raise HTTPException(status_code=404, detail="Album not found")
return result
@router.get(
"/albums/{album_id}/tracks", response_model=list[JellyfinTrackInfo]
)
async def get_jellyfin_album_tracks(
album_id: str,
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> list[JellyfinTrackInfo]:
try:
return await service.get_album_tracks(album_id)
except ExternalServiceError as e:
logger.error("Jellyfin service error getting album tracks %s: %s", album_id, e)
raise HTTPException(status_code=502, detail="Failed to communicate with Jellyfin")
@router.get(
"/albums/match/{musicbrainz_id}", response_model=JellyfinAlbumMatch
)
async def match_jellyfin_album(
musicbrainz_id: str,
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> JellyfinAlbumMatch:
try:
return await service.match_album_by_mbid(musicbrainz_id)
except ExternalServiceError as e:
logger.error("Failed to match Jellyfin album %s: %s", musicbrainz_id, e)
raise HTTPException(status_code=502, detail="Failed to match Jellyfin album")
@router.get("/artists", response_model=list[JellyfinArtistSummary])
async def get_jellyfin_artists(
limit: int = Query(default=50, ge=1, le=200),
offset: int = Query(default=0, ge=0),
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> list[JellyfinArtistSummary]:
return await service.get_artists(limit=limit, offset=offset)
@router.get("/search", response_model=JellyfinSearchResponse)
async def search_jellyfin(
q: str = Query(..., min_length=1),
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> JellyfinSearchResponse:
return await service.search(q)
@router.get("/recent", response_model=list[JellyfinAlbumSummary])
async def get_jellyfin_recent(
limit: int = Query(default=20, ge=1, le=50),
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> list[JellyfinAlbumSummary]:
return await service.get_recently_played(limit=limit)
@router.get("/favorites", response_model=list[JellyfinAlbumSummary])
async def get_jellyfin_favorites(
limit: int = Query(default=20, ge=1, le=50),
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> list[JellyfinAlbumSummary]:
return await service.get_favorites(limit=limit)
@router.get("/genres", response_model=list[str])
async def get_jellyfin_genres(
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> list[str]:
try:
return await service.get_genres()
except ExternalServiceError as e:
logger.error("Jellyfin service error getting genres: %s", e)
raise HTTPException(status_code=502, detail="Failed to communicate with Jellyfin")
@router.get("/stats", response_model=JellyfinLibraryStats)
async def get_jellyfin_stats(
service: JellyfinLibraryService = Depends(get_jellyfin_library_service),
) -> JellyfinLibraryStats:
return await service.get_stats()