- Channel/Subscription/Video/ApiQuotaUsage models + migration 0002 - Synchronous YouTube Data API client with OAuth token refresh and per-call quota accounting (API key preferred for public reads when configured) - Subscription import: upsert channels + subscription links, prune unsubscribed, fetch channel details (uploads playlist, topics, stats, handle, country) - Central quota guard tracking units per US-Pacific day against a daily budget - POST /api/sync/subscriptions and GET /api/sync/status endpoints
40 lines
1.3 KiB
Python
40 lines
1.3 KiB
Python
from fastapi import APIRouter, Depends
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import quota
|
|
from app.auth import current_user
|
|
from app.db import get_db
|
|
from app.models import Channel, Subscription, User, Video
|
|
from app.sync.subscriptions import import_subscriptions
|
|
|
|
router = APIRouter(prefix="/api/sync", tags=["sync"])
|
|
|
|
|
|
@router.post("/subscriptions")
|
|
def sync_subscriptions(
|
|
user: User = Depends(current_user), db: Session = Depends(get_db)
|
|
) -> dict:
|
|
before = quota.units_used_today(db)
|
|
result = import_subscriptions(db, user)
|
|
result["quota_used_estimate"] = quota.units_used_today(db) - before
|
|
result["quota_remaining_today"] = quota.remaining_today(db)
|
|
return result
|
|
|
|
|
|
@router.get("/status")
|
|
def sync_status(
|
|
user: User = Depends(current_user), db: Session = Depends(get_db)
|
|
) -> dict:
|
|
sub_count = db.scalar(
|
|
select(func.count())
|
|
.select_from(Subscription)
|
|
.where(Subscription.user_id == user.id)
|
|
)
|
|
return {
|
|
"subscriptions": sub_count,
|
|
"channels_total": db.scalar(select(func.count()).select_from(Channel)),
|
|
"videos_total": db.scalar(select(func.count()).select_from(Video)),
|
|
"quota_used_today": quota.units_used_today(db),
|
|
"quota_remaining_today": quota.remaining_today(db),
|
|
}
|