From 5305e327b3cfdf05905695d0bf6faec1a5e732e4 Mon Sep 17 00:00:00 2001 From: SBCrumb Date: Mon, 3 Nov 2025 10:37:04 -0500 Subject: [PATCH] web: populate link updates --- nfoguard-web/api/web_routes.py | 128 +++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 4 deletions(-) diff --git a/nfoguard-web/api/web_routes.py b/nfoguard-web/api/web_routes.py index 42d3b64..6c304a2 100644 --- a/nfoguard-web/api/web_routes.py +++ b/nfoguard-web/api/web_routes.py @@ -5,7 +5,7 @@ Provides endpoints for the web-based database manipulation interface import json from datetime import datetime, timezone from typing import List, Optional, Dict, Any -from fastapi import HTTPException, Query +from fastapi import HTTPException, Query, BackgroundTasks from pathlib import Path import sys @@ -14,6 +14,10 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from api.models import * +# Global status tracking for database population +_populate_status = {"running": False, "completed": False} + + def map_source_to_description(source: str) -> str: """Map technical source codes to user-friendly descriptions""" if not source or source == "no_valid_date_source": @@ -1018,12 +1022,117 @@ async def delete_movie(dependencies: dict, imdb_id: str): print(f"⚠️ Failed to add processing history: {e}") return {"success": True, "status": "success", "message": f"Deleted movie {imdb_id}"} - + except Exception as e: print(f"❌ Error deleting movie: {e}") raise HTTPException(status_code=500, detail=f"Failed to delete movie: {str(e)}") +async def populate_database(background_tasks: BackgroundTasks, media_type: str = "both", dependencies: dict = None): + """ + Populate NFOGuard database from Radarr/Sonarr sources + + Args: + background_tasks: FastAPI background tasks + media_type: Type of media to populate ("movies", "tv", or "both") + dependencies: Dictionary with db, radarr_client, sonarr_client + + Returns: + Status message indicating population has started + """ + from core.database_populator import DatabasePopulator + + db = dependencies["db"] + config = dependencies["config"] + + # Get Radarr and Sonarr clients + from clients.radarr_client import RadarrClient + from clients.sonarr_client import SonarrClient + + radarr_client = RadarrClient(config) + sonarr_client = SonarrClient(config) + + if media_type not in ["both", "movies", "tv"]: + raise HTTPException(status_code=400, detail="media_type must be 'both', 'movies', or 'tv'") + + # Create global status tracking + populate_status = { + "running": True, + "media_type": media_type, + "start_time": datetime.now().isoformat(), + "movies": {"status": "pending", "stats": None}, + "tv": {"status": "pending", "stats": None}, + "completed": False, + "error": None + } + + # Store status globally so it can be queried + global _populate_status + _populate_status = populate_status + + async def run_population(): + """Background task to populate the database""" + try: + populator = DatabasePopulator(db, radarr_client, sonarr_client) + + print(f"INFO: Starting database population: {media_type}") + + if media_type == "movies": + populate_status["movies"]["status"] = "running" + movie_stats = populator.populate_movies() + populate_status["movies"]["status"] = "completed" + populate_status["movies"]["stats"] = movie_stats + print(f"INFO: Movie population completed: {movie_stats}") + + elif media_type == "tv": + populate_status["tv"]["status"] = "running" + tv_stats = populator.populate_tv_episodes() + populate_status["tv"]["status"] = "completed" + populate_status["tv"]["stats"] = tv_stats + print(f"INFO: TV population completed: {tv_stats}") + + elif media_type == "both": + populate_status["movies"]["status"] = "running" + movie_stats = populator.populate_movies() + populate_status["movies"]["status"] = "completed" + populate_status["movies"]["stats"] = movie_stats + print(f"INFO: Movie population completed: {movie_stats}") + + populate_status["tv"]["status"] = "running" + tv_stats = populator.populate_tv_episodes() + populate_status["tv"]["status"] = "completed" + populate_status["tv"]["stats"] = tv_stats + print(f"INFO: TV population completed: {tv_stats}") + + populate_status["completed"] = True + populate_status["running"] = False + print("INFO: Database population completed successfully") + + except Exception as e: + print(f"ERROR: Database population failed: {e}") + populate_status["error"] = str(e) + populate_status["running"] = False + populate_status["completed"] = True + + # Add task to background + background_tasks.add_task(run_population) + + print(f"INFO: Database population started for: {media_type}") + return { + "status": "started", + "media_type": media_type, + "message": f"Database population started for {media_type}" + } + + +async def get_populate_status(): + """Get the current status of database population""" + global _populate_status + if '_populate_status' not in globals(): + return {"running": False, "completed": False} + return _populate_status + + def register_web_routes(app, dependencies): """Register all web API routes with FastAPI app""" from fastapi import Request, Response @@ -1147,11 +1256,22 @@ def register_web_routes(app, dependencies): response.delete_cookie("nfoguard_session") return {"status": "logged_out", "message": "Session cleared"} - + + # Database population endpoints + @app.post("/admin/populate-database") + async def api_populate_database(background_tasks: BackgroundTasks, media_type: str = "both"): + """Populate database from Radarr/Sonarr""" + return await populate_database(background_tasks, media_type, dependencies) + + @app.get("/api/populate/status") + async def api_populate_status(): + """Get database population status""" + return await get_populate_status() + # Health endpoint @app.get("/health") async def health_check(): """Health check endpoint for container monitoring""" return {"status": "healthy", "service": "nfoguard-web"} - + print("✅ Web routes registered successfully") \ No newline at end of file