feat: delay show rotation during live recording window

Decouple the like-window boundary (Wed 10pm ET) from when the system
rotates to a new show. NTR_SHOW_ROTATION_DELAY_HOURS=2 keeps the
previous week's show visible during the ~2 hour recording, then creates
the new show at midnight.

Made-with: Cursor
This commit is contained in:
cottongin
2026-04-01 21:29:42 -04:00
parent a328684af0
commit 82049ab47f
7 changed files with 102 additions and 5 deletions

View File

@@ -5,7 +5,7 @@ from fastapi import FastAPI, HTTPException, Depends, Header
from pydantic import BaseModel
from ntr_fetcher.db import Database
from ntr_fetcher.week import get_show_week
from ntr_fetcher.week import get_current_show_week
logger = logging.getLogger(__name__)
@@ -29,6 +29,7 @@ def create_app(
admin_token: str,
show_day: int = 2,
show_hour: int = 22,
rotation_delay_hours: float = 0,
web_user: str | None = None,
web_password: str | None = None,
secret_key: str | None = None,
@@ -44,7 +45,10 @@ def create_app(
def _current_show():
now = datetime.now(timezone.utc)
week_start, week_end = get_show_week(now, show_day=show_day, show_hour=show_hour)
week_start, week_end = get_current_show_week(
now, show_day=show_day, show_hour=show_hour,
rotation_delay_hours=rotation_delay_hours,
)
return db.get_or_create_show(week_start, week_end)
@app.get("/health")

View File

@@ -12,6 +12,7 @@ class Settings(BaseSettings):
soundcloud_user: str = "nicktherat"
show_day: int = 2
show_hour: int = 22
show_rotation_delay_hours: int = 0
web_user: str | None = None
web_password: str | None = None

View File

@@ -72,6 +72,7 @@ def run() -> None:
show_day=settings.show_day,
show_hour=settings.show_hour,
poll_interval=settings.poll_interval_seconds,
rotation_delay_hours=settings.show_rotation_delay_hours,
)
app = create_app(
@@ -80,6 +81,7 @@ def run() -> None:
admin_token=settings.admin_token,
show_day=settings.show_day,
show_hour=settings.show_hour,
rotation_delay_hours=settings.show_rotation_delay_hours,
web_user=settings.web_user,
web_password=settings.web_password,
secret_key=settings.secret_key,

View File

@@ -4,7 +4,7 @@ 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
from ntr_fetcher.week import get_current_show_week
logger = logging.getLogger(__name__)
@@ -18,6 +18,7 @@ class Poller:
show_day: int,
show_hour: int,
poll_interval: float,
rotation_delay_hours: float = 0,
):
self._db = db
self._sc = soundcloud
@@ -25,6 +26,7 @@ class Poller:
self._show_day = show_day
self._show_hour = show_hour
self._poll_interval = poll_interval
self._rotation_delay_hours = rotation_delay_hours
self._user_id: int | None = None
self.last_fetch: datetime | None = None
self.alive = True
@@ -37,7 +39,9 @@ class Poller:
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)
week_start, week_end = get_current_show_week(
now, self._show_day, self._show_hour, self._rotation_delay_hours,
)
show = self._db.get_or_create_show(week_start, week_end)
if show.episode_number is None:

View File

@@ -36,3 +36,23 @@ def get_show_week(
week_end_utc = (candidate + timedelta(days=7)).astimezone(timezone.utc).replace(tzinfo=timezone.utc)
return week_start_utc, week_end_utc
def get_current_show_week(
now_utc: datetime,
show_day: int = SHOW_DAY_DEFAULT,
show_hour: int = SHOW_HOUR_DEFAULT,
rotation_delay_hours: float = 0,
) -> tuple[datetime, datetime]:
"""Return the show week that should be treated as "current" right now.
When *rotation_delay_hours* > 0 the switchover to a new show is postponed
by that many hours after the like-window boundary. During the gap the
previous week's show remains current so the host can view it while
recording. Likes made during the gap are collected by the new show once
it rotates in.
"""
if rotation_delay_hours <= 0:
return get_show_week(now_utc, show_day, show_hour)
effective_now = now_utc - timedelta(hours=rotation_delay_hours)
return get_show_week(effective_now, show_day, show_hour)