This commit is contained in:
+132
-1
@@ -5,12 +5,16 @@ Provides endpoints for the web-based database manipulation interface
|
|||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import List, Optional, Dict, Any
|
from typing import List, Optional, Dict, Any
|
||||||
from fastapi import HTTPException, Query
|
from fastapi import HTTPException, Query, BackgroundTasks
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from api.models import *
|
from api.models import *
|
||||||
|
|
||||||
|
|
||||||
|
# Global status tracking for database population
|
||||||
|
_populate_status = {"running": False, "completed": False}
|
||||||
|
|
||||||
|
|
||||||
def map_source_to_description(source: str) -> str:
|
def map_source_to_description(source: str) -> str:
|
||||||
"""Map technical source codes to user-friendly descriptions"""
|
"""Map technical source codes to user-friendly descriptions"""
|
||||||
if not source or source == "no_valid_date_source":
|
if not source or source == "no_valid_date_source":
|
||||||
@@ -1242,6 +1246,111 @@ async def get_episode_date_options(dependencies: dict, imdb_id: str, season: int
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
def register_web_routes(app, dependencies):
|
||||||
"""Register all web API routes with FastAPI app"""
|
"""Register all web API routes with FastAPI app"""
|
||||||
from fastapi import Request, Response
|
from fastapi import Request, Response
|
||||||
@@ -1944,6 +2053,28 @@ def register_database_admin_routes(app, dependencies):
|
|||||||
"""Get schedule execution history"""
|
"""Get schedule execution history"""
|
||||||
return await get_schedule_executions(dependencies, schedule_id)
|
return await get_schedule_executions(dependencies, schedule_id)
|
||||||
|
|
||||||
|
# Database population endpoints
|
||||||
|
print("🔧 DEBUG: Registering /admin/populate-database endpoint...")
|
||||||
|
|
||||||
|
@app.post("/admin/populate-database")
|
||||||
|
async def api_populate_database(request: Request, background_tasks: BackgroundTasks):
|
||||||
|
"""Populate database from Radarr/Sonarr"""
|
||||||
|
print(f"🔥 DEBUG: populate-database endpoint called!")
|
||||||
|
try:
|
||||||
|
data = await request.json()
|
||||||
|
media_type = data.get("media_type", "both")
|
||||||
|
except Exception:
|
||||||
|
# Fallback to query parameter if JSON parsing fails
|
||||||
|
media_type = request.query_params.get("media_type", "both")
|
||||||
|
return await populate_database(background_tasks, media_type, dependencies)
|
||||||
|
|
||||||
|
print("✅ DEBUG: /admin/populate-database registered")
|
||||||
|
|
||||||
|
@app.get("/api/populate/status")
|
||||||
|
async def api_populate_status():
|
||||||
|
"""Get database population status"""
|
||||||
|
return await get_populate_status()
|
||||||
|
|
||||||
|
|
||||||
# Scheduled Scans Functions
|
# Scheduled Scans Functions
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>NFOGuard - Database Management</title>
|
<title>NFOGuard - Database Management</title>
|
||||||
<link rel="stylesheet" href="/static/css/styles.css?v=2.8.1-populate-fix">
|
<link rel="stylesheet" href="/static/css/styles.css?v=2.8.2-populate-fix2">
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<h1><i class="fas fa-shield-alt"></i> NFOGuard <span style="font-size: 0.5em; color: #888;">v2.8.1-populate-fix</span></h1>
|
<h1><i class="fas fa-shield-alt"></i> NFOGuard <span style="font-size: 0.5em; color: #888;">v2.8.2-populate-fix2</span></h1>
|
||||||
<p>Database Management & Reporting</p>
|
<p>Database Management & Reporting</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="auth-status" id="auth-status" style="display: none;">
|
<div class="auth-status" id="auth-status" style="display: none;">
|
||||||
@@ -711,6 +711,6 @@
|
|||||||
<!-- Toast Notifications -->
|
<!-- Toast Notifications -->
|
||||||
<div class="toast-container" id="toast-container"></div>
|
<div class="toast-container" id="toast-container"></div>
|
||||||
|
|
||||||
<script src="/static/js/app.js?v=2.8.1-populate-fix"></script>
|
<script src="/static/js/app.js?v=2.8.2-populate-fix2"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+2
-2
@@ -29,7 +29,7 @@ def create_web_app() -> FastAPI:
|
|||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="NFOGuard Web Interface",
|
title="NFOGuard Web Interface",
|
||||||
description="Web interface for NFOGuard media database management",
|
description="Web interface for NFOGuard media database management",
|
||||||
version="2.7.0-web",
|
version="2.8.2-populate-fix2",
|
||||||
docs_url=None, # Disable docs in production
|
docs_url=None, # Disable docs in production
|
||||||
redoc_url=None
|
redoc_url=None
|
||||||
)
|
)
|
||||||
@@ -94,7 +94,7 @@ def setup_static_files(app: FastAPI) -> None:
|
|||||||
"status": "healthy",
|
"status": "healthy",
|
||||||
"service": "nfoguard-web",
|
"service": "nfoguard-web",
|
||||||
"timestamp": time.time(),
|
"timestamp": time.time(),
|
||||||
"version": "2.8.0-web"
|
"version": "2.8.2-populate-fix2"
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|||||||
Reference in New Issue
Block a user