Files
musicseerr/backend/services/request_service.py
T
Harvey 343bafd7f4 feat: Requests / Add to Library Rework - Unmonitored album default + … (#25)
* feat: Requests / Add to Library Rework - Unmonitored album default + Resilience

* checking for source + refresh album logic

* artist monitoring + auto downloading + various request fixes

* synchronous album requests

* format
2026-04-06 23:08:58 +01:00

100 lines
4.1 KiB
Python

import logging
from repositories.protocols import LidarrRepositoryProtocol
from infrastructure.queue.request_queue import RequestQueue
from infrastructure.persistence.request_history import RequestHistoryStore
from api.v1.schemas.request import QueueStatusResponse, RequestAcceptedResponse
from core.exceptions import ExternalServiceError
logger = logging.getLogger(__name__)
class RequestService:
def __init__(
self,
lidarr_repo: LidarrRepositoryProtocol,
request_queue: RequestQueue,
request_history: RequestHistoryStore,
):
self._lidarr_repo = lidarr_repo
self._request_queue = request_queue
self._request_history = request_history
async def request_album(
self,
musicbrainz_id: str,
artist: str | None = None,
album: str | None = None,
year: int | None = None,
artist_mbid: str | None = None,
monitor_artist: bool = False,
auto_download_artist: bool = False,
) -> RequestAcceptedResponse:
if not self._lidarr_repo.is_configured():
raise ExternalServiceError("Lidarr isn't configured. Add an API key in Settings before requesting albums.")
try:
# Don't overwrite an active record (pending/downloading) — just re-check the queue.
existing = await self._request_history.async_get_record(musicbrainz_id)
if existing and existing.status in ("pending", "downloading"):
# Merge monitoring flags if the user updated their choice on re-request
if monitor_artist and not existing.monitor_artist:
await self._request_history.async_update_monitoring_flags(
musicbrainz_id, monitor_artist=True, auto_download_artist=auto_download_artist,
)
enqueued = await self._request_queue.enqueue(musicbrainz_id)
return RequestAcceptedResponse(
success=True,
message="Request already in progress",
musicbrainz_id=musicbrainz_id,
status=existing.status,
)
await self._request_history.async_record_request(
musicbrainz_id=musicbrainz_id,
artist_name=artist or "Unknown",
album_title=album or "Unknown",
year=year,
artist_mbid=artist_mbid,
monitor_artist=monitor_artist,
auto_download_artist=auto_download_artist,
)
except Exception as e: # noqa: BLE001
logger.error("Failed to record request history for %s: %s", musicbrainz_id, e)
raise ExternalServiceError(f"Failed to record request: {e}")
try:
enqueued = await self._request_queue.enqueue(musicbrainz_id)
if not enqueued:
return RequestAcceptedResponse(
success=True,
message="Request already in queue",
musicbrainz_id=musicbrainz_id,
status="pending",
)
except Exception as e: # noqa: BLE001
logger.error("Failed to enqueue album %s: %s", musicbrainz_id, e)
try:
from datetime import datetime, timezone
await self._request_history.async_update_status(
musicbrainz_id, "failed",
completed_at=datetime.now(timezone.utc).isoformat(),
)
except Exception: # noqa: BLE001
pass
raise ExternalServiceError(f"Failed to enqueue request: {e}")
return RequestAcceptedResponse(
success=True,
message="Request accepted",
musicbrainz_id=musicbrainz_id,
status="pending",
)
def get_queue_status(self) -> QueueStatusResponse:
status = self._request_queue.get_status()
return QueueStatusResponse(
queue_size=status["queue_size"],
processing=status["processing"],
active_workers=status.get("active_workers", 0),
max_workers=status.get("max_workers", 1),
)