Files
Lyra/worker/lyra_worker/monitor.py
T
2026-07-11 12:16:17 +02:00

77 lines
3.0 KiB
Python

from dataclasses import dataclass
from datetime import date, datetime
import psycopg
from lyra_worker.browser import MbBrowser
_TRUE = {"1", "true", "yes", "on"}
@dataclass(frozen=True)
class MonitorConfig:
enabled: bool = False
poll_interval_hours: int = 24
retry_interval_hours: int = 6
quality_cutoff: int = 2
upgrade_window_days: int = 14
@classmethod
def from_config(cls, config: dict) -> "MonitorConfig":
def _int(key: str, default: int) -> int:
try:
return int(config[key])
except (KeyError, TypeError, ValueError):
return default
return cls(
enabled=str(config.get("monitor.enabled", "")).strip().lower() in _TRUE,
poll_interval_hours=_int("monitor.pollIntervalHours", 24),
retry_interval_hours=_int("monitor.retryIntervalHours", 6),
quality_cutoff=_int("monitor.qualityCutoff", 2),
upgrade_window_days=_int("monitor.upgradeWindowDays", 14),
)
def _is_new(first_release_date: str, monitor_from: datetime) -> bool:
"""A release is 'new going forward' if its first-release date is after monitorFrom."""
if not first_release_date:
return False
try:
frd = date.fromisoformat(first_release_date[:10])
except ValueError:
return False
return frd > monitor_from.date()
def discover(conn: psycopg.Connection, browser: MbBrowser, cfg: MonitorConfig) -> int:
"""Poll each due watched artist; insert newly-seen release-groups. Returns #rows inserted."""
with conn.cursor() as cur:
cur.execute(
'SELECT id, mbid, name, "autoMonitorFuture", "monitorFrom" FROM "WatchedArtist" '
'WHERE "lastPolledAt" IS NULL '
' OR "lastPolledAt" < now() - make_interval(hours => %s)',
(cfg.poll_interval_hours,),
)
artists = cur.fetchall()
inserted = 0
for artist_id, mbid, name, auto_future, monitor_from in artists:
for rg in browser.browse_release_groups(mbid):
monitored = bool(auto_future) and _is_new(rg.first_release_date, monitor_from)
with conn.cursor() as cur:
cur.execute(
'INSERT INTO "MonitoredRelease" (id, "watchedArtistId", "artistMbid", '
'"artistName", "rgMbid", album, "primaryType", "secondaryTypes", '
'"firstReleaseDate", monitored, state, "createdAt") '
"VALUES (gen_random_uuid()::text, %s, %s, %s, %s, %s, %s, %s, %s, %s, 'wanted', now()) "
'ON CONFLICT ("rgMbid") DO NOTHING',
(artist_id, mbid, name, rg.rg_mbid, rg.title, rg.primary_type or None,
list(rg.secondary_types), rg.first_release_date or None, monitored),
)
inserted += cur.rowcount
with conn.cursor() as cur:
cur.execute('UPDATE "WatchedArtist" SET "lastPolledAt" = now() WHERE id = %s', (artist_id,))
conn.commit()
return inserted