import argparse import asyncio import logging from datetime import date import uvicorn from ntr_fetcher.api import create_app from ntr_fetcher.backfill import run_backfill from ntr_fetcher.config import Settings from ntr_fetcher.db import Database from ntr_fetcher.poller import Poller from ntr_fetcher.soundcloud import SoundCloudClient logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s", ) logger = logging.getLogger(__name__) def _parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="NtR SoundCloud Fetcher") parser.add_argument( "--init", action="store_true", help="Run historical backfill instead of starting the server", ) parser.add_argument( "--show", type=int, help="Anchor episode number (required with --init)", ) parser.add_argument( "--aired", type=date.fromisoformat, help="Air date of anchor episode as YYYY-MM-DD (required with --init)", ) args = parser.parse_args() if args.init and (args.show is None or args.aired is None): parser.error("--init requires both --show and --aired") return args def run() -> None: args = _parse_args() settings = Settings() db = Database(settings.db_path) db.initialize() logger.info("Database initialized at %s", settings.db_path) if args.init: sc = SoundCloudClient() asyncio.run( run_backfill( db=db, soundcloud=sc, soundcloud_user=settings.soundcloud_user, show_day=settings.show_day, show_hour=settings.show_hour, anchor_episode=args.show, anchor_aired=args.aired, ) ) asyncio.run(sc.close()) logger.info("Backfill complete") return sc = SoundCloudClient() poller = Poller( db=db, soundcloud=sc, soundcloud_user=settings.soundcloud_user, show_day=settings.show_day, show_hour=settings.show_hour, poll_interval=settings.poll_interval_seconds, ) app = create_app( db=db, poller=poller, admin_token=settings.admin_token, show_day=settings.show_day, show_hour=settings.show_hour, ) @app.on_event("startup") async def start_poller(): logger.info("Starting poller (interval=%ds)", settings.poll_interval_seconds) asyncio.create_task(poller.run_supervised()) @app.on_event("shutdown") async def shutdown(): logger.info("Shutting down") await sc.close() uvicorn.run(app, host=settings.host, port=settings.port) if __name__ == "__main__": run()