feat: add historical backfill with --init CLI and episode numbering

Adds a --init mode that seeds the database with past shows from a given
anchor episode/date forward, batch-fetching likes from SoundCloud and
partitioning them into weekly buckets. Episode numbers are tracked in
the shows table and auto-incremented by the poller for new shows.

Includes full API documentation (docs/api.md) and updated README.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-12 02:09:15 -04:00
parent c88826ac4d
commit cb3ae403cf
14 changed files with 922 additions and 21 deletions

View File

@@ -1,9 +1,12 @@
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
@@ -16,13 +19,51 @@ logging.basicConfig(
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,