import asyncio import logging from datetime import datetime, timezone from ntr_fetcher.db import Database from ntr_fetcher.soundcloud import SoundCloudClient from ntr_fetcher.week import get_show_week logger = logging.getLogger(__name__) class Poller: def __init__( self, db: Database, soundcloud: SoundCloudClient, soundcloud_user: str, show_day: int, show_hour: int, poll_interval: float, ): self._db = db self._sc = soundcloud self._user = soundcloud_user self._show_day = show_day self._show_hour = show_hour self._poll_interval = poll_interval self._user_id: int | None = None self.last_fetch: datetime | None = None self.alive = True async def _get_user_id(self) -> int: if self._user_id is None: self._user_id = await self._sc.resolve_user(self._user) return self._user_id async def poll_once(self, full: bool = False) -> None: user_id = await self._get_user_id() now = datetime.now(timezone.utc) week_start, week_end = get_show_week(now, self._show_day, self._show_hour) show = self._db.get_or_create_show(week_start, week_end) if show.episode_number is None: latest = self._db.get_latest_episode_number() if latest is not None: new_ep = latest + 1 self._db.update_show_episode_number(show.id, new_ep) logger.info("Auto-assigned episode #%d to show %d", new_ep, show.id) tracks = await self._sc.fetch_likes( user_id=user_id, since=week_start, until=week_end, ) for track in tracks: self._db.upsert_track(track) track_ids = [t.id for t in tracks] self._db.set_show_tracks(show.id, track_ids) self.last_fetch = datetime.now(timezone.utc) logger.info("Fetched %d tracks for show %d", len(tracks), show.id) async def run_supervised(self, restart_delay: float = 30.0) -> None: while True: try: self.alive = True await self.poll_once() await asyncio.sleep(self._poll_interval) except asyncio.CancelledError: self.alive = False raise except Exception: self.alive = False logger.exception("Poller failed, restarting in %.1fs", restart_delay) await asyncio.sleep(restart_delay)