From 6561738502da8899ac93d79521f1ff44e29b1a30 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 12 Jun 2026 00:00:50 +0200 Subject: [PATCH] feat(channels): kick recent backfill immediately on 'full history' opt-in When a user requests full history for a channel whose recent uploads aren't fetched yet, run a one-channel recent backfill synchronously in the request so the feed populates at once instead of waiting for the scheduler. Deep paging still follows on the scheduler (recent-then-deep). The deep-toggle mutation now also refreshes my-status and the feed. --- backend/app/routes/channels.py | 15 ++++++++++++++- frontend/src/components/Channels.tsx | 9 ++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/backend/app/routes/channels.py b/backend/app/routes/channels.py index b2338ce..d458670 100644 --- a/backend/app/routes/channels.py +++ b/backend/app/routes/channels.py @@ -8,6 +8,7 @@ from sqlalchemy.orm import Session from app.auth import current_user, has_write_scope from app.db import get_db from app.models import Channel, ChannelTag, Subscription, Tag, User, Video +from app.sync.runner import run_recent_backfill from app.youtube.client import YouTubeClient, YouTubeError router = APIRouter(prefix="/api/channels", tags=["channels"]) @@ -84,6 +85,8 @@ def update_channel( db: Session = Depends(get_db), ) -> dict: sub = _user_subscription(db, user, channel_id) + channel = db.get(Channel, channel_id) + deep_turned_on = False if "priority" in payload: sub.priority = int(payload["priority"]) if "hidden" in payload: @@ -92,13 +95,23 @@ def update_channel( # Opt this channel into (or out of) full-history backfill. The deep scheduler # picks the flag up on its next run; turning it off won't undo already-fetched # videos, it just stops further deep paging if nobody else still wants it. - sub.deep_requested = bool(payload["deep_requested"]) + want = bool(payload["deep_requested"]) + deep_turned_on = want and not sub.deep_requested + sub.deep_requested = want db.commit() + + # Opting a channel into full history should give an immediate feed: if we haven't even + # fetched its recent uploads yet, do that one channel now (cheap) instead of waiting for + # the scheduler. Deep paging still follows on the scheduler's next run (recent-then-deep). + if deep_turned_on and channel is not None and channel.recent_synced_at is None: + run_recent_backfill(db, [channel], max_channels=1) + return { "id": channel_id, "priority": sub.priority, "hidden": sub.hidden, "deep_requested": sub.deep_requested, + "recent_synced": channel.recent_synced_at is not None if channel else None, } diff --git a/frontend/src/components/Channels.tsx b/frontend/src/components/Channels.tsx index a9cb47b..d27bba0 100644 --- a/frontend/src/components/Channels.tsx +++ b/frontend/src/components/Channels.tsx @@ -44,7 +44,14 @@ export default function Channels({ id: string; body: { priority?: number; hidden?: boolean; deep_requested?: boolean }; }) => api.updateChannel(v.id, v.body), - onSuccess: () => qc.invalidateQueries({ queryKey: ["channels"] }), + // Requesting full history may have just pulled in a channel's recent uploads, so + // refresh the per-user status and feed too — not only the channel list. + onSuccess: () => { + qc.invalidateQueries({ queryKey: ["channels"] }); + qc.invalidateQueries({ queryKey: ["my-status"] }); + qc.invalidateQueries({ queryKey: ["feed"] }); + qc.invalidateQueries({ queryKey: ["feed-count"] }); + }, }); const attach = useMutation({ mutationFn: (v: { id: string; tagId: number }) => api.attachChannelTag(v.id, v.tagId),