diff --git a/api/routes.py b/api/routes.py index 3857ba3..e049bac 100644 --- a/api/routes.py +++ b/api/routes.py @@ -2277,63 +2277,71 @@ def register_routes(app, dependencies: dict): # - Health checks (/health) # # Web interface available on separate container port 8081 - @app.get("/admin/nfo-repair-scan") - 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""" - import os - import xml.etree.ElementTree as ET - logger = dependencies.get("logger") - config = dependencies.get("config") - db = dependencies.get("db") - - if not logger or not config or not db: - raise HTTPException(status_code=500, detail="Dependencies not available") - - logger.info("🔧 Starting NFO repair scan from core container") - - missing_items = { - "episodes": [], - "movies": [] - } - - try: - # 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 - """ + async def nfo_repair_scan(): + """Scan filesystem for episodes/movies missing dateadded elements in NFO files""" + import os + import xml.etree.ElementTree as ET - with db.get_connection() as conn: - cursor = conn.cursor() - cursor.execute(episode_query) - episodes = [dict(row) for row in cursor.fetchall()] - - logger.info(f"📊 Found {len(episodes)} episodes in database") + logger = dependencies.get("logger") + config = dependencies.get("config") + db = dependencies.get("db") - 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" - ) + if not logger or not config or not db: + raise HTTPException(status_code=500, detail="Dependencies not available") + + logger.info("🔧 Starting NFO repair scan from core container") + + missing_items = { + "episodes": [], + "movies": [] + } + + try: + # 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 + """ - # 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: + with db.get_connection() as conn: + cursor = conn.cursor() + cursor.execute(episode_query) + episodes = [dict(row) for row in cursor.fetchall()] + + 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}") missing_items["episodes"].append({ "imdb_id": episode["imdb_id"], "season": episode["season"], @@ -2341,83 +2349,76 @@ async def nfo_repair_scan(dependencies: dict): "series_name": episode["series_name"], "episode_name": episode["episode_name"], "dateadded": episode["dateadded"], - "nfo_path": nfo_path + "nfo_path": nfo_path, + "error": f"Parse error: {str(e)}" }) - 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 - """ - - with db.get_connection() as conn: - cursor = conn.cursor() - cursor.execute(movie_query) - movies = [dict(row) for row in cursor.fetchall()] + # 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 + """ - logger.info(f"📊 Found {len(movies)} movies in database") + with db.get_connection() as conn: + cursor = conn.cursor() + cursor.execute(movie_query) + movies = [dict(row) for row in cursor.fetchall()] + + 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: + 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}") missing_items["movies"].append({ "imdb_id": movie["imdb_id"], "title": movie["title"], "dateadded": movie["dateadded"], - "nfo_path": nfo_path + "nfo_path": nfo_path, + "error": f"Parse error: {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)}" - }) - - 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)}") + + 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)}") + + @app.get("/admin/nfo-repair-scan") + async def _nfo_repair_scan(): + return await nfo_repair_scan() # --------------------------- # Core API - No Web Interface