2026-03-12 02:09:15 -04:00
|
|
|
import argparse
|
2026-03-12 01:41:16 -04:00
|
|
|
import asyncio
|
|
|
|
|
import logging
|
2026-03-12 02:09:15 -04:00
|
|
|
from datetime import date
|
2026-03-12 01:41:16 -04:00
|
|
|
|
|
|
|
|
import uvicorn
|
|
|
|
|
|
|
|
|
|
from ntr_fetcher.api import create_app
|
2026-03-12 02:09:15 -04:00
|
|
|
from ntr_fetcher.backfill import run_backfill
|
2026-03-12 01:41:16 -04:00
|
|
|
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__)
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 02:09:15 -04:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 01:16:16 -04:00
|
|
|
def run() -> None:
|
2026-03-12 02:09:15 -04:00
|
|
|
args = _parse_args()
|
2026-03-12 01:41:16 -04:00
|
|
|
settings = Settings()
|
|
|
|
|
|
|
|
|
|
db = Database(settings.db_path)
|
|
|
|
|
db.initialize()
|
|
|
|
|
logger.info("Database initialized at %s", settings.db_path)
|
|
|
|
|
|
2026-03-12 02:09:15 -04:00
|
|
|
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
|
|
|
|
|
|
2026-03-12 01:41:16 -04:00
|
|
|
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,
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-12 01:46:23 -04:00
|
|
|
app = create_app(
|
|
|
|
|
db=db,
|
|
|
|
|
poller=poller,
|
|
|
|
|
admin_token=settings.admin_token,
|
|
|
|
|
show_day=settings.show_day,
|
|
|
|
|
show_hour=settings.show_hour,
|
|
|
|
|
)
|
2026-03-12 01:41:16 -04:00
|
|
|
|
|
|
|
|
@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()
|