tubewatch/playlist-monitor/app/api/system.py

163 lines
5.3 KiB
Python

"""
System API endpoints
"""
import logging
from typing import Dict, Any, List
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import func
from sqlalchemy.orm import Session
from ..core.database import get_db
from ..core.scheduler import scheduler_manager
from ..services.metube_client import MeTubeClient
from ..models.playlist import PlaylistSubscription
from ..models.video import VideoRecord, VideoStatus
from ..core.config import settings
logger = logging.getLogger(__name__)
router = APIRouter()
# Pydantic models for API responses
class SystemStatus(BaseModel):
"""System status response"""
total_playlists: int
active_playlists: int
total_videos: int
pending_downloads: int
active_downloads: int
completed_downloads: int
failed_downloads: int
skipped_downloads: int
metube_status: Dict[str, Any]
class SchedulerStatus(BaseModel):
"""Scheduler status response"""
running: bool
jobs: List[Dict[str, Any]]
class SyncResponse(BaseModel):
"""Sync response"""
status: str
synced_videos: int
message: str
@router.get("/status", response_model=SystemStatus)
async def get_system_status(db: Session = Depends(get_db)):
"""Get overall system status"""
try:
# Get playlist statistics
total_playlists = db.query(PlaylistSubscription).count()
active_playlists = db.query(PlaylistSubscription).filter(
PlaylistSubscription.enabled == True
).count()
# Get video statistics
total_videos = db.query(VideoRecord).count()
pending_downloads = db.query(VideoRecord).filter(
VideoRecord.status == VideoStatus.PENDING
).count()
active_downloads = db.query(VideoRecord).filter(
VideoRecord.status == VideoStatus.DOWNLOADING
).count()
completed_downloads = db.query(VideoRecord).filter(
VideoRecord.status == VideoStatus.COMPLETED
).count()
failed_downloads = db.query(VideoRecord).filter(
VideoRecord.status == VideoStatus.FAILED
).count()
skipped_downloads = db.query(VideoRecord).filter(
VideoRecord.status == VideoStatus.SKIPPED
).count()
# Check MeTube connection
metube_status = {
"connected": False,
"error": None
}
try:
# Create a temporary MeTube client for health check
client = MeTubeClient(settings.METUBE_URL)
await client.connect()
metube_status["connected"] = await client.health_check()
await client.disconnect()
except Exception as e:
metube_status["error"] = str(e)
logger.error(f"Error checking MeTube status: {e}")
return SystemStatus(
total_playlists=total_playlists,
active_playlists=active_playlists,
total_videos=total_videos,
pending_downloads=pending_downloads,
active_downloads=active_downloads,
completed_downloads=completed_downloads,
failed_downloads=failed_downloads,
skipped_downloads=skipped_downloads,
metube_status=metube_status
)
except Exception as e:
logger.error(f"Error getting system status: {e}")
raise HTTPException(status_code=500, detail=f"Error getting system status: {str(e)}")
@router.get("/scheduler/status", response_model=SchedulerStatus)
async def get_scheduler_status():
"""Get scheduler status and jobs"""
try:
running = scheduler_manager.scheduler and scheduler_manager.scheduler.running
jobs = scheduler_manager.get_all_jobs() if running else []
return SchedulerStatus(
running=running,
jobs=jobs
)
except Exception as e:
logger.error(f"Error getting scheduler status: {e}")
raise HTTPException(status_code=500, detail=f"Error getting scheduler status: {str(e)}")
@router.post("/sync-metube", response_model=SyncResponse)
async def sync_with_metube(db: Session = Depends(get_db)):
"""Manually sync video status with MeTube"""
try:
from ..services.video_service import VideoService
service = VideoService(db)
synced_count = await service.sync_with_metube()
return SyncResponse(
status="ok",
synced_videos=synced_count,
message=f"Successfully synced {synced_count} videos with MeTube"
)
except Exception as e:
logger.error(f"Error syncing with MeTube: {e}")
raise HTTPException(status_code=500, detail=f"Error syncing with MeTube: {str(e)}")
@router.get("/health")
async def health_check():
"""Simple health check endpoint"""
try:
# Basic health check - just return OK
# More detailed health checks are done in the main app's health endpoint
return {
"status": "healthy",
"service": "playlist-monitor",
"version": "0.1.0"
}
except Exception as e:
logger.error(f"Health check failed: {e}")
raise HTTPException(status_code=503, detail="Service unhealthy")