Channel features: subscribers, new-videos badges, activity-driven sync

- Store subscriber count from YouTube statistics and show it on channel page
- Sync 50 videos per channel with playlistItems pagination support
- Show per-channel and per-category new-videos counters (2-day window)
- Replace hourly videos sync with activity trigger (2h idle) and
  incremental backfill (hard cap 200 per channel)
- Clicking the sidebar new-videos count filters the category feed to
  recent videos only (new_only)
- Update agent-team docs: deploy after green checks
This commit is contained in:
vrubelroman 2026-09-17 21:07:33 +00:00
parent fde9a439df
commit e10df8dcbd
27 changed files with 1420 additions and 107 deletions

View file

@ -1,10 +1,11 @@
import base64
from datetime import datetime, timezone
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import func, or_, select
from sqlalchemy.orm import Session
from app.config import settings
from app.core.auth_dependency import require_session
from app.db import get_db
from app.models.channel import Channel
@ -80,6 +81,7 @@ def get_feed(
channel_id: int | None = None,
downloaded: bool = False,
search: str | None = Query(None, max_length=200),
new_only: bool = False,
limit: int = Query(DEFAULT_LIMIT, ge=1, le=MAX_LIMIT),
cursor: str | None = None,
db: Session = Depends(get_db),
@ -97,6 +99,15 @@ def get_feed(
)
query = query.filter(Video.channel_id.in_(channel_ids_in_category))
if new_only:
since = datetime.now(timezone.utc) - timedelta(days=settings.new_videos_window_days)
query = query.filter(Video.published_at >= since)
# Align with the sidebar badge count (categories.py), which only
# counts subscribed channels: after unsubscribing, a channel's
# fresh videos must disappear from "new only" too.
subscribed_channel_ids = select(Channel.id).where(Channel.subscribed.is_(True))
query = query.filter(Video.channel_id.in_(subscribed_channel_ids))
if downloaded:
query = query.filter(Video.id.in_(_completed_video_ids()))