feat: sync status indicator, admin pause/resume, filtered video count

- Header shows a live sync status (total videos + channels still backfilling, or
  "paused"), polled every 30s
- Admins can pause/resume the background sync; a paused flag in app_state makes
  scheduled jobs skip (migration 0006)
- GET /api/feed/count returns the number of videos matching the current filters;
  shared filter builder keeps it in sync with /api/feed; shown above the feed
- /api/sync/status reports backfill progress, pending enrichment and paused state
This commit is contained in:
npeter83 2026-06-11 04:15:25 +02:00
parent f73cbdb490
commit dc73b43b71
10 changed files with 298 additions and 69 deletions

View file

@ -1,8 +1,8 @@
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import func, select
from sqlalchemy.orm import Session
from app import quota
from app import quota, state
from app.auth import current_user
from app.db import get_db
from app.models import Channel, Subscription, User, Video
@ -79,7 +79,35 @@ def sync_status(
return {
"subscriptions": sub_count,
"channels_total": db.scalar(select(func.count()).select_from(Channel)),
"channels_backfilling": db.scalar(
select(func.count()).select_from(Channel).where(Channel.backfill_done.is_(False))
),
"videos_total": db.scalar(select(func.count()).select_from(Video)),
"pending_enrich": db.scalar(
select(func.count()).select_from(Video).where(Video.enriched_at.is_(None))
),
"quota_used_today": quota.units_used_today(db),
"quota_remaining_today": quota.remaining_today(db),
"paused": state.is_sync_paused(db),
"is_admin": user.role == "admin",
}
@router.post("/pause")
def pause_sync(
user: User = Depends(current_user), db: Session = Depends(get_db)
) -> dict:
if user.role != "admin":
raise HTTPException(status_code=403, detail="Admin only")
state.set_sync_paused(db, True)
return {"paused": True}
@router.post("/resume")
def resume_sync(
user: User = Depends(current_user), db: Session = Depends(get_db)
) -> dict:
if user.role != "admin":
raise HTTPException(status_code=403, detail="Admin only")
state.set_sync_paused(db, False)
return {"paused": False}