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

133 lines
4.9 KiB
Python

import logging
from fastapi import APIRouter, Depends, HTTPException
from api.v1.schemas.settings import (
LastFmAuthTokenResponse,
LastFmAuthSessionRequest,
LastFmAuthSessionResponse,
LastFmConnectionSettings,
LASTFM_SECRET_MASK,
)
from core.dependencies import (
get_lastfm_auth_service,
get_lastfm_repository,
get_preferences_service,
clear_lastfm_dependent_caches,
)
from core.exceptions import ConfigurationError, ExternalServiceError, TokenNotAuthorizedError
from infrastructure.msgspec_fastapi import MsgSpecBody, MsgSpecRoute
from services.lastfm_auth_service import LastFmAuthService
from services.preferences_service import PreferencesService
logger = logging.getLogger(__name__)
router = APIRouter(route_class=MsgSpecRoute, prefix="/lastfm", tags=["lastfm"])
@router.post("/auth/token", response_model=LastFmAuthTokenResponse)
async def request_auth_token(
auth_service: LastFmAuthService = Depends(get_lastfm_auth_service),
preferences_service: PreferencesService = Depends(get_preferences_service),
):
try:
settings = preferences_service.get_lastfm_connection()
if not settings.api_key or not settings.shared_secret:
raise HTTPException(
status_code=400,
detail="Add a Last.fm API key and shared secret first",
)
token, auth_url = await auth_service.request_token(settings.api_key)
logger.info(
"Last.fm auth token requested",
extra={"step": "token_requested", "status": "success"},
)
return LastFmAuthTokenResponse(token=token, auth_url=auth_url)
except HTTPException:
raise
except ConfigurationError as e:
logger.warning(
"Last.fm auth token request failed (config): %s",
e,
extra={"step": "token_requested", "status": "config_error"},
)
raise HTTPException(status_code=400, detail="Last.fm settings are incomplete or invalid")
except ExternalServiceError as e:
logger.warning(
"Last.fm auth token request failed (external): %s",
e,
extra={"step": "token_requested", "status": "external_error"},
)
raise HTTPException(status_code=502, detail="Couldn't reach Last.fm for a sign-in token")
@router.post("/auth/session", response_model=LastFmAuthSessionResponse)
async def exchange_auth_session(
request: LastFmAuthSessionRequest = MsgSpecBody(LastFmAuthSessionRequest),
auth_service: LastFmAuthService = Depends(get_lastfm_auth_service),
preferences_service: PreferencesService = Depends(get_preferences_service),
):
try:
username, session_key, _ = await auth_service.exchange_session(request.token)
settings = preferences_service.get_lastfm_connection()
updated = LastFmConnectionSettings(
api_key=settings.api_key,
shared_secret=settings.shared_secret,
session_key=session_key,
username=username,
enabled=settings.enabled,
)
preferences_service.save_lastfm_connection(updated)
get_lastfm_repository.cache_clear()
get_lastfm_auth_service.cache_clear()
clear_lastfm_dependent_caches()
logger.info(
"Last.fm session exchanged for user %s",
username,
extra={"step": "session_exchanged", "status": "success"},
)
return LastFmAuthSessionResponse(
username=username,
success=True,
message=f"Connected as {username}",
)
except TokenNotAuthorizedError:
message = "Last.fm access hasn't been approved yet. Authorize it in the Last.fm tab, then try again."
error_code = "token_not_authorized"
logger.warning(
"Last.fm session exchange failed: token not authorized",
extra={
"step": "session_exchanged",
"status": "token_not_authorized",
"error_code": error_code,
},
)
raise HTTPException(status_code=502, detail=message)
except ExternalServiceError as e:
message = "Couldn't finish the Last.fm sign-in. Please try again."
error_code = "external_error"
logger.warning(
"Last.fm session exchange failed: %s",
e,
extra={
"step": "session_exchanged",
"status": "external_error",
"error_code": error_code,
},
)
raise HTTPException(status_code=502, detail=message)
except ConfigurationError as e:
logger.warning(
"Last.fm session exchange rejected: %s",
e,
extra={
"step": "session_exchanged",
"status": "configuration_error",
"error_code": "configuration_error",
},
)
raise HTTPException(status_code=422, detail="Last.fm configuration error. Check your settings and try again.")