diff --git a/api/routes.py b/api/routes.py index 36de384..856a54e 100644 --- a/api/routes.py +++ b/api/routes.py @@ -2278,71 +2278,63 @@ def register_routes(app, dependencies: dict): # # Web interface available on separate container port 8081 @app.get("/admin/nfo-repair-scan") - async def nfo_repair_scan(dependencies: dict): - """Scan filesystem for episodes/movies missing dateadded elements in NFO files""" - from nfoguard.utils.db_utils import get_db_connection - import os - import xml.etree.ElementTree as ET + async def _nfo_repair_scan(): + return await nfo_repair_scan(dependencies) + +async def nfo_repair_scan(dependencies: dict): + """Scan filesystem for episodes/movies missing dateadded elements in NFO files""" + from nfoguard.utils.db_utils import get_db_connection + import os + import xml.etree.ElementTree as ET + + logger = dependencies.get("logger") + config = dependencies.get("config") + + if not logger or not config: + raise HTTPException(status_code=500, detail="Dependencies not available") + + logger.info("🔧 Starting NFO repair scan from core container") + + missing_items = { + "episodes": [], + "movies": [] + } + + try: + # Get database connection + db_conn = get_db_connection(config) + if not db_conn: + raise HTTPException(status_code=500, detail="Database connection failed") - logger = dependencies.get("logger") - config = dependencies.get("config") + # Scan episodes + logger.info("📺 Scanning episodes for missing dateadded elements") + episode_query = """ + SELECT DISTINCT imdb_id, season, episode, series_name, episode_name, dateadded + FROM episodes + WHERE dateadded IS NOT NULL + ORDER BY imdb_id, season, episode + """ - if not logger or not config: - raise HTTPException(status_code=500, detail="Dependencies not available") + episodes = db_conn.fetch_all(episode_query) + logger.info(f"📊 Found {len(episodes)} episodes in database") - logger.info("🔧 Starting NFO repair scan from core container") - - missing_items = { - "episodes": [], - "movies": [] - } - - try: - # Get database connection - db_conn = get_db_connection(config) - if not db_conn: - raise HTTPException(status_code=500, detail="Database connection failed") + for episode in episodes: + # Build NFO path + nfo_path = os.path.join( + config.tv_library_path, + episode["series_name"], + f"Season {episode['season']:02d}", + f"S{episode['season']:02d}E{episode['episode']:02d}.nfo" + ) - # Scan episodes - logger.info("📺 Scanning episodes for missing dateadded elements") - episode_query = """ - SELECT DISTINCT imdb_id, season, episode, series_name, episode_name, dateadded - FROM episodes - WHERE dateadded IS NOT NULL - ORDER BY imdb_id, season, episode - """ - - episodes = db_conn.fetch_all(episode_query) - logger.info(f"📊 Found {len(episodes)} episodes in database") - - for episode in episodes: - # Build NFO path - nfo_path = os.path.join( - config.tv_library_path, - episode["series_name"], - f"Season {episode['season']:02d}", - f"S{episode['season']:02d}E{episode['episode']:02d}.nfo" - ) - - # Check if NFO file exists and has dateadded - if os.path.exists(nfo_path): - try: - tree = ET.parse(nfo_path) - root = tree.getroot() - dateadded_elem = root.find("dateadded") - - if dateadded_elem is None or not dateadded_elem.text: - missing_items["episodes"].append({ - "imdb_id": episode["imdb_id"], - "season": episode["season"], - "episode": episode["episode"], - "series_name": episode["series_name"], - "episode_name": episode["episode_name"], - "dateadded": episode["dateadded"], - "nfo_path": nfo_path - }) - except ET.ParseError as e: - logger.warning(f"⚠️ Could not parse NFO file {nfo_path}: {e}") + # Check if NFO file exists and has dateadded + if os.path.exists(nfo_path): + try: + tree = ET.parse(nfo_path) + root = tree.getroot() + dateadded_elem = root.find("dateadded") + + if dateadded_elem is None or not dateadded_elem.text: missing_items["episodes"].append({ "imdb_id": episode["imdb_id"], "season": episode["season"], @@ -2350,70 +2342,81 @@ def register_routes(app, dependencies: dict): "series_name": episode["series_name"], "episode_name": episode["episode_name"], "dateadded": episode["dateadded"], - "nfo_path": nfo_path, - "error": f"Parse error: {str(e)}" + "nfo_path": nfo_path }) + except ET.ParseError as e: + logger.warning(f"⚠️ Could not parse NFO file {nfo_path}: {e}") + missing_items["episodes"].append({ + "imdb_id": episode["imdb_id"], + "season": episode["season"], + "episode": episode["episode"], + "series_name": episode["series_name"], + "episode_name": episode["episode_name"], + "dateadded": episode["dateadded"], + "nfo_path": nfo_path, + "error": f"Parse error: {str(e)}" + }) + + # Scan movies + logger.info("🎬 Scanning movies for missing dateadded elements") + movie_query = """ + SELECT DISTINCT imdb_id, title, dateadded + FROM movies + WHERE dateadded IS NOT NULL + ORDER BY title + """ + + movies = db_conn.fetch_all(movie_query) + logger.info(f"📊 Found {len(movies)} movies in database") + + for movie in movies: + # Build NFO path + nfo_path = os.path.join( + config.movie_library_path, + movie["title"], + f"{movie['title']}.nfo" + ) - # Scan movies - logger.info("🎬 Scanning movies for missing dateadded elements") - movie_query = """ - SELECT DISTINCT imdb_id, title, dateadded - FROM movies - WHERE dateadded IS NOT NULL - ORDER BY title - """ - - movies = db_conn.fetch_all(movie_query) - logger.info(f"📊 Found {len(movies)} movies in database") - - for movie in movies: - # Build NFO path - nfo_path = os.path.join( - config.movie_library_path, - movie["title"], - f"{movie['title']}.nfo" - ) - - # Check if NFO file exists and has dateadded - if os.path.exists(nfo_path): - try: - tree = ET.parse(nfo_path) - root = tree.getroot() - dateadded_elem = root.find("dateadded") - - if dateadded_elem is None or not dateadded_elem.text: - missing_items["movies"].append({ - "imdb_id": movie["imdb_id"], - "title": movie["title"], - "dateadded": movie["dateadded"], - "nfo_path": nfo_path - }) - except ET.ParseError as e: - logger.warning(f"⚠️ Could not parse NFO file {nfo_path}: {e}") + # Check if NFO file exists and has dateadded + if os.path.exists(nfo_path): + try: + tree = ET.parse(nfo_path) + root = tree.getroot() + dateadded_elem = root.find("dateadded") + + if dateadded_elem is None or not dateadded_elem.text: missing_items["movies"].append({ "imdb_id": movie["imdb_id"], "title": movie["title"], "dateadded": movie["dateadded"], - "nfo_path": nfo_path, - "error": f"Parse error: {str(e)}" + "nfo_path": nfo_path }) - - db_conn.close() - - total_missing = len(missing_items["episodes"]) + len(missing_items["movies"]) - logger.info(f"✅ NFO repair scan complete: {total_missing} items missing dateadded elements") - - return { - "status": "success", - "total_missing": total_missing, - "episodes_missing": len(missing_items["episodes"]), - "movies_missing": len(missing_items["movies"]), - "missing_items": missing_items - } - - except Exception as e: - logger.error(f"❌ Error during NFO repair scan: {str(e)}") - raise HTTPException(status_code=500, detail=f"NFO repair scan failed: {str(e)}") + except ET.ParseError as e: + logger.warning(f"⚠️ Could not parse NFO file {nfo_path}: {e}") + missing_items["movies"].append({ + "imdb_id": movie["imdb_id"], + "title": movie["title"], + "dateadded": movie["dateadded"], + "nfo_path": nfo_path, + "error": f"Parse error: {str(e)}" + }) + + db_conn.close() + + total_missing = len(missing_items["episodes"]) + len(missing_items["movies"]) + logger.info(f"✅ NFO repair scan complete: {total_missing} items missing dateadded elements") + + return { + "status": "success", + "total_missing": total_missing, + "episodes_missing": len(missing_items["episodes"]), + "movies_missing": len(missing_items["movies"]), + "missing_items": missing_items + } + + except Exception as e: + logger.error(f"❌ Error during NFO repair scan: {str(e)}") + raise HTTPException(status_code=500, detail=f"NFO repair scan failed: {str(e)}") # --------------------------- # Core API - No Web Interface